1 /*
2 * Copyright 2002-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Ingo Weinhold, bonefish@users.sf.net
7 * Axel Dörfler, axeld@pinc-software.de
8 */
9
10
11 #include <NodeInfo.h>
12
13 #include <new>
14 #include <string.h>
15
16 #include <MimeTypes.h>
17 #include <Bitmap.h>
18 #include <Entry.h>
19 #include <IconUtils.h>
20 #include <Node.h>
21 #include <Path.h>
22 #include <Rect.h>
23
24 #include <fs_attr.h>
25 #include <fs_info.h>
26
27
28 using namespace std;
29
30
31 // attribute names
32 #define NI_BEOS "BEOS"
33 static const char* kNITypeAttribute = NI_BEOS ":TYPE";
34 static const char* kNIPreferredAppAttribute = NI_BEOS ":PREF_APP";
35 static const char* kNIAppHintAttribute = NI_BEOS ":PPATH";
36 static const char* kNIMiniIconAttribute = NI_BEOS ":M:STD_ICON";
37 static const char* kNILargeIconAttribute = NI_BEOS ":L:STD_ICON";
38 static const char* kNIIconAttribute = NI_BEOS ":ICON";
39
40
41 // #pragma mark - BNodeInfo
42
43
BNodeInfo()44 BNodeInfo::BNodeInfo()
45 :
46 fNode(NULL),
47 fCStatus(B_NO_INIT)
48 {
49 }
50
51
BNodeInfo(BNode * node)52 BNodeInfo::BNodeInfo(BNode* node)
53 :
54 fNode(NULL),
55 fCStatus(B_NO_INIT)
56 {
57 fCStatus = SetTo(node);
58 }
59
60
~BNodeInfo()61 BNodeInfo::~BNodeInfo()
62 {
63 }
64
65
66 status_t
SetTo(BNode * node)67 BNodeInfo::SetTo(BNode* node)
68 {
69 fNode = NULL;
70 // check parameter
71 fCStatus = (node && node->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
72 if (fCStatus == B_OK)
73 fNode = node;
74
75 return fCStatus;
76 }
77
78
79 status_t
InitCheck() const80 BNodeInfo::InitCheck() const
81 {
82 return fCStatus;
83 }
84
85
86 status_t
GetType(char * type) const87 BNodeInfo::GetType(char* type) const
88 {
89 // check parameter and initialization
90 status_t result = (type ? B_OK : B_BAD_VALUE);
91 if (result == B_OK && InitCheck() != B_OK)
92 result = B_NO_INIT;
93
94 // get the attribute info and check type and length of the attr contents
95 attr_info attrInfo;
96 if (result == B_OK)
97 result = fNode->GetAttrInfo(kNITypeAttribute, &attrInfo);
98
99 if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
100 result = B_BAD_TYPE;
101
102 if (result == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
103 result = B_BAD_DATA;
104
105 // read the data
106 if (result == B_OK) {
107 ssize_t read = fNode->ReadAttr(kNITypeAttribute, attrInfo.type, 0,
108 type, attrInfo.size);
109 if (read < 0)
110 result = read;
111 else if (read != attrInfo.size)
112 result = B_ERROR;
113
114 if (result == B_OK) {
115 // attribute strings doesn't have to be null terminated
116 type[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
117 }
118 }
119
120 return result;
121 }
122
123
124 status_t
SetType(const char * type)125 BNodeInfo::SetType(const char* type)
126 {
127 // check parameter and initialization
128 status_t result = B_OK;
129 if (result == B_OK && type && strlen(type) >= B_MIME_TYPE_LENGTH)
130 result = B_BAD_VALUE;
131
132 if (result == B_OK && InitCheck() != B_OK)
133 result = B_NO_INIT;
134
135 // write/remove the attribute
136 if (result == B_OK) {
137 if (type != NULL) {
138 size_t toWrite = strlen(type) + 1;
139 ssize_t written = fNode->WriteAttr(kNITypeAttribute,
140 B_MIME_STRING_TYPE, 0, type, toWrite);
141 if (written < 0)
142 result = written;
143 else if (written != (ssize_t)toWrite)
144 result = B_ERROR;
145 } else
146 result = fNode->RemoveAttr(kNITypeAttribute);
147 }
148
149 return result;
150 }
151
152
153 status_t
GetIcon(BBitmap * icon,icon_size which) const154 BNodeInfo::GetIcon(BBitmap* icon, icon_size which) const
155 {
156 const char* iconAttribute = kNIIconAttribute;
157 const char* miniIconAttribute = kNIMiniIconAttribute;
158 const char* largeIconAttribute = kNILargeIconAttribute;
159
160 return BIconUtils::GetIcon(fNode, iconAttribute, miniIconAttribute,
161 largeIconAttribute, which, icon);
162 }
163
164
165 status_t
SetIcon(const BBitmap * icon,icon_size which)166 BNodeInfo::SetIcon(const BBitmap* icon, icon_size which)
167 {
168 status_t result = B_OK;
169
170 // set some icon size related variables
171 const char* attribute = NULL;
172 BRect bounds;
173 uint32 attrType = 0;
174 size_t attrSize = 0;
175
176 switch (which) {
177 case B_MINI_ICON:
178 attribute = kNIMiniIconAttribute;
179 bounds.Set(0, 0, 15, 15);
180 attrType = B_MINI_ICON_TYPE;
181 attrSize = 16 * 16;
182 break;
183
184 case B_LARGE_ICON:
185 attribute = kNILargeIconAttribute;
186 bounds.Set(0, 0, 31, 31);
187 attrType = B_LARGE_ICON_TYPE;
188 attrSize = 32 * 32;
189 break;
190
191 default:
192 result = B_BAD_VALUE;
193 break;
194 }
195
196 // check parameter and initialization
197 if (result == B_OK && icon != NULL
198 && (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
199 result = B_BAD_VALUE;
200 }
201 if (result == B_OK && InitCheck() != B_OK)
202 result = B_NO_INIT;
203
204 // write/remove the attribute
205 if (result == B_OK) {
206 if (icon != NULL) {
207 bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
208 ssize_t written = 0;
209 if (otherColorSpace) {
210 BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
211 result = bitmap.InitCheck();
212 if (result == B_OK)
213 result = bitmap.ImportBits(icon);
214
215 if (result == B_OK) {
216 written = fNode->WriteAttr(attribute, attrType, 0,
217 bitmap.Bits(), attrSize);
218 }
219 } else {
220 written = fNode->WriteAttr(attribute, attrType, 0,
221 icon->Bits(), attrSize);
222 }
223 if (result == B_OK) {
224 if (written < 0)
225 result = written;
226 else if (written != (ssize_t)attrSize)
227 result = B_ERROR;
228 }
229 } else {
230 // no icon given => remove
231 result = fNode->RemoveAttr(attribute);
232 }
233 }
234
235 return result;
236 }
237
238
239 status_t
GetIcon(uint8 ** data,size_t * size,type_code * type) const240 BNodeInfo::GetIcon(uint8** data, size_t* size, type_code* type) const
241 {
242 // check params
243 if (data == NULL || size == NULL || type == NULL)
244 return B_BAD_VALUE;
245
246 // check initialization
247 if (InitCheck() != B_OK)
248 return B_NO_INIT;
249
250 // get the attribute info and check type and size of the attr contents
251 attr_info attrInfo;
252 status_t result = fNode->GetAttrInfo(kNIIconAttribute, &attrInfo);
253 if (result != B_OK)
254 return result;
255
256 // chicken out on unrealisticly large attributes
257 if (attrInfo.size > 128 * 1024)
258 return B_ERROR;
259
260 // fill the params
261 *type = attrInfo.type;
262 *size = attrInfo.size;
263 *data = new (nothrow) uint8[*size];
264 if (*data == NULL)
265 return B_NO_MEMORY;
266
267 // featch the data
268 ssize_t read = fNode->ReadAttr(kNIIconAttribute, *type, 0, *data, *size);
269 if (read != attrInfo.size) {
270 delete[] *data;
271 *data = NULL;
272 return B_ERROR;
273 }
274
275 return B_OK;
276 }
277
278
279 status_t
SetIcon(const uint8 * data,size_t size)280 BNodeInfo::SetIcon(const uint8* data, size_t size)
281 {
282 // check initialization
283 if (InitCheck() != B_OK)
284 return B_NO_INIT;
285
286 status_t result = B_OK;
287
288 // write/remove the attribute
289 if (data && size > 0) {
290 ssize_t written = fNode->WriteAttr(kNIIconAttribute,
291 B_VECTOR_ICON_TYPE, 0, data, size);
292 if (written < 0)
293 result = (status_t)written;
294 else if (written != (ssize_t)size)
295 result = B_ERROR;
296 } else {
297 // no icon given => remove
298 result = fNode->RemoveAttr(kNIIconAttribute);
299 }
300
301 return result;
302 }
303
304
305 status_t
GetPreferredApp(char * signature,app_verb verb) const306 BNodeInfo::GetPreferredApp(char* signature, app_verb verb) const
307 {
308 // check parameter and initialization
309 status_t result = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE);
310 if (result == B_OK && InitCheck() != B_OK)
311 result = B_NO_INIT;
312
313 // get the attribute info and check type and length of the attr contents
314 attr_info attrInfo;
315 if (result == B_OK)
316 result = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo);
317
318 if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
319 result = B_BAD_TYPE;
320
321 if (result == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
322 result = B_BAD_DATA;
323
324 // read the data
325 if (result == B_OK) {
326 ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type,
327 0, signature, attrInfo.size);
328 if (read < 0)
329 result = read;
330 else if (read != attrInfo.size)
331 result = B_ERROR;
332
333 if (result == B_OK) {
334 // attribute strings doesn't have to be null terminated
335 signature[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
336 }
337 }
338
339 return result;
340 }
341
342
343 status_t
SetPreferredApp(const char * signature,app_verb verb)344 BNodeInfo::SetPreferredApp(const char* signature, app_verb verb)
345 {
346 // check parameters and initialization
347 status_t result = (verb == B_OPEN ? B_OK : B_BAD_VALUE);
348 if (result == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH)
349 result = B_BAD_VALUE;
350
351 if (result == B_OK && InitCheck() != B_OK)
352 result = B_NO_INIT;
353
354 // write/remove the attribute
355 if (result == B_OK) {
356 if (signature) {
357 size_t toWrite = strlen(signature) + 1;
358 ssize_t written = fNode->WriteAttr(kNIPreferredAppAttribute,
359 B_MIME_STRING_TYPE, 0, signature, toWrite);
360 if (written < 0)
361 result = written;
362 else if (written != (ssize_t)toWrite)
363 result = B_ERROR;
364 } else
365 result = fNode->RemoveAttr(kNIPreferredAppAttribute);
366 }
367
368 return result;
369 }
370
371
372 status_t
GetAppHint(entry_ref * ref) const373 BNodeInfo::GetAppHint(entry_ref* ref) const
374 {
375 // check parameter and initialization
376 status_t result = (ref ? B_OK : B_BAD_VALUE);
377 if (result == B_OK && InitCheck() != B_OK)
378 result = B_NO_INIT;
379
380 // get the attribute info and check type and length of the attr contents
381 attr_info attrInfo;
382 if (result == B_OK)
383 result = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo);
384
385 // NOTE: The attribute type should be B_STRING_TYPE, but R5 uses
386 // B_MIME_STRING_TYPE.
387 if (result == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
388 result = B_BAD_TYPE;
389
390 if (result == B_OK && attrInfo.size > B_PATH_NAME_LENGTH)
391 result = B_BAD_DATA;
392
393 // read the data
394 if (result == B_OK) {
395 char path[B_PATH_NAME_LENGTH];
396 ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0,
397 path, attrInfo.size);
398 if (read < 0)
399 result = read;
400 else if (read != attrInfo.size)
401 result = B_ERROR;
402
403 // get the entry_ref for the path
404 if (result == B_OK) {
405 // attribute strings doesn't have to be null terminated
406 path[min_c(attrInfo.size, B_PATH_NAME_LENGTH - 1)] = '\0';
407 result = get_ref_for_path(path, ref);
408 }
409 }
410
411 return result;
412 }
413
414
415 status_t
SetAppHint(const entry_ref * ref)416 BNodeInfo::SetAppHint(const entry_ref* ref)
417 {
418 // check parameter and initialization
419 if (InitCheck() != B_OK)
420 return B_NO_INIT;
421
422 status_t result = B_OK;
423 if (ref != NULL) {
424 // write/remove the attribute
425 BPath path;
426 result = path.SetTo(ref);
427 if (result == B_OK) {
428 size_t toWrite = strlen(path.Path()) + 1;
429 ssize_t written = fNode->WriteAttr(kNIAppHintAttribute,
430 B_MIME_STRING_TYPE, 0, path.Path(), toWrite);
431 if (written < 0)
432 result = written;
433 else if (written != (ssize_t)toWrite)
434 result = B_ERROR;
435 }
436 } else
437 result = fNode->RemoveAttr(kNIAppHintAttribute);
438
439 return result;
440 }
441
442
443 status_t
GetTrackerIcon(BBitmap * icon,icon_size which) const444 BNodeInfo::GetTrackerIcon(BBitmap* icon, icon_size which) const
445 {
446 if (icon == NULL)
447 return B_BAD_VALUE;
448
449 // set some icon size related variables
450 BRect bounds;
451 switch (which) {
452 case B_MINI_ICON:
453 bounds.Set(0, 0, 15, 15);
454 break;
455
456 case B_LARGE_ICON:
457 bounds.Set(0, 0, 31, 31);
458 break;
459
460 default:
461 // result = B_BAD_VALUE;
462 // NOTE: added to be less strict and support scaled icons
463 bounds = icon->Bounds();
464 break;
465 }
466
467 // check parameters and initialization
468 if (icon->InitCheck() != B_OK || icon->Bounds() != bounds)
469 return B_BAD_VALUE;
470
471 if (InitCheck() != B_OK)
472 return B_NO_INIT;
473
474 // Ask GetIcon() first.
475 if (GetIcon(icon, which) == B_OK)
476 return B_OK;
477
478 // If not successful, see if the node has a type available at all.
479 // If no type is available, use one of the standard types.
480 status_t result = B_OK;
481 char mimeString[B_MIME_TYPE_LENGTH];
482 if (GetType(mimeString) != B_OK) {
483 // Get the icon from a mime type...
484 BMimeType type;
485
486 struct stat stat;
487 result = fNode->GetStat(&stat);
488 if (result == B_OK) {
489 // no type available -- get the icon for the appropriate type
490 // (file/dir/etc.)
491 if (S_ISREG(stat.st_mode)) {
492 // is it an application (executable) or just a regular file?
493 if ((stat.st_mode & S_IXUSR) != 0)
494 type.SetTo(B_APP_MIME_TYPE);
495 else
496 type.SetTo(B_FILE_MIME_TYPE);
497 } else if (S_ISDIR(stat.st_mode)) {
498 // it's either a volume or just a standard directory
499 fs_info info;
500 if (fs_stat_dev(stat.st_dev, &info) == 0
501 && stat.st_ino == info.root) {
502 type.SetTo(B_VOLUME_MIME_TYPE);
503 } else
504 type.SetTo(B_DIRECTORY_MIME_TYPE);
505 } else if (S_ISLNK(stat.st_mode))
506 type.SetTo(B_SYMLINK_MIME_TYPE);
507 } else {
508 // GetStat() failed. Return the icon for
509 // "application/octet-stream" from the MIME database.
510 type.SetTo(B_FILE_MIME_TYPE);
511 }
512
513 return type.GetIcon(icon, which);
514 } else {
515 // We know the mimetype of the node.
516 bool success = false;
517
518 // Get the preferred application and ask the MIME database, if that
519 // application has a special icon for the node's file type.
520 char signature[B_MIME_TYPE_LENGTH];
521 if (GetPreferredApp(signature) == B_OK) {
522 BMimeType type(signature);
523 success = type.GetIconForType(mimeString, icon, which) == B_OK;
524 }
525
526 // ToDo: Confirm Tracker asks preferred app icons before asking
527 // mime icons.
528
529 BMimeType nodeType(mimeString);
530
531 // Ask the MIME database for the preferred application for the node's
532 // file type and whether this application has a special icon for the
533 // type.
534 if (!success && nodeType.GetPreferredApp(signature) == B_OK) {
535 BMimeType type(signature);
536 success = type.GetIconForType(mimeString, icon, which) == B_OK;
537 }
538
539 // Ask the MIME database whether there is an icon for the node's file
540 // type.
541 if (!success)
542 success = nodeType.GetIcon(icon, which) == B_OK;
543
544 // Get the super type if still no success.
545 BMimeType superType;
546 if (!success && nodeType.GetSupertype(&superType) == B_OK) {
547 // Ask the MIME database for the preferred application for the
548 // node's super type and whether this application has a special
549 // icon for the type.
550 if (superType.GetPreferredApp(signature) == B_OK) {
551 BMimeType type(signature);
552 success = type.GetIconForType(superType.Type(), icon,
553 which) == B_OK;
554 }
555 // Get the icon of the super type itself.
556 if (!success)
557 success = superType.GetIcon(icon, which) == B_OK;
558 }
559
560 if (success)
561 return B_OK;
562 }
563
564 return B_ERROR;
565 }
566
567
568 status_t
GetTrackerIcon(const entry_ref * ref,BBitmap * icon,icon_size which)569 BNodeInfo::GetTrackerIcon(const entry_ref* ref, BBitmap* icon, icon_size which)
570 {
571 // check ref param
572 status_t result = (ref ? B_OK : B_BAD_VALUE);
573
574 // init a BNode
575 BNode node;
576 if (result == B_OK)
577 result = node.SetTo(ref);
578
579 // init a BNodeInfo
580 BNodeInfo nodeInfo;
581 if (result == B_OK)
582 result = nodeInfo.SetTo(&node);
583
584 // let the non-static GetTrackerIcon() do the dirty work
585 if (result == B_OK)
586 result = nodeInfo.GetTrackerIcon(icon, which);
587
588 return result;
589 }
590
591
592 /*! This method is provided for binary compatibility purposes
593 (for example the program "Guido" depends on it.)
594 */
595 extern "C"
596 status_t
GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(BNodeInfo * nodeInfo,entry_ref * ref,BBitmap * bitmap,icon_size iconSize)597 GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
598 BNodeInfo* nodeInfo, entry_ref* ref,
599 BBitmap* bitmap, icon_size iconSize)
600 {
601 // NOTE: nodeInfo is ignored - maybe that's wrong!
602 return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
603 }
604
605
_ReservedNodeInfo1()606 void BNodeInfo::_ReservedNodeInfo1() {}
_ReservedNodeInfo2()607 void BNodeInfo::_ReservedNodeInfo2() {}
_ReservedNodeInfo3()608 void BNodeInfo::_ReservedNodeInfo3() {}
609
610
611 #ifdef __HAIKU_BEOS_COMPATIBLE
612 /*! Assignment operator is declared private to prevent it from being created
613 automatically by the compiler.
614 */
615 BNodeInfo&
operator =(const BNodeInfo & nodeInfo)616 BNodeInfo::operator=(const BNodeInfo &nodeInfo)
617 {
618 return *this;
619 }
620
621
622 /*! Copy constructor is declared private to prevent it from being created
623 automatically by the compiler.
624 */
BNodeInfo(const BNodeInfo &)625 BNodeInfo::BNodeInfo(const BNodeInfo &)
626 {
627 }
628 #endif
629