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