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 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)); 92*c3cad236SAndrew Lindesay BitmapSize storedSize; 93f0e491d3SAndrew Lindesay 94*c3cad236SAndrew Lindesay if (_LeafNameToBitmapSize(leafName, &storedSize) == B_OK) 95*c3cad236SAndrew Lindesay fPackageIconTarRepository->AddIconTarPtr(packageName, storedSize, offset); 96f0e491d3SAndrew Lindesay 97f0e491d3SAndrew Lindesay return B_OK; 98f0e491d3SAndrew Lindesay } 99f0e491d3SAndrew Lindesay 100f0e491d3SAndrew Lindesay 101f0e491d3SAndrew Lindesay status_t 102*c3cad236SAndrew Lindesay IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName, BitmapSize* storedSize) 103f0e491d3SAndrew Lindesay { 104f0e491d3SAndrew Lindesay if (leafName == "icon.hvif") { 105*c3cad236SAndrew Lindesay *storedSize = BITMAP_SIZE_ANY; 106f0e491d3SAndrew Lindesay return B_OK; 107f0e491d3SAndrew Lindesay } 108f0e491d3SAndrew Lindesay if (leafName == "64.png") { 109*c3cad236SAndrew Lindesay *storedSize = BITMAP_SIZE_64; 110f0e491d3SAndrew Lindesay return B_OK; 111f0e491d3SAndrew Lindesay } 112f0e491d3SAndrew Lindesay if (leafName == "32.png") { 113*c3cad236SAndrew Lindesay *storedSize = BITMAP_SIZE_32; 114f0e491d3SAndrew Lindesay return B_OK; 115f0e491d3SAndrew Lindesay } 116f0e491d3SAndrew Lindesay if (leafName == "16.png") { 117*c3cad236SAndrew Lindesay *storedSize = BITMAP_SIZE_16; 118f0e491d3SAndrew Lindesay return B_OK; 119f0e491d3SAndrew Lindesay } 120f0e491d3SAndrew Lindesay return B_BAD_VALUE; 121f0e491d3SAndrew Lindesay } 122f0e491d3SAndrew Lindesay 123f0e491d3SAndrew Lindesay 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 { 133f0e491d3SAndrew Lindesay } 134f0e491d3SAndrew Lindesay 135f0e491d3SAndrew Lindesay 136f0e491d3SAndrew Lindesay PackageIconTarRepository::~PackageIconTarRepository() 137f0e491d3SAndrew Lindesay { 13866ee6532SAndrew Lindesay delete fIconDataBuffer; 139f0e491d3SAndrew Lindesay } 140f0e491d3SAndrew Lindesay 141f0e491d3SAndrew Lindesay 142d75b4d61SAndrew Lindesay void 143d75b4d61SAndrew Lindesay PackageIconTarRepository::Clear() { 144d75b4d61SAndrew Lindesay BAutolock locker(&fLock); 145d75b4d61SAndrew Lindesay fIconCache.Clear(); 14666ee6532SAndrew Lindesay fDefaultIconCache.Clear(); 147d75b4d61SAndrew Lindesay } 148d75b4d61SAndrew Lindesay 149d75b4d61SAndrew Lindesay 150f0e491d3SAndrew Lindesay /*! This method will reconfigure itself using the data in the tar file supplied. 151f0e491d3SAndrew Lindesay Any existing data will be flushed and the new tar will be scanned for 152f0e491d3SAndrew Lindesay offsets to usable files. 153f0e491d3SAndrew Lindesay */ 154f0e491d3SAndrew Lindesay 155f0e491d3SAndrew Lindesay status_t 156f0e491d3SAndrew Lindesay PackageIconTarRepository::Init(BPath& tarPath) 157f0e491d3SAndrew Lindesay { 158f0e491d3SAndrew Lindesay BAutolock locker(&fLock); 15966ee6532SAndrew Lindesay 160f0e491d3SAndrew Lindesay _Close(); 16166ee6532SAndrew Lindesay 16266ee6532SAndrew Lindesay _InitDefaultVectorIcon(); 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 211f0e491d3SAndrew Lindesay PackageIconTarRepository::_Close() 212f0e491d3SAndrew Lindesay { 213d75b4d61SAndrew Lindesay fIconCache.Clear(); 214f0e491d3SAndrew Lindesay delete fTarIo; 215f0e491d3SAndrew Lindesay fTarIo = NULL; 216f0e491d3SAndrew Lindesay fIconTarPtrs.Clear(); 21766ee6532SAndrew Lindesay 21866ee6532SAndrew Lindesay delete fDefaultIconVectorData; 21966ee6532SAndrew Lindesay fDefaultIconVectorData = NULL; 22066ee6532SAndrew Lindesay fDefaultIconVectorDataSize = 0; 22166ee6532SAndrew Lindesay fDefaultIconCache.Clear(); 222f0e491d3SAndrew Lindesay } 223f0e491d3SAndrew Lindesay 224f0e491d3SAndrew Lindesay 225f0e491d3SAndrew Lindesay /*! This method should be treated private and only called from a situation 226f0e491d3SAndrew Lindesay in which the class's lock is acquired. It is used to populate data from 227f0e491d3SAndrew Lindesay the parsing of the tar headers. It is called from the listener above. 228f0e491d3SAndrew Lindesay */ 229f0e491d3SAndrew Lindesay void 230*c3cad236SAndrew Lindesay PackageIconTarRepository::AddIconTarPtr(const BString& packageName, BitmapSize storedSize, 23166ee6532SAndrew Lindesay off_t offset) 232f0e491d3SAndrew Lindesay { 233f0e491d3SAndrew Lindesay IconTarPtrRef tarPtrRef = _GetOrCreateIconTarPtr(packageName); 234*c3cad236SAndrew Lindesay tarPtrRef->SetOffset(storedSize, offset); 235f0e491d3SAndrew Lindesay } 236f0e491d3SAndrew Lindesay 237f0e491d3SAndrew Lindesay 238f0e491d3SAndrew Lindesay bool 239f0e491d3SAndrew Lindesay PackageIconTarRepository::HasAnyIcon(const BString& pkgName) 240f0e491d3SAndrew Lindesay { 241f0e491d3SAndrew Lindesay BAutolock locker(&fLock); 242f0e491d3SAndrew Lindesay HashString key(pkgName); 243f0e491d3SAndrew Lindesay return fIconTarPtrs.ContainsKey(key); 244f0e491d3SAndrew Lindesay } 245f0e491d3SAndrew Lindesay 246f0e491d3SAndrew Lindesay 247f0e491d3SAndrew Lindesay status_t 24866ee6532SAndrew Lindesay PackageIconTarRepository::GetIcon(const BString& pkgName, uint32 size, 24966ee6532SAndrew Lindesay BitmapHolderRef& bitmapHolderRef) 250f0e491d3SAndrew Lindesay { 25166ee6532SAndrew Lindesay if (0 == size || size > MAX_IMAGE_SIZE) { 25266ee6532SAndrew Lindesay HDERROR("request to get icon for pkg [%s] with bad size %" B_PRIu32, pkgName.String(), 25366ee6532SAndrew Lindesay size); 25466ee6532SAndrew Lindesay return B_BAD_VALUE; 25566ee6532SAndrew Lindesay } 25666ee6532SAndrew Lindesay 25766ee6532SAndrew Lindesay bitmapHolderRef.Unset(); 25866ee6532SAndrew Lindesay 259f0e491d3SAndrew Lindesay BAutolock locker(&fLock); 260f0e491d3SAndrew Lindesay status_t result = B_OK; 261f0e491d3SAndrew Lindesay off_t iconDataTarOffset = -1; 262f0e491d3SAndrew Lindesay const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName); 263*c3cad236SAndrew Lindesay BitmapSize storedSize; 264f0e491d3SAndrew Lindesay 265779ab335SX512 if (tarPtrRef.IsSet()) { 266*c3cad236SAndrew Lindesay storedSize = _BestStoredSize(tarPtrRef, size); 267*c3cad236SAndrew Lindesay iconDataTarOffset = tarPtrRef->Offset(storedSize); 268f0e491d3SAndrew Lindesay } 269f0e491d3SAndrew Lindesay 27066ee6532SAndrew Lindesay if (iconDataTarOffset >= 0) { 271*c3cad236SAndrew Lindesay HashString key = _ToIconCacheKey(pkgName, storedSize, size); 272f0e491d3SAndrew Lindesay 27366ee6532SAndrew Lindesay if (fIconCache.ContainsKey(key)) { 27466ee6532SAndrew Lindesay bitmapHolderRef.SetTo(fIconCache.Get(key).Get()); 27566ee6532SAndrew Lindesay } else { 276*c3cad236SAndrew Lindesay result = _CreateIconFromTarOffset(iconDataTarOffset, storedSize, size, bitmapHolderRef); 27766ee6532SAndrew Lindesay if (result == B_OK) { 27866ee6532SAndrew Lindesay HDTRACE("loaded package icon [%s] of size %" B_PRId32, pkgName.String(), size); 27966ee6532SAndrew Lindesay fIconCache.Put(key, bitmapHolderRef); 28066ee6532SAndrew Lindesay bitmapHolderRef.SetTo(fIconCache.Get(key).Get()); 28166ee6532SAndrew Lindesay } else { 282f0e491d3SAndrew Lindesay HDERROR("failure to read image for package [%s] at offset %" 283dfbcbde1SAndrew Lindesay B_PRIdOFF, pkgName.String(), iconDataTarOffset); 284f0e491d3SAndrew Lindesay } 285f0e491d3SAndrew Lindesay } 286f0e491d3SAndrew Lindesay } 28766ee6532SAndrew Lindesay 28866ee6532SAndrew Lindesay if (!bitmapHolderRef.IsSet()) 28966ee6532SAndrew Lindesay result = _GetDefaultIcon(size, bitmapHolderRef); 29066ee6532SAndrew Lindesay 291f0e491d3SAndrew Lindesay return result; 292f0e491d3SAndrew Lindesay } 293f0e491d3SAndrew Lindesay 294f0e491d3SAndrew Lindesay 295f0e491d3SAndrew Lindesay IconTarPtrRef 296f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetIconTarPtr(const BString& pkgName) const 297f0e491d3SAndrew Lindesay { 298f0e491d3SAndrew Lindesay return fIconTarPtrs.Get(HashString(pkgName)); 299f0e491d3SAndrew Lindesay } 300f0e491d3SAndrew Lindesay 301f0e491d3SAndrew Lindesay 302f0e491d3SAndrew Lindesay const char* 303*c3cad236SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKeyPart(BitmapSize storedSize) 304f0e491d3SAndrew Lindesay { 305*c3cad236SAndrew Lindesay switch (storedSize) { 306f0e491d3SAndrew Lindesay case BITMAP_SIZE_16: 307f0e491d3SAndrew Lindesay return "16"; 308f0e491d3SAndrew Lindesay // note that size 22 is not supported. 309f0e491d3SAndrew Lindesay case BITMAP_SIZE_32: 310f0e491d3SAndrew Lindesay return "32"; 311f0e491d3SAndrew Lindesay case BITMAP_SIZE_64: 312f0e491d3SAndrew Lindesay return "64"; 313f0e491d3SAndrew Lindesay case BITMAP_SIZE_ANY: 314f0e491d3SAndrew Lindesay return "any"; 315f0e491d3SAndrew Lindesay default: 31605880d13SAndrew Lindesay HDFATAL("unsupported bitmap size"); 317f0e491d3SAndrew Lindesay break; 318f0e491d3SAndrew Lindesay } 319f0e491d3SAndrew Lindesay } 320f0e491d3SAndrew Lindesay 321f0e491d3SAndrew Lindesay 322f0e491d3SAndrew Lindesay const HashString 323*c3cad236SAndrew Lindesay PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName, BitmapSize storedSize, 324*c3cad236SAndrew Lindesay uint32 size) 325f0e491d3SAndrew Lindesay { 326*c3cad236SAndrew Lindesay return HashString( 327*c3cad236SAndrew Lindesay BString(pkgName) << "__s" << _ToIconCacheKeyPart(storedSize) << "__x" << size); 328f0e491d3SAndrew Lindesay } 329f0e491d3SAndrew Lindesay 330f0e491d3SAndrew Lindesay 33166ee6532SAndrew Lindesay /*! This method must only be invoked with the class locked. 33266ee6532SAndrew Lindesay */ 333f0e491d3SAndrew Lindesay status_t 334*c3cad236SAndrew Lindesay PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset, BitmapSize storedSize, uint32 size, 335*c3cad236SAndrew Lindesay BitmapHolderRef& bitmapHolderRef) 336f0e491d3SAndrew Lindesay { 337f0e491d3SAndrew Lindesay fTarIo->Seek(offset, SEEK_SET); 33866ee6532SAndrew Lindesay fIconDataBuffer->Seek(0, SEEK_SET); 33966ee6532SAndrew Lindesay 340f0e491d3SAndrew Lindesay TarArchiveHeader header; 341f0e491d3SAndrew Lindesay status_t result = TarArchiveService::GetEntry(*fTarIo, header); 342f0e491d3SAndrew Lindesay 34366ee6532SAndrew Lindesay if (result == B_OK && (header.Length() <= 0 || header.Length() > ICON_BUFFER_SIZE_MAX)) { 34466ee6532SAndrew Lindesay HDERROR("the icon tar entry at %" B_PRIdOFF " has a bad length %" B_PRIdSSIZE, offset, 34566ee6532SAndrew Lindesay header.Length()); 346f0e491d3SAndrew Lindesay result = B_BAD_DATA; 34766ee6532SAndrew Lindesay } 34866ee6532SAndrew Lindesay 34966ee6532SAndrew Lindesay off_t iconDataBufferSize = 0; 350f0e491d3SAndrew Lindesay 351f0e491d3SAndrew Lindesay if (result == B_OK) 35266ee6532SAndrew Lindesay result = fIconDataBuffer->GetSize(&iconDataBufferSize); 35366ee6532SAndrew Lindesay 35466ee6532SAndrew Lindesay if (result == B_OK && static_cast<size_t>(iconDataBufferSize) < header.Length()) 35566ee6532SAndrew Lindesay result = fIconDataBuffer->SetSize(header.Length()); 35666ee6532SAndrew Lindesay 35766ee6532SAndrew Lindesay if (result == B_OK) { 35866ee6532SAndrew Lindesay BDataIO* tarImageIO = new ConstraintedDataIO(fTarIo, header.Length()); 35966ee6532SAndrew Lindesay result = DataIOUtils::CopyAll(fIconDataBuffer, tarImageIO); 36066ee6532SAndrew Lindesay delete tarImageIO; 36166ee6532SAndrew Lindesay } else { 36266ee6532SAndrew Lindesay HDERROR("unable to extract data from tar for icon image"); 36366ee6532SAndrew Lindesay } 36466ee6532SAndrew Lindesay 36566ee6532SAndrew Lindesay fIconDataBuffer->Seek(0, SEEK_SET); 36666ee6532SAndrew Lindesay 367*c3cad236SAndrew Lindesay BBitmap* bitmap = NULL; 368*c3cad236SAndrew Lindesay 36966ee6532SAndrew Lindesay if (result == B_OK) { 370*c3cad236SAndrew Lindesay if (BITMAP_SIZE_ANY == storedSize) { 371*c3cad236SAndrew Lindesay bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32); 372*c3cad236SAndrew Lindesay result = bitmap->InitCheck(); 373*c3cad236SAndrew Lindesay result = BIconUtils::GetVectorIcon( 374*c3cad236SAndrew Lindesay reinterpret_cast<const uint8*>(fIconDataBuffer->Buffer()), header.Length(), bitmap); 375*c3cad236SAndrew Lindesay } else { 376*c3cad236SAndrew Lindesay bitmap = BTranslationUtils::GetBitmap(fIconDataBuffer); 37766ee6532SAndrew Lindesay 37866ee6532SAndrew Lindesay if (bitmap == NULL) { 37966ee6532SAndrew Lindesay HDERROR("unable to decode data from tar for icon image"); 38066ee6532SAndrew Lindesay result = B_ERROR; 381*c3cad236SAndrew Lindesay } 382*c3cad236SAndrew Lindesay } 383*c3cad236SAndrew Lindesay } 384*c3cad236SAndrew Lindesay 385*c3cad236SAndrew Lindesay if (result != B_OK) 386*c3cad236SAndrew Lindesay delete bitmap; 387*c3cad236SAndrew Lindesay else 38866ee6532SAndrew Lindesay bitmapHolderRef.SetTo(new(std::nothrow) BitmapHolder(bitmap), true); 389f0e491d3SAndrew Lindesay 390f0e491d3SAndrew Lindesay return result; 391f0e491d3SAndrew Lindesay } 392f0e491d3SAndrew Lindesay 393f0e491d3SAndrew Lindesay 394f0e491d3SAndrew Lindesay /*! If there is a vector representation (HVIF) then this will be the best 395f0e491d3SAndrew Lindesay option. If there are only bitmap images to choose from then consider what 396f0e491d3SAndrew Lindesay the target size is and choose the best image to match. 397f0e491d3SAndrew Lindesay */ 39866ee6532SAndrew Lindesay /*static*/ BitmapSize 39966ee6532SAndrew Lindesay PackageIconTarRepository::_BestStoredSize(const IconTarPtrRef iconTarPtrRef, int32 desiredSize) 400f0e491d3SAndrew Lindesay { 40166ee6532SAndrew Lindesay if (iconTarPtrRef->HasOffset(BITMAP_SIZE_ANY)) 40266ee6532SAndrew Lindesay return BITMAP_SIZE_ANY; 40366ee6532SAndrew Lindesay if (iconTarPtrRef->HasOffset(BITMAP_SIZE_64) && desiredSize >= 64) 40466ee6532SAndrew Lindesay return BITMAP_SIZE_64; 40566ee6532SAndrew Lindesay if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32) && desiredSize >= 32) 40666ee6532SAndrew Lindesay return BITMAP_SIZE_32; 40766ee6532SAndrew Lindesay if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32)) 40866ee6532SAndrew Lindesay return BITMAP_SIZE_16; 40966ee6532SAndrew Lindesay HDFATAL("unable to get the best stored icon for size"); 410f0e491d3SAndrew Lindesay } 411f0e491d3SAndrew Lindesay 412f0e491d3SAndrew Lindesay 413f0e491d3SAndrew Lindesay IconTarPtrRef 414f0e491d3SAndrew Lindesay PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName) 415f0e491d3SAndrew Lindesay { 416f0e491d3SAndrew Lindesay BAutolock locker(&fLock); 417f0e491d3SAndrew Lindesay HashString key(pkgName); 418f0e491d3SAndrew Lindesay if (!fIconTarPtrs.ContainsKey(key)) { 419f0e491d3SAndrew Lindesay IconTarPtrRef value(new IconTarPtr(pkgName)); 420f0e491d3SAndrew Lindesay fIconTarPtrs.Put(key, value); 421f0e491d3SAndrew Lindesay return value; 422f0e491d3SAndrew Lindesay } 423f0e491d3SAndrew Lindesay return fIconTarPtrs.Get(key); 424f0e491d3SAndrew Lindesay } 425f0e491d3SAndrew Lindesay 426f0e491d3SAndrew Lindesay 42766ee6532SAndrew Lindesay status_t 42866ee6532SAndrew Lindesay PackageIconTarRepository::_GetDefaultIcon(uint32 size, BitmapHolderRef& bitmapHolderRef) 429f0e491d3SAndrew Lindesay { 43066ee6532SAndrew Lindesay if (fDefaultIconVectorData == NULL) 43166ee6532SAndrew Lindesay return B_NOT_INITIALIZED; 43266ee6532SAndrew Lindesay 43366ee6532SAndrew Lindesay bitmapHolderRef.Unset(); 43466ee6532SAndrew Lindesay 43566ee6532SAndrew Lindesay status_t status = B_OK; 43666ee6532SAndrew Lindesay HashString key(BString() << size); 43766ee6532SAndrew Lindesay 43866ee6532SAndrew Lindesay if (!fDefaultIconCache.ContainsKey(key)) { 43966ee6532SAndrew Lindesay BBitmap* bitmap = NULL; 44066ee6532SAndrew Lindesay 44166ee6532SAndrew Lindesay if (status == B_OK) { 44266ee6532SAndrew Lindesay bitmap = new BBitmap(BRect(0, 0, size - 1, size - 1), 0, B_RGBA32); 44366ee6532SAndrew Lindesay status = bitmap->InitCheck(); 44466ee6532SAndrew Lindesay } 44566ee6532SAndrew Lindesay 44666ee6532SAndrew Lindesay if (status == B_OK) { 44766ee6532SAndrew Lindesay status = BIconUtils::GetVectorIcon(fDefaultIconVectorData, fDefaultIconVectorDataSize, 44866ee6532SAndrew Lindesay bitmap); 44966ee6532SAndrew Lindesay } 45066ee6532SAndrew Lindesay 45166ee6532SAndrew Lindesay if (status == B_OK) { 45266ee6532SAndrew Lindesay HDINFO("did create default package icon size %" B_PRId32, size); 45366ee6532SAndrew Lindesay BitmapHolderRef bitmapHolder(new(std::nothrow) BitmapHolder(bitmap), true); 45466ee6532SAndrew Lindesay fDefaultIconCache.Put(key, bitmapHolder); 45566ee6532SAndrew Lindesay } else { 45666ee6532SAndrew Lindesay delete bitmap; 45766ee6532SAndrew Lindesay bitmap = NULL; 45866ee6532SAndrew Lindesay } 45966ee6532SAndrew Lindesay } 46066ee6532SAndrew Lindesay 46166ee6532SAndrew Lindesay if (status == B_OK) 46266ee6532SAndrew Lindesay bitmapHolderRef.SetTo(fDefaultIconCache.Get(key).Get()); 46366ee6532SAndrew Lindesay else 46466ee6532SAndrew Lindesay HDERROR("failed to create default package icon size %" B_PRId32, size); 46566ee6532SAndrew Lindesay 46666ee6532SAndrew Lindesay return status; 46766ee6532SAndrew Lindesay } 46866ee6532SAndrew Lindesay 46966ee6532SAndrew Lindesay 47066ee6532SAndrew Lindesay void 47166ee6532SAndrew Lindesay PackageIconTarRepository::_InitDefaultVectorIcon() 47266ee6532SAndrew Lindesay { 47366ee6532SAndrew Lindesay if (fDefaultIconVectorData != NULL) { 47466ee6532SAndrew Lindesay delete fDefaultIconVectorData; 47566ee6532SAndrew Lindesay fDefaultIconVectorData = NULL; 47666ee6532SAndrew Lindesay } 47766ee6532SAndrew Lindesay 47866ee6532SAndrew Lindesay fDefaultIconVectorDataSize = 0; 47966ee6532SAndrew Lindesay 48066ee6532SAndrew Lindesay BMimeType mimeType("application/x-vnd.haiku-package"); 48166ee6532SAndrew Lindesay status_t status = mimeType.InitCheck(); 48266ee6532SAndrew Lindesay 48366ee6532SAndrew Lindesay uint8* data; 48466ee6532SAndrew Lindesay size_t dataSize; 48566ee6532SAndrew Lindesay 48666ee6532SAndrew Lindesay if (status == B_OK) 48766ee6532SAndrew Lindesay status = mimeType.GetIcon(&data, &dataSize); 48866ee6532SAndrew Lindesay 48966ee6532SAndrew Lindesay if (status == B_OK) { 49066ee6532SAndrew Lindesay fDefaultIconVectorData = new(std::nothrow) uint8[dataSize]; 49166ee6532SAndrew Lindesay 49266ee6532SAndrew Lindesay if (fDefaultIconVectorData == NULL) 49366ee6532SAndrew Lindesay HDFATAL("unable to allocate memory for the default icon"); 49466ee6532SAndrew Lindesay 49566ee6532SAndrew Lindesay memcpy(fDefaultIconVectorData, data, dataSize); 49666ee6532SAndrew Lindesay fDefaultIconVectorDataSize = dataSize; 49766ee6532SAndrew Lindesay } else { 49866ee6532SAndrew Lindesay fDefaultIconVectorData = NULL; 49966ee6532SAndrew Lindesay fDefaultIconVectorDataSize = 0; 50066ee6532SAndrew Lindesay } 501f0e491d3SAndrew Lindesay } 502