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
do_mime_update(int32 what,const char * path,int recursive,int synchronous,int force)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
update_mime_info(const char * path,int recursive,int synchronous,int force)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
create_app_meta_mime(const char * path,int recursive,int synchronous,int force)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
get_device_icon(const char * device,void * icon,int32 size)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, sizeof(device_icon)) != 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
get_device_icon(const char * device,BBitmap * icon,icon_size which)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
get_device_icon(const char * device,uint8 ** _data,size_t * _size,type_code * _type)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, sizeof(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
get_named_icon(const char * name,BBitmap * icon,icon_size which)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
get_named_icon(const char * name,uint8 ** _data,size_t * _size,type_code * _type)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