xref: /haiku/src/kits/storage/NodeInfo.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 
399 // GetIcon
400 /*!	\brief Gets the node's icon.
401 
402 	The icon stored in the node's "BEOS:ICON" attribute is retrieved.
403 	The caller is responsible to \c delete[] the returned data if the
404 	function was successful.
405 
406 	\param data A pointer in which a pointer to the icon data
407 		   will be returned.
408 	\param size A pointer in which the size of the found icon data
409 		   will be returned.
410 	\param type A pointer in which the type of the found icon data
411 		   will be returned.
412 	\return
413 	- \c B_OK: Everything went fine.
414 	- \c B_NO_INIT: The object is not properly initialized.
415 	- \c B_BAD_VALUE: \c NULL \a data, \c NULL size or \c NULL \a type.
416 	- \c B_NO_MEMORY: No memory to allocate the data buffer.
417 	- other error codes
418 */
419 status_t
420 BNodeInfo::GetIcon(uint8** data, size_t* size, type_code* type) const
421 {
422 	// check params
423 	if (!data || !size || !type)
424 		return B_BAD_VALUE;
425 
426 	// check initialization
427 	if (InitCheck() != B_OK)
428 		return B_NO_INIT;
429 
430 	// get the attribute info and check type and size of the attr contents
431 	attr_info attrInfo;
432 	status_t ret = fNode->GetAttrInfo(kNIIconAttribute, &attrInfo);
433 	if (ret < B_OK)
434 		return ret;
435 
436 	// chicken out on unrealisticly large attributes
437 	if (attrInfo.size > 128 * 1024)
438 		return B_ERROR;
439 
440 	// fill the params
441 	*type = attrInfo.type;
442 	*size = attrInfo.size;
443 	*data = new (nothrow) uint8[*size];
444 
445 	if (!*data)
446 		return B_NO_MEMORY;
447 
448 	// featch the data
449 	ssize_t read = fNode->ReadAttr(kNIIconAttribute, *type, 0, *data, *size);
450 	if (read != attrInfo.size) {
451 		delete[] *data;
452 		*data = NULL;
453 		return B_ERROR;
454 	}
455 
456 	return B_OK;
457 }
458 
459 // SetIcon
460 /*!	\brief Sets the node's icon.
461 
462 	The icon is stored in the node's "BEOS:ICON" attribute.
463 
464 	If \a data is \c NULL, the respective attribute is removed.
465 
466 	\param data A pointer to valid vector icon data.
467 		   May be \c NULL.
468 	\param size Specifies the size of the provided data buffer.
469 	\return
470 	- \c B_OK: Everything went fine.
471 	- \c B_NO_INIT: The object is not properly initialized.
472 	- other error codes
473 */
474 status_t
475 BNodeInfo::SetIcon(const uint8* data, size_t size)
476 {
477 	// check initialization
478 	if (InitCheck() != B_OK)
479 		return B_NO_INIT;
480 
481 	status_t error = B_OK;
482 
483 	// write/remove the attribute
484 	if (data && size > 0) {
485 		ssize_t written = fNode->WriteAttr(kNIIconAttribute,
486 										   B_VECTOR_ICON_TYPE,
487 										   0, data, size);
488 		if (written < 0)
489 			error = (status_t)written;
490 		else if (written != (ssize_t)size)
491 			error = B_ERROR;
492 	} else	// no icon given => remove
493 		error = fNode->RemoveAttr(kNIIconAttribute);
494 
495 	return error;
496 }
497 
498 // GetPreferredApp
499 /*!	\brief Gets the node's preferred application.
500 
501 	Writes the contents of the "BEOS:PREF_APP" attribute into the supplied
502 	buffer \a signature. The preferred application is identifief by its
503 	signature.
504 
505 	\param signature A pointer to a pre-allocated character buffer of size
506 		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
507 		   preferred application shall be written.
508 	\param verb Specifies the type of access the preferred application is
509 		   requested for. Currently only \c B_OPEN is meaningful.
510 	\return
511 	- \c B_OK: Everything went fine.
512 	- \c B_NO_INIT: The object is not properly initialized.
513 	- \c B_BAD_VALUE: \c NULL \a signature or bad app_verb \a verb.
514 	- other error codes
515 */
516 status_t
517 BNodeInfo::GetPreferredApp(char *signature, app_verb verb) const
518 {
519 	// check parameter and initialization
520 	status_t error = (signature && verb == B_OPEN ? B_OK : B_BAD_VALUE);
521 	if (error == B_OK && InitCheck() != B_OK)
522 		error = B_NO_INIT;
523 
524 	// get the attribute info and check type and length of the attr contents
525 	attr_info attrInfo;
526 	if (error == B_OK)
527 		error = fNode->GetAttrInfo(kNIPreferredAppAttribute, &attrInfo);
528 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
529 		error = B_BAD_TYPE;
530 	if (error == B_OK && attrInfo.size > B_MIME_TYPE_LENGTH)
531 		error = B_BAD_DATA;
532 
533 	// read the data
534 	if (error == B_OK) {
535 		ssize_t read = fNode->ReadAttr(kNIPreferredAppAttribute, attrInfo.type,
536 									   0, signature, attrInfo.size);
537 		if (read < 0)
538 			error = read;
539 		else if (read != attrInfo.size)
540 			error = B_ERROR;
541 
542 		if (error == B_OK) {
543 			// attribute strings doesn't have to be null terminated
544 			signature[min_c(attrInfo.size, B_MIME_TYPE_LENGTH - 1)] = '\0';
545 		}
546 	}
547 	return error;
548 }
549 
550 // SetPreferredApp
551 /*!	\brief Sets the node's preferred application.
552 
553 	The supplied string is written into the node's "BEOS:PREF_APP" attribute.
554 
555 	If \a signature is \c NULL, the respective attribute is removed.
556 
557 	\param signature The signature of the preferred application to be set.
558 		   Must not be longer than \c B_MIME_TYPE_LENGTH (including the
559 		   terminating null). May be \c NULL.
560 	\param verb Specifies the type of access the preferred application shall
561 		   be set for. Currently only \c B_OPEN is meaningful.
562 	\return
563 	- \c B_OK: Everything went fine.
564 	- \c B_NO_INIT: The object is not properly initialized.
565 	- \c B_BAD_VALUE: \c NULL \a signature, \a signature is longer than
566 	  \c B_MIME_TYPE_LENGTH or bad app_verb \a verb.
567 	- other error codes
568 */
569 status_t
570 BNodeInfo::SetPreferredApp(const char *signature, app_verb verb)
571 {
572 	// check parameters and initialization
573 	status_t error = (verb == B_OPEN ? B_OK : B_BAD_VALUE);
574 	if (error == B_OK && signature && strlen(signature) >= B_MIME_TYPE_LENGTH)
575 		error = B_BAD_VALUE;
576 	if (error == B_OK && InitCheck() != B_OK)
577 		error = B_NO_INIT;
578 
579 	// write/remove the attribute
580 	if (error == B_OK) {
581 		if (signature) {
582 			size_t toWrite = strlen(signature) + 1;
583 			ssize_t written = fNode->WriteAttr(kNIPreferredAppAttribute,
584 											   B_MIME_STRING_TYPE, 0,
585 											   signature, toWrite);
586 			if (written < 0)
587 				error = written;
588 			else if (written != (ssize_t)toWrite)
589 				error = B_ERROR;
590 		} else
591 			error = fNode->RemoveAttr(kNIPreferredAppAttribute);
592 	}
593 	return error;
594 }
595 
596 // GetAppHint
597 /*!	\brief Returns a hint in form of and entry_ref to the application that
598 		   shall be used to open this node.
599 
600 	The path contained in the node's "BEOS:PPATH" attribute is converted into
601 	an entry_ref and returned in \a ref.
602 
603 	\param ref A pointer to a pre-allocated entry_ref into which the requested
604 		   app hint shall be written.
605 	\return
606 	- \c B_OK: Everything went fine.
607 	- \c B_NO_INIT: The object is not properly initialized.
608 	- \c B_BAD_VALUE: \c NULL \a ref.
609 	- other error codes
610 */
611 status_t
612 BNodeInfo::GetAppHint(entry_ref *ref) const
613 {
614 	// check parameter and initialization
615 	status_t error = (ref ? B_OK : B_BAD_VALUE);
616 	if (error == B_OK && InitCheck() != B_OK)
617 		error = B_NO_INIT;
618 
619 	// get the attribute info and check type and length of the attr contents
620 	attr_info attrInfo;
621 	if (error == B_OK)
622 		error = fNode->GetAttrInfo(kNIAppHintAttribute, &attrInfo);
623 	// NOTE: The attribute type should be B_STRING_TYPE, but R5 uses
624 	// B_MIME_STRING_TYPE.
625 	if (error == B_OK && attrInfo.type != B_MIME_STRING_TYPE)
626 		error = B_BAD_TYPE;
627 	if (error == B_OK && attrInfo.size > B_PATH_NAME_LENGTH)
628 		error = B_BAD_DATA;
629 
630 	// read the data
631 	if (error == B_OK) {
632 		char path[B_PATH_NAME_LENGTH];
633 		ssize_t read = fNode->ReadAttr(kNIAppHintAttribute, attrInfo.type, 0,
634 									   path, attrInfo.size);
635 		if (read < 0)
636 			error = read;
637 		else if (read != attrInfo.size)
638 			error = B_ERROR;
639 		// get the entry_ref for the path
640 		if (error == B_OK) {
641 			// attribute strings doesn't have to be null terminated
642 			path[min_c(attrInfo.size, B_PATH_NAME_LENGTH - 1)] = '\0';
643 			error = get_ref_for_path(path, ref);
644 		}
645 	}
646 	return error;
647 }
648 
649 // SetAppHint
650 /*!	\brief Sets the node's app hint.
651 
652 	The supplied entry_ref is converted into a path and stored in the node's
653 	"BEOS:PPATH" attribute.
654 
655 	If \a ref is \c NULL, the respective attribute is removed.
656 
657 	\param ref A pointer to an entry_ref referring to the application.
658 		   May be \c NULL.
659 	\return
660 	- \c B_OK: Everything went fine.
661 	- \c B_NO_INIT: The object is not properly initialized.
662 	- \c B_BAD_VALUE: \c NULL \a ref.
663 	- other error codes
664 */
665 status_t
666 BNodeInfo::SetAppHint(const entry_ref *ref)
667 {
668 	// check parameter and initialization
669 	status_t error = B_OK;
670 	if (error == B_OK && InitCheck() != B_OK)
671 		error = B_NO_INIT;
672 
673 	// write/remove the attribute
674 	if (error == B_OK) {
675 		if (ref) {
676 			BPath path;
677 			error = path.SetTo(ref);
678 			if (error == B_OK) {
679 				size_t toWrite = strlen(path.Path()) + 1;
680 				ssize_t written = fNode->WriteAttr(kNIAppHintAttribute,
681 												   B_MIME_STRING_TYPE, 0,
682 												   path.Path(), toWrite);
683 				if (written < 0)
684 					error = written;
685 				else if (written != (ssize_t)toWrite)
686 					error = B_ERROR;
687 			}
688 		} else
689 			error = fNode->RemoveAttr(kNIAppHintAttribute);
690 	}
691 	return error;
692 }
693 
694 // GetTrackerIcon
695 /*!	\brief Gets the icon which tracker displays.
696 
697 	This method tries real hard to find an icon for the node:
698 	- If the node has no type, return the icon for B_FILE_MIME_TYPE if it's a
699 	  regular file, for B_DIRECTORY_MIME_TYPE if it's a directory, etc. from
700 	  the MIME database. Even, if the node has an own icon!
701 	- Ask GetIcon().
702 	- Get the preferred application and ask the MIME database, if that
703 	  application has a special icon for the node's file type.
704 	- Ask the MIME database whether there is an icon for the node's file type.
705 	- Ask the MIME database for the preferred application for the node's
706 	  file type and whether this application has a special icon for the type.
707 	- Return the icon for whatever type of node (file/dir/etc.) from the MIME database.
708 	This list is processed in the given order and the icon the first
709 	successful attempt provides is returned. In case none of them yields an
710 	icon, this method fails. This is very unlikely though.
711 
712 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
713 		   to store the requested icon (16x16 for the mini and 32x32 for the
714 		   large icon).
715 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
716 		   for the mini and \c B_LARGE_ICON for the large icon.
717 	\return
718 	- \c B_OK: Everything went fine.
719 	- \c B_NO_INIT: The object is not properly initialized.
720 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a iconSize or bitmap
721 		 dimensions (\a icon) and icon size (\a iconSize) do not match.
722 	- other error codes
723 */
724 status_t
725 BNodeInfo::GetTrackerIcon(BBitmap *icon, icon_size iconSize) const
726 {
727 	if (!icon)
728 		return B_BAD_VALUE;
729 
730 	// set some icon size related variables
731 	status_t error = B_OK;
732 	BRect bounds;
733 	switch (iconSize) {
734 		case B_MINI_ICON:
735 			bounds.Set(0, 0, 15, 15);
736 			break;
737 		case B_LARGE_ICON:
738 			bounds.Set(0, 0, 31, 31);
739 			break;
740 		default:
741 //			error = B_BAD_VALUE;
742 			// NOTE: added to be less strict and support scaled icons
743 			bounds = icon->Bounds();
744 			break;
745 	}
746 
747 	// check parameters and initialization
748 	if (error == B_OK
749 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
750 		error = B_BAD_VALUE;
751 	}
752 	if (error == B_OK && InitCheck() != B_OK)
753 		error = B_NO_INIT;
754 
755 	bool success = false;
756 
757 	// get node MIME type, and, if that fails, the generic icon
758 	char mimeString[B_MIME_TYPE_LENGTH];
759 	if (error == B_OK) {
760 		if (GetType(mimeString) != B_OK) {
761 			struct stat stat;
762 			error = fNode->GetStat(&stat);
763 			if (error == B_OK) {
764 				// no type available -- get the icon for the appropriate type (file/dir/etc.)
765 				BMimeType type;
766 				if (S_ISREG(stat.st_mode)) {
767 					// is it an application (executable) or just a regular file?
768 					if ((stat.st_mode & S_IXUSR) != 0)
769 						type.SetTo(B_APP_MIME_TYPE);
770 					else
771 						type.SetTo(B_FILE_MIME_TYPE);
772 				} else if (S_ISDIR(stat.st_mode)) {
773 					// it's either a volume or just a standard directory
774 					fs_info info;
775 					if (fs_stat_dev(stat.st_dev, &info) == 0 && stat.st_ino == info.root)
776 						type.SetTo(B_VOLUME_MIME_TYPE);
777 					else
778 						type.SetTo(B_DIRECTORY_MIME_TYPE);
779 				} else if (S_ISLNK(stat.st_mode))
780 					type.SetTo(B_SYMLINK_MIME_TYPE);
781 
782 				success = (type.GetIcon(icon, iconSize) == B_OK);
783 					// NOTE: if there is an icon but getting it failes for some reason,
784 					// the error is not reported, and the fall back retrieval methods
785 					// are still tried. (IAW, we can't differentiate the reason for error.)
786 			}
787 		}
788 	}
789 
790 	// Ask GetIcon().
791 	if (error == B_OK && !success)
792 		success = (GetIcon(icon, iconSize) == B_OK);
793 
794 	// Get the preferred application and ask the MIME database, if that
795 	// application has a special icon for the node's file type.
796 	if (error == B_OK && !success) {
797 		char signature[B_MIME_TYPE_LENGTH];
798 		if (GetPreferredApp(signature) == B_OK) {
799 			BMimeType type(signature);
800 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
801 		}
802 	}
803 
804 	// Ask the MIME database whether there is an icon for the node's file type.
805 	BMimeType nodeType;
806 	if (error == B_OK && !success) {
807 		nodeType.SetTo(mimeString);
808 		success = (nodeType.GetIcon(icon, iconSize) == B_OK);
809 	}
810 
811 	// Ask the MIME database for the preferred application for the node's
812 	// file type and whether this application has a special icon for the type.
813 	if (error == B_OK && !success) {
814 		char signature[B_MIME_TYPE_LENGTH];
815 		if (nodeType.GetPreferredApp(signature) == B_OK) {
816 			BMimeType type(signature);
817 			success = (type.GetIconForType(mimeString, icon, iconSize) == B_OK);
818 		}
819 	}
820 
821 	// Return the icon for "application/octet-stream" from the MIME database.
822 	if (error == B_OK && !success) {
823 		// get the "application/octet-stream" icon
824 		BMimeType type(B_FILE_MIME_TYPE);
825 		error = type.GetIcon(icon, iconSize);
826 		success = (error == B_OK);
827 	}
828 	return error;
829 }
830 
831 // GetTrackerIcon
832 /*!	\brief Gets the icon which tracker displays for the node referred to by
833 		   the supplied entry_ref.
834 
835 	This methods works similar to the non-static version. The first argument
836 	\a ref identifies the node in question.
837 
838 	\param ref An entry_ref referring to the node for which the icon shall be
839 		   retrieved.
840 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
841 		   to store the requested icon (16x16 for the mini and 32x32 for the
842 		   large icon).
843 	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
844 		   for the mini and \c B_LARGE_ICON for the large icon.
845 	\return
846 	- \c B_OK: Everything went fine.
847 	- \c B_NO_INIT: The object is not properly initialized.
848 	- \c B_BAD_VALUE: \c NULL ref or \a icon, unsupported icon size \a iconSize or
849 		 bitmap dimensions (\a icon) and icon size (\a iconSize) do not match.
850 	- other error codes
851 */
852 status_t
853 BNodeInfo::GetTrackerIcon(const entry_ref *ref, BBitmap *icon, icon_size iconSize)
854 {
855 	// check ref param
856 	status_t error = (ref ? B_OK : B_BAD_VALUE);
857 
858 	// init a BNode
859 	BNode node;
860 	if (error == B_OK)
861 		error = node.SetTo(ref);
862 
863 	// init a BNodeInfo
864 	BNodeInfo nodeInfo;
865 	if (error == B_OK)
866 		error = nodeInfo.SetTo(&node);
867 
868 	// let the non-static GetTrackerIcon() do the dirty work
869 	if (error == B_OK)
870 		error = nodeInfo.GetTrackerIcon(icon, iconSize);
871 	return error;
872 }
873 
874 // TODO: just here for providing binary compatibility
875 // (for example "Guido" needs this)
876 extern "C"
877 status_t
878 GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
879 	BNodeInfo *nodeInfo, entry_ref* ref,
880 	BBitmap* bitmap, icon_size iconSize)
881 {
882 	// NOTE: nodeInfo is ignored - maybe that's wrong!
883 	return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
884 }
885 
886 void
887 BNodeInfo::_ReservedNodeInfo1()
888 {
889 }
890 
891 void
892 BNodeInfo::_ReservedNodeInfo2()
893 {
894 }
895 
896 void
897 BNodeInfo::_ReservedNodeInfo3()
898 {
899 }
900 
901 // =
902 /*!	\brief Privatized assignment operator to prevent usage.
903 */
904 BNodeInfo &
905 BNodeInfo::operator=(const BNodeInfo &nodeInfo)
906 {
907 	return *this;
908 }
909 
910 // copy constructor
911 /*!	\brief Privatized copy constructor to prevent usage.
912 */
913 BNodeInfo::BNodeInfo(const BNodeInfo &)
914 {
915 }
916 
917 
918 //	#pragma mark -
919 
920 namespace BPrivate {
921 
922 /*!
923 	Private function used by Tracker. Should be moved into the Tracker sources.
924 */
925 extern bool
926 CheckNodeIconHintPrivate(const BNode *node, bool checkMiniIconOnly)
927 {
928 	attr_info info;
929 	if (node->GetAttrInfo(kNIMiniIconAttribute, &info) != B_OK && checkMiniIconOnly)
930 		return false;
931 
932 	if (node->GetAttrInfo(kNILargeIconAttribute, &info) != B_OK)
933 		return false;
934 
935 	return true;
936 }
937 
938 }	// namespace BPrivate
939