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