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