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