xref: /haiku/src/kits/storage/AppFileInfo.cpp (revision c41356fab56ee714d3930183e09d7ee5ad9c1de4)
1 /*
2  * Copyright 2002-2014, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, ingo_weinhold@gmx.de
7  */
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 <IconUtils.h>
20 #include <MimeType.h>
21 #include <RegistrarDefs.h>
22 #include <Resources.h>
23 #include <Roster.h>
24 #include <String.h>
25 
26 
27 // debugging
28 //#define DBG(x) x
29 #define DBG(x)
30 #define OUT	printf
31 
32 
33 // type codes
34 enum {
35 	B_APP_FLAGS_TYPE	= 'APPF',
36 	B_VERSION_INFO_TYPE	= 'APPV',
37 };
38 
39 
40 // attributes
41 static const char* kTypeAttribute				= "BEOS:TYPE";
42 static const char* kSignatureAttribute			= "BEOS:APP_SIG";
43 static const char* kAppFlagsAttribute			= "BEOS:APP_FLAGS";
44 static const char* kSupportedTypesAttribute		= "BEOS:FILE_TYPES";
45 static const char* kVersionInfoAttribute		= "BEOS:APP_VERSION";
46 static const char* kMiniIconAttribute			= "BEOS:M:";
47 static const char* kLargeIconAttribute			= "BEOS:L:";
48 static const char* kIconAttribute				= "BEOS:";
49 static const char* kStandardIconType			= "STD_ICON";
50 static const char* kIconType					= "ICON";
51 static const char* kCatalogEntryAttribute		= "SYS:NAME";
52 
53 // resource IDs
54 static const int32 kTypeResourceID				= 2;
55 static const int32 kSignatureResourceID			= 1;
56 static const int32 kAppFlagsResourceID			= 1;
57 static const int32 kSupportedTypesResourceID	= 1;
58 static const int32 kMiniIconResourceID			= 101;
59 static const int32 kLargeIconResourceID			= 101;
60 static const int32 kIconResourceID				= 101;
61 static const int32 kVersionInfoResourceID		= 1;
62 static const int32 kMiniIconForTypeResourceID	= 0;
63 static const int32 kLargeIconForTypeResourceID	= 0;
64 static const int32 kIconForTypeResourceID		= 0;
65 static const int32 kCatalogEntryResourceID		= 1;
66 
67 // R5 also exports these (Tracker is using them):
68 // (maybe we better want to drop them silently and declare
69 // the above in a public Haiku header - and use that one in
70 // Tracker when compiled for Haiku)
71 extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE;
72 const uint32 MINI_ICON_TYPE = 'MICN';
73 const uint32 LARGE_ICON_TYPE = 'ICON';
74 
75 
76 BAppFileInfo::BAppFileInfo()
77 	:
78 	fResources(NULL),
79 	fWhere(B_USE_BOTH_LOCATIONS)
80 {
81 }
82 
83 
84 BAppFileInfo::BAppFileInfo(BFile* file)
85 	:
86 	fResources(NULL),
87 	fWhere(B_USE_BOTH_LOCATIONS)
88 {
89 	SetTo(file);
90 }
91 
92 
93 BAppFileInfo::~BAppFileInfo()
94 {
95 	delete fResources;
96 }
97 
98 
99 status_t
100 BAppFileInfo::SetTo(BFile* file)
101 {
102 	// unset the old file
103 	BNodeInfo::SetTo(NULL);
104 	if (fResources) {
105 		delete fResources;
106 		fResources = NULL;
107 	}
108 
109 	// check param
110 	status_t error
111 		= file != NULL && file->InitCheck() == B_OK ? B_OK : B_BAD_VALUE;
112 
113 	info_location where = B_USE_BOTH_LOCATIONS;
114 
115 	// create resources
116 	if (error == B_OK) {
117 		fResources = new(std::nothrow) BResources();
118 		if (fResources) {
119 			error = fResources->SetTo(file);
120 			if (error != B_OK) {
121 				// no resources - this is no critical error, we'll just use
122 				// attributes only, then
123 				where = B_USE_ATTRIBUTES;
124 				error = B_OK;
125 			}
126 		} else
127 			error = B_NO_MEMORY;
128 	}
129 
130 	// set node info
131 	if (error == B_OK)
132 		error = BNodeInfo::SetTo(file);
133 
134 	if (error != B_OK || (where & B_USE_RESOURCES) == 0) {
135 		delete fResources;
136 		fResources = NULL;
137 	}
138 
139 	// clean up on error
140 	if (error != B_OK) {
141 		if (InitCheck() == B_OK)
142 			BNodeInfo::SetTo(NULL);
143 	}
144 
145 	// set data location
146 	if (error == B_OK)
147 		SetInfoLocation(where);
148 
149 	// set error
150 	fCStatus = error;
151 	return error;
152 }
153 
154 
155 status_t
156 BAppFileInfo::GetType(char* type) const
157 {
158 	// check param and initialization
159 	status_t error = type != NULL ? B_OK : B_BAD_VALUE;
160 	if (error == B_OK && InitCheck() != B_OK)
161 		error = B_NO_INIT;
162 	// read the data
163 	size_t read = 0;
164 	if (error == B_OK) {
165 		error = _ReadData(kTypeAttribute, kTypeResourceID, B_MIME_STRING_TYPE,
166 			type, B_MIME_TYPE_LENGTH, read);
167 	}
168 	// check the read data -- null terminate the string
169 	if (error == B_OK && type[read - 1] != '\0') {
170 		if (read == B_MIME_TYPE_LENGTH)
171 			error = B_ERROR;
172 		else
173 			type[read] = '\0';
174 	}
175 	return error;
176 }
177 
178 
179 status_t
180 BAppFileInfo::SetType(const char* type)
181 {
182 	// check initialization
183 	status_t error = B_OK;
184 	if (error == B_OK && InitCheck() != B_OK)
185 		error = B_NO_INIT;
186 	if (error == B_OK) {
187 		if (type != NULL) {
188 			// check param
189 			size_t typeLen = strlen(type);
190 			if (error == B_OK && typeLen >= B_MIME_TYPE_LENGTH)
191 				error = B_BAD_VALUE;
192 			// write the data
193 			if (error == B_OK) {
194 				error = _WriteData(kTypeAttribute, kTypeResourceID,
195 					B_MIME_STRING_TYPE, type, typeLen + 1);
196 			}
197 		} else
198 			error = _RemoveData(kTypeAttribute, B_MIME_STRING_TYPE);
199 	}
200 	return error;
201 }
202 
203 
204 status_t
205 BAppFileInfo::GetSignature(char* signature) const
206 {
207 	// check param and initialization
208 	status_t error = (signature ? B_OK : B_BAD_VALUE);
209 	if (error == B_OK && InitCheck() != B_OK)
210 		error = B_NO_INIT;
211 	// read the data
212 	size_t read = 0;
213 	if (error == B_OK) {
214 		error = _ReadData(kSignatureAttribute, kSignatureResourceID,
215 			B_MIME_STRING_TYPE, signature, B_MIME_TYPE_LENGTH, read);
216 	}
217 	// check the read data -- null terminate the string
218 	if (error == B_OK && signature[read - 1] != '\0') {
219 		if (read == B_MIME_TYPE_LENGTH)
220 			error = B_ERROR;
221 		else
222 			signature[read] = '\0';
223 	}
224 	return error;
225 }
226 
227 
228 status_t
229 BAppFileInfo::SetSignature(const char* signature)
230 {
231 	// check initialization
232 	status_t error = B_OK;
233 	if (error == B_OK && InitCheck() != B_OK)
234 		error = B_NO_INIT;
235 	if (error == B_OK) {
236 		if (signature) {
237 			// check param
238 			size_t signatureLen = strlen(signature);
239 			if (error == B_OK && signatureLen >= B_MIME_TYPE_LENGTH)
240 				error = B_BAD_VALUE;
241 			// write the data
242 			if (error == B_OK) {
243 				error = _WriteData(kSignatureAttribute, kSignatureResourceID,
244 					B_MIME_STRING_TYPE, signature, signatureLen + 1);
245 			}
246 		} else
247 			error = _RemoveData(kSignatureAttribute, B_MIME_STRING_TYPE);
248 	}
249 	return error;
250 }
251 
252 
253 status_t
254 BAppFileInfo::GetCatalogEntry(char* catalogEntry) const
255 {
256 	if (catalogEntry == NULL)
257 		return B_BAD_VALUE;
258 
259 	if (InitCheck() != B_OK)
260 		return B_NO_INIT;
261 
262 	size_t read = 0;
263 	status_t error = _ReadData(kCatalogEntryAttribute, kCatalogEntryResourceID,
264 		B_STRING_TYPE, catalogEntry, B_MIME_TYPE_LENGTH * 3, read);
265 
266 	if (error != B_OK)
267 		return error;
268 
269 	if (read >= B_MIME_TYPE_LENGTH * 3)
270 		return B_ERROR;
271 
272 	catalogEntry[read] = '\0';
273 
274 	return B_OK;
275 }
276 
277 
278 status_t
279 BAppFileInfo::SetCatalogEntry(const char* catalogEntry)
280 {
281 	if (InitCheck() != B_OK)
282 		return B_NO_INIT;
283 
284 	if (catalogEntry == NULL)
285 		return _RemoveData(kCatalogEntryAttribute, B_STRING_TYPE);
286 
287 	size_t nameLength = strlen(catalogEntry);
288 	if (nameLength > B_MIME_TYPE_LENGTH * 3)
289 		return B_BAD_VALUE;
290 
291 	return _WriteData(kCatalogEntryAttribute, kCatalogEntryResourceID,
292 		B_STRING_TYPE, catalogEntry, nameLength + 1);
293 }
294 
295 
296 status_t
297 BAppFileInfo::GetAppFlags(uint32* flags) const
298 {
299 	// check param and initialization
300 	status_t error = flags != NULL ? B_OK : B_BAD_VALUE;
301 	if (error == B_OK && InitCheck() != B_OK)
302 		error = B_NO_INIT;
303 	// read the data
304 	size_t read = 0;
305 	if (error == B_OK) {
306 		error = _ReadData(kAppFlagsAttribute, kAppFlagsResourceID,
307 			B_APP_FLAGS_TYPE, flags, sizeof(uint32), read);
308 	}
309 	// check the read data
310 	if (error == B_OK && read != sizeof(uint32))
311 		error = B_ERROR;
312 	return error;
313 }
314 
315 
316 status_t
317 BAppFileInfo::SetAppFlags(uint32 flags)
318 {
319 	// check initialization
320 	status_t error = B_OK;
321 	if (error == B_OK && InitCheck() != B_OK)
322 		error = B_NO_INIT;
323 	if (error == B_OK) {
324 		// write the data
325 		error = _WriteData(kAppFlagsAttribute, kAppFlagsResourceID,
326 			B_APP_FLAGS_TYPE, &flags, sizeof(uint32));
327 	}
328 	return error;
329 }
330 
331 
332 status_t
333 BAppFileInfo::RemoveAppFlags()
334 {
335 	// check initialization
336 	status_t error = B_OK;
337 	if (error == B_OK && InitCheck() != B_OK)
338 		error = B_NO_INIT;
339 	if (error == B_OK) {
340 		// remove the data
341 		error = _RemoveData(kAppFlagsAttribute, B_APP_FLAGS_TYPE);
342 	}
343 	return error;
344 }
345 
346 
347 status_t
348 BAppFileInfo::GetSupportedTypes(BMessage* types) const
349 {
350 	// check param and initialization
351 	status_t error = types != NULL ? B_OK : B_BAD_VALUE;
352 	if (error == B_OK && InitCheck() != B_OK)
353 		error = B_NO_INIT;
354 	// read the data
355 	size_t read = 0;
356 	void* buffer = NULL;
357 	if (error == B_OK) {
358 		error = _ReadData(kSupportedTypesAttribute, kSupportedTypesResourceID,
359 			B_MESSAGE_TYPE, NULL, 0, read, &buffer);
360 	}
361 	// unflatten the buffer
362 	if (error == B_OK)
363 		error = types->Unflatten((const char*)buffer);
364 	// clean up
365 	free(buffer);
366 	return error;
367 }
368 
369 
370 status_t
371 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool updateMimeDB,
372 	bool syncAll)
373 {
374 	// check initialization
375 	status_t error = B_OK;
376 	if (error == B_OK && InitCheck() != B_OK)
377 		error = B_NO_INIT;
378 
379 	BMimeType mimeType;
380 	if (error == B_OK)
381 		error = GetMetaMime(&mimeType);
382 
383 	if (error == B_OK || error == B_ENTRY_NOT_FOUND) {
384 		error = B_OK;
385 		if (types) {
386 			// check param -- supported types must be valid
387 			const char* type;
388 			for (int32 i = 0;
389 				 error == B_OK && types->FindString("types", i, &type) == B_OK;
390 				 i++) {
391 				if (!BMimeType::IsValid(type))
392 					error = B_BAD_VALUE;
393 			}
394 
395 			// get flattened size
396 			ssize_t size = 0;
397 			if (error == B_OK) {
398 				size = types->FlattenedSize();
399 				if (size < 0)
400 					error = size;
401 			}
402 
403 			// allocate a buffer for the flattened data
404 			char* buffer = NULL;
405 			if (error == B_OK) {
406 				buffer = new(std::nothrow) char[size];
407 				if (!buffer)
408 					error = B_NO_MEMORY;
409 			}
410 
411 			// flatten the message
412 			if (error == B_OK)
413 				error = types->Flatten(buffer, size);
414 
415 			// write the data
416 			if (error == B_OK) {
417 				error = _WriteData(kSupportedTypesAttribute,
418 					kSupportedTypesResourceID, B_MESSAGE_TYPE, buffer, size);
419 			}
420 
421 			delete[] buffer;
422 		} else
423 			error = _RemoveData(kSupportedTypesAttribute, B_MESSAGE_TYPE);
424 
425 		// update the MIME database, if the app signature is installed
426 		if (updateMimeDB && error == B_OK && mimeType.IsInstalled())
427 			error = mimeType.SetSupportedTypes(types, syncAll);
428 	}
429 	return error;
430 }
431 
432 
433 status_t
434 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
435 {
436 	return SetSupportedTypes(types, true, syncAll);
437 }
438 
439 
440 status_t
441 BAppFileInfo::SetSupportedTypes(const BMessage* types)
442 {
443 	return SetSupportedTypes(types, true, false);
444 }
445 
446 
447 bool
448 BAppFileInfo::IsSupportedType(const char* type) const
449 {
450 	status_t error = type != NULL ? B_OK : B_BAD_VALUE;
451 	// get the supported types
452 	BMessage types;
453 	if (error == B_OK)
454 		error = GetSupportedTypes(&types);
455 	// turn type into a BMimeType
456 	BMimeType mimeType;
457 	if (error == B_OK)
458 		error = mimeType.SetTo(type);
459 	// iterate through the supported types
460 	bool found = false;
461 	if (error == B_OK) {
462 		const char* supportedType;
463 		for (int32 i = 0;
464 			 !found && types.FindString("types", i, &supportedType) == B_OK;
465 			 i++) {
466 			found = strcmp(supportedType, "application/octet-stream") == 0
467 				|| BMimeType(supportedType).Contains(&mimeType);
468 		}
469 	}
470 	return found;
471 }
472 
473 
474 bool
475 BAppFileInfo::Supports(BMimeType* type) const
476 {
477 	status_t error
478 		= type != NULL && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE;
479 	// get the supported types
480 	BMessage types;
481 	if (error == B_OK)
482 		error = GetSupportedTypes(&types);
483 	// iterate through the supported types
484 	bool found = false;
485 	if (error == B_OK) {
486 		const char* supportedType;
487 		for (int32 i = 0;
488 			 !found && types.FindString("types", i, &supportedType) == B_OK;
489 			 i++) {
490 			found = BMimeType(supportedType).Contains(type);
491 		}
492 	}
493 	return found;
494 }
495 
496 
497 status_t
498 BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
499 {
500 	return GetIconForType(NULL, icon, which);
501 }
502 
503 
504 status_t
505 BAppFileInfo::GetIcon(uint8** data, size_t* size) const
506 {
507 	return GetIconForType(NULL, data, size);
508 }
509 
510 
511 status_t
512 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB)
513 {
514 	return SetIconForType(NULL, icon, which, updateMimeDB);
515 }
516 
517 
518 status_t
519 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
520 {
521 	return SetIconForType(NULL, icon, which, true);
522 }
523 
524 
525 status_t
526 BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB)
527 {
528 	return SetIconForType(NULL, data, size, updateMimeDB);
529 }
530 
531 
532 status_t
533 BAppFileInfo::SetIcon(const uint8* data, size_t size)
534 {
535 	return SetIconForType(NULL, data, size, true);
536 }
537 
538 
539 status_t
540 BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const
541 {
542 	// check params and initialization
543 	if (info == NULL)
544 		return B_BAD_VALUE;
545 
546 	int32 index = 0;
547 	switch (kind) {
548 		case B_APP_VERSION_KIND:
549 			index = 0;
550 			break;
551 		case B_SYSTEM_VERSION_KIND:
552 			index = 1;
553 			break;
554 		default:
555 			return B_BAD_VALUE;
556 	}
557 
558 	if (InitCheck() != B_OK)
559 		return B_NO_INIT;
560 
561 	// read the data
562 	size_t read = 0;
563 	version_info infos[2];
564 	status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
565 		B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
566 	if (error != B_OK)
567 		return error;
568 
569 	// check the read data
570 	if (read == sizeof(version_info)) {
571 		// only the app version info is there -- return a cleared system info
572 		if (index == 0)
573 			*info = infos[index];
574 		else if (index == 1)
575 			memset(info, 0, sizeof(version_info));
576 	} else if (read == 2 * sizeof(version_info)) {
577 		*info = infos[index];
578 	} else
579 		return B_ERROR;
580 
581 	// return result
582 	return B_OK;
583 }
584 
585 
586 status_t
587 BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind)
588 {
589 	// check initialization
590 	status_t error = B_OK;
591 	if (error == B_OK && InitCheck() != B_OK)
592 		error = B_NO_INIT;
593 	if (error == B_OK) {
594 		if (info != NULL) {
595 			// check param
596 			int32 index = 0;
597 			if (error == B_OK) {
598 				switch (kind) {
599 					case B_APP_VERSION_KIND:
600 						index = 0;
601 						break;
602 					case B_SYSTEM_VERSION_KIND:
603 						index = 1;
604 						break;
605 					default:
606 						error = B_BAD_VALUE;
607 						break;
608 				}
609 			}
610 			// read both infos
611 			version_info infos[2];
612 			if (error == B_OK) {
613 				size_t read;
614 				if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
615 						B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
616 						read) == B_OK) {
617 					// clear the part that hasn't been read
618 					if (read < sizeof(infos))
619 						memset((char*)infos + read, 0, sizeof(infos) - read);
620 				} else {
621 					// failed to read -- clear
622 					memset(infos, 0, sizeof(infos));
623 				}
624 			}
625 			infos[index] = *info;
626 			// write the data
627 			if (error == B_OK) {
628 				error = _WriteData(kVersionInfoAttribute,
629 					kVersionInfoResourceID, B_VERSION_INFO_TYPE, infos,
630 					2 * sizeof(version_info));
631 			}
632 		} else
633 			error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
634 	}
635 	return error;
636 }
637 
638 
639 status_t
640 BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, icon_size size)
641 	const
642 {
643 	if (InitCheck() != B_OK)
644 		return B_NO_INIT;
645 
646 	if (icon == NULL || icon->InitCheck() != B_OK)
647 		return B_BAD_VALUE;
648 
649 	// TODO: for consistency with attribute based icon reading, we
650 	// could also prefer B_CMAP8 icons here if the provided bitmap
651 	// is in that format. Right now, an existing B_CMAP8 icon resource
652 	// would be ignored as soon as a vector icon is present. On the other
653 	// hand, maybe this still results in a more consistent user interface,
654 	// since Tracker/Deskbar would surely show the vector icon.
655 
656 	// try vector icon first
657 	BString vectorAttributeName(kIconAttribute);
658 
659 	// check type param
660 	if (type != NULL) {
661 		if (BMimeType::IsValid(type))
662 			vectorAttributeName += type;
663 		else
664 			return B_BAD_VALUE;
665 	} else {
666 		vectorAttributeName += kIconType;
667 	}
668 	const char* attribute = vectorAttributeName.String();
669 
670 	size_t bytesRead;
671 	void* allocatedBuffer;
672 	status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0,
673 		bytesRead, &allocatedBuffer);
674 	if (error == B_OK) {
675 		error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer,
676 										  bytesRead, icon);
677 		free(allocatedBuffer);
678 		return error;
679 	}
680 
681 	// no vector icon if we got this far,
682 	// align size argument just in case
683 	if (size < B_LARGE_ICON)
684 		size = B_MINI_ICON;
685 	else
686 		size = B_LARGE_ICON;
687 
688 	error = B_OK;
689 	// set some icon size related variables
690 	BString attributeString;
691 	BRect bounds;
692 	uint32 attrType = 0;
693 	size_t attrSize = 0;
694 	switch (size) {
695 		case B_MINI_ICON:
696 			attributeString = kMiniIconAttribute;
697 			bounds.Set(0, 0, 15, 15);
698 			attrType = B_MINI_ICON_TYPE;
699 			attrSize = 16 * 16;
700 			break;
701 		case B_LARGE_ICON:
702 			attributeString = kLargeIconAttribute;
703 			bounds.Set(0, 0, 31, 31);
704 			attrType = B_LARGE_ICON_TYPE;
705 			attrSize = 32 * 32;
706 			break;
707 		default:
708 			return B_BAD_VALUE;
709 	}
710 
711 	// compose attribute name
712 	attributeString += type != NULL ? type : kStandardIconType;
713 	attribute = attributeString.String();
714 
715 	// check parameters
716 	// currently, scaling B_CMAP8 icons is not supported
717 	if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds)
718 		return B_BAD_VALUE;
719 
720 	// read the data
721 	if (error == B_OK) {
722 		bool tempBuffer
723 			= icon->ColorSpace() != B_CMAP8 || icon->Bounds() != bounds;
724 		uint8* buffer = NULL;
725 		size_t read;
726 		if (tempBuffer) {
727 			// other color space or bitmap size than stored in attribute
728 			buffer = new(std::nothrow) uint8[attrSize];
729 			if (!buffer) {
730 				error = B_NO_MEMORY;
731 			} else {
732 				error = _ReadData(attribute, -1, attrType, buffer, attrSize,
733 					read);
734 			}
735 		} else {
736 			error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
737 				read);
738 		}
739 		if (error == B_OK && read != attrSize)
740 			error = B_ERROR;
741 		if (tempBuffer) {
742 			// other color space than stored in attribute
743 			if (error == B_OK) {
744 				error = BIconUtils::ConvertFromCMAP8(buffer, (uint32)size,
745 					(uint32)size, (uint32)size, icon);
746 			}
747 			delete[] buffer;
748 		}
749 	}
750 	return error;
751 }
752 
753 
754 status_t
755 BAppFileInfo::GetIconForType(const char* type, uint8** data, size_t* size) const
756 {
757 	if (InitCheck() != B_OK)
758 		return B_NO_INIT;
759 
760 	if (data == NULL || size == NULL)
761 		return B_BAD_VALUE;
762 
763 	// get vector icon
764 	BString attributeName(kIconAttribute);
765 
766 	// check type param
767 	if (type != NULL) {
768 		if (BMimeType::IsValid(type))
769 			attributeName += type;
770 		else
771 			return B_BAD_VALUE;
772 	} else
773 		attributeName += kIconType;
774 
775 	void* allocatedBuffer = NULL;
776 	status_t ret = _ReadData(attributeName.String(), -1, B_VECTOR_ICON_TYPE,
777 		NULL, 0, *size, &allocatedBuffer);
778 
779 	if (ret < B_OK)
780 		return ret;
781 
782 	*data = (uint8*)allocatedBuffer;
783 	return B_OK;
784 }
785 
786 
787 status_t
788 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
789 	icon_size which, bool updateMimeDB)
790 {
791 	status_t error = B_OK;
792 
793 	// set some icon size related variables
794 	BString attributeString;
795 	BRect bounds;
796 	uint32 attrType = 0;
797 	size_t attrSize = 0;
798 	int32 resourceID = 0;
799 	switch (which) {
800 		case B_MINI_ICON:
801 			attributeString = kMiniIconAttribute;
802 			bounds.Set(0, 0, 15, 15);
803 			attrType = B_MINI_ICON_TYPE;
804 			attrSize = 16 * 16;
805 			resourceID = type != NULL
806 				? kMiniIconForTypeResourceID : kMiniIconResourceID;
807 			break;
808 		case B_LARGE_ICON:
809 			attributeString = kLargeIconAttribute;
810 			bounds.Set(0, 0, 31, 31);
811 			attrType = B_LARGE_ICON_TYPE;
812 			attrSize = 32 * 32;
813 			resourceID = type != NULL
814 				? kLargeIconForTypeResourceID : kLargeIconResourceID;
815 			break;
816 		default:
817 			error = B_BAD_VALUE;
818 			break;
819 	}
820 
821 	// check type param
822 	if (error == B_OK) {
823 		if (type != NULL) {
824 			if (BMimeType::IsValid(type))
825 				attributeString += type;
826 			else
827 				error = B_BAD_VALUE;
828 		} else
829 			attributeString += kStandardIconType;
830 	}
831 	const char* attribute = attributeString.String();
832 
833 	// check parameter and initialization
834 	if (error == B_OK && icon != NULL
835 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
836 		error = B_BAD_VALUE;
837 	}
838 	if (error == B_OK && InitCheck() != B_OK)
839 		error = B_NO_INIT;
840 
841 	// write/remove the attribute
842 	if (error == B_OK) {
843 		if (icon != NULL) {
844 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
845 			if (otherColorSpace) {
846 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
847 				error = bitmap.InitCheck();
848 				if (error == B_OK)
849 					error = bitmap.ImportBits(icon);
850 				if (error == B_OK) {
851 					error = _WriteData(attribute, resourceID, attrType,
852 						bitmap.Bits(), attrSize, true);
853 				}
854 			} else {
855 				error = _WriteData(attribute, resourceID, attrType,
856 					icon->Bits(), attrSize, true);
857 			}
858 		} else	// no icon given => remove
859 			error = _RemoveData(attribute, attrType);
860 	}
861 
862 	// set the attribute on the MIME type, if the file has a signature
863 	BMimeType mimeType;
864 	if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
865 		if (!mimeType.IsInstalled())
866 			error = mimeType.Install();
867 		if (error == B_OK)
868 			error = mimeType.SetIconForType(type, icon, which);
869 	}
870 	return error;
871 }
872 
873 
874 status_t
875 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
876 	icon_size which)
877 {
878 	return SetIconForType(type, icon, which, true);
879 }
880 
881 
882 status_t
883 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size,
884 	bool updateMimeDB)
885 {
886 	if (InitCheck() != B_OK)
887 		return B_NO_INIT;
888 
889 	// set some icon related variables
890 	BString attributeString = kIconAttribute;
891 	int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID;
892 	uint32 attrType = B_VECTOR_ICON_TYPE;
893 
894 	// check type param
895 	if (type != NULL) {
896 		if (BMimeType::IsValid(type))
897 			attributeString += type;
898 		else
899 			return B_BAD_VALUE;
900 	} else
901 		attributeString += kIconType;
902 
903 	const char* attribute = attributeString.String();
904 
905 	status_t error;
906 	// write/remove the attribute
907 	if (data != NULL)
908 		error = _WriteData(attribute, resourceID, attrType, data, size, true);
909 	else	// no icon given => remove
910 		error = _RemoveData(attribute, attrType);
911 
912 	// set the attribute on the MIME type, if the file has a signature
913 	BMimeType mimeType;
914 	if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
915 		if (!mimeType.IsInstalled())
916 			error = mimeType.Install();
917 		if (error == B_OK)
918 			error = mimeType.SetIconForType(type, data, size);
919 	}
920 	return error;
921 }
922 
923 
924 status_t
925 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size)
926 {
927 	return SetIconForType(type, data, size, true);
928 }
929 
930 
931 void
932 BAppFileInfo::SetInfoLocation(info_location location)
933 {
934 	// if the resources failed to initialize, we must not use them
935 	if (fResources == NULL)
936 		location = info_location(location & ~B_USE_RESOURCES);
937 
938 	fWhere = location;
939 }
940 
941 bool
942 BAppFileInfo::IsUsingAttributes() const
943 {
944 	return (fWhere & B_USE_ATTRIBUTES) != 0;
945 }
946 
947 
948 bool
949 BAppFileInfo::IsUsingResources() const
950 {
951 	return (fWhere & B_USE_RESOURCES) != 0;
952 }
953 
954 
955 // FBC
956 void BAppFileInfo::_ReservedAppFileInfo1() {}
957 void BAppFileInfo::_ReservedAppFileInfo2() {}
958 void BAppFileInfo::_ReservedAppFileInfo3() {}
959 
960 
961 BAppFileInfo&
962 BAppFileInfo::operator=(const BAppFileInfo&)
963 {
964 	return *this;
965 }
966 
967 
968 BAppFileInfo::BAppFileInfo(const BAppFileInfo&)
969 {
970 }
971 
972 
973 status_t
974 BAppFileInfo::GetMetaMime(BMimeType* meta) const
975 {
976 	char signature[B_MIME_TYPE_LENGTH];
977 	status_t error = GetSignature(signature);
978 	if (error == B_OK)
979 		error = meta->SetTo(signature);
980 	else if (error == B_BAD_VALUE)
981 		error = B_ENTRY_NOT_FOUND;
982 	if (error == B_OK && !meta->IsValid())
983 		error = B_BAD_VALUE;
984 	return error;
985 }
986 
987 
988 status_t
989 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type,
990 	void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer)
991 	const
992 {
993 	status_t error = B_OK;
994 
995 	if (allocatedBuffer)
996 		buffer = NULL;
997 
998 	bool foundData = false;
999 
1000 	if (IsUsingAttributes()) {
1001 		// get an attribute info
1002 		attr_info info;
1003 		if (error == B_OK)
1004 			error = fNode->GetAttrInfo(name, &info);
1005 
1006 		// check type and size, allocate a buffer, if required
1007 		if (error == B_OK && info.type != type)
1008 			error = B_BAD_VALUE;
1009 		if (error == B_OK && allocatedBuffer != NULL) {
1010 			buffer = malloc(info.size);
1011 			if (buffer == NULL)
1012 				error = B_NO_MEMORY;
1013 			bufferSize = info.size;
1014 		}
1015 		if (error == B_OK && (off_t)bufferSize < info.size)
1016 			error = B_BAD_VALUE;
1017 
1018 		// read the data
1019 		if (error == B_OK) {
1020 			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1021 			if (read < 0)
1022 				error = read;
1023 			else if (read != info.size)
1024 				error = B_ERROR;
1025 			else
1026 				bytesRead = read;
1027 		}
1028 
1029 		foundData = error == B_OK;
1030 
1031 		// free the allocated buffer on error
1032 		if (!foundData && allocatedBuffer != NULL && buffer != NULL) {
1033 			free(buffer);
1034 			buffer = NULL;
1035 		}
1036 	}
1037 
1038 	if (!foundData && IsUsingResources()) {
1039 		// get a resource info
1040 		error = B_OK;
1041 		int32 idFound;
1042 		size_t sizeFound;
1043 		if (error == B_OK) {
1044 			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1045 				error = B_ENTRY_NOT_FOUND;
1046 		}
1047 
1048 		// check id and size, allocate a buffer, if required
1049 		if (error == B_OK && id >= 0 && idFound != id)
1050 			error = B_ENTRY_NOT_FOUND;
1051 		if (error == B_OK && allocatedBuffer) {
1052 			buffer = malloc(sizeFound);
1053 			if (!buffer)
1054 				error = B_NO_MEMORY;
1055 			bufferSize = sizeFound;
1056 		}
1057 		if (error == B_OK && bufferSize < sizeFound)
1058 			error = B_BAD_VALUE;
1059 
1060 		// load resource
1061 		const void* resourceData = NULL;
1062 		if (error == B_OK) {
1063 			resourceData = fResources->LoadResource(type, name, &bytesRead);
1064 			if (resourceData != NULL && sizeFound == bytesRead)
1065 				memcpy(buffer, resourceData, bytesRead);
1066 			else
1067 				error = B_ERROR;
1068 		}
1069 	} else if (!foundData)
1070 		error = B_BAD_VALUE;
1071 
1072 	// return the allocated buffer, or free it on error
1073 	if (allocatedBuffer != NULL) {
1074 		if (error == B_OK)
1075 			*allocatedBuffer = buffer;
1076 		else
1077 			free(buffer);
1078 	}
1079 
1080 	return error;
1081 }
1082 
1083 
1084 status_t
1085 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type,
1086 	const void* buffer, size_t bufferSize, bool findID)
1087 {
1088 	if (!IsUsingAttributes() && !IsUsingResources())
1089 		return B_NO_INIT;
1090 
1091 	status_t error = B_OK;
1092 
1093 	// write to attribute
1094 	if (IsUsingAttributes()) {
1095 		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1096 		if (written < 0)
1097 			error = written;
1098 		else if (written != (ssize_t)bufferSize)
1099 			error = B_ERROR;
1100 	}
1101 	// write to resource
1102 	if (IsUsingResources() && error == B_OK) {
1103 		if (findID) {
1104 			// get the resource info
1105 			int32 idFound;
1106 			size_t sizeFound;
1107 			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1108 				id = idFound;
1109 			else {
1110 				// type-name pair doesn't exist yet -- find unused ID
1111 				while (fResources->HasResource(type, id))
1112 					id++;
1113 			}
1114 		}
1115 		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1116 	}
1117 	return error;
1118 }
1119 
1120 
1121 status_t
1122 BAppFileInfo::_RemoveData(const char* name, type_code type)
1123 {
1124 	if (!IsUsingAttributes() && !IsUsingResources())
1125 		return B_NO_INIT;
1126 
1127 	status_t error = B_OK;
1128 
1129 	// remove the attribute
1130 	if (IsUsingAttributes()) {
1131 		error = fNode->RemoveAttr(name);
1132 		// It's no error, if there has been no attribute.
1133 		if (error == B_ENTRY_NOT_FOUND)
1134 			error = B_OK;
1135 	}
1136 	// remove the resource
1137 	if (IsUsingResources() && error == B_OK) {
1138 		// get a resource info
1139 		int32 idFound;
1140 		size_t sizeFound;
1141 		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1142 			error = fResources->RemoveResource(type, idFound);
1143 	}
1144 	return error;
1145 }
1146