1/*
2 * Copyright 2013-2014, Stephan A��mus <superstippi@gmx.de>.
3 * Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7#include "SharedBitmap.h"
8
9#include <algorithm>
10
11#include <Application.h>
12#include <Bitmap.h>
13#include <DataIO.h>
14#include <IconUtils.h>
15#include <Message.h>
16#include <MimeType.h>
17#include <Resources.h>
18#include <TranslationUtils.h>
19
20#include "Logger.h"
21
22#include "support.h"
23
24
25SharedBitmap::SharedBitmap(BBitmap* bitmap)
26	:
27	BReferenceable(),
28	fResourceID(-1),
29	fBuffer(NULL),
30	fSize(0),
31	fMimeType()
32{
33	fBitmap[0] = bitmap;
34	fBitmap[1] = NULL;
35	fBitmap[2] = NULL;
36	fBitmap[3] = NULL;
37}
38
39
40SharedBitmap::SharedBitmap(int32 resourceID)
41	:
42	BReferenceable(),
43	fResourceID(resourceID),
44	fBuffer(NULL),
45	fSize(0),
46	fMimeType()
47{
48	fBitmap[0] = NULL;
49	fBitmap[1] = NULL;
50	fBitmap[2] = NULL;
51	fBitmap[3] = NULL;
52}
53
54
55SharedBitmap::SharedBitmap(const char* mimeType)
56	:
57	BReferenceable(),
58	fResourceID(-1),
59	fBuffer(NULL),
60	fSize(0),
61	fMimeType(mimeType)
62{
63	fBitmap[0] = NULL;
64	fBitmap[1] = NULL;
65	fBitmap[2] = NULL;
66	fBitmap[3] = NULL;
67}
68
69
70SharedBitmap::SharedBitmap(BPositionIO& data)
71	:
72	BReferenceable(),
73	fResourceID(-1),
74	fBuffer(NULL),
75	fSize(0),
76	fMimeType()
77{
78	off_t size;
79	if (data.GetSize(&size) == B_OK) {
80		data.Seek(0, SEEK_SET);
81		_InitWithData(data, size);
82	}
83	fBitmap[0] = NULL;
84	fBitmap[1] = NULL;
85	fBitmap[2] = NULL;
86	fBitmap[3] = NULL;
87}
88
89SharedBitmap::SharedBitmap(BDataIO& data, size_t size)
90	:
91	BReferenceable(),
92	fResourceID(-1),
93	fBuffer(NULL),
94	fSize(0),
95	fMimeType()
96{
97	_InitWithData(data, size);
98}
99
100
101SharedBitmap::~SharedBitmap()
102{
103	delete fBitmap[0];
104	delete fBitmap[1];
105	delete fBitmap[2];
106	delete fBitmap[3];
107	delete[] fBuffer;
108}
109
110
111void
112SharedBitmap::_InitWithData(BDataIO& data, size_t size)
113{
114	fSize = size;
115	const off_t kMaxSize = 1024 * 1024;
116	if (size > 0 && size <= kMaxSize) {
117		fBuffer = new(std::nothrow) uint8[size];
118		if (fBuffer != NULL) {
119			if (data.ReadExactly(fBuffer, size) == B_OK)
120				fSize = size;
121			else {
122				delete[] fBuffer;
123				fBuffer = NULL;
124			}
125		}
126	} else {
127		HDERROR("image data too large to deal with; %" B_PRIi64
128			", max: %" B_PRIi64, fSize, kMaxSize);
129	}
130
131	fBitmap[0] = NULL;
132	fBitmap[1] = NULL;
133	fBitmap[2] = NULL;
134	fBitmap[3] = NULL;
135}
136
137
138const BBitmap*
139SharedBitmap::Bitmap(BitmapSize which)
140{
141	if (fResourceID == -1 && fMimeType.Length() == 0 && fBuffer == NULL)
142		return fBitmap[0];
143
144	int32 index = 0;
145	int32 size = 16;
146
147	switch (which) {
148		default:
149		case BITMAP_SIZE_16:
150			break;
151
152		case BITMAP_SIZE_22:
153			index = 1;
154			size = 22;
155			break;
156
157		case BITMAP_SIZE_32:
158			index = 2;
159			size = 32;
160			break;
161
162		case BITMAP_SIZE_64:
163			index = 3;
164			size = 64;
165			break;
166	}
167
168	if (fBitmap[index] == NULL) {
169		if (fResourceID >= 0)
170			fBitmap[index] = _CreateBitmapFromResource(size);
171		else if (fBuffer != NULL)
172			fBitmap[index] = _CreateBitmapFromBuffer(size);
173		else if (fMimeType.Length() > 0)
174			fBitmap[index] = _CreateBitmapFromMimeType(size);
175	}
176
177	return fBitmap[index];
178}
179
180
181BBitmap*
182SharedBitmap::_CreateBitmapFromResource(int32 size) const
183{
184	BResources resources;
185	status_t status = get_app_resources(resources);
186	if (status != B_OK)
187		return NULL;
188
189	size_t dataSize;
190	const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE, fResourceID,
191		&dataSize);
192	if (data != NULL)
193		return _LoadIconFromBuffer(data, dataSize, size);
194
195	data = resources.LoadResource(B_MESSAGE_TYPE, fResourceID, &dataSize);
196	if (data != NULL)
197		return _LoadBitmapFromBuffer(data, dataSize);
198
199	return NULL;
200}
201
202
203BBitmap*
204SharedBitmap::_CreateBitmapFromBuffer(int32 size) const
205{
206	BBitmap* bitmap = _LoadIconFromBuffer(fBuffer, fSize, size);
207
208	if (bitmap == NULL)
209		bitmap = _LoadBitmapFromBuffer(fBuffer, fSize);
210
211	return bitmap;
212}
213
214
215BBitmap*
216SharedBitmap::_CreateBitmapFromMimeType(int32 size) const
217{
218	BMimeType mimeType(fMimeType.String());
219	status_t status = mimeType.InitCheck();
220	if (status != B_OK)
221		return NULL;
222
223	BBitmap* bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
224	status = bitmap->InitCheck();
225	if (status == B_OK)
226		status = mimeType.GetIcon(bitmap, B_MINI_ICON);
227
228	if (status != B_OK) {
229		delete bitmap;
230		bitmap = NULL;
231	}
232
233	return bitmap;
234}
235
236
237BBitmap*
238SharedBitmap::_LoadBitmapFromBuffer(const void* buffer, size_t size) const
239{
240	BMemoryIO stream(buffer, size);
241
242	// Try to read as an archived bitmap.
243	BBitmap* bitmap = _LoadArchivedBitmapFromStream(stream);
244
245	if (bitmap == NULL) {
246		// Try to read as a translator bitmap
247		stream.Seek(0, SEEK_SET);
248		bitmap = _LoadTranslatorBitmapFromStream(stream);
249	}
250
251	if (bitmap != NULL) {
252		status_t status = bitmap->InitCheck();
253		if (status != B_OK) {
254			delete bitmap;
255			bitmap = NULL;
256		}
257	}
258
259	return bitmap;
260}
261
262
263BBitmap*
264SharedBitmap::_LoadArchivedBitmapFromStream(BPositionIO& stream) const
265{
266	BMessage archive;
267	status_t status = archive.Unflatten(&stream);
268	if (status != B_OK)
269		return NULL;
270
271	return new BBitmap(&archive);
272}
273
274
275BBitmap*
276SharedBitmap::_LoadTranslatorBitmapFromStream(BPositionIO& stream) const
277{
278	return BTranslationUtils::GetBitmap(&stream);
279}
280
281
282BBitmap*
283SharedBitmap::_LoadIconFromBuffer(const void* data, size_t dataSize,
284	int32 size) const
285{
286	BBitmap* bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0,
287		B_RGBA32);
288	status_t status = bitmap->InitCheck();
289	if (status == B_OK) {
290		status = BIconUtils::GetVectorIcon(
291			reinterpret_cast<const uint8*>(data), dataSize, bitmap);
292	};
293
294	if (status != B_OK) {
295		delete bitmap;
296		bitmap = NULL;
297	}
298
299	return bitmap;
300}
301
302