xref: /haiku/src/apps/haikudepot/model/PackageIconTarRepository.cpp (revision 1c4d43a6b09fcdf141a46af71c233bb144468b2a)
1f0e491d3SAndrew Lindesay /*
266ee6532SAndrew 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>
866ee6532SAndrew Lindesay #include <Autolock.h>
9f0e491d3SAndrew Lindesay #include <File.h>
1066ee6532SAndrew Lindesay #include <IconUtils.h>
113538133fSAndrew Lindesay #include <StopWatch.h>
1266ee6532SAndrew Lindesay #include <TranslationUtils.h>
13f0e491d3SAndrew Lindesay 
1466ee6532SAndrew 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
2066ee6532SAndrew Lindesay #define ICON_BUFFER_SIZE_INITIAL 4096
2166ee6532SAndrew 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 
IconTarPtrEntryListener(PackageIconTarRepository * packageIconTarRepository)51f0e491d3SAndrew Lindesay IconTarPtrEntryListener::IconTarPtrEntryListener(
52f0e491d3SAndrew Lindesay 	PackageIconTarRepository* packageIconTarRepository)
53f0e491d3SAndrew Lindesay 	:
54f0e491d3SAndrew Lindesay 	fPackageIconTarRepository(packageIconTarRepository)
55f0e491d3SAndrew Lindesay {
56f0e491d3SAndrew Lindesay }
57f0e491d3SAndrew Lindesay 
58f0e491d3SAndrew Lindesay 
~IconTarPtrEntryListener()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
Handle(const TarArchiveHeader & header,size_t offset,BDataIO * data)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));
92c3cad236SAndrew Lindesay 	BitmapSize storedSize;
93f0e491d3SAndrew Lindesay 
94c3cad236SAndrew Lindesay 	if (_LeafNameToBitmapSize(leafName, &storedSize) == B_OK)
95c3cad236SAndrew Lindesay 		fPackageIconTarRepository->AddIconTarPtr(packageName, storedSize, offset);
96f0e491d3SAndrew Lindesay 
97f0e491d3SAndrew Lindesay 	return B_OK;
98f0e491d3SAndrew Lindesay }
99f0e491d3SAndrew Lindesay 
100f0e491d3SAndrew Lindesay 
101f0e491d3SAndrew Lindesay status_t
_LeafNameToBitmapSize(BString & leafName,BitmapSize * storedSize)102c3cad236SAndrew Lindesay IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName, BitmapSize* storedSize)
103f0e491d3SAndrew Lindesay {
104f0e491d3SAndrew Lindesay 	if (leafName == "icon.hvif") {
105c3cad236SAndrew Lindesay 		*storedSize = BITMAP_SIZE_ANY;
106f0e491d3SAndrew Lindesay 		return B_OK;
107f0e491d3SAndrew Lindesay 	}
108f0e491d3SAndrew Lindesay 	if (leafName == "64.png") {
109c3cad236SAndrew Lindesay 		*storedSize = BITMAP_SIZE_64;
110f0e491d3SAndrew Lindesay 		return B_OK;
111f0e491d3SAndrew Lindesay 	}
112f0e491d3SAndrew Lindesay 	if (leafName == "32.png") {
113c3cad236SAndrew Lindesay 		*storedSize = BITMAP_SIZE_32;
114f0e491d3SAndrew Lindesay 		return B_OK;
115f0e491d3SAndrew Lindesay 	}
116f0e491d3SAndrew Lindesay 	if (leafName == "16.png") {
117c3cad236SAndrew Lindesay 		*storedSize = BITMAP_SIZE_16;
118f0e491d3SAndrew Lindesay 		return B_OK;
119f0e491d3SAndrew Lindesay 	}
120f0e491d3SAndrew Lindesay 	return B_BAD_VALUE;
121f0e491d3SAndrew Lindesay }
122f0e491d3SAndrew Lindesay 
123f0e491d3SAndrew Lindesay 
PackageIconTarRepository()124f0e491d3SAndrew Lindesay PackageIconTarRepository::PackageIconTarRepository()
125f0e491d3SAndrew Lindesay 	:
126027d6086SAndrew Lindesay 	fTarIo(NULL),
12766ee6532SAndrew Lindesay 	fIconCache(LIMIT_ICON_CACHE),
12866ee6532SAndrew Lindesay 	fDefaultIconVectorData(NULL),
12966ee6532SAndrew Lindesay 	fDefaultIconVectorDataSize(0),
13066ee6532SAndrew Lindesay 	fDefaultIconCache(LIMIT_ICON_CACHE),
13166ee6532SAndrew Lindesay 	fIconDataBuffer(new BMallocIO())
132f0e491d3SAndrew Lindesay {
133*1c4d43a6SAndrew Lindesay 	_InitDefaultVectorIcon();
134f0e491d3SAndrew Lindesay }
135f0e491d3SAndrew Lindesay 
136f0e491d3SAndrew Lindesay 
~PackageIconTarRepository()137f0e491d3SAndrew Lindesay PackageIconTarRepository::~PackageIconTarRepository()
138f0e491d3SAndrew Lindesay {
13966ee6532SAndrew Lindesay 	delete fIconDataBuffer;
140*1c4d43a6SAndrew Lindesay 	delete fDefaultIconVectorData;
141f0e491d3SAndrew Lindesay }
142f0e491d3SAndrew Lindesay 
143f0e491d3SAndrew Lindesay 
144d75b4d61SAndrew Lindesay void
Clear()145d75b4d61SAndrew Lindesay PackageIconTarRepository::Clear() {
146d75b4d61SAndrew Lindesay 	BAutolock locker(&fLock);
147d75b4d61SAndrew Lindesay 	fIconCache.Clear();
14866ee6532SAndrew Lindesay 	fDefaultIconCache.Clear();
149d75b4d61SAndrew Lindesay }
150d75b4d61SAndrew Lindesay 
151d75b4d61SAndrew Lindesay 
152f0e491d3SAndrew Lindesay /*!	This method will reconfigure itself using the data in the tar file supplied.
153f0e491d3SAndrew Lindesay 	Any existing data will be flushed and the new tar will be scanned for
154f0e491d3SAndrew Lindesay 	offsets to usable files.
155f0e491d3SAndrew Lindesay */
156f0e491d3SAndrew Lindesay 
157f0e491d3SAndrew Lindesay status_t
Init(BPath & tarPath)158f0e491d3SAndrew Lindesay PackageIconTarRepository::Init(BPath& tarPath)
159f0e491d3SAndrew Lindesay {
160f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
16166ee6532SAndrew Lindesay 
162f0e491d3SAndrew Lindesay 	_Close();
16366ee6532SAndrew Lindesay 
164f0e491d3SAndrew Lindesay 	status_t result = B_OK;
165f0e491d3SAndrew Lindesay 
166f0e491d3SAndrew Lindesay 	if (tarPath.Path() == NULL) {
167f0e491d3SAndrew Lindesay 		HDINFO("empty path to tar-ball");
168f0e491d3SAndrew Lindesay 		result = B_BAD_VALUE;
169f0e491d3SAndrew Lindesay 	}
170f0e491d3SAndrew Lindesay 
171f0e491d3SAndrew Lindesay 	BFile *tarIo = NULL;
172f0e491d3SAndrew Lindesay 
173f0e491d3SAndrew Lindesay 	if (result == B_OK) {
174f0e491d3SAndrew Lindesay 		HDINFO("will init icon model from tar [%s]", tarPath.Path());
175f0e491d3SAndrew Lindesay 		tarIo = new BFile(tarPath.Path(), O_RDONLY);
176f0e491d3SAndrew Lindesay 
177f0e491d3SAndrew Lindesay 		if (!tarIo->IsReadable()) {
178f0e491d3SAndrew Lindesay 			HDERROR("unable to read the tar [%s]", tarPath.Path());
179f0e491d3SAndrew Lindesay 			result = B_IO_ERROR;
180f0e491d3SAndrew Lindesay 		}
181f0e491d3SAndrew Lindesay 	}
182f0e491d3SAndrew Lindesay 
183f0e491d3SAndrew Lindesay 	// will fill the model up with records from the tar-ball.
184f0e491d3SAndrew Lindesay 
185f0e491d3SAndrew Lindesay 	if (result == B_OK) {
186f0e491d3SAndrew Lindesay 		BStopWatch watch("PackageIconTarRepository::Init", true);
187f0e491d3SAndrew Lindesay 		HDINFO("will read [%s] and collect the tar pointers", tarPath.Path());
188f0e491d3SAndrew Lindesay 
189f0e491d3SAndrew Lindesay 		IconTarPtrEntryListener* listener = new IconTarPtrEntryListener(this);
190f0e491d3SAndrew Lindesay 		ObjectDeleter<IconTarPtrEntryListener> listenerDeleter(listener);
191f0e491d3SAndrew Lindesay 		TarArchiveService::ForEachEntry(*tarIo, listener);
192f0e491d3SAndrew Lindesay 
193f0e491d3SAndrew Lindesay 		double secs = watch.ElapsedTime() / 1000000.0;
194f0e491d3SAndrew Lindesay 		HDINFO("did collect %" B_PRIi32 " tar pointers (%6.3g secs)",
195f0e491d3SAndrew Lindesay 			fIconTarPtrs.Size(), secs);
196f0e491d3SAndrew Lindesay 	}
197f0e491d3SAndrew Lindesay 
198f0e491d3SAndrew Lindesay 	if (result == B_OK)
199f0e491d3SAndrew Lindesay 		fTarIo = tarIo;
200f0e491d3SAndrew Lindesay 	else
201f0e491d3SAndrew Lindesay 		delete tarIo;
202f0e491d3SAndrew Lindesay 
20366ee6532SAndrew Lindesay 	if (result == B_OK)
20466ee6532SAndrew Lindesay 		result = fIconDataBuffer->SetSize(ICON_BUFFER_SIZE_INITIAL);
20566ee6532SAndrew Lindesay 
206f0e491d3SAndrew Lindesay 	return result;
207f0e491d3SAndrew Lindesay }
208f0e491d3SAndrew Lindesay 
209f0e491d3SAndrew Lindesay 
210f0e491d3SAndrew Lindesay void
_Close()211f0e491d3SAndrew Lindesay PackageIconTarRepository::_Close()
212f0e491d3SAndrew Lindesay {
213d75b4d61SAndrew Lindesay 	fIconCache.Clear();
214f0e491d3SAndrew Lindesay 	delete fTarIo;
215f0e491d3SAndrew Lindesay 	fTarIo = NULL;
216f0e491d3SAndrew Lindesay 	fIconTarPtrs.Clear();
21766ee6532SAndrew Lindesay 	fDefaultIconCache.Clear();
218f0e491d3SAndrew Lindesay }
219f0e491d3SAndrew Lindesay 
220f0e491d3SAndrew Lindesay 
221f0e491d3SAndrew Lindesay /*!	This method should be treated private and only called from a situation
222f0e491d3SAndrew Lindesay 	in which the class's lock is acquired.  It is used to populate data from
223f0e491d3SAndrew Lindesay 	the parsing of the tar headers.  It is called from the listener above.
224f0e491d3SAndrew Lindesay */
225f0e491d3SAndrew Lindesay void
AddIconTarPtr(const BString & packageName,BitmapSize storedSize,off_t offset)226c3cad236SAndrew Lindesay PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize storedSize,
22766ee6532SAndrew Lindesay 	off_t offset)
228f0e491d3SAndrew Lindesay {
229f0e491d3SAndrew Lindesay 	IconTarPtrRef tarPtrRef = _GetOrCreateIconTarPtr(packageName);
230c3cad236SAndrew Lindesay 	tarPtrRef->SetOffset(storedSize, offset);
231f0e491d3SAndrew Lindesay }
232f0e491d3SAndrew Lindesay 
233f0e491d3SAndrew Lindesay 
234f0e491d3SAndrew Lindesay bool
HasAnyIcon(const BString & pkgName)235f0e491d3SAndrew Lindesay PackageIconTarRepository::HasAnyIcon(const BString& pkgName)
236f0e491d3SAndrew Lindesay {
237f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
238f0e491d3SAndrew Lindesay 	HashString key(pkgName);
239f0e491d3SAndrew Lindesay 	return fIconTarPtrs.ContainsKey(key);
240f0e491d3SAndrew Lindesay }
241f0e491d3SAndrew Lindesay 
242f0e491d3SAndrew Lindesay 
243f0e491d3SAndrew Lindesay status_t
GetIcon(const BString & pkgName,uint32 size,BitmapHolderRef & bitmapHolderRef)24466ee6532SAndrew Lindesay PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size,
24566ee6532SAndrew Lindesay 	BitmapHolderRef& bitmapHolderRef)
246f0e491d3SAndrew Lindesay {
24766ee6532SAndrew Lindesay 	if (0 == size || size > MAX_IMAGE_SIZE) {
24866ee6532SAndrew Lindesay 		HDERROR("request to get icon for pkg [%s] with bad size %" B_PRIu32, pkgName.String(),
24966ee6532SAndrew Lindesay 			size);
25066ee6532SAndrew Lindesay 		return B_BAD_VALUE;
25166ee6532SAndrew Lindesay 	}
25266ee6532SAndrew Lindesay 
25366ee6532SAndrew Lindesay 	bitmapHolderRef.Unset();
25466ee6532SAndrew Lindesay 
255f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
256f0e491d3SAndrew Lindesay 	status_t result = B_OK;
257f0e491d3SAndrew Lindesay 	off_t iconDataTarOffset = -1;
258f0e491d3SAndrew Lindesay 	const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
259c3cad236SAndrew Lindesay 	BitmapSize storedSize;
260f0e491d3SAndrew Lindesay 
261779ab335SX512 	if (tarPtrRef.IsSet()) {
262c3cad236SAndrew Lindesay 		storedSize = _BestStoredSize(tarPtrRef, size);
263c3cad236SAndrew Lindesay 		iconDataTarOffset = tarPtrRef->Offset(storedSize);
264f0e491d3SAndrew Lindesay 	}
265f0e491d3SAndrew Lindesay 
26666ee6532SAndrew Lindesay 	if (iconDataTarOffset >= 0) {
267c3cad236SAndrew Lindesay 		HashString key = _ToIconCacheKey(pkgName, storedSize, size);
268f0e491d3SAndrew Lindesay 
26966ee6532SAndrew Lindesay 		if (fIconCache.ContainsKey(key)) {
27066ee6532SAndrew Lindesay 			bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
27166ee6532SAndrew Lindesay 		} else {
272c3cad236SAndrew Lindesay 			result = _CreateIconFromTarOffset(iconDataTarOffset, storedSize, size, bitmapHolderRef);
27366ee6532SAndrew Lindesay 			if (result == B_OK) {
27466ee6532SAndrew Lindesay 				HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size);
27566ee6532SAndrew Lindesay 				fIconCache.Put(key, bitmapHolderRef);
27666ee6532SAndrew Lindesay 				bitmapHolderRef.SetTo(fIconCache.Get(key).Get());
27766ee6532SAndrew Lindesay 			} else {
278f0e491d3SAndrew Lindesay 				HDERROR("failure to read image for package [%s] at offset %"
279dfbcbde1SAndrew Lindesay 					B_PRIdOFF, pkgName.String(), iconDataTarOffset);
280f0e491d3SAndrew Lindesay 			}
281f0e491d3SAndrew Lindesay 		}
282f0e491d3SAndrew Lindesay 	}
28366ee6532SAndrew Lindesay 
28466ee6532SAndrew Lindesay 	if (!bitmapHolderRef.IsSet())
28566ee6532SAndrew Lindesay 		result = _GetDefaultIcon(size, bitmapHolderRef);
28666ee6532SAndrew Lindesay 
287f0e491d3SAndrew Lindesay 	return result;
288f0e491d3SAndrew Lindesay }
289f0e491d3SAndrew Lindesay 
290f0e491d3SAndrew Lindesay 
291f0e491d3SAndrew Lindesay IconTarPtrRef
_GetIconTarPtr(const BString & pkgName) const292f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetIconTarPtr(const BString& pkgName) const
293f0e491d3SAndrew Lindesay {
294f0e491d3SAndrew Lindesay 	return fIconTarPtrs.Get(HashString(pkgName));
295f0e491d3SAndrew Lindesay }
296f0e491d3SAndrew Lindesay 
297f0e491d3SAndrew Lindesay 
298f0e491d3SAndrew Lindesay const char*
_ToIconCacheKeyPart(BitmapSize storedSize)299c3cad236SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKeyPart(BitmapSize storedSize)
300f0e491d3SAndrew Lindesay {
301c3cad236SAndrew Lindesay 	switch (storedSize) {
302f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_16:
303f0e491d3SAndrew Lindesay 			return "16";
304f0e491d3SAndrew Lindesay 		// note that size 22 is not supported.
305f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_32:
306f0e491d3SAndrew Lindesay 			return "32";
307f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_64:
308f0e491d3SAndrew Lindesay 			return "64";
309f0e491d3SAndrew Lindesay 		case BITMAP_SIZE_ANY:
310f0e491d3SAndrew Lindesay 			return "any";
311f0e491d3SAndrew Lindesay 		default:
31205880d13SAndrew Lindesay 			HDFATAL("unsupported bitmap size");
313f0e491d3SAndrew Lindesay 			break;
314f0e491d3SAndrew Lindesay 	}
315f0e491d3SAndrew Lindesay }
316f0e491d3SAndrew Lindesay 
317f0e491d3SAndrew Lindesay 
318f0e491d3SAndrew Lindesay const HashString
_ToIconCacheKey(const BString & pkgName,BitmapSize storedSize,uint32 size)319c3cad236SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize storedSize,
320c3cad236SAndrew Lindesay 	uint32 size)
321f0e491d3SAndrew Lindesay {
322c3cad236SAndrew Lindesay 	return HashString(
323c3cad236SAndrew Lindesay 		BString(pkgName) << "__s" << _ToIconCacheKeyPart(storedSize) << "__x" << size);
324f0e491d3SAndrew Lindesay }
325f0e491d3SAndrew Lindesay 
326f0e491d3SAndrew Lindesay 
32766ee6532SAndrew Lindesay /*!	This method must only be invoked with the class locked.
32866ee6532SAndrew Lindesay  */
329f0e491d3SAndrew Lindesay status_t
_CreateIconFromTarOffset(off_t offset,BitmapSize storedSize,uint32 size,BitmapHolderRef & bitmapHolderRef)330c3cad236SAndrew Lindesay PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapSize storedSize, uint32 size,
331c3cad236SAndrew Lindesay 	BitmapHolderRef& bitmapHolderRef)
332f0e491d3SAndrew Lindesay {
333f0e491d3SAndrew Lindesay 	fTarIo->Seek(offset, SEEK_SET);
33466ee6532SAndrew Lindesay 	fIconDataBuffer->Seek(0, SEEK_SET);
33566ee6532SAndrew Lindesay 
336f0e491d3SAndrew Lindesay 	TarArchiveHeader header;
337f0e491d3SAndrew Lindesay 	status_t result = TarArchiveService::GetEntry(*fTarIo, header);
338f0e491d3SAndrew Lindesay 
33966ee6532SAndrew Lindesay 	if (result == B_OK && (header.Length() <= 0 || header.Length() > ICON_BUFFER_SIZE_MAX)) {
34066ee6532SAndrew Lindesay 		HDERROR("the icon tar entry at %" B_PRIdOFF " has a bad length %" B_PRIdSSIZE, offset,
34166ee6532SAndrew Lindesay 			header.Length());
342f0e491d3SAndrew Lindesay 		result = B_BAD_DATA;
34366ee6532SAndrew Lindesay 	}
34466ee6532SAndrew Lindesay 
34566ee6532SAndrew Lindesay 	off_t iconDataBufferSize = 0;
346f0e491d3SAndrew Lindesay 
347f0e491d3SAndrew Lindesay 	if (result == B_OK)
34866ee6532SAndrew Lindesay 		result = fIconDataBuffer->GetSize(&iconDataBufferSize);
34966ee6532SAndrew Lindesay 
35066ee6532SAndrew Lindesay 	if (result == B_OK && static_cast<size_t>(iconDataBufferSize) < header.Length())
35166ee6532SAndrew Lindesay 		result = fIconDataBuffer->SetSize(header.Length());
35266ee6532SAndrew Lindesay 
35366ee6532SAndrew Lindesay 	if (result == B_OK) {
35466ee6532SAndrew Lindesay 		BDataIO* tarImageIO = new ConstraintedDataIO(fTarIo, header.Length());
35566ee6532SAndrew Lindesay 		result = DataIOUtils::CopyAll(fIconDataBuffer, tarImageIO);
35666ee6532SAndrew Lindesay 		delete tarImageIO;
35766ee6532SAndrew Lindesay 	} else {
35866ee6532SAndrew Lindesay 		HDERROR("unable to extract data from tar for icon image");
35966ee6532SAndrew Lindesay 	}
36066ee6532SAndrew Lindesay 
36166ee6532SAndrew Lindesay 	fIconDataBuffer->Seek(0, SEEK_SET);
36266ee6532SAndrew Lindesay 
363c3cad236SAndrew Lindesay 	BBitmap* bitmap = NULL;
364c3cad236SAndrew Lindesay 
36566ee6532SAndrew Lindesay 	if (result == B_OK) {
366c3cad236SAndrew Lindesay 		if (BITMAP_SIZE_ANY == storedSize) {
367c3cad236SAndrew Lindesay 			bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
368c3cad236SAndrew Lindesay 			result = bitmap->InitCheck();
369c3cad236SAndrew Lindesay 			result = BIconUtils::GetVectorIcon(
370c3cad236SAndrew Lindesay 				reinterpret_cast<const uint8*>(fIconDataBuffer->Buffer()), header.Length(), bitmap);
371c3cad236SAndrew Lindesay 		} else {
372c3cad236SAndrew Lindesay 			bitmap = BTranslationUtils::GetBitmap(fIconDataBuffer);
37366ee6532SAndrew Lindesay 
37466ee6532SAndrew Lindesay 			if (bitmap == NULL) {
37566ee6532SAndrew Lindesay 				HDERROR("unable to decode data from tar for icon image");
37666ee6532SAndrew Lindesay 				result = B_ERROR;
377c3cad236SAndrew Lindesay 			}
378c3cad236SAndrew Lindesay 		}
379c3cad236SAndrew Lindesay 	}
380c3cad236SAndrew Lindesay 
381c3cad236SAndrew Lindesay 	if (result != B_OK)
382c3cad236SAndrew Lindesay 		delete bitmap;
383c3cad236SAndrew Lindesay 	else
38466ee6532SAndrew Lindesay 		bitmapHolderRef.SetTo(new(std::nothrow) BitmapHolder(bitmap), true);
385f0e491d3SAndrew Lindesay 
386f0e491d3SAndrew Lindesay 	return result;
387f0e491d3SAndrew Lindesay }
388f0e491d3SAndrew Lindesay 
389f0e491d3SAndrew Lindesay 
390f0e491d3SAndrew Lindesay /*!	If there is a vector representation (HVIF) then this will be the best
391f0e491d3SAndrew Lindesay 	option.  If there are only bitmap images to choose from then consider what
392f0e491d3SAndrew Lindesay 	the target size is and choose the best image to match.
393f0e491d3SAndrew Lindesay */
39466ee6532SAndrew Lindesay /*static*/ BitmapSize
_BestStoredSize(const IconTarPtrRef iconTarPtrRef,int32 desiredSize)39566ee6532SAndrew Lindesay PackageIconTarRepository::_BestStoredSize(const IconTarPtrRef iconTarPtrRef, int32 desiredSize)
396f0e491d3SAndrew Lindesay {
39766ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_ANY))
39866ee6532SAndrew Lindesay 		return BITMAP_SIZE_ANY;
39966ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_64) && desiredSize >= 64)
40066ee6532SAndrew Lindesay 		return BITMAP_SIZE_64;
40166ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32) && desiredSize >= 32)
40266ee6532SAndrew Lindesay 		return BITMAP_SIZE_32;
40366ee6532SAndrew Lindesay 	if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32))
40466ee6532SAndrew Lindesay 		return BITMAP_SIZE_16;
40566ee6532SAndrew Lindesay 	HDFATAL("unable to get the best stored icon for size");
406f0e491d3SAndrew Lindesay }
407f0e491d3SAndrew Lindesay 
408f0e491d3SAndrew Lindesay 
409f0e491d3SAndrew Lindesay IconTarPtrRef
_GetOrCreateIconTarPtr(const BString & pkgName)410f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName)
411f0e491d3SAndrew Lindesay {
412f0e491d3SAndrew Lindesay 	BAutolock locker(&fLock);
413f0e491d3SAndrew Lindesay 	HashString key(pkgName);
414f0e491d3SAndrew Lindesay 	if (!fIconTarPtrs.ContainsKey(key)) {
415f0e491d3SAndrew Lindesay 		IconTarPtrRef value(new IconTarPtr(pkgName));
416f0e491d3SAndrew Lindesay 		fIconTarPtrs.Put(key, value);
417f0e491d3SAndrew Lindesay 		return value;
418f0e491d3SAndrew Lindesay 	}
419f0e491d3SAndrew Lindesay 	return fIconTarPtrs.Get(key);
420f0e491d3SAndrew Lindesay }
421f0e491d3SAndrew Lindesay 
422f0e491d3SAndrew Lindesay 
42366ee6532SAndrew Lindesay status_t
_GetDefaultIcon(uint32 size,BitmapHolderRef & bitmapHolderRef)42466ee6532SAndrew Lindesay PackageIconTarRepository::_GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef)
425f0e491d3SAndrew Lindesay {
42666ee6532SAndrew Lindesay 	if (fDefaultIconVectorData == NULL)
42766ee6532SAndrew Lindesay 		return B_NOT_INITIALIZED;
42866ee6532SAndrew Lindesay 
42966ee6532SAndrew Lindesay 	bitmapHolderRef.Unset();
43066ee6532SAndrew Lindesay 
43166ee6532SAndrew Lindesay 	status_t status = B_OK;
43266ee6532SAndrew Lindesay 	HashString key(BString() << size);
43366ee6532SAndrew Lindesay 
43466ee6532SAndrew Lindesay 	if (!fDefaultIconCache.ContainsKey(key)) {
43566ee6532SAndrew Lindesay 		BBitmap* bitmap = NULL;
43666ee6532SAndrew Lindesay 
43766ee6532SAndrew Lindesay 		if (status == B_OK) {
43866ee6532SAndrew Lindesay 			bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32);
43966ee6532SAndrew Lindesay 			status = bitmap->InitCheck();
44066ee6532SAndrew Lindesay 		}
44166ee6532SAndrew Lindesay 
44266ee6532SAndrew Lindesay 		if (status == B_OK) {
44366ee6532SAndrew Lindesay 			status = BIconUtils::GetVectorIcon(fDefaultIconVectorData, fDefaultIconVectorDataSize,
44466ee6532SAndrew Lindesay 				bitmap);
44566ee6532SAndrew Lindesay 		}
44666ee6532SAndrew Lindesay 
44766ee6532SAndrew Lindesay 		if (status == B_OK) {
44866ee6532SAndrew Lindesay 			HDINFO("did create default package icon size %" B_PRId32, size);
44966ee6532SAndrew Lindesay 			BitmapHolderRef bitmapHolder(new(std::nothrow) BitmapHolder(bitmap), true);
45066ee6532SAndrew Lindesay 			fDefaultIconCache.Put(key, bitmapHolder);
45166ee6532SAndrew Lindesay 		} else {
45266ee6532SAndrew Lindesay 			delete bitmap;
45366ee6532SAndrew Lindesay 			bitmap = NULL;
45466ee6532SAndrew Lindesay 		}
45566ee6532SAndrew Lindesay 	}
45666ee6532SAndrew Lindesay 
45766ee6532SAndrew Lindesay 	if (status == B_OK)
45866ee6532SAndrew Lindesay 		bitmapHolderRef.SetTo(fDefaultIconCache.Get(key).Get());
45966ee6532SAndrew Lindesay 	else
46066ee6532SAndrew Lindesay 		HDERROR("failed to create default package icon size %" B_PRId32, size);
46166ee6532SAndrew Lindesay 
46266ee6532SAndrew Lindesay 	return status;
46366ee6532SAndrew Lindesay }
46466ee6532SAndrew Lindesay 
46566ee6532SAndrew Lindesay 
46666ee6532SAndrew Lindesay void
_InitDefaultVectorIcon()46766ee6532SAndrew Lindesay PackageIconTarRepository::_InitDefaultVectorIcon()
46866ee6532SAndrew Lindesay {
46966ee6532SAndrew Lindesay 	if (fDefaultIconVectorData != NULL) {
47066ee6532SAndrew Lindesay 		delete fDefaultIconVectorData;
47166ee6532SAndrew Lindesay 		fDefaultIconVectorData = NULL;
47266ee6532SAndrew Lindesay 	}
47366ee6532SAndrew Lindesay 
47466ee6532SAndrew Lindesay 	fDefaultIconVectorDataSize = 0;
47566ee6532SAndrew Lindesay 
47666ee6532SAndrew Lindesay 	BMimeType mimeType("application/x-vnd.haiku-package");
47766ee6532SAndrew Lindesay 	status_t status = mimeType.InitCheck();
47866ee6532SAndrew Lindesay 
47966ee6532SAndrew Lindesay 	uint8* data;
48066ee6532SAndrew Lindesay 	size_t dataSize;
48166ee6532SAndrew Lindesay 
48266ee6532SAndrew Lindesay 	if (status == B_OK)
48366ee6532SAndrew Lindesay 		status = mimeType.GetIcon(&data, &dataSize);
48466ee6532SAndrew Lindesay 
48566ee6532SAndrew Lindesay 	if (status == B_OK) {
48666ee6532SAndrew Lindesay 		fDefaultIconVectorData = new(std::nothrow) uint8[dataSize];
48766ee6532SAndrew Lindesay 
48866ee6532SAndrew Lindesay 		if (fDefaultIconVectorData == NULL)
48966ee6532SAndrew Lindesay 			HDFATAL("unable to allocate memory for the default icon");
49066ee6532SAndrew Lindesay 
49166ee6532SAndrew Lindesay 		memcpy(fDefaultIconVectorData, data, dataSize);
49266ee6532SAndrew Lindesay 		fDefaultIconVectorDataSize = dataSize;
49366ee6532SAndrew Lindesay 	} else {
49466ee6532SAndrew Lindesay 		fDefaultIconVectorData = NULL;
49566ee6532SAndrew Lindesay 		fDefaultIconVectorDataSize = 0;
49666ee6532SAndrew Lindesay 	}
497f0e491d3SAndrew Lindesay }
498