xref: /haiku/src/kits/storage/NodeInfo.cpp (revision f23596149e0d173463f70629581aa10cc305d32e)
1 /*
2  * Copyright 2002-2006, Haiku Inc.
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 using namespace std;
28 
29 // attribute names
30 #define NI_BEOS "BEOS"
31 static const char *kNITypeAttribute			= NI_BEOS ":TYPE";
32 static const char *kNIPreferredAppAttribute	= NI_BEOS ":PREF_APP";
33 static const char *kNIAppHintAttribute		= NI_BEOS ":PPATH";
34 static const char *kNIMiniIconAttribute		= NI_BEOS ":M:STD_ICON";
35 static const char *kNILargeIconAttribute	= NI_BEOS ":L:STD_ICON";
36 static const char *kNIIconAttribute			= NI_BEOS ":ICON";
37 
38 
39 /*!	\brief Creates an uninitialized BNodeInfo object.
40 
41 	After created a BNodeInfo with this, you should call SetTo().
42 
43 	\see SetTo(BNode *node)
44 */
45 BNodeInfo::BNodeInfo()
46 	:
47 	fNode(NULL),
48 	fCStatus(B_NO_INIT)
49 {
50 }
51 
52 // constructor
53 /*!	\brief Creates a BNodeInfo object and initializes it to the supplied node.
54 
55 	\param node The node to gather information on. Can be any flavor.
56 
57 	\see SetTo(BNode *node)
58 */
59 BNodeInfo::BNodeInfo(BNode *node)
60 	:
61 	fNode(NULL),
62 	fCStatus(B_NO_INIT)
63 {
64 	fCStatus = SetTo(node);
65 }
66 
67 // destructor
68 /*!	\brief Frees all resources associated with this object.
69 
70 	The BNode object passed to the constructor or to SetTo() is not deleted.
71 */
72 BNodeInfo::~BNodeInfo()
73 {
74 }
75 
76 // SetTo
77 /*!	\brief Initializes the BNodeInfo to the supplied node.
78 
79 	The BNodeInfo object does not copy the supplied object, but uses it
80 	directly. You must not delete the object you supply while the BNodeInfo
81 	does exist. The BNodeInfo does not take over ownership of the BNode and
82 	it doesn't delete it on destruction.
83 
84 	\param node The node to play with
85 
86 	\return
87 	- \c B_OK: Everything went fine.
88 	- \c B_BAD_VALUE: The node was bad.
89 */
90 status_t
91 BNodeInfo::SetTo(BNode *node)
92 {
93 	fNode = NULL;
94 	// check parameter
95 	fCStatus = (node && node->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
96 	if (fCStatus == B_OK)
97 		fNode = node;
98 	return fCStatus;
99 }
100 
101 // InitCheck
102 /*!	\brief returns whether the object has been properly initialized.
103 
104 	\return
105 	- \c B_OK: Everything went fine.
106 	- \c B_NO_INIT: The node is not properly initialized.
107 */
108 status_t
109 BNodeInfo::InitCheck() const
110 {
111 	return fCStatus;
112 }
113 
114 // GetType
115 /*!	\brief Gets the node's MIME type.
116 
117 	Writes the contents of the "BEOS:TYPE" attribute into the supplied buffer
118 	\a type.
119 
120 	\param type A pointer to a pre-allocated character buffer of size
121 		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
122 		   node shall be written.
123 	\return
124 	- \c B_OK: Everything went fine.
125 	- \c B_NO_INIT: The object is not properly initialized.
126 	- \c B_BAD_VALUE: \c NULL \a type or the type string stored in the
127 	  attribute is longer than \c B_MIME_TYPE_LENGTH.
128 	- \c B_BAD_TYPE: The attribute the type string is stored in has the wrong
129 	   type.
130 	- \c B_ENTRY_NOT_FOUND: No type is set on the node.
131 	- other error codes
132 */
133 status_t
134 BNodeInfo::GetType(char *type) const
135 {
136 	// check parameter and initialization
137 	status_t error = (type ? B_OK : B_BAD_VALUE);
138 	if (error == B_OK && InitCheck() != B_OK)
139 		error = B_NO_INIT;
140 	// get the attribute info and check type and length of the attr contents
141 	attr_info attrInfo;
142 	if (error == B_OK)
143 		error = fNode->GetAttrInfo(kNITypeAttribute, &attrInfo);
144 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
145 		error = B_BAD_TYPE;
146 	if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
147 		error = B_BAD_DATA;
148 
149 	// read the data
150 	if (error == B_OK) {
151 		ssize_t read = fNode->ReadAttr(kNITypeAttribute, attrInfo.type, 0,
152 									   type, attrInfo.size);
153 		if (read < 0)
154 			error = read;
155 		else if (read != attrInfo.size)
156 			error = B_ERROR;
157 
158 		if (error == B_OK) {
159 			// attribute strings doesn't have to be null terminated
160 			type[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
161 		}
162 	}
163 	return error;
164 }
165 
166 // SetType
167 /*!	\brief Sets the node's MIME type.
168 
169 	The supplied string is written into the node's "BEOS:TYPE" attribute.
170 
171 	If \a type is \c NULL, the respective attribute is removed.
172 
173 	\param type The MIME type to be assigned to the node. Must not be longer
174 		   than \c B_MIME_TYPE_LENGTH (including the terminating null).
175 		   May be \c NULL.
176 	\return
177 	- \c B_OK: Everything went fine.
178 	- \c B_NO_INIT: The object is not properly initialized.
179 	- \c B_BAD_VALUE: \a type is longer than \c B_MIME_TYPE_LENGTH.
180 	- other error codes
181 */
182 status_t
183 BNodeInfo::SetType(const char *type)
184 {
185 	// check parameter and initialization
186 	status_t error = B_OK;
187 	if (error == B_OK && type && strlen(type) >= B_MIME_TYPE_LENGTH)
188 		error = B_BAD_VALUE;
189 	if (error == B_OK && InitCheck() != B_OK)
190 		error = B_NO_INIT;
191 
192 	// write/remove the attribute
193 	if (error == B_OK) {
194 		if (type) {
195 			size_t toWrite = strlen(type) + 1;
196 			ssize_t written = fNode->WriteAttr(kNITypeAttribute,
197 											   B_MIME_STRING_TYPE, 0, type,
198 											   toWrite);
199 			if (written < 0)
200 				error = written;
201 			else if (written != (ssize_t)toWrite)
202 				error = B_ERROR;
203 		} else
204 			error = fNode->RemoveAttr(kNITypeAttribute);
205 	}
206 	return error;
207 }
208 
209 // GetIcon
210 /*!	\brief Gets the node's icon.
211 
212 	The icon stored in the node's "BEOS:L:STD_ICON" (large) or
213 	"BEOS:M:STD_ICON" (mini) attribute is retrieved.
214 
215 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
216 		   to store the requested icon (16x16 for the mini and 32x32 for the
217 		   large icon).
218 	\param k Specifies the size of the icon to be retrieved: \c B_MINI_ICON
219 		   for the mini and \c B_LARGE_ICON for the large icon.
220 	\return
221 	- \c B_OK: Everything went fine.
222 	- \c B_NO_INIT: The object is not properly initialized.
223 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a k or bitmap
224 		 dimensions (\a icon) and icon size (\a k) do not match.
225 	- other error codes
226 */
227 status_t
228 BNodeInfo::GetIcon(BBitmap *icon, icon_size k) const
229 {
230 	const char* iconAttribute = kNIIconAttribute;
231 	const char* miniIconAttribute = kNIMiniIconAttribute;
232 	const char* largeIconAttribute = kNILargeIconAttribute;
233 
234 	return BIconUtils::GetIcon(fNode, iconAttribute, miniIconAttribute,
235 							   largeIconAttribute, k, icon);
236 
237 //	status_t error = B_OK;
238 //	// set some icon size related variables
239 //	const char *attribute = NULL;
240 //	BRect bounds;
241 //	uint32 attrType = 0;
242 //	size_t attrSize = 0;
243 //	switch (k) {
244 //		case B_MINI_ICON:
245 //			attribute = kNIMiniIconAttribute;
246 //			bounds.Set(0, 0, 15, 15);
247 //			attrType = B_MINI_ICON_TYPE;
248 //			attrSize = 16 * 16;
249 //			break;
250 //		case B_LARGE_ICON:
251 //			attribute = kNILargeIconAttribute;
252 //			bounds.Set(0, 0, 31, 31);
253 //			attrType = B_LARGE_ICON_TYPE;
254 //			attrSize = 32 * 32;
255 //			break;
256 //		default:
257 //			error = B_BAD_VALUE;
258 //			break;
259 //	}
260 //
261 //	// check parameter and initialization
262 //	if (error == B_OK
263 //		&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
264 //		error = B_BAD_VALUE;
265 //	}
266 //	if (error == B_OK && InitCheck() != B_OK)
267 //		error = B_NO_INIT;
268 //
269 //	// get the attribute info and check type and size of the attr contents
270 //	attr_info attrInfo;
271 //	if (error == B_OK)
272 //		error = fNode->GetAttrInfo(attribute, &attrInfo);
273 //	if (error == B_OK && attrInfo.type != attrType)
274 //		error = B_BAD_TYPE;
275 //	if (error == B_OK && attrInfo.size != attrSize)
276 //		error = B_BAD_DATA;
277 //
278 //	// read the attribute
279 //	if (error == B_OK) {
280 //		bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
281 //		char *buffer = NULL;
282 //		ssize_t read;
283 //		if (otherColorSpace) {
284 //			// other color space than stored in attribute
285 //			buffer = new(nothrow) char[attrSize];
286 //			if (!buffer)
287 //				error = B_NO_MEMORY;
288 //			if (error == B_OK) {
289 //				read = fNode->ReadAttr(attribute, attrType, 0, buffer,
290 //									   attrSize);
291 //			}
292 //		} else {
293 //			read = fNode->ReadAttr(attribute, attrType, 0, icon->Bits(),
294 //								   attrSize);
295 //		}
296 //		if (error == B_OK) {
297 //			if (read < 0)
298 //				error = read;
299 //			else if (read != attrInfo.size)
300 //				error = B_ERROR;
301 //		}
302 //		if (otherColorSpace) {
303 //			// other color space than stored in attribute
304 //			if (error == B_OK) {
305 //				error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW,
306 //										 0, B_CMAP8);
307 //			}
308 //			delete[] buffer;
309 //		}
310 //	}
311 //	return error;
312 }
313 
314 // SetIcon
315 /*!	\brief Sets the node's icon.
316 
317 	The icon is stored in the node's "BEOS:L:STD_ICON" (large) or
318 	"BEOS:M:STD_ICON" (mini) attribute.
319 
320 	If \a icon is \c NULL, the respective attribute is removed.
321 
322 	\param icon A pointer to the BBitmap containing the icon to be set.
323 		   May be \c NULL.
324 	\param k Specifies the size of the icon to be set: \c B_MINI_ICON
325 		   for the mini and \c B_LARGE_ICON for the large icon.
326 	\return
327 	- \c B_OK: Everything went fine.
328 	- \c B_NO_INIT: The object is not properly initialized.
329 	- \c B_BAD_VALUE: Unknown icon size \a k or bitmap dimensions (\a icon)
330 		 and icon size (\a k) do not match.
331 	- other error codes
332 */
333 status_t
334 BNodeInfo::SetIcon(const BBitmap *icon, icon_size k)
335 {
336 	status_t error = B_OK;
337 	// set some icon size related variables
338 	const char *attribute = NULL;
339 	BRect bounds;
340 	uint32 attrType = 0;
341 	size_t attrSize = 0;
342 	switch (k) {
343 		case B_MINI_ICON:
344 			attribute = kNIMiniIconAttribute;
345 			bounds.Set(0, 0, 15, 15);
346 			attrType = B_MINI_ICON_TYPE;
347 			attrSize = 16 * 16;
348 			break;
349 		case B_LARGE_ICON:
350 			attribute = kNILargeIconAttribute;
351 			bounds.Set(0, 0, 31, 31);
352 			attrType = B_LARGE_ICON_TYPE;
353 			attrSize = 32 * 32;
354 			break;
355 		default:
356 			error = B_BAD_VALUE;
357 			break;
358 	}
359 
360 	// check parameter and initialization
361 	if (error == B_OK && icon
362 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
363 		error = B_BAD_VALUE;
364 	}
365 	if (error == B_OK && InitCheck() != B_OK)
366 		error = B_NO_INIT;
367 
368 	// write/remove the attribute
369 	if (error == B_OK) {
370 		if (icon) {
371 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
372 			ssize_t written = 0;
373 			if (otherColorSpace) {
374 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
375 				error = bitmap.InitCheck();
376 				if (error == B_OK)
377 					error = bitmap.ImportBits(icon);
378 				if (error == B_OK) {
379 					written = fNode->WriteAttr(attribute, attrType, 0,
380 											   bitmap.Bits(), attrSize);
381 				}
382 			} else {
383 				written = fNode->WriteAttr(attribute, attrType, 0,
384 										   icon->Bits(), attrSize);
385 			}
386 			if (error == B_OK) {
387 				if (written < 0)
388 					error = written;
389 				else if (written != (ssize_t)attrSize)
390 					error = B_ERROR;
391 			}
392 		} else	// no icon given => remove
393 			error = fNode->RemoveAttr(attribute);
394 	}
395 	return error;
396 }
397 
398 // GetPreferredApp
399 /*!	\brief Gets the node's preferred application.
400 
401 	Writes the contents of the "BEOS:PREF_APP" attribute into the supplied
402 	buffer \a signature. The preferred application is identifief by its
403 	signature.
404 
405 	\param signature A pointer to a pre-allocated character buffer of size
406 		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
407 		   preferred application shall be written.
408 	\param verb Specifies the type of access the preferred application is
409 		   requested for. Currently only \c B_OPEN is meaningful.
410 	\return
411 	- \c B_OK: Everything went fine.
412 	- \c B_NO_INIT: The object is not properly initialized.
413 	- \c B_BAD_VALUE: \c NULL \a signature or bad app_verb \a verb.
414 	- other error codes
415 */
416 status_t
417 BNodeInfo::GetPreferredApp(char *signature, app_verb verb) const
418 {
419 	// check parameter and initialization
420 	status_t error = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE);
421 	if (error == B_OK && InitCheck() != B_OK)
422 		error = B_NO_INIT;
423 
424 	// get the attribute info and check type and length of the attr contents
425 	attr_info attrInfo;
426 	if (error == B_OK)
427 		error = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo);
428 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
429 		error = B_BAD_TYPE;
430 	if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
431 		error = B_BAD_DATA;
432 
433 	// read the data
434 	if (error == B_OK) {
435 		ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type,
436 									   0, signature, attrInfo.size);
437 		if (read < 0)
438 			error = read;
439 		else if (read != attrInfo.size)
440 			error = B_ERROR;
441 
442 		if (error == B_OK) {
443 			// attribute strings doesn't have to be null terminated
444 			signature[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
445 		}
446 	}
447 	return error;
448 }
449 
450 // SetPreferredApp
451 /*!	\brief Sets the node's preferred application.
452 
453 	The supplied string is written into the node's "BEOS:PREF_APP" attribute.
454 
455 	If \a signature is \c NULL, the respective attribute is removed.
456 
457 	\param signature The signature of the preferred application to be set.
458 		   Must not be longer than \c B_MIME_TYPE_LENGTH (including the
459 		   terminating null). May be \c NULL.
460 	\param verb Specifies the type of access the preferred application shall
461 		   be set for. Currently only \c B_OPEN is meaningful.
462 	\return
463 	- \c B_OK: Everything went fine.
464 	- \c B_NO_INIT: The object is not properly initialized.
465 	- \c B_BAD_VALUE: \c NULL \a signature, \a signature is longer than
466 	  \c B_MIME_TYPE_LENGTH or bad app_verb \a verb.
467 	- other error codes
468 */
469 status_t
470 BNodeInfo::SetPreferredApp(const char *signature, app_verb verb)
471 {
472 	// check parameters and initialization
473 	status_t error = (verb == B_OPEN ? B_OK : B_BAD_VALUE);
474 	if (error == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH)
475 		error = B_BAD_VALUE;
476 	if (error == B_OK && InitCheck() != B_OK)
477 		error = B_NO_INIT;
478 
479 	// write/remove the attribute
480 	if (error == B_OK) {
481 		if (signature) {
482 			size_t toWrite = strlen(signature) + 1;
483 			ssize_t written = fNode->WriteAttr(kNIPreferredAppAttribute,
484 											   B_MIME_STRING_TYPE, 0,
485 											   signature, toWrite);
486 			if (written < 0)
487 				error = written;
488 			else if (written != (ssize_t)toWrite)
489 				error = B_ERROR;
490 		} else
491 			error = fNode->RemoveAttr(kNIPreferredAppAttribute);
492 	}
493 	return error;
494 }
495 
496 // GetAppHint
497 /*!	\brief Returns a hint in form of and entry_ref to the application that
498 		   shall be used to open this node.
499 
500 	The path contained in the node's "BEOS:PPATH" attribute is converted into
501 	an entry_ref and returned in \a ref.
502 
503 	\param ref A pointer to a pre-allocated entry_ref into which the requested
504 		   app hint shall be written.
505 	\return
506 	- \c B_OK: Everything went fine.
507 	- \c B_NO_INIT: The object is not properly initialized.
508 	- \c B_BAD_VALUE: \c NULL \a ref.
509 	- other error codes
510 */
511 status_t
512 BNodeInfo::GetAppHint(entry_ref *ref) const
513 {
514 	// check parameter and initialization
515 	status_t error = (ref ? B_OK : B_BAD_VALUE);
516 	if (error == B_OK && InitCheck() != B_OK)
517 		error = B_NO_INIT;
518 
519 	// get the attribute info and check type and length of the attr contents
520 	attr_info attrInfo;
521 	if (error == B_OK)
522 		error = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo);
523 	// NOTE: The attribute type should be B_STRING_TYPE, but R5 uses
524 	// B_MIME_STRING_TYPE.
525 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
526 		error = B_BAD_TYPE;
527 	if (error == B_OK && attrInfo.size > B_PATH_NAME_LENGTH)
528 		error = B_BAD_DATA;
529 
530 	// read the data
531 	if (error == B_OK) {
532 		char path[B_PATH_NAME_LENGTH];
533 		ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0,
534 									   path, attrInfo.size);
535 		if (read < 0)
536 			error = read;
537 		else if (read != attrInfo.size)
538 			error = B_ERROR;
539 		// get the entry_ref for the path
540 		if (error == B_OK) {
541 			// attribute strings doesn't have to be null terminated
542 			path[min_c(attrInfo.size, B_PATH_NAME_LENGTH - 1)] = '\0';
543 			error = get_ref_for_path(path, ref);
544 		}
545 	}
546 	return error;
547 }
548 
549 // SetAppHint
550 /*!	\brief Sets the node's app hint.
551 
552 	The supplied entry_ref is converted into a path and stored in the node's
553 	"BEOS:PPATH" attribute.
554 
555 	If \a ref is \c NULL, the respective attribute is removed.
556 
557 	\param ref A pointer to an entry_ref referring to the application.
558 		   May be \c NULL.
559 	\return
560 	- \c B_OK: Everything went fine.
561 	- \c B_NO_INIT: The object is not properly initialized.
562 	- \c B_BAD_VALUE: \c NULL \a ref.
563 	- other error codes
564 */
565 status_t
566 BNodeInfo::SetAppHint(const entry_ref *ref)
567 {
568 	// check parameter and initialization
569 	status_t error = B_OK;
570 	if (error == B_OK && InitCheck() != B_OK)
571 		error = B_NO_INIT;
572 
573 	// write/remove the attribute
574 	if (error == B_OK) {
575 		if (ref) {
576 			BPath path;
577 			error = path.SetTo(ref);
578 			if (error == B_OK) {
579 				size_t toWrite = strlen(path.Path()) + 1;
580 				ssize_t written = fNode->WriteAttr(kNIAppHintAttribute,
581 												   B_MIME_STRING_TYPE, 0,
582 												   path.Path(), toWrite);
583 				if (written < 0)
584 					error = written;
585 				else if (written != (ssize_t)toWrite)
586 					error = B_ERROR;
587 			}
588 		} else
589 			error = fNode->RemoveAttr(kNIAppHintAttribute);
590 	}
591 	return error;
592 }
593 
594 // GetTrackerIcon
595 /*!	\brief Gets the icon which tracker displays.
596 
597 	This method tries real hard to find an icon for the node:
598 	- If the node has no type, return the icon for B_FILE_MIME_TYPE if it's a
599 	  regular file, for B_DIRECTORY_MIME_TYPE if it's a directory, etc. from
600 	  the MIME database. Even, if the node has an own icon!
601 	- Ask GetIcon().
602 	- Get the preferred application and ask the MIME database, if that
603 	  application has a special icon for the node's file type.
604 	- Ask the MIME database whether there is an icon for the node's file type.
605 	- Ask the MIME database for the preferred application for the node's
606 	  file type and whether this application has a special icon for the type.
607 	- Return the icon for whatever type of node (file/dir/etc.) from the MIME database.
608 	This list is processed in the given order and the icon the first
609 	successful attempt provides is returned. In case none of them yields an
610 	icon, this method fails. This is very unlikely though.
611 
612 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
613 		   to store the requested icon (16x16 for the mini and 32x32 for the
614 		   large icon).
615 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
616 		   for the mini and \c B_LARGE_ICON for the large icon.
617 	\return
618 	- \c B_OK: Everything went fine.
619 	- \c B_NO_INIT: The object is not properly initialized.
620 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a iconSize or bitmap
621 		 dimensions (\a icon) and icon size (\a iconSize) do not match.
622 	- other error codes
623 */
624 status_t
625 BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size iconSize) const
626 {
627 	if (!icon)
628 		return B_BAD_VALUE;
629 
630 	// set some icon size related variables
631 	status_t error = B_OK;
632 	BRect bounds;
633 	switch (iconSize) {
634 		case B_MINI_ICON:
635 			bounds.Set(0, 0, 15, 15);
636 			break;
637 		case B_LARGE_ICON:
638 			bounds.Set(0, 0, 31, 31);
639 			break;
640 		default:
641 //			error = B_BAD_VALUE;
642 			// NOTE: added to be less strict and support scaled icons
643 			bounds = icon->Bounds();
644 			break;
645 	}
646 
647 	// check parameters and initialization
648 	if (error == B_OK
649 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
650 		error = B_BAD_VALUE;
651 	}
652 	if (error == B_OK && InitCheck() != B_OK)
653 		error = B_NO_INIT;
654 
655 	bool success = false;
656 
657 	// get node MIME type, and, if that fails, the generic icon
658 	char mimeString[B_MIME_TYPE_LENGTH];
659 	if (error == B_OK) {
660 		if (GetType(mimeString) != B_OK) {
661 			struct stat stat;
662 			error = fNode->GetStat(&stat);
663 			if (error == B_OK) {
664 				// no type available -- get the icon for the appropriate type (file/dir/etc.)
665 				BMimeType type;
666 				if (S_ISREG(stat.st_mode)) {
667 					// is it an application (executable) or just a regular file?
668 					if ((stat.st_mode & S_IXUSR) != 0)
669 						type.SetTo(B_APP_MIME_TYPE);
670 					else
671 						type.SetTo(B_FILE_MIME_TYPE);
672 				} else if (S_ISDIR(stat.st_mode)) {
673 					// it's either a volume or just a standard directory
674 					fs_info info;
675 					if (fs_stat_dev(stat.st_dev, &info) == 0 && stat.st_ino == info.root)
676 						type.SetTo(B_VOLUME_MIME_TYPE);
677 					else
678 						type.SetTo(B_DIRECTORY_MIME_TYPE);
679 				} else if (S_ISLNK(stat.st_mode))
680 					type.SetTo(B_SYMLINK_MIME_TYPE);
681 
682 				success = (type.GetIcon(icon, iconSize) == B_OK);
683 					// NOTE: if there is an icon but getting it failes for some reason,
684 					// the error is not reported, and the fall back retrieval methods
685 					// are still tried. (IAW, we can't differentiate the reason for error.)
686 			}
687 		}
688 	}
689 
690 	// Ask GetIcon().
691 	if (error == B_OK && !success)
692 		success = (GetIcon(icon, iconSize) == B_OK);
693 
694 	// Get the preferred application and ask the MIME database, if that
695 	// application has a special icon for the node's file type.
696 	if (error == B_OK && !success) {
697 		char signature[B_MIME_TYPE_LENGTH];
698 		if (GetPreferredApp(signature) == B_OK) {
699 			BMimeType type(signature);
700 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
701 		}
702 	}
703 
704 	// Ask the MIME database whether there is an icon for the node's file type.
705 	BMimeType nodeType;
706 	if (error == B_OK && !success) {
707 		nodeType.SetTo(mimeString);
708 		success = (nodeType.GetIcon(icon, iconSize) == B_OK);
709 	}
710 
711 	// Ask the MIME database for the preferred application for the node's
712 	// file type and whether this application has a special icon for the type.
713 	if (error == B_OK && !success) {
714 		char signature[B_MIME_TYPE_LENGTH];
715 		if (nodeType.GetPreferredApp(signature) == B_OK) {
716 			BMimeType type(signature);
717 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
718 		}
719 	}
720 
721 	// Return the icon for "application/octet-stream" from the MIME database.
722 	if (error == B_OK && !success) {
723 		// get the "application/octet-stream" icon
724 		BMimeType type(B_FILE_MIME_TYPE);
725 		error = type.GetIcon(icon, iconSize);
726 		success = (error == B_OK);
727 	}
728 	return error;
729 }
730 
731 // GetTrackerIcon
732 /*!	\brief Gets the icon which tracker displays for the node referred to by
733 		   the supplied entry_ref.
734 
735 	This methods works similar to the non-static version. The first argument
736 	\a ref identifies the node in question.
737 
738 	\param ref An entry_ref referring to the node for which the icon shall be
739 		   retrieved.
740 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
741 		   to store the requested icon (16x16 for the mini and 32x32 for the
742 		   large icon).
743 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
744 		   for the mini and \c B_LARGE_ICON for the large icon.
745 	\return
746 	- \c B_OK: Everything went fine.
747 	- \c B_NO_INIT: The object is not properly initialized.
748 	- \c B_BAD_VALUE: \c NULL ref or \a icon, unsupported icon size \a iconSize or
749 		 bitmap dimensions (\a icon) and icon size (\a iconSize) do not match.
750 	- other error codes
751 */
752 status_t
753 BNodeInfo::GetTrackerIcon(const entry_ref *ref, BBitmap *icon, icon_size iconSize)
754 {
755 	// check ref param
756 	status_t error = (ref ? B_OK : B_BAD_VALUE);
757 
758 	// init a BNode
759 	BNode node;
760 	if (error == B_OK)
761 		error = node.SetTo(ref);
762 
763 	// init a BNodeInfo
764 	BNodeInfo nodeInfo;
765 	if (error == B_OK)
766 		error = nodeInfo.SetTo(&node);
767 
768 	// let the non-static GetTrackerIcon() do the dirty work
769 	if (error == B_OK)
770 		error = nodeInfo.GetTrackerIcon(icon, iconSize);
771 	return error;
772 }
773 
774 // TODO: just here for providing binary compatibility
775 // (for example "Guido" needs this)
776 extern "C"
777 status_t
778 GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
779 	BNodeInfo *nodeInfo, entry_ref* ref,
780 	BBitmap* bitmap, icon_size iconSize)
781 {
782 	// NOTE: nodeInfo is ignored - maybe that's wrong!
783 	return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
784 }
785 
786 void
787 BNodeInfo::_ReservedNodeInfo1()
788 {
789 }
790 
791 void
792 BNodeInfo::_ReservedNodeInfo2()
793 {
794 }
795 
796 void
797 BNodeInfo::_ReservedNodeInfo3()
798 {
799 }
800 
801 // =
802 /*!	\brief Privatized assignment operator to prevent usage.
803 */
804 BNodeInfo &
805 BNodeInfo::operator=(const BNodeInfo &nodeInfo)
806 {
807 	return *this;
808 }
809 
810 // copy constructor
811 /*!	\brief Privatized copy constructor to prevent usage.
812 */
813 BNodeInfo::BNodeInfo(const BNodeInfo &)
814 {
815 }
816 
817 
818 //	#pragma mark -
819 
820 namespace BPrivate {
821 
822 /*!
823 	Private function used by Tracker. Should be moved into the Tracker sources.
824 */
825 extern bool
826 CheckNodeIconHintPrivate(const BNode *node, bool checkMiniIconOnly)
827 {
828 	attr_info info;
829 	if (node->GetAttrInfo(kNIMiniIconAttribute, &info) != B_OK && checkMiniIconOnly)
830 		return false;
831 
832 	if (node->GetAttrInfo(kNILargeIconAttribute, &info) != B_OK)
833 		return false;
834 
835 	return true;
836 }
837 
838 }	// namespace BPrivate
839