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