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
27using namespace std;
28
29// attribute names
30#define NI_BEOS "BEOS"
31static const char *kNITypeAttribute			= NI_BEOS ":TYPE";
32static const char *kNIPreferredAppAttribute	= NI_BEOS ":PREF_APP";
33static const char *kNIAppHintAttribute		= NI_BEOS ":PPATH";
34static const char *kNIMiniIconAttribute		= NI_BEOS ":M:STD_ICON";
35static const char *kNILargeIconAttribute	= NI_BEOS ":L:STD_ICON";
36static 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*/
45BNodeInfo::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*/
59BNodeInfo::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*/
72BNodeInfo::~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*/
90status_t
91BNodeInfo::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*/
108status_t
109BNodeInfo::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*/
133status_t
134BNodeInfo::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*/
182status_t
183BNodeInfo::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*/
227status_t
228BNodeInfo::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*/
333status_t
334BNodeInfo::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*/
419status_t
420BNodeInfo::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*/
474status_t
475BNodeInfo::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*/
516status_t
517BNodeInfo::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*/
569status_t
570BNodeInfo::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*/
611status_t
612BNodeInfo::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*/
665status_t
666BNodeInfo::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*/
724status_t
725BNodeInfo::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	BRect bounds;
732	switch (iconSize) {
733		case B_MINI_ICON:
734			bounds.Set(0, 0, 15, 15);
735			break;
736		case B_LARGE_ICON:
737			bounds.Set(0, 0, 31, 31);
738			break;
739		default:
740//			error = B_BAD_VALUE;
741			// NOTE: added to be less strict and support scaled icons
742			bounds = icon->Bounds();
743			break;
744	}
745
746	// check parameters and initialization
747	if (icon->InitCheck() != B_OK || icon->Bounds() != bounds)
748		return B_BAD_VALUE;
749
750	if (InitCheck() != B_OK)
751		return B_NO_INIT;
752
753	// Ask GetIcon() first.
754	if (GetIcon(icon, iconSize) == B_OK)
755		return B_OK;
756
757	// If not successful, see if the node has a type available at all. If no type
758	// is available, use one of the standard types depending on
759	status_t error = B_OK;
760	char mimeString[B_MIME_TYPE_LENGTH];
761	if (GetType(mimeString) != B_OK) {
762		// Get the icon from a mime type...
763		BMimeType type;
764
765		struct stat stat;
766		error = fNode->GetStat(&stat);
767		if (error == B_OK) {
768			// no type available -- get the icon for the appropriate type (file/dir/etc.)
769			if (S_ISREG(stat.st_mode)) {
770				// is it an application (executable) or just a regular file?
771				if ((stat.st_mode & S_IXUSR) != 0)
772					type.SetTo(B_APP_MIME_TYPE);
773				else
774					type.SetTo(B_FILE_MIME_TYPE);
775			} else if (S_ISDIR(stat.st_mode)) {
776				// it's either a volume or just a standard directory
777				fs_info info;
778				if (fs_stat_dev(stat.st_dev, &info) == 0 && stat.st_ino == info.root)
779					type.SetTo(B_VOLUME_MIME_TYPE);
780				else
781					type.SetTo(B_DIRECTORY_MIME_TYPE);
782			} else if (S_ISLNK(stat.st_mode))
783				type.SetTo(B_SYMLINK_MIME_TYPE);
784		} else {
785			// GetStat() failed.
786			// Return the icon for "application/octet-stream" from the MIME database.
787			type.SetTo(B_FILE_MIME_TYPE);
788		}
789
790		return type.GetIcon(icon, iconSize);
791
792	} else {
793		// We know the mimetype of the node.
794		bool success = false;
795
796		// Get the preferred application and ask the MIME database, if that
797		// application has a special icon for the node's file type.
798		char signature[B_MIME_TYPE_LENGTH];
799		if (GetPreferredApp(signature) == B_OK) {
800			BMimeType type(signature);
801			success = type.GetIconForType(mimeString, icon, iconSize) == B_OK;
802		}
803
804		// TODO: Confirm Tracker asks preferred app icons before asking mime icons.
805
806		BMimeType nodeType(mimeString);
807
808		// Ask the MIME database for the preferred application for the node's
809		// file type and whether this application has a special icon for the type.
810		if (!success && nodeType.GetPreferredApp(signature) == B_OK) {
811			BMimeType type(signature);
812			success = type.GetIconForType(mimeString, icon, iconSize) == B_OK;
813		}
814
815		// Ask the MIME database whether there is an icon for the node's file type.
816		if (!success)
817			success = nodeType.GetIcon(icon, iconSize) == B_OK;
818
819		// Get the super type if still no success.
820		BMimeType superType;
821		if (!success && nodeType.GetSupertype(&superType) == B_OK) {
822			// Ask the MIME database for the preferred application for the node's
823			// super type and whether this application has a special icon for the type.
824			if (superType.GetPreferredApp(signature) == B_OK) {
825				BMimeType type(signature);
826				success = type.GetIconForType(superType.Type(), icon, iconSize) == B_OK;
827			}
828			// Get the icon of the super type itself.
829			if (!success)
830				success = superType.GetIcon(icon, iconSize) == B_OK;
831		}
832
833		if (success)
834			return B_OK;
835	}
836
837	return B_ERROR;
838}
839
840// GetTrackerIcon
841/*!	\brief Gets the icon which tracker displays for the node referred to by
842		   the supplied entry_ref.
843
844	This methods works similar to the non-static version. The first argument
845	\a ref identifies the node in question.
846
847	\param ref An entry_ref referring to the node for which the icon shall be
848		   retrieved.
849	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
850		   to store the requested icon (16x16 for the mini and 32x32 for the
851		   large icon).
852	\param iconSize Specifies the size of the icon to be retrieved: \c B_MINI_ICON
853		   for the mini and \c B_LARGE_ICON for the large icon.
854	\return
855	- \c B_OK: Everything went fine.
856	- \c B_NO_INIT: The object is not properly initialized.
857	- \c B_BAD_VALUE: \c NULL ref or \a icon, unsupported icon size \a iconSize or
858		 bitmap dimensions (\a icon) and icon size (\a iconSize) do not match.
859	- other error codes
860*/
861status_t
862BNodeInfo::GetTrackerIcon(const entry_ref *ref, BBitmap *icon, icon_size iconSize)
863{
864	// check ref param
865	status_t error = (ref ? B_OK : B_BAD_VALUE);
866
867	// init a BNode
868	BNode node;
869	if (error == B_OK)
870		error = node.SetTo(ref);
871
872	// init a BNodeInfo
873	BNodeInfo nodeInfo;
874	if (error == B_OK)
875		error = nodeInfo.SetTo(&node);
876
877	// let the non-static GetTrackerIcon() do the dirty work
878	if (error == B_OK)
879		error = nodeInfo.GetTrackerIcon(icon, iconSize);
880	return error;
881}
882
883// TODO: just here for providing binary compatibility
884// (for example "Guido" needs this)
885extern "C"
886status_t
887GetTrackerIcon__9BNodeInfoP9entry_refP7BBitmap9icon_size(
888	BNodeInfo *nodeInfo, entry_ref* ref,
889	BBitmap* bitmap, icon_size iconSize)
890{
891	// NOTE: nodeInfo is ignored - maybe that's wrong!
892	return BNodeInfo::GetTrackerIcon(ref, bitmap, iconSize);
893}
894
895void
896BNodeInfo::_ReservedNodeInfo1()
897{
898}
899
900void
901BNodeInfo::_ReservedNodeInfo2()
902{
903}
904
905void
906BNodeInfo::_ReservedNodeInfo3()
907{
908}
909
910// =
911/*!	\brief Privatized assignment operator to prevent usage.
912*/
913BNodeInfo &
914BNodeInfo::operator=(const BNodeInfo &nodeInfo)
915{
916	return *this;
917}
918
919// copy constructor
920/*!	\brief Privatized copy constructor to prevent usage.
921*/
922BNodeInfo::BNodeInfo(const BNodeInfo &)
923{
924}
925
926
927//	#pragma mark -
928
929namespace BPrivate {
930
931/*!
932	Private function used by Tracker. Should be moved into the Tracker sources.
933*/
934extern bool
935CheckNodeIconHintPrivate(const BNode *node, bool checkMiniIconOnly)
936{
937	attr_info info;
938	if (node->GetAttrInfo(kNIMiniIconAttribute, &info) != B_OK && checkMiniIconOnly)
939		return false;
940
941	if (node->GetAttrInfo(kNILargeIconAttribute, &info) != B_OK)
942		return false;
943
944	return true;
945}
946
947}	// namespace BPrivate
948