xref: /haiku/src/build/libbe/storage/AppFileInfo.cpp (revision 837b16251d4b2b6249ebcaa19bb319cbe82c6126)
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 <stdlib.h>
13 #include <string>
14 
15 #include <AppFileInfo.h>
16 #include <Bitmap.h>
17 #include <File.h>
18 #include <fs_attr.h>
19 #include <MimeType.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 static const char *kCatalogEntryAttribute		= "SYS:NAME";
36 
37 // resource IDs
38 static const int32 kTypeResourceID				= 2;
39 static const int32 kSignatureResourceID			= 1;
40 static const int32 kAppFlagsResourceID			= 1;
41 static const int32 kSupportedTypesResourceID	= 1;
42 static const int32 kMiniIconResourceID			= 101;
43 static const int32 kLargeIconResourceID			= 101;
44 static const int32 kVersionInfoResourceID		= 1;
45 static const int32 kMiniIconForTypeResourceID	= 0;
46 static const int32 kLargeIconForTypeResourceID	= 0;
47 static const int32 kCatalogEntryResourceID		= 1;
48 
49 // type codes
50 enum {
51 	B_APP_FLAGS_TYPE	= 'APPF',
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 
314 // GetCatalogEntry
315 /*!	\brief Gets the file's catalog entry. (localization)
316 
317 	\param catalogEntry A pointer to a pre-allocated character buffer of size
318 		   \c B_MIME_TYPE_LENGTH * 3 or larger into which the catalog entry
319 		   of the file shall be written.
320 	\return
321 	- \c B_OK: Everything went fine.
322 	- \c B_NO_INIT: The object is not properly initialized.
323 	- \c B_BAD_VALUE: \c NULL \a catalogEntry or the entry stored in the
324 	  attribute/resources is longer than \c B_MIME_TYPE_LENGTH * 3.
325 	- \c B_BAD_TYPE: The attribute/resources the entry is stored in have
326 	  the wrong type.
327 	- \c B_ENTRY_NOT_FOUND: No catalog entry is set on the file.
328 	- other error codes
329 */
330 status_t
331 BAppFileInfo::GetCatalogEntry(char *catalogEntry) const
332 {
333 	if (catalogEntry == NULL)
334 		return B_BAD_VALUE;
335 
336 	if (InitCheck() != B_OK)
337 		return B_NO_INIT;
338 
339 	size_t read = 0;
340 	status_t error = _ReadData(kCatalogEntryAttribute, kCatalogEntryResourceID,
341 		B_STRING_TYPE, catalogEntry, B_MIME_TYPE_LENGTH * 3, read);
342 
343 	if (error != B_OK)
344 		return error;
345 
346 	if (read >= B_MIME_TYPE_LENGTH * 3)
347 		return B_ERROR;
348 
349 	catalogEntry[read] = '\0';
350 
351 	return B_OK;
352 }
353 
354 
355 // SetCatalogEntry
356 /*!	\brief Sets the file's catalog entry. (localization)
357 
358 	If \a catalogEntry is \c NULL the file's catalog entry is unset.
359 
360 	\param catalogEntry The catalog entry to be assigned to the file.
361 		Of the form "x-vnd.Haiku-app:context:name".
362 		Must not be longer than \c B_MIME_TYPE_LENGTH * 3
363 		(including the terminating null). May be \c NULL.
364 	\return
365 	- \c B_OK: Everything went fine.
366 	- \c B_NO_INIT: The object is not properly initialized.
367 	- \c B_BAD_VALUE: \a catalogEntry is longer than \c B_MIME_TYPE_LENGTH * 3.
368 	- other error codes
369 */
370 status_t
371 BAppFileInfo::SetCatalogEntry(const char *catalogEntry)
372 {
373 	if (InitCheck() != B_OK)
374 		return B_NO_INIT;
375 
376 	if (catalogEntry == NULL)
377 		return _RemoveData(kCatalogEntryAttribute, B_STRING_TYPE);
378 
379 	size_t nameLength = strlen(catalogEntry);
380 	if (nameLength > B_MIME_TYPE_LENGTH * 3)
381 		return B_BAD_VALUE;
382 
383 	return _WriteData(kCatalogEntryAttribute, kCatalogEntryResourceID,
384 		B_STRING_TYPE, catalogEntry, nameLength + 1);
385 }
386 
387 
388 // GetAppFlags
389 /*!	\brief Gets the file's application flags.
390 
391 	\param flags A pointer to a pre-allocated uint32 into which the application
392 		   flags of the file 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 flags.
397 	- \c B_BAD_TYPE: The attribute/resources the flags are stored in have
398 	  the wrong type.
399 	- \c B_ENTRY_NOT_FOUND: No application flags are set on the file.
400 	- other error codes
401 */
402 status_t
403 BAppFileInfo::GetAppFlags(uint32 *flags) const
404 {
405 	// check param and initialization
406 	status_t error = (flags ? 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 	if (error == B_OK) {
412 		error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID,
413 						  B_APP_FLAGS_TYPE, flags, sizeof(uint32),
414 						  read);
415 	}
416 	// check the read data
417 	if (error == B_OK && read != sizeof(uint32))
418 		error = B_ERROR;
419 	return error;
420 }
421 
422 // SetAppFlags
423 /*!	\brief Sets the file's application flags.
424 	\param flags The application flags to be assigned to the file.
425 	\return
426 	- \c B_OK: Everything went fine.
427 	- \c B_NO_INIT: The object is not properly initialized.
428 	- other error codes
429 */
430 status_t
431 BAppFileInfo::SetAppFlags(uint32 flags)
432 {
433 	// check initialization
434 	status_t error = B_OK;
435 	if (error == B_OK && InitCheck() != B_OK)
436 		error = B_NO_INIT;
437 	if (error == B_OK) {
438 		// write the data
439 		if (error == B_OK) {
440 			error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID,
441 							   B_APP_FLAGS_TYPE, &flags, sizeof(uint32));
442 		}
443 	}
444 	return error;
445 }
446 
447 // GetSupportedTypes
448 /*!	\brief Gets the MIME types supported by the application.
449 
450 	The supported MIME types are added to a field "types" of type
451 	\c B_STRING_TYPE in \a types.
452 
453 	\param types A pointer to a pre-allocated BMessage into which the
454 		   MIME types supported by the appplication shall be written.
455 	\return
456 	- \c B_OK: Everything went fine.
457 	- \c B_NO_INIT: The object is not properly initialized.
458 	- \c B_BAD_VALUE: \c NULL \a types.
459 	- \c B_BAD_TYPE: The attribute/resources the supported types are stored in
460 	  have the wrong type.
461 	- \c B_ENTRY_NOT_FOUND: No supported types are set on the file.
462 	- other error codes
463 */
464 status_t
465 BAppFileInfo::GetSupportedTypes(BMessage *types) const
466 {
467 	// check param and initialization
468 	status_t error = (types ? B_OK : B_BAD_VALUE);
469 	if (error == B_OK && InitCheck() != B_OK)
470 		error = B_NO_INIT;
471 	// read the data
472 	size_t read = 0;
473 	void *buffer = NULL;
474 	if (error == B_OK) {
475 		error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID,
476 						  B_MESSAGE_TYPE, NULL, 0, read, &buffer);
477 	}
478 	// unflatten the buffer
479 	if (error == B_OK)
480 		error = types->Unflatten((const char*)buffer);
481 	// clean up
482 	if (buffer)
483 		free(buffer);
484 	return error;
485 }
486 
487 // SetSupportedTypes
488 /*!	\brief Sets the MIME types supported by the application.
489 
490 	If \a types is \c NULL the application's supported types are unset.
491 
492 	The supported MIME types must be stored in a field "types" of type
493 	\c B_STRING_TYPE in \a types.
494 
495 	The method informs the registrar about this news.
496 	For each supported type the result of BMimeType::GetSupportingApps() will
497 	afterwards include the signature of this application. That is, the
498 	application file needs to have a signature set.
499 
500 	\a syncAll specifies whether the not longer supported types shall be
501 	updated as well, i.e. whether this application shall be remove from the
502 	lists of supporting applications.
503 
504 	\param types The supported types to be assigned to the file.
505 		   May be \c NULL.
506 	\param syncAll \c true to also synchronize the not longer supported
507 		   types, \c false otherwise.
508 	\return
509 	- \c B_OK: Everything went fine.
510 	- \c B_NO_INIT: The object is not properly initialized.
511 	- other error codes
512 */
513 status_t
514 BAppFileInfo::SetSupportedTypes(const BMessage *types, bool syncAll)
515 {
516 	// check initialization
517 	status_t error = B_OK;
518 	if (error == B_OK && InitCheck() != B_OK)
519 		error = B_NO_INIT;
520 	BMimeType mimeType;
521 	if (error == B_OK)
522 		error = GetMetaMime(&mimeType);
523 	if (error == B_OK || error == B_ENTRY_NOT_FOUND) {
524 		error = B_OK;
525 		if (types) {
526 			// check param -- supported types must be valid
527 			const char *type;
528 			for (int32 i = 0;
529 				 error == B_OK && types->FindString("types", i, &type) == B_OK;
530 				 i++) {
531 				if (!BMimeType::IsValid(type))
532 					error = B_BAD_VALUE;
533 			}
534 			// get flattened size
535 			ssize_t size = 0;
536 			if (error == B_OK) {
537 				size = types->FlattenedSize();
538 				if (size < 0)
539 					error = size;
540 			}
541 			// allocate a buffer for the flattened data
542 			char *buffer = NULL;
543 			if (error == B_OK) {
544 				buffer = new(nothrow) char[size];
545 				if (!buffer)
546 					error = B_NO_MEMORY;
547 			}
548 			// flatten the message
549 			if (error == B_OK)
550 				error = types->Flatten(buffer, size);
551 			// write the data
552 			if (error == B_OK) {
553 				error = _WriteData(kSupportedTypesAttribute,
554 								   kSupportedTypesResourceID, B_MESSAGE_TYPE,
555 								   buffer, size);
556 			}
557 			// clean up
558 			if (buffer)
559 				delete[] buffer;
560 		} else
561 			error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE);
562 		// update the MIME database, if the app signature is installed
563 //		if (error == B_OK && mimeType.IsInstalled())
564 //			error = mimeType.SetSupportedTypes(types, syncAll);
565 	}
566 	return error;
567 }
568 
569 // SetSupportedTypes
570 /*!	\brief Sets the MIME types supported by the application.
571 
572 	This method is a short-hand for SetSupportedTypes(types, false).
573 	\see SetSupportedType(const BMessage*, bool) for detailed information.
574 
575 	\param types The supported types to be assigned to the file.
576 		   May be \c NULL.
577 	\return
578 	- \c B_OK: Everything went fine.
579 	- \c B_NO_INIT: The object is not properly initialized.
580 	- other error codes
581 */
582 status_t
583 BAppFileInfo::SetSupportedTypes(const BMessage *types)
584 {
585 	return SetSupportedTypes(types, false);
586 }
587 
588 // IsSupportedType
589 /*!	\brief Returns whether the application supports the supplied MIME type.
590 
591 	If the application supports the wildcard type "application/octet-stream"
592 	any this method returns \c true for any MIME type.
593 
594 	\param type The MIME type in question.
595 	\return \c true, if \a type is a valid MIME type and it is supported by
596 			the application, \c false otherwise.
597 */
598 bool
599 BAppFileInfo::IsSupportedType(const char *type) const
600 {
601 	status_t error = (type ? B_OK : B_BAD_VALUE);
602 	// get the supported types
603 	BMessage types;
604 	if (error == B_OK)
605 		error = GetSupportedTypes(&types);
606 	// turn type into a BMimeType
607 	BMimeType mimeType;
608 	if (error == B_OK)
609 		error = mimeType.SetTo(type);
610 	// iterate through the supported types
611 	bool found = false;
612 	if (error == B_OK) {
613 		const char *supportedType;
614 		for (int32 i = 0;
615 			 !found && types.FindString("types", i, &supportedType) == B_OK;
616 			 i++) {
617 			found = !strcmp(supportedType, "application/octet-stream")
618 					|| BMimeType(supportedType).Contains(&mimeType);
619 		}
620 	}
621 	return found;
622 }
623 
624 // Supports
625 /*!	\brief Returns whether the application supports the supplied MIME type
626 		   explicitly.
627 
628 	Unlike IsSupportedType(), this method returns \c true, only if the type
629 	is explicitly supported, regardless of whether it supports
630 	"application/octet-stream".
631 
632 	\param type The MIME type in question.
633 	\return \c true, if \a type is a valid MIME type and it is explicitly
634 			supported by the application, \c false otherwise.
635 */
636 bool
637 BAppFileInfo::Supports(BMimeType *type) const
638 {
639 	status_t error = (type && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
640 	// get the supported types
641 	BMessage types;
642 	if (error == B_OK)
643 		error = GetSupportedTypes(&types);
644 	// iterate through the supported types
645 	bool found = false;
646 	if (error == B_OK) {
647 		const char *supportedType;
648 		for (int32 i = 0;
649 			 !found && types.FindString("types", i, &supportedType) == B_OK;
650 			 i++) {
651 			found = BMimeType(supportedType).Contains(type);
652 		}
653 	}
654 	return found;
655 }
656 
657 // GetIcon
658 /*!	\brief Gets the file's icon.
659 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
660 		   to store the requested icon (16x16 for the mini and 32x32 for the
661 		   large icon).
662 	\param which Specifies the size of the icon to be retrieved:
663 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
664 	\return
665 	- \c B_OK: Everything went fine.
666 	- \c B_NO_INIT: The object is not properly initialized.
667 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size \a which or bitmap
668 		 dimensions (\a icon) and icon size (\a which) do not match.
669 	- other error codes
670 */
671 status_t
672 BAppFileInfo::GetIcon(BBitmap *icon, icon_size which) const
673 {
674 	return GetIconForType(NULL, icon, which);
675 }
676 
677 // SetIcon
678 /*!	\brief Sets the file's icon.
679 
680 	If \a icon is \c NULL the file's icon is unset.
681 
682 	\param icon A pointer to the BBitmap containing the icon to be set.
683 		   May be \c NULL.
684 	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
685 		   for the mini and \c B_LARGE_ICON for the large icon.
686 	\return
687 	- \c B_OK: Everything went fine.
688 	- \c B_NO_INIT: The object is not properly initialized.
689 	- \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon)
690 		 and icon size (\a which) do not match.
691 	- other error codes
692 */
693 status_t
694 BAppFileInfo::SetIcon(const BBitmap *icon, icon_size which)
695 {
696 	return SetIconForType(NULL, icon, which);
697 }
698 
699 // GetVersionInfo
700 /*!	\brief Gets the file's version info.
701 	\param info A pointer to a pre-allocated version_info structure into which
702 		   the version info should be written.
703 	\param kind Specifies the kind of the version info to be retrieved:
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 	- \c B_BAD_VALUE: \c NULL \a info.
711 	- other error codes
712 */
713 status_t
714 BAppFileInfo::GetVersionInfo(version_info *info, version_kind kind) const
715 {
716 	// check params and initialization
717 	if (!info)
718 		return B_BAD_VALUE;
719 
720 	int32 index = 0;
721 	switch (kind) {
722 		case B_APP_VERSION_KIND:
723 			index = 0;
724 			break;
725 		case B_SYSTEM_VERSION_KIND:
726 			index = 1;
727 			break;
728 		default:
729 			return B_BAD_VALUE;
730 	}
731 
732 	if (InitCheck() != B_OK)
733 		return B_NO_INIT;
734 
735 	// read the data
736 	size_t read = 0;
737 	version_info infos[2];
738 	status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
739 		B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
740 	if (error != B_OK)
741 		return error;
742 
743 	// check the read data
744 	if (read == sizeof(version_info)) {
745 		// only the app version info is there -- return a cleared system info
746 		if (index == 0)
747 			*info = infos[index];
748 		else if (index == 1)
749 			memset(info, 0, sizeof(version_info));
750 	} else if (read == 2 * sizeof(version_info)) {
751 		*info = infos[index];
752 	} else
753 		return B_ERROR;
754 
755 	// return result
756 	return B_OK;
757 }
758 
759 // SetVersionInfo
760 /*!	\brief Sets the file's version info.
761 
762 	If \a info is \c NULL the file's version info is unset.
763 
764 	\param info The version info to be set. May be \c NULL.
765 	\param kind Specifies kind of version info to be set:
766 		   \c B_APP_VERSION_KIND for the application's version info and
767 		   \c B_SYSTEM_VERSION_KIND for the suite's info the application
768 		   belongs to.
769 	\return
770 	- \c B_OK: Everything went fine.
771 	- \c B_NO_INIT: The object is not properly initialized.
772 	- other error codes
773 */
774 status_t
775 BAppFileInfo::SetVersionInfo(const version_info *info, version_kind kind)
776 {
777 	// check initialization
778 	status_t error = B_OK;
779 	if (error == B_OK && InitCheck() != B_OK)
780 		error = B_NO_INIT;
781 	if (error == B_OK) {
782 		if (info) {
783 			// check param
784 			int32 index = 0;
785 			if (error == B_OK) {
786 				switch (kind) {
787 					case B_APP_VERSION_KIND:
788 						index = 0;
789 						break;
790 					case B_SYSTEM_VERSION_KIND:
791 						index = 1;
792 						break;
793 					default:
794 						error = B_BAD_VALUE;
795 						break;
796 				}
797 			}
798 			// read both infos
799 			version_info infos[2];
800 			if (error == B_OK) {
801 				size_t read;
802 				if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
803 						B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
804 						read) == B_OK) {
805 					// clear the part that hasn't been read
806 					if (read < sizeof(infos))
807 						memset((char*)infos + read, 0, sizeof(infos) - read);
808 				} else {
809 					// failed to read -- clear
810 					memset(infos, 0, sizeof(infos));
811 				}
812 			}
813 			infos[index] = *info;
814 			// write the data
815 			if (error == B_OK) {
816 				error = _WriteData(kVersionInfoAttribute,
817 								   kVersionInfoResourceID,
818 								   B_VERSION_INFO_TYPE, infos,
819 								   2 * sizeof(version_info));
820 			}
821 		} else
822 			error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
823 	}
824 	return error;
825 }
826 
827 // GetIconForType
828 /*!	\brief Gets the icon the application provides for a given MIME type.
829 
830 	If \a type is \c NULL, the application's icon is retrieved.
831 
832 	\param type The MIME type in question. May be \c NULL.
833 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
834 		   to store the requested icon (16x16 for the mini and 32x32 for the
835 		   large icon).
836 	\param which Specifies the size of the icon to be retrieved:
837 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
838 	\return
839 	- \c B_OK: Everything went fine.
840 	- \c B_NO_INIT: The object is not properly initialized.
841 	- \c B_BAD_VALUE: \c NULL \a icon, unsupported icon size
842 		 \a which or bitmap dimensions (\a icon) and icon size (\a which) do
843 		 not match.
844 	- other error codes
845 */
846 status_t
847 BAppFileInfo::GetIconForType(const char *type, BBitmap *icon,
848 							 icon_size which) const
849 {
850 	status_t error = B_OK;
851 	// set some icon size related variables
852 	BString attributeString;
853 	BRect bounds;
854 	uint32 attrType = 0;
855 	size_t attrSize = 0;
856 	switch (which) {
857 		case B_MINI_ICON:
858 			attributeString = kMiniIconAttribute;
859 			bounds.Set(0, 0, 15, 15);
860 			attrType = B_MINI_ICON_TYPE;
861 			attrSize = 16 * 16;
862 			break;
863 		case B_LARGE_ICON:
864 			attributeString = kLargeIconAttribute;
865 			bounds.Set(0, 0, 31, 31);
866 			attrType = B_LARGE_ICON_TYPE;
867 			attrSize = 32 * 32;
868 			break;
869 		default:
870 			error = B_BAD_VALUE;
871 			break;
872 	}
873 	// check type param
874 	if (error == B_OK) {
875 		if (type) {
876 			if (BMimeType::IsValid(type))
877 				attributeString += type;
878 			else
879 				error = B_BAD_VALUE;
880 		} else
881 			attributeString += kStandardIconType;
882 	}
883 	const char *attribute = attributeString.String();
884 
885 	// check parameter and initialization
886 	if (error == B_OK
887 		&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
888 		error = B_BAD_VALUE;
889 	}
890 	if (error == B_OK && InitCheck() != B_OK)
891 		error = B_NO_INIT;
892 	// read the data
893 	if (error == B_OK) {
894 		bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
895 		char *buffer = NULL;
896 		size_t read;
897 		if (otherColorSpace) {
898 			// other color space than stored in attribute
899 			buffer = new(nothrow) char[attrSize];
900 			if (!buffer)
901 				error = B_NO_MEMORY;
902 			if (error == B_OK) {
903 				error = _ReadData(attribute, -1, attrType, buffer, attrSize,
904 								  read);
905 			}
906 		} else {
907 			error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
908 							  read);
909 		}
910 		if (error == B_OK && read != attrSize)
911 			error = B_ERROR;
912 		if (otherColorSpace) {
913 			// other color space than stored in attribute
914 			if (error == B_OK) {
915 				error = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW,
916 										 0, B_CMAP8);
917 			}
918 			delete[] buffer;
919 		}
920 	}
921 	return error;
922 }
923 
924 // SetIconForType
925 /*!	\brief Sets the icon the application provides for a given MIME type.
926 
927 	If \a type is \c NULL, the application's icon is set.
928 	If \a icon is \c NULL the icon is unset.
929 
930 	If the file has a signature, then the icon is also set on the MIME type.
931 	If the type for the signature has not been installed yet, it is installed
932 	before.
933 
934 	\param type The MIME type in question. May be \c NULL.
935 	\param icon A pointer to the BBitmap containing the icon to be set.
936 		   May be \c NULL.
937 	\param which Specifies the size of the icon to be set: \c B_MINI_ICON
938 		   for the mini and \c B_LARGE_ICON for the large icon.
939 	\return
940 	- \c B_OK: Everything went fine.
941 	- \c B_NO_INIT: The object is not properly initialized.
942 	- \c B_BAD_VALUE: Unknown icon size \a which or bitmap dimensions (\a icon)
943 		 and icon size (\a which) do not match.
944 	- other error codes
945 */
946 status_t
947 BAppFileInfo::SetIconForType(const char *type, const BBitmap *icon,
948 							 icon_size which)
949 {
950 	status_t error = B_OK;
951 	// set some icon size related variables
952 	BString attributeString;
953 	BRect bounds;
954 	uint32 attrType = 0;
955 	size_t attrSize = 0;
956 	int32 resourceID = 0;
957 	switch (which) {
958 		case B_MINI_ICON:
959 			attributeString = kMiniIconAttribute;
960 			bounds.Set(0, 0, 15, 15);
961 			attrType = B_MINI_ICON_TYPE;
962 			attrSize = 16 * 16;
963 			resourceID = (type ? kMiniIconForTypeResourceID
964 							   : kMiniIconResourceID);
965 			break;
966 		case B_LARGE_ICON:
967 			attributeString = kLargeIconAttribute;
968 			bounds.Set(0, 0, 31, 31);
969 			attrType = B_LARGE_ICON_TYPE;
970 			attrSize = 32 * 32;
971 			resourceID = (type ? kLargeIconForTypeResourceID
972 							   : kLargeIconResourceID);
973 			break;
974 		default:
975 			error = B_BAD_VALUE;
976 			break;
977 	}
978 	// check type param
979 	if (error == B_OK) {
980 		if (type) {
981 			if (BMimeType::IsValid(type))
982 				attributeString += type;
983 			else
984 				error = B_BAD_VALUE;
985 		} else
986 			attributeString += kStandardIconType;
987 	}
988 	const char *attribute = attributeString.String();
989 	// check parameter and initialization
990 	if (error == B_OK && icon
991 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
992 		error = B_BAD_VALUE;
993 	}
994 	if (error == B_OK && InitCheck() != B_OK)
995 		error = B_NO_INIT;
996 	// write/remove the attribute
997 	if (error == B_OK) {
998 		if (icon) {
999 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
1000 			if (otherColorSpace) {
1001 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
1002 				error = bitmap.InitCheck();
1003 				if (error == B_OK)
1004 					error = bitmap.ImportBits(icon);
1005 				if (error == B_OK) {
1006 					error = _WriteData(attribute, resourceID, attrType,
1007 									   bitmap.Bits(), attrSize, true);
1008 				}
1009 			} else {
1010 				error = _WriteData(attribute, resourceID, attrType,
1011 								   icon->Bits(), attrSize, true);
1012 			}
1013 		} else	// no icon given => remove
1014 			error = _RemoveData(attribute, attrType);
1015 	}
1016 	// set the attribute on the MIME type, if the file has a signature
1017 	BMimeType mimeType;
1018 	if (error == B_OK && GetMetaMime(&mimeType) == B_OK) {
1019 // 		if (!mimeType.IsInstalled())
1020 // 			error = mimeType.Install();
1021 // 		if (error == B_OK)
1022 // 			error = mimeType.SetIconForType(type, icon, which);
1023 	}
1024 	return error;
1025 }
1026 
1027 // SetInfoLocation
1028 /*!	\brief Specifies the location where the meta data shall be stored.
1029 
1030 	The options for \a location are:
1031 	- \c B_USE_ATTRIBUTES: Store the data in the attributes.
1032 	- \c B_USE_RESOURCES: Store the data in the resources.
1033 	- \c B_USE_BOTH_LOCATIONS: Store the data in attributes and resources.
1034 
1035 	\param location The location where the meta data shall be stored.
1036 */
1037 void
1038 BAppFileInfo::SetInfoLocation(info_location location)
1039 {
1040 	fWhere = location;
1041 }
1042 
1043 // IsUsingAttributes
1044 /*!	\brief Returns whether the object stores the meta data (also) in the
1045 		   file's attributes.
1046 	\return \c true, if the meta data are (also) stored in the file's
1047 			attributes, \c false otherwise.
1048 */
1049 bool
1050 BAppFileInfo::IsUsingAttributes() const
1051 {
1052 	return (fWhere & B_USE_ATTRIBUTES);
1053 }
1054 
1055 // IsUsingResources
1056 /*!	\brief Returns whether the object stores the meta data (also) in the
1057 		   file's resources.
1058 	\return \c true, if the meta data are (also) stored in the file's
1059 			resources, \c false otherwise.
1060 */
1061 bool
1062 BAppFileInfo::IsUsingResources() const
1063 {
1064 	return (fWhere & B_USE_RESOURCES);
1065 }
1066 
1067 // FBC
1068 void BAppFileInfo::_ReservedAppFileInfo1() {}
1069 void BAppFileInfo::_ReservedAppFileInfo2() {}
1070 void BAppFileInfo::_ReservedAppFileInfo3() {}
1071 
1072 // =
1073 /*!	\brief Privatized assignment operator to prevent usage.
1074 */
1075 BAppFileInfo &
1076 BAppFileInfo::operator=(const BAppFileInfo &)
1077 {
1078 	return *this;
1079 }
1080 
1081 // copy constructor
1082 /*!	\brief Privatized copy constructor to prevent usage.
1083 */
1084 BAppFileInfo::BAppFileInfo(const BAppFileInfo &)
1085 {
1086 }
1087 
1088 // GetMetaMime
1089 /*!	\brief Initializes a BMimeType to the file's signature.
1090 
1091 	The parameter \a meta is not checked.
1092 
1093 	\param meta A pointer to a pre-allocated BMimeType that shall be
1094 		   initialized to the file's signature.
1095 	\return
1096 	- \c B_OK: Everything went fine.
1097 	- \c B_BAD_VALUE: \c NULL \a meta
1098 	- \c B_ENTRY_NOT_FOUND: The file has not signature or the signature is
1099 (	  not installed in the MIME database.)
1100 	  no valid MIME string.
1101 	- other error codes
1102 */
1103 status_t
1104 BAppFileInfo::GetMetaMime(BMimeType *meta) const
1105 {
1106 	char signature[B_MIME_TYPE_LENGTH];
1107 	status_t error = GetSignature(signature);
1108 	if (error == B_OK)
1109 		error = meta->SetTo(signature);
1110 	else if (error == B_BAD_VALUE)
1111 		error = B_ENTRY_NOT_FOUND;
1112 	if (error == B_OK && !meta->IsValid())
1113 		error = B_BAD_VALUE;
1114 	return error;
1115 }
1116 
1117 // _ReadData
1118 /*!	\brief Reads data from an attribute or resource.
1119 
1120 	The data are read from the location specified by \a fWhere.
1121 
1122 	The object must be properly initialized. The parameters are NOT checked.
1123 
1124 	\param name The name of the attribute/resource to be read.
1125 	\param id The resource ID of the resource to be read. Is ignored, when
1126 		   < 0.
1127 	\param type The type of the attribute/resource to be read.
1128 	\param buffer A pre-allocated buffer for the data to be read.
1129 	\param bufferSize The size of the supplied buffer.
1130 	\param bytesRead A reference parameter, set to the number of bytes
1131 		   actually read.
1132 	\param allocatedBuffer If not \c NULL, the method allocates a buffer
1133 		   large enough too store the whole data and writes a pointer to it
1134 		   into this variable. If \c NULL, the supplied buffer is used.
1135 	\return
1136 	- \c B_OK: Everything went fine.
1137 	- error code
1138 */
1139 status_t
1140 BAppFileInfo::_ReadData(const char *name, int32 id, type_code type,
1141 						void *buffer, size_t bufferSize,
1142 						size_t &bytesRead, void **allocatedBuffer) const
1143 {
1144 	status_t error = B_OK;
1145 
1146 	if (allocatedBuffer)
1147 		buffer = NULL;
1148 
1149 	bool foundData = false;
1150 
1151 	if (IsUsingAttributes()) {
1152 		// get an attribute info
1153 		attr_info info;
1154 		if (error == B_OK)
1155 			error = fNode->GetAttrInfo(name, &info);
1156 
1157 		// check type and size, allocate a buffer, if required
1158 		if (error == B_OK && info.type != type)
1159 			error = B_BAD_VALUE;
1160 		if (error == B_OK && allocatedBuffer) {
1161 			buffer = malloc(info.size);
1162 			if (!buffer)
1163 				error = B_NO_MEMORY;
1164 			bufferSize = info.size;
1165 		}
1166 		if (error == B_OK && (off_t)bufferSize < info.size)
1167 			error = B_BAD_VALUE;
1168 
1169 		// read the data
1170 		if (error == B_OK) {
1171 			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1172 			if (read < 0)
1173 				error = read;
1174 			else if (read != info.size)
1175 				error = B_ERROR;
1176 			else
1177 				bytesRead = read;
1178 		}
1179 
1180 		foundData = (error == B_OK);
1181 
1182 		// free the allocated buffer on error
1183 		if (!foundData && allocatedBuffer && buffer) {
1184 			free(buffer);
1185 			buffer = NULL;
1186 		}
1187 	}
1188 
1189 	if (!foundData && IsUsingResources()) {
1190 		// get a resource info
1191 		error = B_OK;
1192 		int32 idFound;
1193 		size_t sizeFound;
1194 		if (error == B_OK) {
1195 			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1196 				error = B_ENTRY_NOT_FOUND;
1197 		}
1198 
1199 		// check id and size, allocate a buffer, if required
1200 		if (error == B_OK && id >= 0 && idFound != id)
1201 			error = B_ENTRY_NOT_FOUND;
1202 		if (error == B_OK && allocatedBuffer) {
1203 			buffer = malloc(sizeFound);
1204 			if (!buffer)
1205 				error = B_NO_MEMORY;
1206 			bufferSize = sizeFound;
1207 		}
1208 		if (error == B_OK && bufferSize < sizeFound)
1209 			error = B_BAD_VALUE;
1210 
1211 		// load resource
1212 		const void *resourceData = NULL;
1213 		if (error == B_OK) {
1214 			resourceData = fResources->LoadResource(type, name, &bytesRead);
1215 			if (resourceData && sizeFound == bytesRead)
1216 				memcpy(buffer, resourceData, bytesRead);
1217 			else
1218 				error = B_ERROR;
1219 		}
1220 
1221 	} else if (!foundData)
1222 		error = B_BAD_VALUE;
1223 
1224 	// return the allocated buffer, or free it on error
1225 	if (allocatedBuffer) {
1226 		if (error == B_OK)
1227 			*allocatedBuffer = buffer;
1228 		else
1229 			free(buffer);
1230 	}
1231 
1232 	return error;
1233 }
1234 
1235 // _WriteData
1236 /*!	\brief Writes data to an attribute or resource.
1237 
1238 	The data are written to the location(s) specified by \a fWhere.
1239 
1240 	The object must be properly initialized. The parameters are NOT checked.
1241 
1242 	\param name The name of the attribute/resource to be written.
1243 	\param id The resource ID of the resource to be written.
1244 	\param type The type of the attribute/resource to be written.
1245 	\param buffer A buffer containing the data to be written.
1246 	\param bufferSize The size of the supplied buffer.
1247 	\param findID If set to \c true use the ID that is already assigned to the
1248 		   \a name / \a type pair or take the first unused ID >= \a id.
1249 		   If \c false, \a id is used.
1250 	If \a id is already in use and .
1251 	\return
1252 	- \c B_OK: Everything went fine.
1253 	- error code
1254 */
1255 status_t
1256 BAppFileInfo::_WriteData(const char *name, int32 id, type_code type,
1257 						 const void *buffer, size_t bufferSize, bool findID)
1258 {
1259 	status_t error = B_OK;
1260 	// write to attribute
1261 	if (IsUsingAttributes() && error == B_OK) {
1262 		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1263 		if (written < 0)
1264 			error = written;
1265 		else if (written != (ssize_t)bufferSize)
1266 			error = B_ERROR;
1267 	}
1268 	// write to resource
1269 	if (IsUsingResources() && error == B_OK) {
1270 		if (findID) {
1271 			// get the resource info
1272 			int32 idFound;
1273 			size_t sizeFound;
1274 			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1275 				id = idFound;
1276 			else {
1277 				// type-name pair doesn't exist yet -- find unused ID
1278 				while (fResources->HasResource(type, id))
1279 					id++;
1280 			}
1281 		}
1282 		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1283 	}
1284 	return error;
1285 }
1286 
1287 // _RemoveData
1288 /*!	\brief Removes an attribute or resource.
1289 
1290 	The removal location is specified by \a fWhere.
1291 
1292 	The object must be properly initialized. The parameters are NOT checked.
1293 
1294 	\param name The name of the attribute/resource to be remove.
1295 	\param type The type of the attribute/resource to be removed.
1296 	\return
1297 	- \c B_OK: Everything went fine.
1298 	- error code
1299 */
1300 status_t
1301 BAppFileInfo::_RemoveData(const char *name, type_code type)
1302 {
1303 	status_t error = B_OK;
1304 	// remove the attribute
1305 	if (IsUsingAttributes() && error == B_OK) {
1306 		error = fNode->RemoveAttr(name);
1307 		// It's no error, if there has been no attribute.
1308 		if (error == B_ENTRY_NOT_FOUND)
1309 			error = B_OK;
1310 	}
1311 	// remove the resource
1312 	if (IsUsingResources() && error == B_OK) {
1313 		// get a resource info
1314 		int32 idFound;
1315 		size_t sizeFound;
1316 		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1317 			error = fResources->RemoveResource(type, idFound);
1318 	}
1319 	return error;
1320 }
1321 
1322