xref: /haiku/src/kits/storage/AppFileInfo.cpp (revision b84574958d92055d2e33c26e1f2d43d48c9ed50c)
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 (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 (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 (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 (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 (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 (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 (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 (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 #ifdef _BEOS_R5_COMPATIBLE_
962 //!	Privatized assignment operator to prevent usage.
963 BAppFileInfo&
964 BAppFileInfo::operator=(const BAppFileInfo&)
965 {
966 	return *this;
967 }
968 
969 
970 //! Privatized copy constructor to prevent usage.
971 BAppFileInfo::BAppFileInfo(const BAppFileInfo&)
972 {
973 }
974 #endif
975 
976 
977 /*!	Initializes a BMimeType to the signature of the associated file.
978 
979 	\warning The parameter \a meta is not checked.
980 
981 	\param meta A pointer to a pre-allocated BMimeType that shall be
982 		   initialized to the signature of the associated file.
983 
984 	\returns A status code.
985 	\retval B_OK Everything went fine.
986 	\retval B_BAD_VALUE \c NULL \a meta
987 	\retval B_ENTRY_NOT_FOUND The file has not signature or the signature is
988 	        (not installed in the MIME database.) no valid MIME string.
989 */
990 status_t
991 BAppFileInfo::GetMetaMime(BMimeType* meta) const
992 {
993 	char signature[B_MIME_TYPE_LENGTH];
994 	status_t error = GetSignature(signature);
995 	if (error == B_OK)
996 		error = meta->SetTo(signature);
997 	else if (error == B_BAD_VALUE)
998 		error = B_ENTRY_NOT_FOUND;
999 	if (error == B_OK && !meta->IsValid())
1000 		error = B_BAD_VALUE;
1001 	return error;
1002 }
1003 
1004 
1005 /*!	Reads data from an attribute or resource.
1006 
1007 	\note The data is read from the location specified by \a fWhere.
1008 
1009 	\warning The object must be properly initialized. The parameters are
1010 		\b NOT checked.
1011 
1012 	\param name The name of the attribute/resource to be read.
1013 	\param id The resource ID of the resource to be read. It is ignored
1014 		   when < 0.
1015 	\param type The type of the attribute/resource to be read.
1016 	\param buffer A pre-allocated buffer for the data to be read.
1017 	\param bufferSize The size of the supplied buffer.
1018 	\param bytesRead A reference parameter, set to the number of bytes
1019 		   actually read.
1020 	\param allocatedBuffer If not \c NULL, the method allocates a buffer
1021 		   large enough too store the whole data and writes a pointer to it
1022 		   into this variable. If \c NULL, the supplied buffer is used.
1023 
1024 	\returns A status code.
1025 	\retval B_OK Everything went fine.
1026 	\retval B_ENTRY_NOT_FOUND The entry was not found.
1027 	\retval B_NO_MEMORY Ran out of memory allocating the buffer.
1028 	\retval B_BAD_VALUE \a type did not match.
1029 */
1030 status_t
1031 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type,
1032 	void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer)
1033 	const
1034 {
1035 	status_t error = B_OK;
1036 
1037 	if (allocatedBuffer)
1038 		buffer = NULL;
1039 
1040 	bool foundData = false;
1041 
1042 	if (IsUsingAttributes()) {
1043 		// get an attribute info
1044 		attr_info info;
1045 		if (error == B_OK)
1046 			error = fNode->GetAttrInfo(name, &info);
1047 
1048 		// check type and size, allocate a buffer, if required
1049 		if (error == B_OK && info.type != type)
1050 			error = B_BAD_VALUE;
1051 		if (error == B_OK && allocatedBuffer != NULL) {
1052 			buffer = malloc(info.size);
1053 			if (buffer == NULL)
1054 				error = B_NO_MEMORY;
1055 			bufferSize = info.size;
1056 		}
1057 		if (error == B_OK && (off_t)bufferSize < info.size)
1058 			error = B_BAD_VALUE;
1059 
1060 		// read the data
1061 		if (error == B_OK) {
1062 			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1063 			if (read < 0)
1064 				error = read;
1065 			else if (read != info.size)
1066 				error = B_ERROR;
1067 			else
1068 				bytesRead = read;
1069 		}
1070 
1071 		foundData = error == B_OK;
1072 
1073 		// free the allocated buffer on error
1074 		if (!foundData && allocatedBuffer != NULL && buffer != NULL) {
1075 			free(buffer);
1076 			buffer = NULL;
1077 		}
1078 	}
1079 
1080 	if (!foundData && IsUsingResources()) {
1081 		// get a resource info
1082 		error = B_OK;
1083 		int32 idFound;
1084 		size_t sizeFound;
1085 		if (error == B_OK) {
1086 			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1087 				error = B_ENTRY_NOT_FOUND;
1088 		}
1089 
1090 		// check id and size, allocate a buffer, if required
1091 		if (error == B_OK && id >= 0 && idFound != id)
1092 			error = B_ENTRY_NOT_FOUND;
1093 		if (error == B_OK && allocatedBuffer) {
1094 			buffer = malloc(sizeFound);
1095 			if (!buffer)
1096 				error = B_NO_MEMORY;
1097 			bufferSize = sizeFound;
1098 		}
1099 		if (error == B_OK && bufferSize < sizeFound)
1100 			error = B_BAD_VALUE;
1101 
1102 		// load resource
1103 		const void* resourceData = NULL;
1104 		if (error == B_OK) {
1105 			resourceData = fResources->LoadResource(type, name, &bytesRead);
1106 			if (resourceData != NULL && sizeFound == bytesRead)
1107 				memcpy(buffer, resourceData, bytesRead);
1108 			else
1109 				error = B_ERROR;
1110 		}
1111 	} else if (!foundData)
1112 		error = B_BAD_VALUE;
1113 
1114 	// return the allocated buffer, or free it on error
1115 	if (allocatedBuffer != NULL) {
1116 		if (error == B_OK)
1117 			*allocatedBuffer = buffer;
1118 		else
1119 			free(buffer);
1120 	}
1121 
1122 	return error;
1123 }
1124 
1125 
1126 /*!	Writes data to an attribute or resource.
1127 
1128 	\note The data is written to the location(s) specified by \a fWhere.
1129 
1130 	\warning The object must be properly initialized. The parameters are
1131 		\b NOT checked.
1132 
1133 	\param name The name of the attribute/resource to be written.
1134 	\param id The resource ID of the resource to be written.
1135 	\param type The type of the attribute/resource to be written.
1136 	\param buffer A buffer containing the data to be written.
1137 	\param bufferSize The size of the supplied buffer.
1138 	\param findID If set to \c true use the ID that is already assigned to the
1139 		   \a name / \a type pair or take the first unused ID >= \a id.
1140 		   If \c false, \a id is used.
1141 
1142 	\returns A status code.
1143 	\retval B_OK Everything went fine.
1144 	\retval B_ERROR An error occurred while trying to write the data.
1145 */
1146 status_t
1147 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type,
1148 	const void* buffer, size_t bufferSize, bool findID)
1149 {
1150 	if (!IsUsingAttributes() && !IsUsingResources())
1151 		return B_NO_INIT;
1152 
1153 	status_t error = B_OK;
1154 
1155 	// write to attribute
1156 	if (IsUsingAttributes()) {
1157 		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1158 		if (written < 0)
1159 			error = written;
1160 		else if (written != (ssize_t)bufferSize)
1161 			error = B_ERROR;
1162 	}
1163 	// write to resource
1164 	if (IsUsingResources() && error == B_OK) {
1165 		if (findID) {
1166 			// get the resource info
1167 			int32 idFound;
1168 			size_t sizeFound;
1169 			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1170 				id = idFound;
1171 			else {
1172 				// type-name pair doesn't exist yet -- find unused ID
1173 				while (fResources->HasResource(type, id))
1174 					id++;
1175 			}
1176 		}
1177 		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1178 	}
1179 	return error;
1180 }
1181 
1182 
1183 /*!	Removes an attribute or resource.
1184 
1185 	\note The removal location is specified by \a fWhere.
1186 
1187 	\warning The object must be properly initialized. The parameters are
1188 		\b NOT checked.
1189 
1190 	\param name The name of the attribute/resource to be remove.
1191 	\param type The type of the attribute/resource to be removed.
1192 
1193 	\returns A status code.
1194 	\retval B_OK Everything went fine.
1195 	\retval B_NO_INIT Not using attributes and not using resources.
1196 	\retval B_ENTRY_NOT_FOUND The attribute or resource was not found.
1197 */
1198 status_t
1199 BAppFileInfo::_RemoveData(const char* name, type_code type)
1200 {
1201 	if (!IsUsingAttributes() && !IsUsingResources())
1202 		return B_NO_INIT;
1203 
1204 	status_t error = B_OK;
1205 
1206 	// remove the attribute
1207 	if (IsUsingAttributes()) {
1208 		error = fNode->RemoveAttr(name);
1209 		// It's no error, if there has been no attribute.
1210 		if (error == B_ENTRY_NOT_FOUND)
1211 			error = B_OK;
1212 	}
1213 	// remove the resource
1214 	if (IsUsingResources() && error == B_OK) {
1215 		// get a resource info
1216 		int32 idFound;
1217 		size_t sizeFound;
1218 		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1219 			error = fResources->RemoveResource(type, idFound);
1220 	}
1221 	return error;
1222 }
1223