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