xref: /haiku/src/build/libbe/storage/AppFileInfo.cpp (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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 0
427 		if (updateMimeDB && error == B_OK && mimeType.IsInstalled())
428 			error = mimeType.SetSupportedTypes(types, syncAll);
429 #endif
430 	}
431 	return error;
432 }
433 
434 
435 status_t
436 BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
437 {
438 	return SetSupportedTypes(types, true, syncAll);
439 }
440 
441 
442 status_t
443 BAppFileInfo::SetSupportedTypes(const BMessage* types)
444 {
445 	return SetSupportedTypes(types, true, false);
446 }
447 
448 
449 bool
450 BAppFileInfo::IsSupportedType(const char* type) const
451 {
452 	status_t error = type != NULL ? B_OK : B_BAD_VALUE;
453 	// get the supported types
454 	BMessage types;
455 	if (error == B_OK)
456 		error = GetSupportedTypes(&types);
457 	// turn type into a BMimeType
458 	BMimeType mimeType;
459 	if (error == B_OK)
460 		error = mimeType.SetTo(type);
461 	// iterate through the supported types
462 	bool found = false;
463 	if (error == B_OK) {
464 		const char* supportedType;
465 		for (int32 i = 0;
466 			 !found && types.FindString("types", i, &supportedType) == B_OK;
467 			 i++) {
468 			found = strcmp(supportedType, "application/octet-stream") == 0
469 				|| BMimeType(supportedType).Contains(&mimeType);
470 		}
471 	}
472 	return found;
473 }
474 
475 
476 bool
477 BAppFileInfo::Supports(BMimeType* type) const
478 {
479 	status_t error
480 		= type != NULL && type->InitCheck() == B_OK ? B_OK : B_BAD_VALUE;
481 	// get the supported types
482 	BMessage types;
483 	if (error == B_OK)
484 		error = GetSupportedTypes(&types);
485 	// iterate through the supported types
486 	bool found = false;
487 	if (error == B_OK) {
488 		const char* supportedType;
489 		for (int32 i = 0;
490 			 !found && types.FindString("types", i, &supportedType) == B_OK;
491 			 i++) {
492 			found = BMimeType(supportedType).Contains(type);
493 		}
494 	}
495 	return found;
496 }
497 
498 
499 status_t
500 BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
501 {
502 	return GetIconForType(NULL, icon, which);
503 }
504 
505 
506 status_t
507 BAppFileInfo::GetIcon(uint8** data, size_t* size) const
508 {
509 	return GetIconForType(NULL, data, size);
510 }
511 
512 
513 status_t
514 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB)
515 {
516 	return SetIconForType(NULL, icon, which, updateMimeDB);
517 }
518 
519 
520 status_t
521 BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
522 {
523 	return SetIconForType(NULL, icon, which, true);
524 }
525 
526 
527 status_t
528 BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB)
529 {
530 	return SetIconForType(NULL, data, size, updateMimeDB);
531 }
532 
533 
534 status_t
535 BAppFileInfo::SetIcon(const uint8* data, size_t size)
536 {
537 	return SetIconForType(NULL, data, size, true);
538 }
539 
540 
541 status_t
542 BAppFileInfo::GetVersionInfo(version_info* info, version_kind kind) const
543 {
544 	// check params and initialization
545 	if (info == NULL)
546 		return B_BAD_VALUE;
547 
548 	int32 index = 0;
549 	switch (kind) {
550 		case B_APP_VERSION_KIND:
551 			index = 0;
552 			break;
553 		case B_SYSTEM_VERSION_KIND:
554 			index = 1;
555 			break;
556 		default:
557 			return B_BAD_VALUE;
558 	}
559 
560 	if (InitCheck() != B_OK)
561 		return B_NO_INIT;
562 
563 	// read the data
564 	size_t read = 0;
565 	version_info infos[2];
566 	status_t error = _ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
567 		B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info), read);
568 	if (error != B_OK)
569 		return error;
570 
571 	// check the read data
572 	if (read == sizeof(version_info)) {
573 		// only the app version info is there -- return a cleared system info
574 		if (index == 0)
575 			*info = infos[index];
576 		else if (index == 1)
577 			memset(info, 0, sizeof(version_info));
578 	} else if (read == 2 * sizeof(version_info)) {
579 		*info = infos[index];
580 	} else
581 		return B_ERROR;
582 
583 	// return result
584 	return B_OK;
585 }
586 
587 
588 status_t
589 BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind)
590 {
591 	// check initialization
592 	status_t error = B_OK;
593 	if (error == B_OK && InitCheck() != B_OK)
594 		error = B_NO_INIT;
595 	if (error == B_OK) {
596 		if (info != NULL) {
597 			// check param
598 			int32 index = 0;
599 			if (error == B_OK) {
600 				switch (kind) {
601 					case B_APP_VERSION_KIND:
602 						index = 0;
603 						break;
604 					case B_SYSTEM_VERSION_KIND:
605 						index = 1;
606 						break;
607 					default:
608 						error = B_BAD_VALUE;
609 						break;
610 				}
611 			}
612 			// read both infos
613 			version_info infos[2];
614 			if (error == B_OK) {
615 				size_t read;
616 				if (_ReadData(kVersionInfoAttribute, kVersionInfoResourceID,
617 						B_VERSION_INFO_TYPE, infos, 2 * sizeof(version_info),
618 						read) == B_OK) {
619 					// clear the part that hasn't been read
620 					if (read < sizeof(infos))
621 						memset((char*)infos + read, 0, sizeof(infos) - read);
622 				} else {
623 					// failed to read -- clear
624 					memset(infos, 0, sizeof(infos));
625 				}
626 			}
627 			infos[index] = *info;
628 			// write the data
629 			if (error == B_OK) {
630 				error = _WriteData(kVersionInfoAttribute,
631 					kVersionInfoResourceID, B_VERSION_INFO_TYPE, infos,
632 					2 * sizeof(version_info));
633 			}
634 		} else
635 			error = _RemoveData(kVersionInfoAttribute, B_VERSION_INFO_TYPE);
636 	}
637 	return error;
638 }
639 
640 
641 status_t
642 BAppFileInfo::GetIconForType(const char* type, BBitmap* icon, icon_size size)
643 	const
644 {
645 	if (InitCheck() != B_OK)
646 		return B_NO_INIT;
647 
648 	if (icon == NULL || icon->InitCheck() != B_OK)
649 		return B_BAD_VALUE;
650 
651 	// TODO: for consistency with attribute based icon reading, we
652 	// could also prefer B_CMAP8 icons here if the provided bitmap
653 	// is in that format. Right now, an existing B_CMAP8 icon resource
654 	// would be ignored as soon as a vector icon is present. On the other
655 	// hand, maybe this still results in a more consistent user interface,
656 	// since Tracker/Deskbar would surely show the vector icon.
657 
658 	// try vector icon first
659 	BString vectorAttributeName(kIconAttribute);
660 
661 	// check type param
662 	if (type != NULL) {
663 		if (BMimeType::IsValid(type))
664 			vectorAttributeName += type;
665 		else
666 			return B_BAD_VALUE;
667 	} else {
668 		vectorAttributeName += kIconType;
669 	}
670 	const char* attribute = vectorAttributeName.String();
671 
672 	size_t bytesRead;
673 	void* allocatedBuffer;
674 	status_t error = _ReadData(attribute, -1, B_VECTOR_ICON_TYPE, NULL, 0,
675 		bytesRead, &allocatedBuffer);
676 	if (error == B_OK) {
677 		error = BIconUtils::GetVectorIcon((uint8*)allocatedBuffer,
678 										  bytesRead, icon);
679 		free(allocatedBuffer);
680 		return error;
681 	}
682 
683 	// no vector icon if we got this far,
684 	// align size argument just in case
685 	if (size < B_LARGE_ICON)
686 		size = B_MINI_ICON;
687 	else
688 		size = B_LARGE_ICON;
689 
690 	error = B_OK;
691 	// set some icon size related variables
692 	BString attributeString;
693 	BRect bounds;
694 	uint32 attrType = 0;
695 	size_t attrSize = 0;
696 	switch (size) {
697 		case B_MINI_ICON:
698 			attributeString = kMiniIconAttribute;
699 			bounds.Set(0, 0, 15, 15);
700 			attrType = B_MINI_ICON_TYPE;
701 			attrSize = 16 * 16;
702 			break;
703 		case B_LARGE_ICON:
704 			attributeString = kLargeIconAttribute;
705 			bounds.Set(0, 0, 31, 31);
706 			attrType = B_LARGE_ICON_TYPE;
707 			attrSize = 32 * 32;
708 			break;
709 		default:
710 			return B_BAD_VALUE;
711 	}
712 
713 	// compose attribute name
714 	attributeString += type != NULL ? type : kStandardIconType;
715 	attribute = attributeString.String();
716 
717 	// check parameters
718 	// currently, scaling B_CMAP8 icons is not supported
719 	if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds)
720 		return B_BAD_VALUE;
721 
722 	// read the data
723 	if (error == B_OK) {
724 		bool tempBuffer
725 			= icon->ColorSpace() != B_CMAP8 || icon->Bounds() != bounds;
726 		uint8* buffer = NULL;
727 		size_t read;
728 		if (tempBuffer) {
729 			// other color space or bitmap size than stored in attribute
730 			buffer = new(std::nothrow) uint8[attrSize];
731 			if (!buffer) {
732 				error = B_NO_MEMORY;
733 			} else {
734 				error = _ReadData(attribute, -1, attrType, buffer, attrSize,
735 					read);
736 			}
737 		} else {
738 			error = _ReadData(attribute, -1, attrType, icon->Bits(), attrSize,
739 				read);
740 		}
741 		if (error == B_OK && read != attrSize)
742 			error = B_ERROR;
743 		if (tempBuffer) {
744 			// other color space than stored in attribute
745 			if (error == B_OK) {
746 				error = BIconUtils::ConvertFromCMAP8(buffer, (uint32)size,
747 					(uint32)size, (uint32)size, icon);
748 			}
749 			delete[] buffer;
750 		}
751 	}
752 	return error;
753 }
754 
755 
756 status_t
757 BAppFileInfo::GetIconForType(const char* type, uint8** data, size_t* size) const
758 {
759 	if (InitCheck() != B_OK)
760 		return B_NO_INIT;
761 
762 	if (data == NULL || size == NULL)
763 		return B_BAD_VALUE;
764 
765 	// get vector icon
766 	BString attributeName(kIconAttribute);
767 
768 	// check type param
769 	if (type != NULL) {
770 		if (BMimeType::IsValid(type))
771 			attributeName += type;
772 		else
773 			return B_BAD_VALUE;
774 	} else
775 		attributeName += kIconType;
776 
777 	void* allocatedBuffer = NULL;
778 	status_t ret = _ReadData(attributeName.String(), -1, B_VECTOR_ICON_TYPE,
779 		NULL, 0, *size, &allocatedBuffer);
780 
781 	if (ret < B_OK)
782 		return ret;
783 
784 	*data = (uint8*)allocatedBuffer;
785 	return B_OK;
786 }
787 
788 
789 status_t
790 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
791 	icon_size which, bool updateMimeDB)
792 {
793 	status_t error = B_OK;
794 
795 	// set some icon size related variables
796 	BString attributeString;
797 	BRect bounds;
798 	uint32 attrType = 0;
799 	size_t attrSize = 0;
800 	int32 resourceID = 0;
801 	switch (which) {
802 		case B_MINI_ICON:
803 			attributeString = kMiniIconAttribute;
804 			bounds.Set(0, 0, 15, 15);
805 			attrType = B_MINI_ICON_TYPE;
806 			attrSize = 16 * 16;
807 			resourceID = type != NULL
808 				? kMiniIconForTypeResourceID : kMiniIconResourceID;
809 			break;
810 		case B_LARGE_ICON:
811 			attributeString = kLargeIconAttribute;
812 			bounds.Set(0, 0, 31, 31);
813 			attrType = B_LARGE_ICON_TYPE;
814 			attrSize = 32 * 32;
815 			resourceID = type != NULL
816 				? kLargeIconForTypeResourceID : kLargeIconResourceID;
817 			break;
818 		default:
819 			error = B_BAD_VALUE;
820 			break;
821 	}
822 
823 	// check type param
824 	if (error == B_OK) {
825 		if (type != NULL) {
826 			if (BMimeType::IsValid(type))
827 				attributeString += type;
828 			else
829 				error = B_BAD_VALUE;
830 		} else
831 			attributeString += kStandardIconType;
832 	}
833 	const char* attribute = attributeString.String();
834 
835 	// check parameter and initialization
836 	if (error == B_OK && icon != NULL
837 		&& (icon->InitCheck() != B_OK || icon->Bounds() != bounds)) {
838 		error = B_BAD_VALUE;
839 	}
840 	if (error == B_OK && InitCheck() != B_OK)
841 		error = B_NO_INIT;
842 
843 	// write/remove the attribute
844 	if (error == B_OK) {
845 		if (icon != NULL) {
846 			bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
847 			if (otherColorSpace) {
848 				BBitmap bitmap(bounds, B_BITMAP_NO_SERVER_LINK, B_CMAP8);
849 				error = bitmap.InitCheck();
850 				if (error == B_OK)
851 					error = bitmap.ImportBits(icon);
852 				if (error == B_OK) {
853 					error = _WriteData(attribute, resourceID, attrType,
854 						bitmap.Bits(), attrSize, true);
855 				}
856 			} else {
857 				error = _WriteData(attribute, resourceID, attrType,
858 					icon->Bits(), attrSize, true);
859 			}
860 		} else	// no icon given => remove
861 			error = _RemoveData(attribute, attrType);
862 	}
863 
864 	// set the attribute on the MIME type, if the file has a signature
865 #if 0
866 	BMimeType mimeType;
867 	if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
868 		if (!mimeType.IsInstalled())
869 			error = mimeType.Install();
870 		if (error == B_OK)
871 			error = mimeType.SetIconForType(type, icon, which);
872 	}
873 #endif
874 	return error;
875 }
876 
877 
878 status_t
879 BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
880 	icon_size which)
881 {
882 	return SetIconForType(type, icon, which, true);
883 }
884 
885 
886 status_t
887 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size,
888 	bool updateMimeDB)
889 {
890 	if (InitCheck() != B_OK)
891 		return B_NO_INIT;
892 
893 	// set some icon related variables
894 	BString attributeString = kIconAttribute;
895 	int32 resourceID = type ? kIconForTypeResourceID : kIconResourceID;
896 	uint32 attrType = B_VECTOR_ICON_TYPE;
897 
898 	// check type param
899 	if (type != NULL) {
900 		if (BMimeType::IsValid(type))
901 			attributeString += type;
902 		else
903 			return B_BAD_VALUE;
904 	} else
905 		attributeString += kIconType;
906 
907 	const char* attribute = attributeString.String();
908 
909 	status_t error;
910 	// write/remove the attribute
911 	if (data != NULL)
912 		error = _WriteData(attribute, resourceID, attrType, data, size, true);
913 	else	// no icon given => remove
914 		error = _RemoveData(attribute, attrType);
915 
916 	// set the attribute on the MIME type, if the file has a signature
917 #if 0
918 	BMimeType mimeType;
919 	if (updateMimeDB && error == B_OK && GetMetaMime(&mimeType) == B_OK) {
920 		if (!mimeType.IsInstalled())
921 			error = mimeType.Install();
922 		if (error == B_OK)
923 			error = mimeType.SetIconForType(type, data, size);
924 	}
925 #endif
926 	return error;
927 }
928 
929 
930 status_t
931 BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size)
932 {
933 	return SetIconForType(type, data, size, true);
934 }
935 
936 
937 void
938 BAppFileInfo::SetInfoLocation(info_location location)
939 {
940 	// if the resources failed to initialize, we must not use them
941 	if (fResources == NULL)
942 		location = info_location(location & ~B_USE_RESOURCES);
943 
944 	fWhere = location;
945 }
946 
947 bool
948 BAppFileInfo::IsUsingAttributes() const
949 {
950 	return (fWhere & B_USE_ATTRIBUTES) != 0;
951 }
952 
953 
954 bool
955 BAppFileInfo::IsUsingResources() const
956 {
957 	return (fWhere & B_USE_RESOURCES) != 0;
958 }
959 
960 
961 // FBC
962 void BAppFileInfo::_ReservedAppFileInfo1() {}
963 void BAppFileInfo::_ReservedAppFileInfo2() {}
964 void BAppFileInfo::_ReservedAppFileInfo3() {}
965 
966 
967 BAppFileInfo&
968 BAppFileInfo::operator=(const BAppFileInfo&)
969 {
970 	return *this;
971 }
972 
973 
974 BAppFileInfo::BAppFileInfo(const BAppFileInfo&)
975 {
976 }
977 
978 
979 status_t
980 BAppFileInfo::GetMetaMime(BMimeType* meta) const
981 {
982 	char signature[B_MIME_TYPE_LENGTH];
983 	status_t error = GetSignature(signature);
984 	if (error == B_OK)
985 		error = meta->SetTo(signature);
986 	else if (error == B_BAD_VALUE)
987 		error = B_ENTRY_NOT_FOUND;
988 	if (error == B_OK && !meta->IsValid())
989 		error = B_BAD_VALUE;
990 	return error;
991 }
992 
993 
994 status_t
995 BAppFileInfo::_ReadData(const char* name, int32 id, type_code type,
996 	void* buffer, size_t bufferSize, size_t& bytesRead, void** allocatedBuffer)
997 	const
998 {
999 	status_t error = B_OK;
1000 
1001 	if (allocatedBuffer)
1002 		buffer = NULL;
1003 
1004 	bool foundData = false;
1005 
1006 	if (IsUsingAttributes()) {
1007 		// get an attribute info
1008 		attr_info info;
1009 		if (error == B_OK)
1010 			error = fNode->GetAttrInfo(name, &info);
1011 
1012 		// check type and size, allocate a buffer, if required
1013 		if (error == B_OK && info.type != type)
1014 			error = B_BAD_VALUE;
1015 		if (error == B_OK && allocatedBuffer != NULL) {
1016 			buffer = malloc(info.size);
1017 			if (buffer == NULL)
1018 				error = B_NO_MEMORY;
1019 			bufferSize = info.size;
1020 		}
1021 		if (error == B_OK && (off_t)bufferSize < info.size)
1022 			error = B_BAD_VALUE;
1023 
1024 		// read the data
1025 		if (error == B_OK) {
1026 			ssize_t read = fNode->ReadAttr(name, type, 0, buffer, info.size);
1027 			if (read < 0)
1028 				error = read;
1029 			else if (read != info.size)
1030 				error = B_ERROR;
1031 			else
1032 				bytesRead = read;
1033 		}
1034 
1035 		foundData = error == B_OK;
1036 
1037 		// free the allocated buffer on error
1038 		if (!foundData && allocatedBuffer != NULL && buffer != NULL) {
1039 			free(buffer);
1040 			buffer = NULL;
1041 		}
1042 	}
1043 
1044 	if (!foundData && IsUsingResources()) {
1045 		// get a resource info
1046 		error = B_OK;
1047 		int32 idFound;
1048 		size_t sizeFound;
1049 		if (error == B_OK) {
1050 			if (!fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1051 				error = B_ENTRY_NOT_FOUND;
1052 		}
1053 
1054 		// check id and size, allocate a buffer, if required
1055 		if (error == B_OK && id >= 0 && idFound != id)
1056 			error = B_ENTRY_NOT_FOUND;
1057 		if (error == B_OK && allocatedBuffer) {
1058 			buffer = malloc(sizeFound);
1059 			if (!buffer)
1060 				error = B_NO_MEMORY;
1061 			bufferSize = sizeFound;
1062 		}
1063 		if (error == B_OK && bufferSize < sizeFound)
1064 			error = B_BAD_VALUE;
1065 
1066 		// load resource
1067 		const void* resourceData = NULL;
1068 		if (error == B_OK) {
1069 			resourceData = fResources->LoadResource(type, name, &bytesRead);
1070 			if (resourceData != NULL && sizeFound == bytesRead)
1071 				memcpy(buffer, resourceData, bytesRead);
1072 			else
1073 				error = B_ERROR;
1074 		}
1075 	} else if (!foundData)
1076 		error = B_BAD_VALUE;
1077 
1078 	// return the allocated buffer, or free it on error
1079 	if (allocatedBuffer != NULL) {
1080 		if (error == B_OK)
1081 			*allocatedBuffer = buffer;
1082 		else
1083 			free(buffer);
1084 	}
1085 
1086 	return error;
1087 }
1088 
1089 
1090 status_t
1091 BAppFileInfo::_WriteData(const char* name, int32 id, type_code type,
1092 	const void* buffer, size_t bufferSize, bool findID)
1093 {
1094 	if (!IsUsingAttributes() && !IsUsingResources())
1095 		return B_NO_INIT;
1096 
1097 	status_t error = B_OK;
1098 
1099 	// write to attribute
1100 	if (IsUsingAttributes()) {
1101 		ssize_t written = fNode->WriteAttr(name, type, 0, buffer, bufferSize);
1102 		if (written < 0)
1103 			error = written;
1104 		else if (written != (ssize_t)bufferSize)
1105 			error = B_ERROR;
1106 	}
1107 	// write to resource
1108 	if (IsUsingResources() && error == B_OK) {
1109 		if (findID) {
1110 			// get the resource info
1111 			int32 idFound;
1112 			size_t sizeFound;
1113 			if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1114 				id = idFound;
1115 			else {
1116 				// type-name pair doesn't exist yet -- find unused ID
1117 				while (fResources->HasResource(type, id))
1118 					id++;
1119 			}
1120 		}
1121 		error = fResources->AddResource(type, id, buffer, bufferSize, name);
1122 	}
1123 	return error;
1124 }
1125 
1126 
1127 status_t
1128 BAppFileInfo::_RemoveData(const char* name, type_code type)
1129 {
1130 	if (!IsUsingAttributes() && !IsUsingResources())
1131 		return B_NO_INIT;
1132 
1133 	status_t error = B_OK;
1134 
1135 	// remove the attribute
1136 	if (IsUsingAttributes()) {
1137 		error = fNode->RemoveAttr(name);
1138 		// It's no error, if there has been no attribute.
1139 		if (error == B_ENTRY_NOT_FOUND)
1140 			error = B_OK;
1141 	}
1142 	// remove the resource
1143 	if (IsUsingResources() && error == B_OK) {
1144 		// get a resource info
1145 		int32 idFound;
1146 		size_t sizeFound;
1147 		if (fResources->GetResourceInfo(type, name, &idFound, &sizeFound))
1148 			error = fResources->RemoveResource(type, idFound);
1149 	}
1150 	return error;
1151 }
1152