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