1/*
2 * Copyright 2002-2007, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ingo Weinhold, bonefish@users.sf.net
7 */
8
9
10#include <new>
11#include <set>
12#include <stdlib.h>
13#include <string>
14
15#include <AppFileInfo.h>
16#include <Bitmap.h>
17#include <File.h>
18#include <fs_attr.h>
19#include <IconUtils.h>
20#include <MimeType.h>
21#include <RegistrarDefs.h>
22#include <Resources.h>
23#include <Roster.h>
24#include <String.h>
25
26using namespace std;
27
28// attributes
29static const char* kTypeAttribute				= "BEOS:TYPE";
30static const char* kSignatureAttribute			= "BEOS:APP_SIG";
31static const char* kAppFlagsAttribute			= "BEOS:APP_FLAGS";
32static const char* kSupportedTypesAttribute		= "BEOS:FILE_TYPES";
33static const char* kVersionInfoAttribute		= "BEOS:APP_VERSION";
34static const char* kMiniIconAttribute			= "BEOS:M:";
35static const char* kLargeIconAttribute			= "BEOS:L:";
36static const char* kIconAttribute				= "BEOS:";
37static const char* kStandardIconType			= "STD_ICON";
38static const char* kIconType					= "ICON";
39static const char* kCatalogEntryAttribute		= "SYS:NAME";
40
41// resource IDs
42static const int32 kTypeResourceID				= 2;
43static const int32 kSignatureResourceID			= 1;
44static const int32 kAppFlagsResourceID			= 1;
45static const int32 kSupportedTypesResourceID	= 1;
46static const int32 kMiniIconResourceID			= 101;
47static const int32 kLargeIconResourceID			= 101;
48static const int32 kIconResourceID				= 101;
49static const int32 kVersionInfoResourceID		= 1;
50static const int32 kMiniIconForTypeResourceID	= 0;
51static const int32 kLargeIconForTypeResourceID	= 0;
52static const int32 kIconForTypeResourceID		= 0;
53static const int32 kCatalogEntryResourceID		= 1;
54
55// type codes
56enum {
57	B_APP_FLAGS_TYPE	= 'APPF',
58	B_VERSION_INFO_TYPE	= 'APPV',
59};
60
61// R5 also exports these (Tracker is using them):
62// (maybe we better want to drop them silently and declare
63// the above in a public Haiku header - and use that one in
64// Tracker when compiled for Haiku)
65extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE;
66const uint32 MINI_ICON_TYPE = 'MICN';
67const uint32 LARGE_ICON_TYPE = 'ICON';
68
69// debugging
70//#define DBG(x) x
71#define DBG(x)
72#define OUT	printf
73
74// constructor
75/*!	\brief Creates an uninitialized BAppFileInfo object.
76*/
77BAppFileInfo::BAppFileInfo()
78	:
79	fResources(NULL),
80	fWhere(B_USE_BOTH_LOCATIONS)
81{
82}
83
84
85// constructor
86/*!	\brief Creates an BAppFileInfo object and initializes it to the supplied
87		   file.
88
89	The caller retains ownership of the supplied BFile object. It must not
90	be deleted during the life time of the BAppFileInfo. It is not deleted
91	when the BAppFileInfo is destroyed.
92
93	\param file The file the object shall be initialized to.
94*/
95BAppFileInfo::BAppFileInfo(BFile* file)
96	:
97	fResources(NULL),
98	fWhere(B_USE_BOTH_LOCATIONS)
99{
100	SetTo(file);
101}
102
103
104// destructor
105/*!	\brief Frees all resources associated with this object.
106
107	The BFile the object is set to is not deleted.
108*/
109BAppFileInfo::~BAppFileInfo()
110{
111	delete fResources;
112}
113
114
115// SetTo
116/*!	\brief Initializes the BAppFileInfo to the supplied file.
117
118	The caller retains ownership of the supplied BFile object. It must not
119	be deleted during the life time of the BAppFileInfo. It is not deleted
120	when the BAppFileInfo is destroyed.
121
122	\param file The file the object shall be initialized to.
123
124	\return
125	- \c B_OK: Everything went fine.
126	- \c B_BAD_VALUE: \c NULL \a file or \a file is not properly initialized.
127*/
128status_t
129BAppFileInfo::SetTo(BFile *file)
130{
131	// unset the old file
132	BNodeInfo::SetTo(NULL);
133	if (fResources) {
134		delete fResources;
135		fResources = NULL;
136	}
137
138	// check param
139	status_t error = (file && file->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
140
141	info_location where = B_USE_BOTH_LOCATIONS;
142
143	// create resources
144	if (error == B_OK) {
145		fResources = new(nothrow) BResources();
146		if (fResources) {
147			error = fResources->SetTo(file);
148			if (error != B_OK) {
149				// no resources - this is no critical error, we'll just use
150				// attributes only, then
151				where = B_USE_ATTRIBUTES;
152				error = B_OK;
153			}
154		} else
155			error = B_NO_MEMORY;
156	}
157
158	// set node info
159	if (error == B_OK)
160		error = BNodeInfo::SetTo(file);
161
162	if (error != B_OK || (where & B_USE_RESOURCES) == 0) {
163		delete fResources;
164		fResources = NULL;
165	}
166
167	// clean up on error
168	if (error != B_OK) {
169		if (InitCheck() == B_OK)
170			BNodeInfo::SetTo(NULL);
171	}
172
173	// set data location
174	if (error == B_OK)
175		SetInfoLocation(where);
176
177	// set error
178	fCStatus = error;
179	return error;
180}
181
182
183// GetType
184/*!	\brief Gets the file's MIME type.
185
186	\param type A pointer to a pre-allocated character buffer of size
187		   \c B_MIME_TYPE_LENGTH or larger into which the MIME type of the
188		   file shall be written.
189	\return
190	- \c B_OK: Everything went fine.
191	- \c B_NO_INIT: The object is not properly initialized.
192	- \c B_BAD_VALUE: \c NULL \a type or the type string stored in the
193	  attribute/resources is longer than \c B_MIME_TYPE_LENGTH.
194	- \c B_BAD_TYPE: The attribute/resources the type string is stored in have
195	  the wrong type.
196	- \c B_ENTRY_NOT_FOUND: No type is set on the file.
197	- other error codes
198*/
199status_t
200BAppFileInfo::GetType(char *type) const
201{
202	// check param and initialization
203	status_t error = (type ? B_OK : B_BAD_VALUE);
204	if (error == B_OK && InitCheck() != B_OK)
205		error = B_NO_INIT;
206	// read the data
207	size_t read = 0;
208	if (error == B_OK) {
209		error = _ReadData(kTypeAttribute, kTypeResourceID, B_MIME_STRING_TYPE,
210						  type, B_MIME_TYPE_LENGTH, read);
211	}
212	// check the read data -- null terminate the string
213	if (error == B_OK && type[read - 1] != '\0') {
214		if (read == B_MIME_TYPE_LENGTH)
215			error = B_ERROR;
216		else
217			type[read] = '\0';
218	}
219	return error;
220}
221
222
223// SetType
224/*!	\brief Sets the file's MIME type.
225
226	If \a type is \c NULL the file's MIME type is unset.
227
228	\param type The MIME type to be assigned to the file. Must not be longer
229		   than \c B_MIME_TYPE_LENGTH (including the terminating null).
230		   May be \c NULL.
231	\return
232	- \c B_OK: Everything went fine.
233	- \c B_NO_INIT: The object is not properly initialized.
234	- \c B_BAD_VALUE: \a type is longer than \c B_MIME_TYPE_LENGTH.
235	- other error codes
236*/
237status_t
238BAppFileInfo::SetType(const char* type)
239{
240	// check initialization
241	status_t error = B_OK;
242	if (error == B_OK && InitCheck() != B_OK)
243		error = B_NO_INIT;
244	if (error == B_OK) {
245		if (type) {
246			// check param
247			size_t typeLen = strlen(type);
248			if (error == B_OK && typeLen >= B_MIME_TYPE_LENGTH)
249				error = B_BAD_VALUE;
250			// write the data
251			if (error == B_OK) {
252				error = _WriteData(kTypeAttribute, kTypeResourceID,
253								   B_MIME_STRING_TYPE, type, typeLen + 1);
254			}
255		} else
256			error = _RemoveData(kTypeAttribute, B_MIME_STRING_TYPE);
257	}
258	return error;
259}
260
261
262// GetSignature
263/*!	\brief Gets the file's application signature.
264
265	\param signature A pointer to a pre-allocated character buffer of size
266		   \c B_MIME_TYPE_LENGTH or larger into which the application
267		   signature of the file shall be written.
268	\return
269	- \c B_OK: Everything went fine.
270	- \c B_NO_INIT: The object is not properly initialized.
271	- \c B_BAD_VALUE: \c NULL \a signature or the signature stored in the
272	  attribute/resources is longer than \c B_MIME_TYPE_LENGTH.
273	- \c B_BAD_TYPE: The attribute/resources the signature is stored in have
274	  the wrong type.
275	- \c B_ENTRY_NOT_FOUND: No signature is set on the file.
276	- other error codes
277*/
278status_t
279BAppFileInfo::GetSignature(char* signature) const
280{
281	// check param and initialization
282	status_t error = (signature ? B_OK : B_BAD_VALUE);
283	if (error == B_OK && InitCheck() != B_OK)
284		error = B_NO_INIT;
285	// read the data
286	size_t read = 0;
287	if (error == B_OK) {
288		error = _ReadData(kSignatureAttribute, kSignatureResourceID,
289						  B_MIME_STRING_TYPE, signature,
290						  B_MIME_TYPE_LENGTH, read);
291	}
292	// check the read data -- null terminate the string
293	if (error == B_OK && signature[read - 1] != '\0') {
294		if (read == B_MIME_TYPE_LENGTH)
295			error = B_ERROR;
296		else
297			signature[read] = '\0';
298	}
299	return error;
300}
301
302
303// SetSignature
304/*!	\brief Sets the file's application signature.
305
306	If \a signature is \c NULL the file's application signature is unset.
307
308	\param signature The application signature to be assigned to the file.
309		   Must not be longer than \c B_MIME_TYPE_LENGTH (including the
310		   terminating null). May be \c NULL.
311	\return
312	- \c B_OK: Everything went fine.
313	- \c B_NO_INIT: The object is not properly initialized.
314	- \c B_BAD_VALUE: \a signature is longer than \c B_MIME_TYPE_LENGTH.
315	- other error codes
316*/
317status_t
318BAppFileInfo::SetSignature(const char* signature)
319{
320	// check initialization
321	status_t error = B_OK;
322	if (error == B_OK && InitCheck() != B_OK)
323		error = B_NO_INIT;
324	if (error == B_OK) {
325		if (signature) {
326			// check param
327			size_t signatureLen = strlen(signature);
328			if (error == B_OK && signatureLen >= B_MIME_TYPE_LENGTH)
329				error = B_BAD_VALUE;
330			// write the data
331			if (error == B_OK) {
332				error = _WriteData(kSignatureAttribute, kSignatureResourceID,
333								   B_MIME_STRING_TYPE, signature,
334								   signatureLen + 1);
335			}
336		} else
337			error = _RemoveData(kSignatureAttribute, B_MIME_STRING_TYPE);
338	}
339	return error;
340}
341
342
343// GetCatalogEntry
344/*!	\brief Gets the file's catalog entry. (localization)
345
346	\param catalogEntry A pointer to a pre-allocated character buffer of size
347		   \c B_MIME_TYPE_LENGTH * 3 or larger into which the catalog entry
348		   of the file shall be written.
349	\return
350	- \c B_OK: Everything went fine.
351	- \c B_NO_INIT: The object is not properly initialized.
352	- \c B_BAD_VALUE: \c NULL \a catalogEntry or the entry stored in the
353	  attribute/resources is longer than \c B_MIME_TYPE_LENGTH * 3.
354	- \c B_BAD_TYPE: The attribute/resources the entry is stored in have
355	  the wrong type.
356	- \c B_ENTRY_NOT_FOUND: No catalog entry is set on the file.
357	- other error codes
358*/
359status_t
360BAppFileInfo::GetCatalogEntry(char *catalogEntry) const
361{
362	if (catalogEntry == NULL)
363		return B_BAD_VALUE;
364
365	if (InitCheck() != B_OK)
366		return B_NO_INIT;
367
368	size_t read = 0;
369	status_t error = _ReadData(kCatalogEntryAttribute, kCatalogEntryResourceID,
370		B_STRING_TYPE, catalogEntry, B_MIME_TYPE_LENGTH * 3, read);
371
372	if (error != B_OK)
373		return error;
374
375	if (read >= B_MIME_TYPE_LENGTH * 3)
376		return B_ERROR;
377
378	catalogEntry[read] = '\0';
379
380	return B_OK;
381}
382
383
384// SetCatalogEntry
385/*!	\brief Sets the file's catalog entry. (localization)
386
387	If \a catalogEntry is \c NULL the file's catalog entry is unset.
388
389	\param catalogEntry The catalog entry to be assigned to the file.
390		Of the form "x-vnd.Haiku-app:context:name".
391		Must not be longer than \c B_MIME_TYPE_LENGTH * 3
392		(including the terminating null). May be \c NULL.
393	\return
394	- \c B_OK: Everything went fine.
395	- \c B_NO_INIT: The object is not properly initialized.
396	- \c B_BAD_VALUE: \a catalogEntry is longer than \c B_MIME_TYPE_LENGTH * 3.
397	- other error codes
398*/
399status_t
400BAppFileInfo::SetCatalogEntry(const char* catalogEntry)
401{
402	if (InitCheck() != B_OK)
403		return B_NO_INIT;
404
405	if (catalogEntry == NULL)
406		return _RemoveData(kCatalogEntryAttribute, B_STRING_TYPE);
407
408	size_t nameLength = strlen(catalogEntry);
409	if (nameLength > B_MIME_TYPE_LENGTH * 3)
410		return B_BAD_VALUE;
411
412	return _WriteData(kCatalogEntryAttribute, kCatalogEntryResourceID,
413		B_STRING_TYPE, catalogEntry, nameLength + 1);
414}
415
416
417// GetAppFlags
418/*!	\brief Gets the file's application flags.
419
420	\param flags A pointer to a pre-allocated uint32 into which the application
421		   flags of the file shall be written.
422	\return
423	- \c B_OK: Everything went fine.
424	- \c B_NO_INIT: The object is not properly initialized.
425	- \c B_BAD_VALUE: \c NULL \a flags.
426	- \c B_BAD_TYPE: The attribute/resources the flags are stored in have
427	  the wrong type.
428	- \c B_ENTRY_NOT_FOUND: No application flags are set on the file.
429	- other error codes
430*/
431status_t
432BAppFileInfo::GetAppFlags(uint32* flags) const
433{
434	// check param and initialization
435	status_t error = (flags ? B_OK : B_BAD_VALUE);
436	if (error == B_OK && InitCheck() != B_OK)
437		error = B_NO_INIT;
438	// read the data
439	size_t read = 0;
440	if (error == B_OK) {
441		error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID,
442						  B_APP_FLAGS_TYPE, flags, sizeof(uint32),
443						  read);
444	}
445	// check the read data
446	if (error == B_OK && read != sizeof(uint32))
447		error = B_ERROR;
448	return error;
449}
450
451
452// SetAppFlags
453/*!	\brief Sets the file's application flags.
454	\param flags The application flags to be assigned to the file.
455	\return
456	- \c B_OK: Everything went fine.
457	- \c B_NO_INIT: The object is not properly initialized.
458	- other error codes
459*/
460status_t
461BAppFileInfo::SetAppFlags(uint32 flags)
462{
463	// check initialization
464	status_t error = B_OK;
465	if (error == B_OK && InitCheck() != B_OK)
466		error = B_NO_INIT;
467	if (error == B_OK) {
468		// write the data
469		error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID,
470						   B_APP_FLAGS_TYPE, &flags, sizeof(uint32));
471	}
472	return error;
473}
474
475
476// RemoveAppFlags
477/*!	\brief Removes the file's application flags.
478	\return
479	- \c B_OK: Everything went fine.
480	- \c B_NO_INIT: The object is not properly initialized.
481	- other error codes
482*/
483status_t
484BAppFileInfo::RemoveAppFlags()
485{
486	// check initialization
487	status_t error = B_OK;
488	if (error == B_OK && InitCheck() != B_OK)
489		error = B_NO_INIT;
490	if (error == B_OK) {
491		// remove the data
492		error = _RemoveData(kAppFlagsAttribute, B_APP_FLAGS_TYPE);
493	}
494	return error;
495}
496
497
498// GetSupportedTypes
499/*!	\brief Gets the MIME types supported by the application.
500
501	The supported MIME types are added to a field "types" of type
502	\c B_STRING_TYPE in \a types.
503
504	\param types A pointer to a pre-allocated BMessage into which the
505		   MIME types supported by the appplication shall be written.
506	\return
507	- \c B_OK: Everything went fine.
508	- \c B_NO_INIT: The object is not properly initialized.
509	- \c B_BAD_VALUE: \c NULL \a types.
510	- \c B_BAD_TYPE: The attribute/resources the supported types are stored in
511	  have the wrong type.
512	- \c B_ENTRY_NOT_FOUND: No supported types are set on the file.
513	- other error codes
514*/
515status_t
516BAppFileInfo::GetSupportedTypes(BMessage* types) const
517{
518	// check param and initialization
519	status_t error = (types ? B_OK : B_BAD_VALUE);
520	if (error == B_OK && InitCheck() != B_OK)
521		error = B_NO_INIT;
522	// read the data
523	size_t read = 0;
524	void *buffer = NULL;
525	if (error == B_OK) {
526		error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID,
527						  B_MESSAGE_TYPE, NULL, 0, read, &buffer);
528	}
529	// unflatten the buffer
530	if (error == B_OK)
531		error = types->Unflatten((const char*)buffer);
532	// clean up
533	free(buffer);
534	return error;
535}
536
537
538// SetSupportedTypes
539/*!	\brief Sets the MIME types supported by the application.
540
541	If \a types is \c NULL the application's supported types are unset.
542
543	The supported MIME types must be stored in a field "types" of type
544	\c B_STRING_TYPE in \a types.
545
546	The method informs the registrar about this news.
547	For each supported type the result of BMimeType::GetSupportingApps() will
548	afterwards include the signature of this application. That is, the
549	application file needs to have a signature set.
550
551	\a syncAll specifies whether the not longer supported types shall be
552	updated as well, i.e. whether this application shall be remove from the
553	lists of supporting applications.
554
555	\param types The supported types to be assigned to the file.
556		   May be \c NULL.
557	\param syncAll \c true to also synchronize the not longer supported
558		   types, \c false otherwise.
559	\return
560	- \c B_OK: Everything went fine.
561	- \c B_NO_INIT: The object is not properly initialized.
562	- other error codes
563*/
564status_t
565BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
566{
567	// check initialization
568	status_t error = B_OK;
569	if (error == B_OK && InitCheck() != B_OK)
570		error = B_NO_INIT;
571	BMimeType mimeType;
572	if (error == B_OK)
573		error = GetMetaMime(&mimeType);
574	if (error == B_OK || error == B_ENTRY_NOT_FOUND) {
575		error = B_OK;
576		if (types) {
577			// check param -- supported types must be valid
578			const char* type;
579			for (int32 i = 0;
580				 error == B_OK && types->FindString("types", i, &type) == B_OK;
581				 i++) {
582				if (!BMimeType::IsValid(type))
583					error = B_BAD_VALUE;
584			}
585			// get flattened size
586			ssize_t size = 0;
587			if (error == B_OK) {
588				size = types->FlattenedSize();
589				if (size < 0)
590					error = size;
591			}
592			// allocate a buffer for the flattened data
593			char* buffer = NULL;
594			if (error == B_OK) {
595				buffer = new(nothrow) char[size];
596				if (!buffer)
597					error = B_NO_MEMORY;
598			}
599			// flatten the message
600			if (error == B_OK)
601				error = types->Flatten(buffer, size);
602			// write the data
603			if (error == B_OK) {
604				error = _WriteData(kSupportedTypesAttribute,
605								   kSupportedTypesResourceID, B_MESSAGE_TYPE,
606								   buffer, size);
607			}
608			// clean up
609			delete[] buffer;
610		} else
611			error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE);
612		// update the MIME database, if the app signature is installed
613		if (error == B_OK && mimeType.IsInstalled())
614			error = mimeType.SetSupportedTypes(types, syncAll);
615	}
616	return error;
617}
618
619
620// SetSupportedTypes
621/*!	\brief Sets the MIME types supported by the application.
622
623	This method is a short-hand for SetSupportedTypes(types, false).
624	\see SetSupportedType(const BMessage*, bool) for detailed information.
625
626	\param types The supported types to be assigned to the file.
627		   May be \c NULL.
628	\return
629	- \c B_OK: Everything went fine.
630	- \c B_NO_INIT: The object is not properly initialized.
631	- other error codes
632*/
633status_t
634BAppFileInfo::SetSupportedTypes(const BMessage* types)
635{
636	return SetSupportedTypes(types, false);
637}
638
639
640// IsSupportedType
641/*!	\brief Returns whether the application supports the supplied MIME type.
642
643	If the application supports the wildcard type "application/octet-stream"
644	any this method returns \c true for any MIME type.
645
646	\param type The MIME type in question.
647	\return \c true, if \a type is a valid MIME type and it is supported by
648			the application, \c false otherwise.
649*/
650bool
651BAppFileInfo::IsSupportedType(const char* type) const
652{
653	status_t error = (type ? B_OK : B_BAD_VALUE);
654	// get the supported types
655	BMessage types;
656	if (error == B_OK)
657		error = GetSupportedTypes(&types);
658	// turn type into a BMimeType
659	BMimeType mimeType;
660	if (error == B_OK)
661		error = mimeType.SetTo(type);
662	// iterate through the supported types
663	bool found = false;
664	if (error == B_OK) {
665		const char* supportedType;
666		for (int32 i = 0;
667			 !found && types.FindString("types", i, &supportedType) == B_OK;
668			 i++) {
669			found = !strcmp(supportedType, "application/octet-stream")
670					|| BMimeType(supportedType).Contains(&mimeType);
671		}
672	}
673	return found;
674}
675
676
677// Supports
678/*!	\brief Returns whether the application supports the supplied MIME type
679		   explicitly.
680
681	Unlike IsSupportedType(), this method returns \c true, only if the type
682	is explicitly supported, regardless of whether it supports
683	"application/octet-stream".
684
685	\param type The MIME type in question.
686	\return \c true, if \a type is a valid MIME type and it is explicitly
687			supported by the application, \c false otherwise.
688*/
689bool
690BAppFileInfo::Supports(BMimeType* type) const
691{
692	status_t error = (type && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
693	// get the supported types
694	BMessage types;
695	if (error == B_OK)
696		error = GetSupportedTypes(&types);
697	// iterate through the supported types
698	bool found = false;
699	if (error == B_OK) {
700		const char* supportedType;
701		for (int32 i = 0;
702			 !found && types.FindString("types", i, &supportedType) == B_OK;
703			 i++) {
704			found = BMimeType(supportedType).Contains(type);
705		}
706	}
707	return found;
708}
709
710
711// GetIcon
712/*!	\brief Gets the file's icon.
713	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
714		   to store the requested icon (16x16 for the mini and 32x32 for the
715		   large icon).
716	\param which Specifies the size of the icon to be retrieved:
717		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
718	\return
719	- \c B_OK: Everything went fine.
720	- \c B_NO_INIT: The object is not properly initialized.
721	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a which or bitmap
722		 dimensions (\a icon) and icon size (\a which) do not match.
723	- other error codes
724*/
725status_t
726BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
727{
728	return GetIconForType(NULL, icon, which);
729}
730
731
732// GetIcon
733/*!	\brief Gets the file's icon.
734	\param data The pointer in which the flat icon data will be returned.
735	\param size The pointer in which the size of the data found will be returned.
736	\return
737	- \c B_OK: Everything went fine.
738	- \c B_NO_INIT: The object is not properly initialized.
739	- \c B_BAD_VALUE: \c NULL \a data or \c NULL size.
740	- other error codes
741*/
742status_t
743BAppFileInfo::GetIcon(uint8** data, size_t* size) const
744{
745	return GetIconForType(NULL, data, size);
746}
747
748
749// SetIcon
750/*!	\brief Sets the file's icon.
751
752	If \a icon is \c NULL the file's icon is unset.
753
754	\param icon A pointer to the BBitmap containing the icon to be set.
755		   May be \c NULL.
756	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
757		   for the mini and \c B_LARGE_ICON for the large icon.
758	\return
759	- \c B_OK: Everything went fine.
760	- \c B_NO_INIT: The object is not properly initialized.
761	- \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon)
762		 and icon size (\a which) do not match.
763	- other error codes
764*/
765status_t
766BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
767{
768	return SetIconForType(NULL, icon, which);
769}
770
771
772// SetIcon
773/*!	\brief Sets the file's icon.
774
775	If \a icon is \c NULL the file's icon is unset.
776
777	\param data A pointer to the data buffer containing the vector icon
778		   to be set. May be \c NULL.
779	\param size Specifies the size of buffer pointed to by \a data.
780	\return
781	- \c B_OK: Everything went fine.
782	- \c B_NO_INIT: The object is not properly initialized.
783	- \c B_BAD_VALUE: \c NULL data.
784	- other error codes
785*/
786status_t
787BAppFileInfo::SetIcon(const uint8* data, size_t size)
788{
789	return SetIconForType(NULL, data, size);
790}
791
792
793// GetVersionInfo
794/*!	\brief Gets the file's version info.
795	\param info A pointer to a pre-allocated version_info structure into which
796		   the version info should be written.
797	\param kind Specifies the kind of the version info to be retrieved:
798		   \c B_APP_VERSION_KIND for the application's version info and
799		   \c B_SYSTEM_VERSION_KIND for the suite's info the application
800		   belongs to.
801	\return
802	- \c B_OK: Everything went fine.
803	- \c B_NO_INIT: The object is not properly initialized.
804	- \c B_BAD_VALUE: \c NULL \a info.
805	- other error codes
806*/
807status_t
808BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const
809{
810	// check params and initialization
811	if (!info)
812		return B_BAD_VALUE;
813
814	int32 index = 0;
815	switch (kind) {
816		case B_APP_VERSION_KIND:
817			index = 0;
818			break;
819		case B_SYSTEM_VERSION_KIND:
820			index = 1;
821			break;
822		default:
823			return B_BAD_VALUE;
824	}
825
826	if (InitCheck() != B_OK)
827		return B_NO_INIT;
828
829	// read the data
830	size_t read = 0;
831	version_info infos[2];
832	status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
833		B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
834	if (error != B_OK)
835		return error;
836
837	// check the read data
838	if (read == sizeof(version_info)) {
839		// only the app version info is there -- return a cleared system info
840		if (index == 0)
841			*info = infos[index];
842		else if (index == 1)
843			memset(info, 0, sizeof(version_info));
844	} else if (read == 2 * sizeof(version_info)) {
845		*info = infos[index];
846	} else
847		return B_ERROR;
848
849	// return result
850	return B_OK;
851}
852
853
854// SetVersionInfo
855/*!	\brief Sets the file's version info.
856
857	If \a info is \c NULL the file's version info is unset.
858
859	\param info The version info to be set. May be \c NULL.
860	\param kind Specifies kind of version info to be set:
861		   \c B_APP_VERSION_KIND for the application's version info and
862		   \c B_SYSTEM_VERSION_KIND for the suite's info the application
863		   belongs to.
864	\return
865	- \c B_OK: Everything went fine.
866	- \c B_NO_INIT: The object is not properly initialized.
867	- other error codes
868*/
869status_t
870BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind)
871{
872	// check initialization
873	status_t error = B_OK;
874	if (error == B_OK && InitCheck() != B_OK)
875		error = B_NO_INIT;
876	if (error == B_OK) {
877		if (info) {
878			// check param
879			int32 index = 0;
880			if (error == B_OK) {
881				switch (kind) {
882					case B_APP_VERSION_KIND:
883						index = 0;
884						break;
885					case B_SYSTEM_VERSION_KIND:
886						index = 1;
887						break;
888					default:
889						error = B_BAD_VALUE;
890						break;
891				}
892			}
893			// read both infos
894			version_info infos[2];
895			if (error == B_OK) {
896				size_t read;
897				if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
898						B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
899						read) == B_OK) {
900					// clear the part that hasn't been read
901					if (read < sizeof(infos))
902						memset((char*)infos + read, 0, sizeof(infos) - read);
903				} else {
904					// failed to read -- clear
905					memset(infos, 0, sizeof(infos));
906				}
907			}
908			infos[index] = *info;
909			// write the data
910			if (error == B_OK) {
911				error = _WriteData(kVersionInfoAttribute,
912								   kVersionInfoResourceID,
913								   B_VERSION_INFO_TYPE, infos,
914								   2 * sizeof(version_info));
915			}
916		} else
917			error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
918	}
919	return error;
920}
921
922
923// GetIconForType
924/*!	\brief Gets the icon the application provides for a given MIME type.
925
926	If \a type is \c NULL, the application's icon is retrieved.
927
928	\param type The MIME type in question. May be \c NULL.
929	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
930		   to store the requested icon (16x16 for the mini and 32x32 for the
931		   large icon).
932	\param which Specifies the size of the icon to be retrieved:
933		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
934	\return
935	- \c B_OK: Everything went fine.
936	- \c B_NO_INIT: The object is not properly initialized.
937	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size
938		 \a which or bitmap dimensions (\a icon) and icon size (\a which) do
939		 not match.
940	- other error codes
941*/
942status_t
943BAppFileInfo::GetIconForType(const char* type, BBitmap* icon,
944							 icon_size size) const
945{
946	if (InitCheck() != B_OK)
947		return B_NO_INIT;
948
949	if (!icon || icon->InitCheck() != B_OK)
950		return B_BAD_VALUE;
951
952	// TODO: for consistency with attribute based icon reading, we
953	// could also prefer B_CMAP8 icons here if the provided bitmap
954	// is in that format. Right now, an existing B_CMAP8 icon resource
955	// would be ignored as soon as a vector icon is present. On the other
956	// hand, maybe this still results in a more consistent user interface,
957	// since Tracker/Deskbar would surely show the vector icon.
958
959	// try vector icon first
960	BString vectorAttributeName(kIconAttribute);
961
962	// check type param
963	if (type) {
964		if (BMimeType::IsValid(type))
965			vectorAttributeName += type;
966		else
967			return B_BAD_VALUE;
968	} else {
969		vectorAttributeName += kIconType;
970	}
971	const char* attribute = vectorAttributeName.String();
972
973	size_t bytesRead;
974	void* allocatedBuffer;
975	status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0,
976							   bytesRead, &allocatedBuffer);
977	if (error == B_OK) {
978		error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer,
979										  bytesRead, icon);
980		free(allocatedBuffer);
981		return error;
982	}
983
984	// no vector icon if we got this far,
985	// align size argument just in case
986	if (size < B_LARGE_ICON)
987		size = B_MINI_ICON;
988	else
989		size = B_LARGE_ICON;
990
991	error = B_OK;
992	// set some icon size related variables
993	BString attributeString;
994	BRect bounds;
995	uint32 attrType = 0;
996	size_t attrSize = 0;
997	switch (size) {
998		case B_MINI_ICON:
999			attributeString = kMiniIconAttribute;
1000			bounds.Set(0, 0, 15, 15);
1001			attrType = B_MINI_ICON_TYPE;
1002			attrSize = 16 * 16;
1003			break;
1004		case B_LARGE_ICON:
1005			attributeString = kLargeIconAttribute;
1006			bounds.Set(0, 0, 31, 31);
1007			attrType = B_LARGE_ICON_TYPE;
1008			attrSize = 32 * 32;
1009			break;
1010		default:
1011			return B_BAD_VALUE;
1012	}
1013	// check type param
1014	if (type) {
1015		if (BMimeType::IsValid(type))
1016			attributeString += type;
1017		else
1018			return B_BAD_VALUE;
1019	} else
1020		attributeString += kStandardIconType;
1021
1022	attribute = attributeString.String();
1023
1024	// check parameters
1025	// currently, scaling B_CMAP8 icons is not supported
1026	if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds)
1027		return B_BAD_VALUE;
1028
1029	// read the data
1030	if (error == B_OK) {
1031		bool tempBuffer = (icon->ColorSpace() != B_CMAP8
1032						   || icon->Bounds() != bounds);
1033		uint8* buffer = NULL;
1034		size_t read;
1035		if (tempBuffer) {
1036			// other color space or bitmap size than stored in attribute
1037			buffer = new(nothrow) uint8[attrSize];
1038			if (!buffer) {
1039				error = B_NO_MEMORY;
1040			} else {
1041				error = _ReadData(attribute, -1, attrType, buffer, attrSize,
1042								  read);
1043			}
1044		} else {
1045			error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
1046							  read);
1047		}
1048		if (error == B_OK && read != attrSize)
1049			error = B_ERROR;
1050		if (tempBuffer) {
1051			// other color space than stored in attribute
1052			if (error == B_OK) {
1053				error = BIconUtils::ConvertFromCMAP8(buffer,
1054													 (uint32)size,
1055													 (uint32)size,
1056													 (uint32)size,
1057													 icon);
1058			}
1059			delete[] buffer;
1060		}
1061	}
1062	return error;
1063}
1064
1065
1066// GetIconForType
1067/*!	\brief Gets the icon the application provides for a given MIME type.
1068
1069	If \a type is \c NULL, the application's icon is retrieved.
1070
1071	\param type The MIME type in question. May be \c NULL.
1072	\param data A pointer in which the icon data will be returned. When you
1073	are done with the data, you should use free() to deallocate it.
1074	\param size A pointer in which the size of the retrieved data is returned.
1075	\return
1076	- \c B_OK: Everything went fine.
1077	- \c B_NO_INIT: The object is not properly initialized.
1078	- \c B_BAD_VALUE: \c NULL \a data and/or \a size. Or the supplied
1079	\a type is not a valid MIME type.
1080	- other error codes
1081*/
1082status_t
1083BAppFileInfo::GetIconForType(const char* type, uint8** data,
1084							 size_t* size) const
1085{
1086	if (InitCheck() != B_OK)
1087		return B_NO_INIT;
1088
1089	if (!data || !size)
1090		return B_BAD_VALUE;
1091
1092	// get vector icon
1093	BString attributeName(kIconAttribute);
1094
1095	// check type param
1096	if (type) {
1097		if (BMimeType::IsValid(type))
1098			attributeName += type;
1099		else
1100			return B_BAD_VALUE;
1101	} else {
1102		attributeName += kIconType;
1103	}
1104
1105	void* allocatedBuffer = NULL;
1106	status_t ret = _ReadData(attributeName.String(), -1,
1107							 B_VECTOR_ICON_TYPE, NULL, 0, *size, &allocatedBuffer);
1108
1109	if (ret < B_OK)
1110		return ret;
1111
1112	*data = (uint8*)allocatedBuffer;
1113	return B_OK;
1114}
1115
1116
1117// SetIconForType
1118/*!	\brief Sets the icon the application provides for a given MIME type.
1119
1120	If \a type is \c NULL, the application's icon is set.
1121	If \a icon is \c NULL the icon is unset.
1122
1123	If the file has a signature, then the icon is also set on the MIME type.
1124	If the type for the signature has not been installed yet, it is installed
1125	before.
1126
1127	\param type The MIME type in question. May be \c NULL.
1128	\param icon A pointer to the BBitmap containing the icon to be set.
1129		   May be \c NULL.
1130	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
1131		   for the mini and \c B_LARGE_ICON for the large icon.
1132	\return
1133	- \c B_OK: Everything went fine.
1134	- \c B_NO_INIT: The object is not properly initialized.
1135	- \c B_BAD_VALUE: Either the icon size \a which is unkown, bitmap dimensions (\a icon)
1136		 and icon size (\a which) do not match, or the provided \a type is
1137		 not a valid MIME type.
1138	- other error codes
1139*/
1140status_t
1141BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
1142							 icon_size which)
1143{
1144	status_t error = B_OK;
1145	// set some icon size related variables
1146	BString attributeString;
1147	BRect bounds;
1148	uint32 attrType = 0;
1149	size_t attrSize = 0;
1150	int32 resourceID = 0;
1151	switch (which) {
1152		case B_MINI_ICON:
1153			attributeString = kMiniIconAttribute;
1154			bounds.Set(0, 0, 15, 15);
1155			attrType = B_MINI_ICON_TYPE;
1156			attrSize = 16 * 16;
1157			resourceID = (type ? kMiniIconForTypeResourceID
1158							   : kMiniIconResourceID);
1159			break;
1160		case B_LARGE_ICON:
1161			attributeString = kLargeIconAttribute;
1162			bounds.Set(0, 0, 31, 31);
1163			attrType = B_LARGE_ICON_TYPE;
1164			attrSize = 32 * 32;
1165			resourceID = (type ? kLargeIconForTypeResourceID
1166							   : kLargeIconResourceID);
1167			break;
1168		default:
1169			error = B_BAD_VALUE;
1170			break;
1171	}
1172	// check type param
1173	if (error == B_OK) {
1174		if (type) {
1175			if (BMimeType::IsValid(type))
1176				attributeString += type;
1177			else
1178				error = B_BAD_VALUE;
1179		} else
1180			attributeString += kStandardIconType;
1181	}
1182	const char* attribute = attributeString.String();
1183	// check parameter and initialization
1184	if (error == B_OK && icon
1185		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
1186		error = B_BAD_VALUE;
1187	}
1188	if (error == B_OK && InitCheck() != B_OK)
1189		error = B_NO_INIT;
1190	// write/remove the attribute
1191	if (error == B_OK) {
1192		if (icon) {
1193			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
1194			if (otherColorSpace) {
1195				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
1196				error = bitmap.InitCheck();
1197				if (error == B_OK)
1198					error = bitmap.ImportBits(icon);
1199				if (error == B_OK) {
1200					error = _WriteData(attribute, resourceID, attrType,
1201									   bitmap.Bits(), attrSize, true);
1202				}
1203			} else {
1204				error = _WriteData(attribute, resourceID, attrType,
1205								   icon->Bits(), attrSize, true);
1206			}
1207		} else	// no icon given => remove
1208			error = _RemoveData(attribute, attrType);
1209	}
1210	// set the attribute on the MIME type, if the file has a signature
1211	BMimeType mimeType;
1212	if (error == B_OK && GetMetaMime(&mimeType) == B_OK) {
1213		if (!mimeType.IsInstalled())
1214			error = mimeType.Install();
1215		if (error == B_OK)
1216			error = mimeType.SetIconForType(type, icon, which);
1217	}
1218	return error;
1219}
1220
1221
1222// SetIconForType
1223/*!	\brief Sets the icon the application provides for a given MIME type.
1224
1225	If \a type is \c NULL, the application's icon is set.
1226	If \a data is \c NULL the icon is unset.
1227
1228	If the file has a signature, then the icon is also set on the MIME type.
1229	If the type for the signature has not been installed yet, it is installed
1230	before.
1231
1232	\param type The MIME type in question. May be \c NULL.
1233	\param data A pointer to the data containing the icon to be set.
1234		   May be \c NULL.
1235	\param size Specifies the size of buffer provided in \a data.
1236	\return
1237	- \c B_OK: Everything went fine.
1238	- \c B_NO_INIT: The object is not properly initialized.
1239	- \c B_BAD_VALUE: The provided \a type is not a valid MIME type.
1240	- other error codes
1241*/
1242status_t
1243BAppFileInfo::SetIconForType(const char* type, const uint8* data,
1244							 size_t size)
1245{
1246	if (InitCheck() != B_OK)
1247		return B_NO_INIT;
1248
1249	// set some icon related variables
1250	BString attributeString = kIconAttribute;
1251	int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID;
1252	uint32 attrType = B_VECTOR_ICON_TYPE;
1253
1254	// check type param
1255	if (type) {
1256		if (BMimeType::IsValid(type))
1257			attributeString += type;
1258		else
1259			return B_BAD_VALUE;
1260	} else
1261		attributeString += kIconType;
1262
1263	const char* attribute = attributeString.String();
1264
1265	status_t error;
1266	// write/remove the attribute
1267	if (data)
1268		error = _WriteData(attribute, resourceID, attrType, data, size, true);
1269	else	// no icon given => remove
1270		error = _RemoveData(attribute, attrType);
1271
1272	// set the attribute on the MIME type, if the file has a signature
1273	BMimeType mimeType;
1274	if (error == B_OK && GetMetaMime(&mimeType) == B_OK) {
1275		if (!mimeType.IsInstalled())
1276			error = mimeType.Install();
1277		if (error == B_OK)
1278			error = mimeType.SetIconForType(type, data, size);
1279	}
1280	return error;
1281}
1282
1283
1284// SetInfoLocation
1285/*!	\brief Specifies the location where the meta data shall be stored.
1286
1287	The options for \a location are:
1288	- \c B_USE_ATTRIBUTES: Store the data in the attributes.
1289	- \c B_USE_RESOURCES: Store the data in the resources.
1290	- \c B_USE_BOTH_LOCATIONS: Store the data in attributes and resources.
1291
1292	\param location The location where the meta data shall be stored.
1293*/
1294void
1295BAppFileInfo::SetInfoLocation(info_location location)
1296{
1297	// if the resources failed to initialize, we must not use them
1298	if (fResources == NULL)
1299		location = info_location(location & ~B_USE_RESOURCES);
1300
1301	fWhere = location;
1302}
1303
1304// IsUsingAttributes
1305/*!	\brief Returns whether the object stores the meta data (also) in the
1306		   file's attributes.
1307	\return \c true, if the meta data are (also) stored in the file's
1308			attributes, \c false otherwise.
1309*/
1310bool
1311BAppFileInfo::IsUsingAttributes() const
1312{
1313	return (fWhere & B_USE_ATTRIBUTES) != 0;
1314}
1315
1316
1317// IsUsingResources
1318/*!	\brief Returns whether the object stores the meta data (also) in the
1319		   file's resources.
1320	\return \c true, if the meta data are (also) stored in the file's
1321			resources, \c false otherwise.
1322*/
1323bool
1324BAppFileInfo::IsUsingResources() const
1325{
1326	return (fWhere & B_USE_RESOURCES) != 0;
1327}
1328
1329
1330// FBC
1331void BAppFileInfo::_ReservedAppFileInfo1() {}
1332void BAppFileInfo::_ReservedAppFileInfo2() {}
1333void BAppFileInfo::_ReservedAppFileInfo3() {}
1334
1335
1336// =
1337/*!	\brief Privatized assignment operator to prevent usage.
1338*/
1339BAppFileInfo &
1340BAppFileInfo::operator=(const BAppFileInfo &)
1341{
1342	return *this;
1343}
1344
1345
1346// copy constructor
1347/*!	\brief Privatized copy constructor to prevent usage.
1348*/
1349BAppFileInfo::BAppFileInfo(const BAppFileInfo &)
1350{
1351}
1352
1353
1354// GetMetaMime
1355/*!	\brief Initializes a BMimeType to the file's signature.
1356
1357	The parameter \a meta is not checked.
1358
1359	\param meta A pointer to a pre-allocated BMimeType that shall be
1360		   initialized to the file's signature.
1361	\return
1362	- \c B_OK: Everything went fine.
1363	- \c B_BAD_VALUE: \c NULL \a meta
1364	- \c B_ENTRY_NOT_FOUND: The file has not signature or the signature is
1365(	  not installed in the MIME database.)
1366	  no valid MIME string.
1367	- other error codes
1368*/
1369status_t
1370BAppFileInfo::GetMetaMime(BMimeType* meta) const
1371{
1372	char signature[B_MIME_TYPE_LENGTH];
1373	status_t error = GetSignature(signature);
1374	if (error == B_OK)
1375		error = meta->SetTo(signature);
1376	else if (error == B_BAD_VALUE)
1377		error = B_ENTRY_NOT_FOUND;
1378	if (error == B_OK && !meta->IsValid())
1379		error = B_BAD_VALUE;
1380	return error;
1381}
1382
1383
1384// _ReadData
1385/*!	\brief Reads data from an attribute or resource.
1386
1387	The data are read from the location specified by \a fWhere.
1388
1389	The object must be properly initialized. The parameters are NOT checked.
1390
1391	\param name The name of the attribute/resource to be read.
1392	\param id The resource ID of the resource to be read. Is ignored, when
1393		   < 0.
1394	\param type The type of the attribute/resource to be read.
1395	\param buffer A pre-allocated buffer for the data to be read.
1396	\param bufferSize The size of the supplied buffer.
1397	\param bytesRead A reference parameter, set to the number of bytes
1398		   actually read.
1399	\param allocatedBuffer If not \c NULL, the method allocates a buffer
1400		   large enough too store the whole data and writes a pointer to it
1401		   into this variable. If \c NULL, the supplied buffer is used.
1402	\return
1403	- \c B_OK: Everything went fine.
1404	- error code
1405*/
1406status_t
1407BAppFileInfo::_ReadData(const char* name, int32 id, type_code type,
1408						void* buffer, size_t bufferSize,
1409						size_t &bytesRead, void** allocatedBuffer) const
1410{
1411	status_t error = B_OK;
1412
1413	if (allocatedBuffer)
1414		buffer = NULL;
1415
1416	bool foundData = false;
1417
1418	if (IsUsingAttributes()) {
1419		// get an attribute info
1420		attr_info info;
1421		if (error == B_OK)
1422			error = fNode->GetAttrInfo(name, &info);
1423
1424		// check type and size, allocate a buffer, if required
1425		if (error == B_OK && info.type != type)
1426			error = B_BAD_VALUE;
1427		if (error == B_OK && allocatedBuffer) {
1428			buffer = malloc(info.size);
1429			if (!buffer)
1430				error = B_NO_MEMORY;
1431			bufferSize = info.size;
1432		}
1433		if (error == B_OK && (off_t)bufferSize < info.size)
1434			error = B_BAD_VALUE;
1435
1436		// read the data
1437		if (error == B_OK) {
1438			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1439			if (read < 0)
1440				error = read;
1441			else if (read != info.size)
1442				error = B_ERROR;
1443			else
1444				bytesRead = read;
1445		}
1446
1447		foundData = (error == B_OK);
1448
1449		// free the allocated buffer on error
1450		if (!foundData && allocatedBuffer && buffer) {
1451			free(buffer);
1452			buffer = NULL;
1453		}
1454	}
1455
1456	if (!foundData && IsUsingResources()) {
1457		// get a resource info
1458		error = B_OK;
1459		int32 idFound;
1460		size_t sizeFound;
1461		if (error == B_OK) {
1462			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1463				error = B_ENTRY_NOT_FOUND;
1464		}
1465
1466		// check id and size, allocate a buffer, if required
1467		if (error == B_OK && id >= 0 && idFound != id)
1468			error = B_ENTRY_NOT_FOUND;
1469		if (error == B_OK && allocatedBuffer) {
1470			buffer = malloc(sizeFound);
1471			if (!buffer)
1472				error = B_NO_MEMORY;
1473			bufferSize = sizeFound;
1474		}
1475		if (error == B_OK && bufferSize < sizeFound)
1476			error = B_BAD_VALUE;
1477
1478		// load resource
1479		const void* resourceData = NULL;
1480		if (error == B_OK) {
1481			resourceData = fResources->LoadResource(type, name, &bytesRead);
1482			if (resourceData && sizeFound == bytesRead)
1483				memcpy(buffer, resourceData, bytesRead);
1484			else
1485				error = B_ERROR;
1486		}
1487	} else if (!foundData)
1488		error = B_BAD_VALUE;
1489
1490	// return the allocated buffer, or free it on error
1491	if (allocatedBuffer) {
1492		if (error == B_OK)
1493			*allocatedBuffer = buffer;
1494		else
1495			free(buffer);
1496	}
1497
1498	return error;
1499}
1500
1501
1502// _WriteData
1503/*!	\brief Writes data to an attribute or resource.
1504
1505	The data are written to the location(s) specified by \a fWhere.
1506
1507	The object must be properly initialized. The parameters are NOT checked.
1508
1509	\param name The name of the attribute/resource to be written.
1510	\param id The resource ID of the resource to be written.
1511	\param type The type of the attribute/resource to be written.
1512	\param buffer A buffer containing the data to be written.
1513	\param bufferSize The size of the supplied buffer.
1514	\param findID If set to \c true use the ID that is already assigned to the
1515		   \a name / \a type pair or take the first unused ID >= \a id.
1516		   If \c false, \a id is used.
1517	If \a id is already in use and .
1518	\return
1519	- \c B_OK: Everything went fine.
1520	- error code
1521*/
1522status_t
1523BAppFileInfo::_WriteData(const char* name, int32 id, type_code type,
1524						 const void* buffer, size_t bufferSize, bool findID)
1525{
1526	if (!IsUsingAttributes() && !IsUsingResources())
1527		return B_NO_INIT;
1528
1529	status_t error = B_OK;
1530
1531	// write to attribute
1532	if (IsUsingAttributes()) {
1533		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1534		if (written < 0)
1535			error = written;
1536		else if (written != (ssize_t)bufferSize)
1537			error = B_ERROR;
1538	}
1539	// write to resource
1540	if (IsUsingResources() && error == B_OK) {
1541		if (findID) {
1542			// get the resource info
1543			int32 idFound;
1544			size_t sizeFound;
1545			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1546				id = idFound;
1547			else {
1548				// type-name pair doesn't exist yet -- find unused ID
1549				while (fResources->HasResource(type, id))
1550					id++;
1551			}
1552		}
1553		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1554	}
1555	return error;
1556}
1557
1558// _RemoveData
1559/*!	\brief Removes an attribute or resource.
1560
1561	The removal location is specified by \a fWhere.
1562
1563	The object must be properly initialized. The parameters are NOT checked.
1564
1565	\param name The name of the attribute/resource to be remove.
1566	\param type The type of the attribute/resource to be removed.
1567	\return
1568	- \c B_OK: Everything went fine.
1569	- error code
1570*/
1571status_t
1572BAppFileInfo::_RemoveData(const char* name, type_code type)
1573{
1574	if (!IsUsingAttributes() && !IsUsingResources())
1575		return B_NO_INIT;
1576
1577	status_t error = B_OK;
1578
1579	// remove the attribute
1580	if (IsUsingAttributes()) {
1581		error = fNode->RemoveAttr(name);
1582		// It's no error, if there has been no attribute.
1583		if (error == B_ENTRY_NOT_FOUND)
1584			error = B_OK;
1585	}
1586	// remove the resource
1587	if (IsUsingResources() && error == B_OK) {
1588		// get a resource info
1589		int32 idFound;
1590		size_t sizeFound;
1591		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1592			error = fResources->RemoveResource(type, idFound);
1593	}
1594	return error;
1595}
1596
1597