1 /* 2 * Copyright 2002-2008, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold, bonefish@users.sf.net 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 12 #include <errno.h> 13 #include <new> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/ioctl.h> 17 #include <unistd.h> 18 19 #include <AutoDeleter.h> 20 #include <Bitmap.h> 21 #include <Drivers.h> 22 #include <Entry.h> 23 #include <File.h> 24 #include <FindDirectory.h> 25 #include <fs_attr.h> 26 #include <fs_info.h> 27 #include <IconUtils.h> 28 #include <Mime.h> 29 #include <MimeType.h> 30 #include <Node.h> 31 #include <Path.h> 32 #include <RegistrarDefs.h> 33 #include <Roster.h> 34 #include <RosterPrivate.h> 35 36 37 using namespace BPrivate; 38 39 40 // Helper function that contacts the registrar for mime update calls 41 status_t 42 do_mime_update(int32 what, const char* path, int recursive, 43 int synchronous, int force) 44 { 45 BEntry root; 46 entry_ref ref; 47 48 status_t err = root.SetTo(path ? path : "/"); 49 if (!err) 50 err = root.GetRef(&ref); 51 if (!err) { 52 BMessage msg(what); 53 BMessage reply; 54 status_t result; 55 56 // Build and send the message, read the reply 57 if (!err) 58 err = msg.AddRef("entry", &ref); 59 if (!err) 60 err = msg.AddBool("recursive", recursive); 61 if (!err) 62 err = msg.AddBool("synchronous", synchronous); 63 if (!err) 64 err = msg.AddInt32("force", force); 65 if (!err) 66 err = BRoster::Private().SendTo(&msg, &reply, true); 67 if (!err) 68 err = reply.what == B_REG_RESULT ? B_OK : B_BAD_VALUE; 69 if (!err) 70 err = reply.FindInt32("result", &result); 71 if (!err) 72 err = result; 73 } 74 return err; 75 } 76 77 78 // Updates the MIME information (i.e MIME type) for one or more files. 79 int 80 update_mime_info(const char* path, int recursive, int synchronous, int force) 81 { 82 // Force recursion when given a NULL path 83 if (!path) 84 recursive = true; 85 86 return do_mime_update(B_REG_MIME_UPDATE_MIME_INFO, path, recursive, 87 synchronous, force); 88 } 89 90 91 // Creates a MIME database entry for one or more applications. 92 status_t 93 create_app_meta_mime(const char* path, int recursive, int synchronous, 94 int force) 95 { 96 // Force recursion when given a NULL path 97 if (!path) 98 recursive = true; 99 100 return do_mime_update(B_REG_MIME_CREATE_APP_META_MIME, path, recursive, 101 synchronous, force); 102 } 103 104 105 // Retrieves an icon associated with a given device. 106 status_t 107 get_device_icon(const char* device, void* icon, int32 size) 108 { 109 if (device == NULL || icon == NULL 110 || (size != B_LARGE_ICON && size != B_MINI_ICON)) 111 return B_BAD_VALUE; 112 113 int fd = open(device, O_RDONLY); 114 if (fd < 0) 115 return errno; 116 117 // ToDo: The mounted directories for volumes can also have META:X:STD_ICON 118 // attributes. Should those attributes override the icon returned by 119 // ioctl(,B_GET_ICON,)? 120 device_icon iconData = {size, icon}; 121 if (ioctl(fd, B_GET_ICON, &iconData) != 0) { 122 // legacy icon was not available, try vector icon 123 close(fd); 124 125 uint8* data; 126 size_t dataSize; 127 type_code type; 128 status_t status = get_device_icon(device, &data, &dataSize, &type); 129 if (status == B_OK) { 130 BBitmap* icon32 = new(std::nothrow) BBitmap( 131 BRect(0, 0, size - 1, size - 1), B_BITMAP_NO_SERVER_LINK, 132 B_RGBA32); 133 BBitmap* icon8 = new(std::nothrow) BBitmap( 134 BRect(0, 0, size - 1, size - 1), B_BITMAP_NO_SERVER_LINK, 135 B_CMAP8); 136 137 ArrayDeleter<uint8> dataDeleter(data); 138 ObjectDeleter<BBitmap> icon32Deleter(icon32); 139 ObjectDeleter<BBitmap> icon8Deleter(icon8); 140 141 if (icon32 == NULL || icon32->InitCheck() != B_OK || icon8 == NULL 142 || icon8->InitCheck() != B_OK) { 143 return B_NO_MEMORY; 144 } 145 146 status = BIconUtils::GetVectorIcon(data, dataSize, icon32); 147 if (status == B_OK) 148 status = BIconUtils::ConvertToCMAP8(icon32, icon8); 149 if (status == B_OK) 150 memcpy(icon, icon8->Bits(), icon8->BitsLength()); 151 152 return status; 153 } 154 return errno; 155 } 156 157 close(fd); 158 return B_OK; 159 } 160 161 162 // Retrieves an icon associated with a given device. 163 status_t 164 get_device_icon(const char* device, BBitmap* icon, icon_size which) 165 { 166 // check parameters 167 if (device == NULL || icon == NULL) 168 return B_BAD_VALUE; 169 170 uint8* data; 171 size_t size; 172 type_code type; 173 status_t status = get_device_icon(device, &data, &size, &type); 174 if (status == B_OK) { 175 status = BIconUtils::GetVectorIcon(data, size, icon); 176 delete[] data; 177 return status; 178 } 179 180 // Vector icon was not available, try old one 181 182 BRect rect; 183 if (which == B_MINI_ICON) 184 rect.Set(0, 0, 15, 15); 185 else if (which == B_LARGE_ICON) 186 rect.Set(0, 0, 31, 31); 187 188 BBitmap* bitmap = icon; 189 int32 iconSize = which; 190 191 if (icon->ColorSpace() != B_CMAP8 192 || (which != B_MINI_ICON && which != B_LARGE_ICON)) { 193 if (which < B_LARGE_ICON) 194 iconSize = B_MINI_ICON; 195 else 196 iconSize = B_LARGE_ICON; 197 198 bitmap = new(std::nothrow) BBitmap( 199 BRect(0, 0, iconSize - 1, iconSize -1), B_BITMAP_NO_SERVER_LINK, 200 B_CMAP8); 201 if (bitmap == NULL || bitmap->InitCheck() != B_OK) { 202 delete bitmap; 203 return B_NO_MEMORY; 204 } 205 } 206 207 // get the icon, convert temporary data into bitmap if necessary 208 status = get_device_icon(device, bitmap->Bits(), iconSize); 209 if (status == B_OK && icon != bitmap) 210 status = BIconUtils::ConvertFromCMAP8(bitmap, icon); 211 212 if (icon != bitmap) 213 delete bitmap; 214 215 return status; 216 } 217 218 219 status_t 220 get_device_icon(const char* device, uint8** _data, size_t* _size, 221 type_code* _type) 222 { 223 if (device == NULL || _data == NULL || _size == NULL || _type == NULL) 224 return B_BAD_VALUE; 225 226 int fd = open(device, O_RDONLY); 227 if (fd < 0) 228 return errno; 229 230 // Try to get the icon by name first 231 232 char name[B_FILE_NAME_LENGTH]; 233 if (ioctl(fd, B_GET_ICON_NAME, name) >= 0) { 234 status_t status = get_named_icon(name, _data, _size, _type); 235 if (status == B_OK) { 236 close(fd); 237 return B_OK; 238 } 239 } 240 241 // Getting the named icon failed, try vector icon next 242 243 // NOTE: The actual icon size is unknown as of yet. After the first call 244 // to B_GET_VECTOR_ICON, the actual size is known and the final buffer 245 // is allocated with the correct size. If the buffer needed to be 246 // larger, then the temporary buffer above will not yet contain the 247 // valid icon data. In that case, a second call to B_GET_VECTOR_ICON 248 // retrieves it into the final buffer. 249 uint8 data[8192]; 250 device_icon iconData = {sizeof(data), data}; 251 status_t status = ioctl(fd, B_GET_VECTOR_ICON, &iconData, 252 sizeof(device_icon)); 253 if (status != 0) 254 status = errno; 255 256 if (status == B_OK) { 257 *_data = new(std::nothrow) uint8[iconData.icon_size]; 258 if (*_data == NULL) 259 status = B_NO_MEMORY; 260 } 261 262 if (status == B_OK) { 263 if (iconData.icon_size > (int32)sizeof(data)) { 264 // the stack buffer does not contain the data, see NOTE above 265 iconData.icon_data = *_data; 266 status = ioctl(fd, B_GET_VECTOR_ICON, &iconData, 267 sizeof(device_icon)); 268 if (status != 0) 269 status = errno; 270 } else 271 memcpy(*_data, data, iconData.icon_size); 272 273 *_size = iconData.icon_size; 274 *_type = B_VECTOR_ICON_TYPE; 275 } 276 277 // TODO: also support getting the old icon? 278 close(fd); 279 return status; 280 } 281 282 283 status_t 284 get_named_icon(const char* name, BBitmap* icon, icon_size which) 285 { 286 // check parameters 287 if (name == NULL || icon == NULL) 288 return B_BAD_VALUE; 289 290 BRect rect; 291 if (which == B_MINI_ICON) 292 rect.Set(0, 0, 15, 15); 293 else if (which == B_LARGE_ICON) 294 rect.Set(0, 0, 31, 31); 295 else 296 return B_BAD_VALUE; 297 298 if (icon->Bounds() != rect) 299 return B_BAD_VALUE; 300 301 uint8* data; 302 size_t size; 303 type_code type; 304 status_t status = get_named_icon(name, &data, &size, &type); 305 if (status == B_OK) { 306 status = BIconUtils::GetVectorIcon(data, size, icon); 307 delete[] data; 308 } 309 310 return status; 311 } 312 313 314 status_t 315 get_named_icon(const char* name, uint8** _data, size_t* _size, type_code* _type) 316 { 317 if (name == NULL || _data == NULL || _size == NULL || _type == NULL) 318 return B_BAD_VALUE; 319 320 directory_which kWhich[] = { 321 B_USER_NONPACKAGED_DATA_DIRECTORY, 322 B_USER_DATA_DIRECTORY, 323 B_SYSTEM_NONPACKAGED_DATA_DIRECTORY, 324 B_SYSTEM_DATA_DIRECTORY, 325 }; 326 327 status_t status = B_ENTRY_NOT_FOUND; 328 BFile file; 329 off_t size; 330 331 for (uint32 i = 0; i < sizeof(kWhich) / sizeof(kWhich[0]); i++) { 332 BPath path; 333 if (find_directory(kWhich[i], &path) != B_OK) 334 continue; 335 336 path.Append("icons"); 337 path.Append(name); 338 339 status = file.SetTo(path.Path(), B_READ_ONLY); 340 if (status == B_OK) { 341 status = file.GetSize(&size); 342 if (size > 1024 * 1024) 343 status = B_ERROR; 344 } 345 if (status == B_OK) 346 break; 347 } 348 349 if (status != B_OK) 350 return status; 351 352 *_data = new(std::nothrow) uint8[size]; 353 if (*_data == NULL) 354 return B_NO_MEMORY; 355 356 if (file.Read(*_data, size) != size) { 357 delete[] *_data; 358 return B_ERROR; 359 } 360 361 *_size = size; 362 *_type = B_VECTOR_ICON_TYPE; 363 // TODO: for now 364 365 return B_OK; 366 } 367