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