xref: /haiku/src/kits/storage/AppFileInfo.cpp (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
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 || error == B_ENTRY_NOT_FOUND) {
462 		error = B_OK;
463 		if (types) {
464 			// check param -- supported types must be valid
465 			const char *type;
466 			for (int32 i = 0;
467 				 error == B_OK && types->FindString("types", i, &type) == B_OK;
468 				 i++) {
469 				if (!BMimeType::IsValid(type))
470 					error = B_BAD_VALUE;
471 			}
472 			// get flattened size
473 			ssize_t size = 0;
474 			if (error == B_OK) {
475 				size = types->FlattenedSize();
476 				if (size < 0)
477 					error = size;
478 			}
479 			// allocate a buffer for the flattened data
480 			char *buffer = NULL;
481 			if (error == B_OK) {
482 				buffer = new(nothrow) char[size];
483 				if (!buffer)
484 					error = B_NO_MEMORY;
485 			}
486 			// flatten the message
487 			if (error == B_OK)
488 				error = types->Flatten(buffer, size);
489 			// write the data
490 			if (error == B_OK) {
491 				error = _WriteData(kSupportedTypesAttribute,
492 								   kSupportedTypesResourceID, B_MESSAGE_TYPE,
493 								   buffer, size);
494 			}
495 			// clean up
496 			if (buffer)
497 				delete[] buffer;
498 		} else
499 			error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE);
500 		// update the MIME database, if the app signature is installed
501 		if (error == B_OK && mimeType.IsInstalled())
502 			error = mimeType.SetSupportedTypes(types, syncAll);
503 	}
504 	return error;
505 }
506 
507 // SetSupportedTypes
508 /*!	\brief Sets the MIME types supported by the application.
509 
510 	This method is a short-hand for SetSupportedTypes(types, false).
511 	\see SetSupportedType(const BMessage*, bool) for detailed information.
512 
513 	\param types The supported types to be assigned to the file.
514 		   May be \c NULL.
515 	\return
516 	- \c B_OK: Everything went fine.
517 	- \c B_NO_INIT: The object is not properly initialized.
518 	- other error codes
519 */
520 status_t
521 BAppFileInfo::SetSupportedTypes(const BMessage *types)
522 {
523 	return SetSupportedTypes(types, false);
524 }
525 
526 // IsSupportedType
527 /*!	\brief Returns whether the application supports the supplied MIME type.
528 
529 	If the application supports the wildcard type "application/octet-stream"
530 	any this method returns \c true for any MIME type.
531 
532 	\param type The MIME type in question.
533 	\return \c true, if \a type is a valid MIME type and it is supported by
534 			the application, \c false otherwise.
535 */
536 bool
537 BAppFileInfo::IsSupportedType(const char *type) const
538 {
539 	status_t error = (type ? B_OK : B_BAD_VALUE);
540 	// get the supported types
541 	BMessage types;
542 	if (error == B_OK)
543 		error = GetSupportedTypes(&types);
544 	// turn type into a BMimeType
545 	BMimeType mimeType;
546 	if (error == B_OK)
547 		error = mimeType.SetTo(type);
548 	// iterate through the supported types
549 	bool found = false;
550 	if (error == B_OK) {
551 		const char *supportedType;
552 		for (int32 i = 0;
553 			 !found && types.FindString("types", i, &supportedType) == B_OK;
554 			 i++) {
555 			found = !strcmp(supportedType, "application/octet-stream")
556 					|| BMimeType(supportedType).Contains(&mimeType);
557 		}
558 	}
559 	return found;
560 }
561 
562 // Supports
563 /*!	\brief Returns whether the application supports the supplied MIME type
564 		   explicitly.
565 
566 	Unlike IsSupportedType(), this method returns \c true, only if the type
567 	is explicitly supported, regardless of whether it supports
568 	"application/octet-stream".
569 
570 	\param type The MIME type in question.
571 	\return \c true, if \a type is a valid MIME type and it is explicitly
572 			supported by the application, \c false otherwise.
573 */
574 bool
575 BAppFileInfo::Supports(BMimeType *type) const
576 {
577 	status_t error = (type && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
578 	// get the supported types
579 	BMessage types;
580 	if (error == B_OK)
581 		error = GetSupportedTypes(&types);
582 	// iterate through the supported types
583 	bool found = false;
584 	if (error == B_OK) {
585 		const char *supportedType;
586 		for (int32 i = 0;
587 			 !found && types.FindString("types", i, &supportedType) == B_OK;
588 			 i++) {
589 			found = BMimeType(supportedType).Contains(type);
590 		}
591 	}
592 	return found;
593 }
594 
595 // GetIcon
596 /*!	\brief Gets the file's icon.
597 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
598 		   to store the requested icon (16x16 for the mini and 32x32 for the
599 		   large icon).
600 	\param which Specifies the size of the icon to be retrieved:
601 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
602 	\return
603 	- \c B_OK: Everything went fine.
604 	- \c B_NO_INIT: The object is not properly initialized.
605 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a which or bitmap
606 		 dimensions (\a icon) and icon size (\a which) do not match.
607 	- other error codes
608 */
609 status_t
610 BAppFileInfo::GetIcon(BBitmap *icon, icon_size which) const
611 {
612 	return GetIconForType(NULL, icon, which);
613 }
614 
615 // SetIcon
616 /*!	\brief Sets the file's icon.
617 
618 	If \a icon is \c NULL the file's icon is unset.
619 
620 	\param icon A pointer to the BBitmap containing the icon to be set.
621 		   May be \c NULL.
622 	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
623 		   for the mini and \c B_LARGE_ICON for the large icon.
624 	\return
625 	- \c B_OK: Everything went fine.
626 	- \c B_NO_INIT: The object is not properly initialized.
627 	- \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon)
628 		 and icon size (\a which) do not match.
629 	- other error codes
630 */
631 status_t
632 BAppFileInfo::SetIcon(const BBitmap *icon, icon_size which)
633 {
634 	return SetIconForType(NULL, icon, which);
635 }
636 
637 // GetVersionInfo
638 /*!	\brief Gets the file's version info.
639 	\param info A pointer to a pre-allocated version_info structure into which
640 		   the version info should be written.
641 	\param kind Specifies the kind of the version info to be retrieved:
642 		   \c B_APP_VERSION_KIND for the application's version info and
643 		   \c B_SYSTEM_VERSION_KIND for the suite's info the application
644 		   belongs to.
645 	\return
646 	- \c B_OK: Everything went fine.
647 	- \c B_NO_INIT: The object is not properly initialized.
648 	- \c B_BAD_VALUE: \c NULL \a info.
649 	- other error codes
650 */
651 status_t
652 BAppFileInfo::GetVersionInfo(version_info *info, version_kind kind) const
653 {
654 	// check params and initialization
655 	if (!info)
656 		return B_BAD_VALUE;
657 
658 	int32 index = 0;
659 	switch (kind) {
660 		case B_APP_VERSION_KIND:
661 			index = 0;
662 			break;
663 		case B_SYSTEM_VERSION_KIND:
664 			index = 1;
665 			break;
666 		default:
667 			return B_BAD_VALUE;
668 	}
669 
670 	if (InitCheck() != B_OK)
671 		return B_NO_INIT;
672 
673 	// read the data
674 	size_t read = 0;
675 	version_info infos[2];
676 	status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
677 		B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
678 	if (error != B_OK)
679 		return error;
680 
681 	// check the read data
682 	if (read == sizeof(version_info)) {
683 		// only the app version info is there -- return a cleared system info
684 		if (index == 0)
685 			*info = infos[index];
686 		else if (index == 1)
687 			memset(info, 0, sizeof(version_info));
688 	} else if (read == 2 * sizeof(version_info)) {
689 		*info = infos[index];
690 	} else
691 		return B_ERROR;
692 
693 	// return result
694 	return B_OK;
695 }
696 
697 // SetVersionInfo
698 /*!	\brief Sets the file's version info.
699 
700 	If \a info is \c NULL the file's version info is unset.
701 
702 	\param info The version info to be set. May be \c NULL.
703 	\param kind Specifies kind of version info to be set:
704 		   \c B_APP_VERSION_KIND for the application's version info and
705 		   \c B_SYSTEM_VERSION_KIND for the suite's info the application
706 		   belongs to.
707 	\return
708 	- \c B_OK: Everything went fine.
709 	- \c B_NO_INIT: The object is not properly initialized.
710 	- other error codes
711 */
712 status_t
713 BAppFileInfo::SetVersionInfo(const version_info *info, version_kind kind)
714 {
715 	// check initialization
716 	status_t error = B_OK;
717 	if (error == B_OK && InitCheck() != B_OK)
718 		error = B_NO_INIT;
719 	if (error == B_OK) {
720 		if (info) {
721 			// check param
722 			int32 index = 0;
723 			if (error == B_OK) {
724 				switch (kind) {
725 					case B_APP_VERSION_KIND:
726 						index = 0;
727 						break;
728 					case B_SYSTEM_VERSION_KIND:
729 						index = 1;
730 						break;
731 					default:
732 						error = B_BAD_VALUE;
733 						break;
734 				}
735 			}
736 			// read both infos
737 			version_info infos[2];
738 			if (error == B_OK) {
739 				size_t read;
740 				if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
741 						B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
742 						read) == B_OK) {
743 					// clear the part that hasn't been read
744 					if (read < sizeof(infos))
745 						memset((char*)infos + read, 0, sizeof(infos) - read);
746 				} else {
747 					// failed to read -- clear
748 					memset(infos, 0, sizeof(infos));
749 				}
750 			}
751 			infos[index] = *info;
752 			// write the data
753 			if (error == B_OK) {
754 				error = _WriteData(kVersionInfoAttribute,
755 								   kVersionInfoResourceID,
756 								   B_VERSION_INFO_TYPE, infos,
757 								   2 * sizeof(version_info));
758 			}
759 		} else
760 			error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
761 	}
762 	return error;
763 }
764 
765 // GetIconForType
766 /*!	\brief Gets the icon the application provides for a given MIME type.
767 
768 	If \a type is \c NULL, the application's icon is retrieved.
769 
770 	\param type The MIME type in question. May be \c NULL.
771 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
772 		   to store the requested icon (16x16 for the mini and 32x32 for the
773 		   large icon).
774 	\param which Specifies the size of the icon to be retrieved:
775 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
776 	\return
777 	- \c B_OK: Everything went fine.
778 	- \c B_NO_INIT: The object is not properly initialized.
779 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size
780 		 \a which or bitmap dimensions (\a icon) and icon size (\a which) do
781 		 not match.
782 	- other error codes
783 */
784 status_t
785 BAppFileInfo::GetIconForType(const char *type, BBitmap *icon,
786 							 icon_size which) const
787 {
788 	status_t error = B_OK;
789 	// set some icon size related variables
790 	BString attributeString;
791 	BRect bounds;
792 	uint32 attrType = 0;
793 	size_t attrSize = 0;
794 	switch (which) {
795 		case B_MINI_ICON:
796 			attributeString = kMiniIconAttribute;
797 			bounds.Set(0, 0, 15, 15);
798 			attrType = B_MINI_ICON_TYPE;
799 			attrSize = 16 * 16;
800 			break;
801 		case B_LARGE_ICON:
802 			attributeString = kLargeIconAttribute;
803 			bounds.Set(0, 0, 31, 31);
804 			attrType = B_LARGE_ICON_TYPE;
805 			attrSize = 32 * 32;
806 			break;
807 		default:
808 			error = B_BAD_VALUE;
809 			break;
810 	}
811 	// check type param
812 	if (error == B_OK) {
813 		if (type) {
814 			if (BMimeType::IsValid(type))
815 				attributeString += type;
816 			else
817 				error = B_BAD_VALUE;
818 		} else
819 			attributeString += kStandardIconType;
820 	}
821 	const char *attribute = attributeString.String();
822 
823 	// check parameter and initialization
824 	if (error == B_OK
825 		&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
826 		error = B_BAD_VALUE;
827 	}
828 	if (error == B_OK && InitCheck() != B_OK)
829 		error = B_NO_INIT;
830 	// read the data
831 	if (error == B_OK) {
832 		bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
833 		char *buffer = NULL;
834 		size_t read;
835 		if (otherColorSpace) {
836 			// other color space than stored in attribute
837 			buffer = new(nothrow) char[attrSize];
838 			if (!buffer)
839 				error = B_NO_MEMORY;
840 			if (error == B_OK) {
841 				error = _ReadData(attribute, -1, attrType, buffer, attrSize,
842 								  read);
843 			}
844 		} else {
845 			error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
846 							  read);
847 		}
848 		if (error == B_OK && read != attrSize)
849 			error = B_ERROR;
850 		if (otherColorSpace) {
851 			// other color space than stored in attribute
852 			if (error == B_OK) {
853 				error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW,
854 										 0, B_CMAP8);
855 			}
856 			delete[] buffer;
857 		}
858 	}
859 	return error;
860 }
861 
862 // SetIconForType
863 /*!	\brief Sets the icon the application provides for a given MIME type.
864 
865 	If \a type is \c NULL, the application's icon is set.
866 	If \a icon is \c NULL the icon is unset.
867 
868 	If the file has a signature, then the icon is also set on the MIME type.
869 	If the type for the signature has not been installed yet, it is installed
870 	before.
871 
872 	\param type The MIME type in question. May be \c NULL.
873 	\param icon A pointer to the BBitmap containing the icon to be set.
874 		   May be \c NULL.
875 	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
876 		   for the mini and \c B_LARGE_ICON for the large icon.
877 	\return
878 	- \c B_OK: Everything went fine.
879 	- \c B_NO_INIT: The object is not properly initialized.
880 	- \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon)
881 		 and icon size (\a which) do not match.
882 	- other error codes
883 */
884 status_t
885 BAppFileInfo::SetIconForType(const char *type, const BBitmap *icon,
886 							 icon_size which)
887 {
888 	status_t error = B_OK;
889 	// set some icon size related variables
890 	BString attributeString;
891 	BRect bounds;
892 	uint32 attrType = 0;
893 	size_t attrSize = 0;
894 	int32 resourceID = 0;
895 	switch (which) {
896 		case B_MINI_ICON:
897 			attributeString = kMiniIconAttribute;
898 			bounds.Set(0, 0, 15, 15);
899 			attrType = B_MINI_ICON_TYPE;
900 			attrSize = 16 * 16;
901 			resourceID = (type ? kMiniIconForTypeResourceID
902 							   : kMiniIconResourceID);
903 			break;
904 		case B_LARGE_ICON:
905 			attributeString = kLargeIconAttribute;
906 			bounds.Set(0, 0, 31, 31);
907 			attrType = B_LARGE_ICON_TYPE;
908 			attrSize = 32 * 32;
909 			resourceID = (type ? kLargeIconForTypeResourceID
910 							   : kLargeIconResourceID);
911 			break;
912 		default:
913 			error = B_BAD_VALUE;
914 			break;
915 	}
916 	// check type param
917 	if (error == B_OK) {
918 		if (type) {
919 			if (BMimeType::IsValid(type))
920 				attributeString += type;
921 			else
922 				error = B_BAD_VALUE;
923 		} else
924 			attributeString += kStandardIconType;
925 	}
926 	const char *attribute = attributeString.String();
927 	// check parameter and initialization
928 	if (error == B_OK && icon
929 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
930 		error = B_BAD_VALUE;
931 	}
932 	if (error == B_OK && InitCheck() != B_OK)
933 		error = B_NO_INIT;
934 	// write/remove the attribute
935 	if (error == B_OK) {
936 		if (icon) {
937 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
938 			if (otherColorSpace) {
939 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
940 				error = bitmap.InitCheck();
941 				if (error == B_OK)
942 					error = bitmap.ImportBits(icon);
943 				if (error == B_OK) {
944 					error = _WriteData(attribute, resourceID, attrType,
945 									   bitmap.Bits(), attrSize, true);
946 				}
947 			} else {
948 				error = _WriteData(attribute, resourceID, attrType,
949 								   icon->Bits(), attrSize, true);
950 			}
951 		} else	// no icon given => remove
952 			error = _RemoveData(attribute, attrType);
953 	}
954 	// set the attribute on the MIME type, if the file has a signature
955 	BMimeType mimeType;
956 	if (error == B_OK && GetMetaMime(&mimeType) == B_OK) {
957 		if (!mimeType.IsInstalled())
958 			error = mimeType.Install();
959 		if (error == B_OK)
960 			error = mimeType.SetIconForType(type, icon, which);
961 	}
962 	return error;
963 }
964 
965 // SetInfoLocation
966 /*!	\brief Specifies the location where the meta data shall be stored.
967 
968 	The options for \a location are:
969 	- \c B_USE_ATTRIBUTES: Store the data in the attributes.
970 	- \c B_USE_RESOURCES: Store the data in the resources.
971 	- \c B_USE_BOTH_LOCATIONS: Store the data in attributes and resources.
972 
973 	\param location The location where the meta data shall be stored.
974 */
975 void
976 BAppFileInfo::SetInfoLocation(info_location location)
977 {
978 	fWhere = location;
979 }
980 
981 // IsUsingAttributes
982 /*!	\brief Returns whether the object stores the meta data (also) in the
983 		   file's attributes.
984 	\return \c true, if the meta data are (also) stored in the file's
985 			attributes, \c false otherwise.
986 */
987 bool
988 BAppFileInfo::IsUsingAttributes() const
989 {
990 	return (fWhere & B_USE_ATTRIBUTES);
991 }
992 
993 // IsUsingResources
994 /*!	\brief Returns whether the object stores the meta data (also) in the
995 		   file's resources.
996 	\return \c true, if the meta data are (also) stored in the file's
997 			resources, \c false otherwise.
998 */
999 bool
1000 BAppFileInfo::IsUsingResources() const
1001 {
1002 	return (fWhere & B_USE_RESOURCES);
1003 }
1004 
1005 // FBC
1006 void BAppFileInfo::_ReservedAppFileInfo1() {}
1007 void BAppFileInfo::_ReservedAppFileInfo2() {}
1008 void BAppFileInfo::_ReservedAppFileInfo3() {}
1009 
1010 // =
1011 /*!	\brief Privatized assignment operator to prevent usage.
1012 */
1013 BAppFileInfo &
1014 BAppFileInfo::operator=(const BAppFileInfo &)
1015 {
1016 	return *this;
1017 }
1018 
1019 // copy constructor
1020 /*!	\brief Privatized copy constructor to prevent usage.
1021 */
1022 BAppFileInfo::BAppFileInfo(const BAppFileInfo &)
1023 {
1024 }
1025 
1026 // GetMetaMime
1027 /*!	\brief Initializes a BMimeType to the file's signature.
1028 
1029 	The parameter \a meta is not checked.
1030 
1031 	\param meta A pointer to a pre-allocated BMimeType that shall be
1032 		   initialized to the file's signature.
1033 	\return
1034 	- \c B_OK: Everything went fine.
1035 	- \c B_BAD_VALUE: \c NULL \a meta
1036 	- \c B_ENTRY_NOT_FOUND: The file has not signature or the signature is
1037 (	  not installed in the MIME database.)
1038 	  no valid MIME string.
1039 	- other error codes
1040 */
1041 status_t
1042 BAppFileInfo::GetMetaMime(BMimeType *meta) const
1043 {
1044 	char signature[B_MIME_TYPE_LENGTH];
1045 	status_t error = GetSignature(signature);
1046 	if (error == B_OK)
1047 		error = meta->SetTo(signature);
1048 	else if (error == B_BAD_VALUE)
1049 		error = B_ENTRY_NOT_FOUND;
1050 	if (error == B_OK && !meta->IsValid())
1051 		error = B_BAD_VALUE;
1052 	return error;
1053 }
1054 
1055 // _ReadData
1056 /*!	\brief Reads data from an attribute or resource.
1057 
1058 	The data are read from the location specified by \a fWhere.
1059 
1060 	The object must be properly initialized. The parameters are NOT checked.
1061 
1062 	\param name The name of the attribute/resource to be read.
1063 	\param id The resource ID of the resource to be read. Is ignored, when
1064 		   < 0.
1065 	\param type The type of the attribute/resource to be read.
1066 	\param buffer A pre-allocated buffer for the data to be read.
1067 	\param bufferSize The size of the supplied buffer.
1068 	\param bytesRead A reference parameter, set to the number of bytes
1069 		   actually read.
1070 	\param allocatedBuffer If not \c NULL, the method allocates a buffer
1071 		   large enough too store the whole data and writes a pointer to it
1072 		   into this variable. If \c NULL, the supplied buffer is used.
1073 	\return
1074 	- \c B_OK: Everything went fine.
1075 	- error code
1076 */
1077 status_t
1078 BAppFileInfo::_ReadData(const char *name, int32 id, type_code type,
1079 						void *buffer, size_t bufferSize,
1080 						size_t &bytesRead, void **allocatedBuffer) const
1081 {
1082 	status_t error = B_OK;
1083 
1084 	if (allocatedBuffer)
1085 		buffer = NULL;
1086 
1087 	bool foundData = false;
1088 
1089 	if (IsUsingAttributes()) {
1090 		// get an attribute info
1091 		attr_info info;
1092 		if (error == B_OK)
1093 			error = fNode->GetAttrInfo(name, &info);
1094 
1095 		// check type and size, allocate a buffer, if required
1096 		if (error == B_OK && info.type != type)
1097 			error = B_BAD_VALUE;
1098 		if (error == B_OK && allocatedBuffer) {
1099 			buffer = malloc(info.size);
1100 			if (!buffer)
1101 				error = B_NO_MEMORY;
1102 			bufferSize = info.size;
1103 		}
1104 		if (error == B_OK && bufferSize < info.size)
1105 			error = B_BAD_VALUE;
1106 
1107 		// read the data
1108 		if (error == B_OK) {
1109 			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1110 			if (read < 0)
1111 				error = read;
1112 			else if (read != info.size)
1113 				error = B_ERROR;
1114 			else
1115 				bytesRead = read;
1116 		}
1117 
1118 		foundData = (error == B_OK);
1119 
1120 		// free the allocated buffer on error
1121 		if (!foundData && allocatedBuffer && buffer) {
1122 			free(buffer);
1123 			buffer = NULL;
1124 		}
1125 	}
1126 
1127 	if (!foundData && IsUsingResources()) {
1128 		// get a resource info
1129 		error = B_OK;
1130 		int32 idFound;
1131 		size_t sizeFound;
1132 		if (error == B_OK) {
1133 			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1134 				error = B_ENTRY_NOT_FOUND;
1135 		}
1136 
1137 		// check id and size, allocate a buffer, if required
1138 		if (error == B_OK && id >= 0 && idFound != id)
1139 			error = B_ENTRY_NOT_FOUND;
1140 		if (error == B_OK && allocatedBuffer) {
1141 			buffer = malloc(sizeFound);
1142 			if (!buffer)
1143 				error = B_NO_MEMORY;
1144 			bufferSize = sizeFound;
1145 		}
1146 		if (error == B_OK && bufferSize < sizeFound)
1147 			error = B_BAD_VALUE;
1148 
1149 		// load resource
1150 		const void *resourceData = NULL;
1151 		if (error == B_OK) {
1152 			resourceData = fResources->LoadResource(type, name, &bytesRead);
1153 			if (resourceData && sizeFound == bytesRead)
1154 				memcpy(buffer, resourceData, bytesRead);
1155 			else
1156 				error = B_ERROR;
1157 		}
1158 	} else if (!foundData)
1159 		error = B_BAD_VALUE;
1160 
1161 	// return the allocated buffer, or free it on error
1162 	if (allocatedBuffer) {
1163 		if (error == B_OK)
1164 			*allocatedBuffer = buffer;
1165 		else
1166 			free(buffer);
1167 	}
1168 
1169 	return error;
1170 }
1171 
1172 // _WriteData
1173 /*!	\brief Writes data to an attribute or resource.
1174 
1175 	The data are written to the location(s) specified by \a fWhere.
1176 
1177 	The object must be properly initialized. The parameters are NOT checked.
1178 
1179 	\param name The name of the attribute/resource to be written.
1180 	\param id The resource ID of the resource to be written.
1181 	\param type The type of the attribute/resource to be written.
1182 	\param buffer A buffer containing the data to be written.
1183 	\param bufferSize The size of the supplied buffer.
1184 	\param findID If set to \c true use the ID that is already assigned to the
1185 		   \a name / \a type pair or take the first unused ID >= \a id.
1186 		   If \c false, \a id is used.
1187 	If \a id is already in use and .
1188 	\return
1189 	- \c B_OK: Everything went fine.
1190 	- error code
1191 */
1192 status_t
1193 BAppFileInfo::_WriteData(const char *name, int32 id, type_code type,
1194 						 const void *buffer, size_t bufferSize, bool findID)
1195 {
1196 	status_t error = B_OK;
1197 	// write to attribute
1198 	if (IsUsingAttributes() && error == B_OK) {
1199 		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1200 		if (written < 0)
1201 			error = written;
1202 		else if (written != (ssize_t)bufferSize)
1203 			error = B_ERROR;
1204 	}
1205 	// write to resource
1206 	if (IsUsingResources() && error == B_OK) {
1207 		if (findID) {
1208 			// get the resource info
1209 			int32 idFound;
1210 			size_t sizeFound;
1211 			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1212 				id = idFound;
1213 			else {
1214 				// type-name pair doesn't exist yet -- find unused ID
1215 				while (fResources->HasResource(type, id))
1216 					id++;
1217 			}
1218 		}
1219 		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1220 	}
1221 	return error;
1222 }
1223 
1224 // _RemoveData
1225 /*!	\brief Removes an attribute or resource.
1226 
1227 	The removal location is specified by \a fWhere.
1228 
1229 	The object must be properly initialized. The parameters are NOT checked.
1230 
1231 	\param name The name of the attribute/resource to be remove.
1232 	\param type The type of the attribute/resource to be removed.
1233 	\return
1234 	- \c B_OK: Everything went fine.
1235 	- error code
1236 */
1237 status_t
1238 BAppFileInfo::_RemoveData(const char *name, type_code type)
1239 {
1240 	status_t error = B_OK;
1241 	// remove the attribute
1242 	if (IsUsingAttributes() && error == B_OK) {
1243 		error = fNode->RemoveAttr(name);
1244 		// It's no error, if there has been no attribute.
1245 		if (error == B_ENTRY_NOT_FOUND)
1246 			error = B_OK;
1247 	}
1248 	// remove the resource
1249 	if (IsUsingResources() && error == B_OK) {
1250 		// get a resource info
1251 		int32 idFound;
1252 		size_t sizeFound;
1253 		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1254 			error = fResources->RemoveResource(type, idFound);
1255 	}
1256 	return error;
1257 }
1258 
1259