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