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