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