xref: /haiku/src/apps/haikudepot/model/PackageIconTarRepository.cpp (revision 66ee6532aab036bee121141274257aab39ddbd67)
1f0e491d3SAndrew Lindesay /*
2*66ee6532SAndrew Lindesay  * Copyright 2020-2024, Andrew Lindesay <apl@lindesay.co.nz>.
3f0e491d3SAndrew Lindesay  * All rights reserved. Distributed under the terms of the MIT License.
4f0e491d3SAndrew Lindesay  */
5f0e491d3SAndrew Lindesay #include "PackageIconTarRepository.h"
6f0e491d3SAndrew Lindesay 
7f0e491d3SAndrew Lindesay #include <AutoDeleter.h>
8*66ee6532SAndrew Lindesay #include <Autolock.h>
9f0e491d3SAndrew Lindesay #include <File.h>
10*66ee6532SAndrew Lindesay #include <IconUtils.h>
113538133fSAndrew Lindesay #include <StopWatch.h>
12*66ee6532SAndrew Lindesay #include <TranslationUtils.h>
13f0e491d3SAndrew Lindesay 
14*66ee6532SAndrew Lindesay #include "DataIOUtils.h"
15f0e491d3SAndrew Lindesay #include "Logger.h"
16f0e491d3SAndrew Lindesay #include "TarArchiveService.h"
17f0e491d3SAndrew Lindesay 
18f0e491d3SAndrew Lindesay 
19027d6086SAndrew Lindesay #define LIMIT_ICON_CACHE 50
20*66ee6532SAndrew Lindesay #define ICON_BUFFER_SIZE_INITIAL 4096
21*66ee6532SAndrew Lindesay #define ICON_BUFFER_SIZE_MAX 32768
22f0e491d3SAndrew Lindesay 
23f0e491d3SAndrew Lindesay 
24f0e491d3SAndrew Lindesay /*!	An instance of this class can be provided to the TarArchiveService to
25f0e491d3SAndrew Lindesay 	be called each time a tar entry is found.  This way it is able to capture
26f0e491d3SAndrew Lindesay 	the offsets of the icons in the tar file against the package names.
27f0e491d3SAndrew Lindesay */
28f0e491d3SAndrew Lindesay 
29f0e491d3SAndrew Lindesay class IconTarPtrEntryListener : public TarEntryListener
30f0e491d3SAndrew Lindesay {
31f0e491d3SAndrew Lindesay public:
32f0e491d3SAndrew Lindesay 								IconTarPtrEntryListener(
33f0e491d3SAndrew Lindesay 									PackageIconTarRepository*
34f0e491d3SAndrew Lindesay 									fPackageIconTarRepository);
35f0e491d3SAndrew Lindesay 	virtual						~IconTarPtrEntryListener();
36f0e491d3SAndrew Lindesay 
37f0e491d3SAndrew Lindesay 	virtual status_t			Handle(
38f0e491d3SAndrew Lindesay 									const TarArchiveHeader& header,
39f0e491d3SAndrew Lindesay 									size_t offset,
40f0e491d3SAndrew Lindesay 									BDataIO *data);
41f0e491d3SAndrew Lindesay private:
42f0e491d3SAndrew Lindesay 			status_t			_LeafNameToBitmapSize(BString& leafName,
43f0e491d3SAndrew Lindesay 									BitmapSize* bitmapSize);
44f0e491d3SAndrew Lindesay 
45f0e491d3SAndrew Lindesay private:
46f0e491d3SAndrew Lindesay 			PackageIconTarRepository*
47f0e491d3SAndrew Lindesay 								fPackageIconTarRepository;
48f0e491d3SAndrew Lindesay };
49f0e491d3SAndrew Lindesay 
50f0e491d3SAndrew Lindesay 
51f0e491d3SAndrew Lindesay IconTarPtrEntryListener::IconTarPtrEntryListener(
52f0e491d3SAndrew Lindesay 	PackageIconTarRepository* packageIconTarRepository)
53f0e491d3SAndrew Lindesay 	:
54f0e491d3SAndrew Lindesay 	fPackageIconTarRepository(packageIconTarRepository)
55f0e491d3SAndrew Lindesay {
56f0e491d3SAndrew Lindesay }
57f0e491d3SAndrew Lindesay 
58f0e491d3SAndrew Lindesay 
59f0e491d3SAndrew Lindesay IconTarPtrEntryListener::~IconTarPtrEntryListener()
60f0e491d3SAndrew Lindesay {
61f0e491d3SAndrew Lindesay }
62f0e491d3SAndrew Lindesay 
63f0e491d3SAndrew Lindesay 
64f0e491d3SAndrew Lindesay /*!	The format of the filenames in the archive are of the format;
65f0e491d3SAndrew Lindesay 	\code
66f0e491d3SAndrew Lindesay 	hicn/ardino/icon.hvif
67f0e491d3SAndrew Lindesay 	\endcode
68f0e491d3SAndrew Lindesay 	The leafname (the last part of the path) determines the type of the file as
69f0e491d3SAndrew Lindesay 	it could be either in HVIF format or a PNG of various sizes.
70f0e491d3SAndrew Lindesay */
71f0e491d3SAndrew Lindesay 
72f0e491d3SAndrew Lindesay status_t
73f0e491d3SAndrew Lindesay IconTarPtrEntryListener::Handle(const TarArchiveHeader& header,
74f0e491d3SAndrew Lindesay 	size_t offset, BDataIO *data)
75f0e491d3SAndrew Lindesay {
76f0e491d3SAndrew Lindesay 	if (header.FileType() != TAR_FILE_TYPE_NORMAL)
77f0e491d3SAndrew Lindesay 		return B_OK;
78f0e491d3SAndrew Lindesay 
79f0e491d3SAndrew Lindesay 	BString fileName = header.FileName();
80f0e491d3SAndrew Lindesay 	if (!fileName.StartsWith("hicn/"))
81f0e491d3SAndrew Lindesay 		return B_OK;
82f0e491d3SAndrew Lindesay 
83f0e491d3SAndrew Lindesay 	int32 secondSlashIdx = fileName.FindFirst("/", 5);
84f0e491d3SAndrew Lindesay 	if (secondSlashIdx == B_ERROR || secondSlashIdx == 5)
85f0e491d3SAndrew Lindesay 		return B_OK;
86f0e491d3SAndrew Lindesay 
87f0e491d3SAndrew Lindesay 	BString packageName;
88f0e491d3SAndrew Lindesay 	BString leafName;
89f0e491d3SAndrew Lindesay 	fileName.CopyInto(packageName, 5, secondSlashIdx - 5);
90f0e491d3SAndrew Lindesay 	fileName.CopyInto(leafName, secondSlashIdx + 1,
91f0e491d3SAndrew Lindesay 		fileName.Length() - (secondSlashIdx + 1));
92f0e491d3SAndrew Lindesay 	BitmapSize bitmapSize;
93f0e491d3SAndrew Lindesay 
94f0e491d3SAndrew Lindesay 	if (_LeafNameToBitmapSize(leafName, &bitmapSize) == B_OK) {
95f0e491d3SAndrew Lindesay 		fPackageIconTarRepository->AddIconTarPtr(packageName, bitmapSize,
96f0e491d3SAndrew Lindesay 			offset);
97f0e491d3SAndrew Lindesay 	}
98f0e491d3SAndrew Lindesay 
99f0e491d3SAndrew Lindesay 	return B_OK;
100f0e491d3SAndrew Lindesay }
101f0e491d3SAndrew Lindesay 
102f0e491d3SAndrew Lindesay 
103f0e491d3SAndrew Lindesay status_t
104f0e491d3SAndrew Lindesay IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName,
105f0e491d3SAndrew Lindesay 	BitmapSize* bitmapSize)
106f0e491d3SAndrew Lindesay {
107f0e491d3SAndrew Lindesay 	if (leafName == "icon.hvif") {
108f0e491d3SAndrew Lindesay 		*bitmapSize = BITMAP_SIZE_ANY;
109f0e491d3SAndrew Lindesay 		return B_OK;
110f0e491d3SAndrew Lindesay 	}
111f0e491d3SAndrew Lindesay 	if (leafName == "64.png") {
112f0e491d3SAndrew Lindesay 		*bitmapSize = BITMAP_SIZE_64;
113f0e491d3SAndrew Lindesay 		return B_OK;
114f0e491d3SAndrew Lindesay 	}
115f0e491d3SAndrew Lindesay 	if (leafName == "32.png") {
116f0e491d3SAndrew Lindesay 		*bitmapSize = BITMAP_SIZE_32;
117f0e491d3SAndrew Lindesay 		return B_OK;
118f0e491d3SAndrew Lindesay 	}
119f0e491d3SAndrew Lindesay 	if (leafName == "16.png") {
120f0e491d3SAndrew Lindesay 		*bitmapSize = BITMAP_SIZE_16;
121f0e491d3SAndrew Lindesay 		return B_OK;
122f0e491d3SAndrew Lindesay 	}
123f0e491d3SAndrew Lindesay 	return B_BAD_VALUE;
124f0e491d3SAndrew Lindesay }
125f0e491d3SAndrew Lindesay 
126f0e491d3SAndrew Lindesay 
127f0e491d3SAndrew Lindesay PackageIconTarRepository::PackageIconTarRepository()
128f0e491d3SAndrew Lindesay 	:
129027d6086SAndrew Lindesay 	fTarIo(NULL),
130*66ee6532SAndrew Lindesay 	fIconCache(LIMIT_ICON_CACHE),
131*66ee6532SAndrew Lindesay 	fDefaultIconVectorData(NULL),
132*66ee6532SAndrew Lindesay 	fDefaultIconVectorDataSize(0),
133*66ee6532SAndrew Lindesay 	fDefaultIconCache(LIMIT_ICON_CACHE),
134*66ee6532SAndrew Lindesay 	fIconDataBuffer(new BMallocIO())
135f0e491d3SAndrew Lindesay {
136f0e491d3SAndrew Lindesay }
137f0e491d3SAndrew Lindesay 
138f0e491d3SAndrew Lindesay 
139f0e491d3SAndrew Lindesay PackageIconTarRepository::~PackageIconTarRepository()
140f0e491d3SAndrew Lindesay {
141*66ee6532SAndrew Lindesay 	delete fIconDataBuffer;
142f0e491d3SAndrew Lindesay }
143f0e491d3SAndrew Lindesay 
144f0e491d3SAndrew Lindesay 
145d75b4d61SAndrew Lindesay void
146d75b4d61SAndrew Lindesay PackageIconTarRepository::Clear() {
147d75b4d61SAndrew Lindesay 	BAutolock locker(&fLock);
148d75b4d61SAndrew Lindesay 	fIconCache.Clear();
149*66ee6532SAndrew Lindesay 	fDefaultIconCache.Clear();
150d75b4d61SAndrew Lindesay }
151d75b4d61SAndrew Lindesay 
152d75b4d61SAndrew Lindesay 
153f0e491d3SAndrew Lindesay /*!	This method will reconfigure itself using the data in the tar file supplied.
154f0e491d3SAndrew Lindesay 	Any existing data will be flushed and the new tar will be scanned for
155f0e491d3SAndrew Lindesay 	offsets to usable files.
156f0e491d3SAndrew Lindesay */
157f0e491d3SAndrew Lindesay 
158f0e491d3SAndrew Lindesay status_t
159f0e491d3SAndrew Lindesay PackageIconTarRepository::Init(BPath& tarPath)
160f0e491d3SAndrew Lindesay {
161f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
162*66ee6532SAndrew Lindesay 
163f0e491d3SAndrew Lindesay 	_Close();
164*66ee6532SAndrew Lindesay 
165*66ee6532SAndrew Lindesay 	_InitDefaultVectorIcon();
166*66ee6532SAndrew Lindesay 
167f0e491d3SAndrew Lindesay 	status_t result = B_OK;
168f0e491d3SAndrew Lindesay 
169f0e491d3SAndrew Lindesay 	if (tarPath.Path() == NULL) {
170f0e491d3SAndrew Lindesay 		HDINFO("empty path to tar-ball");
171f0e491d3SAndrew Lindesay 		result = B_BAD_VALUE;
172f0e491d3SAndrew Lindesay 	}
173f0e491d3SAndrew Lindesay 
174f0e491d3SAndrew Lindesay 	BFile *tarIo = NULL;
175f0e491d3SAndrew Lindesay 
176f0e491d3SAndrew Lindesay 	if (result == B_OK) {
177f0e491d3SAndrew Lindesay 		HDINFO("will init icon model from tar [%s]", tarPath.Path());
178f0e491d3SAndrew Lindesay 		tarIo = new BFile(tarPath.Path(), O_RDONLY);
179f0e491d3SAndrew Lindesay 
180f0e491d3SAndrew Lindesay 		if (!tarIo->IsReadable()) {
181f0e491d3SAndrew Lindesay 			HDERROR("unable to read the tar [%s]", tarPath.Path());
182f0e491d3SAndrew Lindesay 			result = B_IO_ERROR;
183f0e491d3SAndrew Lindesay 		}
184f0e491d3SAndrew Lindesay 	}
185f0e491d3SAndrew Lindesay 
186f0e491d3SAndrew Lindesay 	// will fill the model up with records from the tar-ball.
187f0e491d3SAndrew Lindesay 
188f0e491d3SAndrew Lindesay 	if (result == B_OK) {
189f0e491d3SAndrew Lindesay 		BStopWatch watch("PackageIconTarRepository::Init", true);
190f0e491d3SAndrew Lindesay 		HDINFO("will read [%s] and collect the tar pointers", tarPath.Path());
191f0e491d3SAndrew Lindesay 
192f0e491d3SAndrew Lindesay 		IconTarPtrEntryListener* listener = new IconTarPtrEntryListener(this);
193f0e491d3SAndrew Lindesay 		ObjectDeleter<IconTarPtrEntryListener> listenerDeleter(listener);
194f0e491d3SAndrew Lindesay 		TarArchiveService::ForEachEntry(*tarIo, listener);
195f0e491d3SAndrew Lindesay 
196f0e491d3SAndrew Lindesay 		double secs = watch.ElapsedTime() / 1000000.0;
197f0e491d3SAndrew Lindesay 		HDINFO("did collect %" B_PRIi32 " tar pointers (%6.3g secs)",
198f0e491d3SAndrew Lindesay 			fIconTarPtrs.Size(), secs);
199f0e491d3SAndrew Lindesay 	}
200f0e491d3SAndrew Lindesay 
201f0e491d3SAndrew Lindesay 	if (result == B_OK)
202f0e491d3SAndrew Lindesay 		fTarIo = tarIo;
203f0e491d3SAndrew Lindesay 	else
204f0e491d3SAndrew Lindesay 		delete tarIo;
205f0e491d3SAndrew Lindesay 
206*66ee6532SAndrew Lindesay 	if (result == B_OK)
207*66ee6532SAndrew Lindesay 		result = fIconDataBuffer->SetSize(ICON_BUFFER_SIZE_INITIAL);
208*66ee6532SAndrew Lindesay 
209f0e491d3SAndrew Lindesay 	return result;
210f0e491d3SAndrew Lindesay }
211f0e491d3SAndrew Lindesay 
212f0e491d3SAndrew Lindesay 
213f0e491d3SAndrew Lindesay void
214f0e491d3SAndrew Lindesay PackageIconTarRepository::_Close()
215f0e491d3SAndrew Lindesay {
216d75b4d61SAndrew Lindesay 	fIconCache.Clear();
217f0e491d3SAndrew Lindesay 	delete fTarIo;
218f0e491d3SAndrew Lindesay 	fTarIo = NULL;
219f0e491d3SAndrew Lindesay 	fIconTarPtrs.Clear();
220*66ee6532SAndrew Lindesay 
221*66ee6532SAndrew Lindesay 	delete fDefaultIconVectorData;
222*66ee6532SAndrew Lindesay 	fDefaultIconVectorData = NULL;
223*66ee6532SAndrew Lindesay 	fDefaultIconVectorDataSize = 0;
224*66ee6532SAndrew Lindesay 	fDefaultIconCache.Clear();
225f0e491d3SAndrew Lindesay }
226f0e491d3SAndrew Lindesay 
227f0e491d3SAndrew Lindesay 
228f0e491d3SAndrew Lindesay /*!	This method should be treated private and only called from a situation
229f0e491d3SAndrew Lindesay 	in which the class's lock is acquired.  It is used to populate data from
230f0e491d3SAndrew Lindesay 	the parsing of the tar headers.  It is called from the listener above.
231f0e491d3SAndrew Lindesay */
232f0e491d3SAndrew Lindesay void
233*66ee6532SAndrew Lindesay PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize bitmapSize,
234*66ee6532SAndrew Lindesay 	off_t offset)
235f0e491d3SAndrew Lindesay {
236f0e491d3SAndrew Lindesay 	IconTarPtrRef tarPtrRef = _GetOrCreateIconTarPtr(packageName);
237f0e491d3SAndrew Lindesay 	tarPtrRef->SetOffset(bitmapSize, offset);
238f0e491d3SAndrew Lindesay }
239f0e491d3SAndrew Lindesay 
240f0e491d3SAndrew Lindesay 
241f0e491d3SAndrew Lindesay bool
242f0e491d3SAndrew Lindesay PackageIconTarRepository::HasAnyIcon(const BString& pkgName)
243f0e491d3SAndrew Lindesay {
244f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
245f0e491d3SAndrew Lindesay 	HashString key(pkgName);
246f0e491d3SAndrew Lindesay 	return fIconTarPtrs.ContainsKey(key);
247f0e491d3SAndrew Lindesay }
248f0e491d3SAndrew Lindesay 
249f0e491d3SAndrew Lindesay 
250f0e491d3SAndrew Lindesay status_t
251*66ee6532SAndrew Lindesay PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size,
252*66ee6532SAndrew Lindesay 	BitmapHolderRef& bitmapHolderRef)
253f0e491d3SAndrew Lindesay {
254*66ee6532SAndrew Lindesay 	if (0 == size || size > MAX_IMAGE_SIZE) {
255*66ee6532SAndrew Lindesay 		HDERROR("request to get icon for pkg [%s] with bad size %" B_PRIu32, pkgName.String(),
256*66ee6532SAndrew Lindesay 			size);
257*66ee6532SAndrew Lindesay 		return B_BAD_VALUE;
258*66ee6532SAndrew Lindesay 	}
259*66ee6532SAndrew Lindesay 
260*66ee6532SAndrew Lindesay 	bitmapHolderRef.Unset();
261*66ee6532SAndrew Lindesay 
262f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
263f0e491d3SAndrew Lindesay 	status_t result = B_OK;
264f0e491d3SAndrew Lindesay 	off_t iconDataTarOffset = -1;
265f0e491d3SAndrew Lindesay 	const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
266*66ee6532SAndrew Lindesay 	BitmapSize bitmapSize;
267f0e491d3SAndrew Lindesay 
268779ab335SX512 	if (tarPtrRef.IsSet()) {
269*66ee6532SAndrew Lindesay 		bitmapSize = _BestStoredSize(tarPtrRef, size);
270*66ee6532SAndrew Lindesay 		iconDataTarOffset = tarPtrRef->Offset(bitmapSize);
271f0e491d3SAndrew Lindesay 	}
272f0e491d3SAndrew Lindesay 
273*66ee6532SAndrew Lindesay 	if (iconDataTarOffset >= 0) {
274*66ee6532SAndrew Lindesay 		HashString key = _ToIconCacheKey(pkgName, bitmapSize);
275f0e491d3SAndrew Lindesay 
276*66ee6532SAndrew Lindesay 		if (fIconCache.ContainsKey(key)) {
277*66ee6532SAndrew Lindesay 			bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
278*66ee6532SAndrew Lindesay 		} else {
279*66ee6532SAndrew Lindesay 			result = _CreateIconFromTarOffset(iconDataTarOffset, bitmapHolderRef);
280*66ee6532SAndrew Lindesay 			if (result == B_OK) {
281*66ee6532SAndrew Lindesay 				HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size);
282*66ee6532SAndrew Lindesay 				fIconCache.Put(key, bitmapHolderRef);
283*66ee6532SAndrew Lindesay 				bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
284*66ee6532SAndrew Lindesay 			} else {
285f0e491d3SAndrew Lindesay 				HDERROR("failure to read image for package [%s] at offset %"
286dfbcbde1SAndrew Lindesay 					B_PRIdOFF, pkgName.String(), iconDataTarOffset);
287f0e491d3SAndrew Lindesay 			}
288f0e491d3SAndrew Lindesay 		}
289f0e491d3SAndrew Lindesay 	}
290*66ee6532SAndrew Lindesay 
291*66ee6532SAndrew Lindesay 	if (!bitmapHolderRef.IsSet())
292*66ee6532SAndrew Lindesay 		result = _GetDefaultIcon(size, bitmapHolderRef);
293*66ee6532SAndrew Lindesay 
294f0e491d3SAndrew Lindesay 	return result;
295f0e491d3SAndrew Lindesay }
296f0e491d3SAndrew Lindesay 
297f0e491d3SAndrew Lindesay 
298f0e491d3SAndrew Lindesay IconTarPtrRef
299f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetIconTarPtr(const BString& pkgName) const
300f0e491d3SAndrew Lindesay {
301f0e491d3SAndrew Lindesay 	return fIconTarPtrs.Get(HashString(pkgName));
302f0e491d3SAndrew Lindesay }
303f0e491d3SAndrew Lindesay 
304f0e491d3SAndrew Lindesay 
305f0e491d3SAndrew Lindesay const char*
306f0e491d3SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKeySuffix(BitmapSize size)
307f0e491d3SAndrew Lindesay {
308f0e491d3SAndrew Lindesay 	switch (size)
309f0e491d3SAndrew Lindesay 	{
310f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_16:
311f0e491d3SAndrew Lindesay 			return "16";
312f0e491d3SAndrew Lindesay 		// note that size 22 is not supported.
313f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_32:
314f0e491d3SAndrew Lindesay 			return "32";
315f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_64:
316f0e491d3SAndrew Lindesay 			return "64";
317f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_ANY:
318f0e491d3SAndrew Lindesay 			return "any";
319f0e491d3SAndrew Lindesay 		default:
32005880d13SAndrew Lindesay 			HDFATAL("unsupported bitmap size");
321f0e491d3SAndrew Lindesay 			break;
322f0e491d3SAndrew Lindesay 	}
323f0e491d3SAndrew Lindesay }
324f0e491d3SAndrew Lindesay 
325f0e491d3SAndrew Lindesay 
326f0e491d3SAndrew Lindesay const HashString
327*66ee6532SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize size)
328f0e491d3SAndrew Lindesay {
329f0e491d3SAndrew Lindesay 	return HashString(BString(pkgName) << "__x" << _ToIconCacheKeySuffix(size));
330f0e491d3SAndrew Lindesay }
331f0e491d3SAndrew Lindesay 
332f0e491d3SAndrew Lindesay 
333*66ee6532SAndrew Lindesay /*!	This method must only be invoked with the class locked.
334*66ee6532SAndrew Lindesay  */
335f0e491d3SAndrew Lindesay status_t
336*66ee6532SAndrew Lindesay PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapHolderRef& bitmapHolderRef)
337f0e491d3SAndrew Lindesay {
338f0e491d3SAndrew Lindesay 	fTarIo->Seek(offset, SEEK_SET);
339*66ee6532SAndrew Lindesay 	fIconDataBuffer->Seek(0, SEEK_SET);
340*66ee6532SAndrew Lindesay 
341f0e491d3SAndrew Lindesay 	TarArchiveHeader header;
342f0e491d3SAndrew Lindesay 	status_t result = TarArchiveService::GetEntry(*fTarIo, header);
343f0e491d3SAndrew Lindesay 
344*66ee6532SAndrew Lindesay 	if (result == B_OK && (header.Length() <= 0 || header.Length() > ICON_BUFFER_SIZE_MAX)) {
345*66ee6532SAndrew Lindesay 		HDERROR("the icon tar entry at %" B_PRIdOFF " has a bad length %" B_PRIdSSIZE, offset,
346*66ee6532SAndrew Lindesay 			header.Length());
347f0e491d3SAndrew Lindesay 		result = B_BAD_DATA;
348*66ee6532SAndrew Lindesay 	}
349*66ee6532SAndrew Lindesay 
350*66ee6532SAndrew Lindesay 	off_t iconDataBufferSize = 0;
351f0e491d3SAndrew Lindesay 
352f0e491d3SAndrew Lindesay 	if (result == B_OK)
353*66ee6532SAndrew Lindesay 		result = fIconDataBuffer->GetSize(&iconDataBufferSize);
354*66ee6532SAndrew Lindesay 
355*66ee6532SAndrew Lindesay 	if (result == B_OK && static_cast<size_t>(iconDataBufferSize) < header.Length())
356*66ee6532SAndrew Lindesay 		result = fIconDataBuffer->SetSize(header.Length());
357*66ee6532SAndrew Lindesay 
358*66ee6532SAndrew Lindesay 	if (result == B_OK) {
359*66ee6532SAndrew Lindesay 		BDataIO* tarImageIO = new ConstraintedDataIO(fTarIo, header.Length());
360*66ee6532SAndrew Lindesay 		result = DataIOUtils::CopyAll(fIconDataBuffer, tarImageIO);
361*66ee6532SAndrew Lindesay 		delete tarImageIO;
362*66ee6532SAndrew Lindesay 	} else {
363*66ee6532SAndrew Lindesay 		HDERROR("unable to extract data from tar for icon image");
364*66ee6532SAndrew Lindesay 	}
365*66ee6532SAndrew Lindesay 
366*66ee6532SAndrew Lindesay 	fIconDataBuffer->Seek(0, SEEK_SET);
367*66ee6532SAndrew Lindesay 
368*66ee6532SAndrew Lindesay 	if (result == B_OK) {
369*66ee6532SAndrew Lindesay 		BBitmap* bitmap = BTranslationUtils::GetBitmap(fIconDataBuffer);
370*66ee6532SAndrew Lindesay 
371*66ee6532SAndrew Lindesay 		if (bitmap == NULL) {
372*66ee6532SAndrew Lindesay 			HDERROR("unable to decode data from tar for icon image");
373*66ee6532SAndrew Lindesay 			result = B_ERROR;
374*66ee6532SAndrew Lindesay 		} else {
375*66ee6532SAndrew Lindesay 			bitmapHolderRef.SetTo(new(std::nothrow) BitmapHolder(bitmap), true);
376*66ee6532SAndrew Lindesay 		}
377*66ee6532SAndrew Lindesay 	}
378f0e491d3SAndrew Lindesay 
379f0e491d3SAndrew Lindesay 	return result;
380f0e491d3SAndrew Lindesay }
381f0e491d3SAndrew Lindesay 
382f0e491d3SAndrew Lindesay 
383f0e491d3SAndrew Lindesay /*!	If there is a vector representation (HVIF) then this will be the best
384f0e491d3SAndrew Lindesay 	option.  If there are only bitmap images to choose from then consider what
385f0e491d3SAndrew Lindesay 	the target size is and choose the best image to match.
386f0e491d3SAndrew Lindesay */
387*66ee6532SAndrew Lindesay /*static*/ BitmapSize
388*66ee6532SAndrew Lindesay PackageIconTarRepository::_BestStoredSize(const IconTarPtrRef iconTarPtrRef, int32 desiredSize)
389f0e491d3SAndrew Lindesay {
390*66ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_ANY))
391*66ee6532SAndrew Lindesay 		return BITMAP_SIZE_ANY;
392*66ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_64) && desiredSize >= 64)
393*66ee6532SAndrew Lindesay 		return BITMAP_SIZE_64;
394*66ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32) && desiredSize >= 32)
395*66ee6532SAndrew Lindesay 		return BITMAP_SIZE_32;
396*66ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32))
397*66ee6532SAndrew Lindesay 		return BITMAP_SIZE_16;
398*66ee6532SAndrew Lindesay 	HDFATAL("unable to get the best stored icon for size");
399f0e491d3SAndrew Lindesay }
400f0e491d3SAndrew Lindesay 
401f0e491d3SAndrew Lindesay 
402f0e491d3SAndrew Lindesay IconTarPtrRef
403f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName)
404f0e491d3SAndrew Lindesay {
405f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
406f0e491d3SAndrew Lindesay 	HashString key(pkgName);
407f0e491d3SAndrew Lindesay 	if (!fIconTarPtrs.ContainsKey(key)) {
408f0e491d3SAndrew Lindesay 		IconTarPtrRef value(new IconTarPtr(pkgName));
409f0e491d3SAndrew Lindesay 		fIconTarPtrs.Put(key, value);
410f0e491d3SAndrew Lindesay 		return value;
411f0e491d3SAndrew Lindesay 	}
412f0e491d3SAndrew Lindesay 	return fIconTarPtrs.Get(key);
413f0e491d3SAndrew Lindesay }
414f0e491d3SAndrew Lindesay 
415f0e491d3SAndrew Lindesay 
416*66ee6532SAndrew Lindesay status_t
417*66ee6532SAndrew Lindesay PackageIconTarRepository::_GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef)
418f0e491d3SAndrew Lindesay {
419*66ee6532SAndrew Lindesay 	if (fDefaultIconVectorData == NULL)
420*66ee6532SAndrew Lindesay 		return B_NOT_INITIALIZED;
421*66ee6532SAndrew Lindesay 
422*66ee6532SAndrew Lindesay 	bitmapHolderRef.Unset();
423*66ee6532SAndrew Lindesay 
424*66ee6532SAndrew Lindesay 	status_t status = B_OK;
425*66ee6532SAndrew Lindesay 	HashString key(BString() << size);
426*66ee6532SAndrew Lindesay 
427*66ee6532SAndrew Lindesay 	if (!fDefaultIconCache.ContainsKey(key)) {
428*66ee6532SAndrew Lindesay 		BBitmap* bitmap = NULL;
429*66ee6532SAndrew Lindesay 
430*66ee6532SAndrew Lindesay 		if (status == B_OK) {
431*66ee6532SAndrew Lindesay 			bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
432*66ee6532SAndrew Lindesay 			status = bitmap->InitCheck();
433*66ee6532SAndrew Lindesay 		}
434*66ee6532SAndrew Lindesay 
435*66ee6532SAndrew Lindesay 		if (status == B_OK) {
436*66ee6532SAndrew Lindesay 			status = BIconUtils::GetVectorIcon(fDefaultIconVectorData, fDefaultIconVectorDataSize,
437*66ee6532SAndrew Lindesay 				bitmap);
438*66ee6532SAndrew Lindesay 		}
439*66ee6532SAndrew Lindesay 
440*66ee6532SAndrew Lindesay 		if (status == B_OK) {
441*66ee6532SAndrew Lindesay 			HDINFO("did create default package icon size %" B_PRId32, size);
442*66ee6532SAndrew Lindesay 			BitmapHolderRef bitmapHolder(new(std::nothrow) BitmapHolder(bitmap), true);
443*66ee6532SAndrew Lindesay 			fDefaultIconCache.Put(key, bitmapHolder);
444*66ee6532SAndrew Lindesay 		} else {
445*66ee6532SAndrew Lindesay 			delete bitmap;
446*66ee6532SAndrew Lindesay 			bitmap = NULL;
447*66ee6532SAndrew Lindesay 		}
448*66ee6532SAndrew Lindesay 	}
449*66ee6532SAndrew Lindesay 
450*66ee6532SAndrew Lindesay 	if (status == B_OK)
451*66ee6532SAndrew Lindesay 		bitmapHolderRef.SetTo(fDefaultIconCache.Get(key).Get());
452*66ee6532SAndrew Lindesay 	else
453*66ee6532SAndrew Lindesay 		HDERROR("failed to create default package icon size %" B_PRId32, size);
454*66ee6532SAndrew Lindesay 
455*66ee6532SAndrew Lindesay 	return status;
456*66ee6532SAndrew Lindesay }
457*66ee6532SAndrew Lindesay 
458*66ee6532SAndrew Lindesay 
459*66ee6532SAndrew Lindesay void
460*66ee6532SAndrew Lindesay PackageIconTarRepository::_InitDefaultVectorIcon()
461*66ee6532SAndrew Lindesay {
462*66ee6532SAndrew Lindesay 	if (fDefaultIconVectorData != NULL) {
463*66ee6532SAndrew Lindesay 		delete fDefaultIconVectorData;
464*66ee6532SAndrew Lindesay 		fDefaultIconVectorData = NULL;
465*66ee6532SAndrew Lindesay 	}
466*66ee6532SAndrew Lindesay 
467*66ee6532SAndrew Lindesay 	fDefaultIconVectorDataSize = 0;
468*66ee6532SAndrew Lindesay 
469*66ee6532SAndrew Lindesay 	BMimeType mimeType("application/x-vnd.haiku-package");
470*66ee6532SAndrew Lindesay 	status_t status = mimeType.InitCheck();
471*66ee6532SAndrew Lindesay 
472*66ee6532SAndrew Lindesay 	uint8* data;
473*66ee6532SAndrew Lindesay 	size_t dataSize;
474*66ee6532SAndrew Lindesay 
475*66ee6532SAndrew Lindesay 	if (status == B_OK)
476*66ee6532SAndrew Lindesay 		status = mimeType.GetIcon(&data, &dataSize);
477*66ee6532SAndrew Lindesay 
478*66ee6532SAndrew Lindesay 	if (status == B_OK) {
479*66ee6532SAndrew Lindesay 		fDefaultIconVectorData = new(std::nothrow) uint8[dataSize];
480*66ee6532SAndrew Lindesay 
481*66ee6532SAndrew Lindesay 		if (fDefaultIconVectorData == NULL)
482*66ee6532SAndrew Lindesay 			HDFATAL("unable to allocate memory for the default icon");
483*66ee6532SAndrew Lindesay 
484*66ee6532SAndrew Lindesay 		memcpy(fDefaultIconVectorData, data, dataSize);
485*66ee6532SAndrew Lindesay 		fDefaultIconVectorDataSize = dataSize;
486*66ee6532SAndrew Lindesay 	} else {
487*66ee6532SAndrew Lindesay 		fDefaultIconVectorData = NULL;
488*66ee6532SAndrew Lindesay 		fDefaultIconVectorDataSize = 0;
489*66ee6532SAndrew Lindesay 	}
490f0e491d3SAndrew Lindesay }
491