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
34enum {
35	B_APP_FLAGS_TYPE	= 'APPF',
36	B_VERSION_INFO_TYPE	= 'APPV',
37};
38
39
40// attributes
41static const char* kTypeAttribute				= "BEOS:TYPE";
42static const char* kSignatureAttribute			= "BEOS:APP_SIG";
43static const char* kAppFlagsAttribute			= "BEOS:APP_FLAGS";
44static const char* kSupportedTypesAttribute		= "BEOS:FILE_TYPES";
45static const char* kVersionInfoAttribute		= "BEOS:APP_VERSION";
46static const char* kMiniIconAttribute			= "BEOS:M:";
47static const char* kLargeIconAttribute			= "BEOS:L:";
48static const char* kIconAttribute				= "BEOS:";
49static const char* kStandardIconType			= "STD_ICON";
50static const char* kIconType					= "ICON";
51static const char* kCatalogEntryAttribute		= "SYS:NAME";
52
53// resource IDs
54static const int32 kTypeResourceID				= 2;
55static const int32 kSignatureResourceID			= 1;
56static const int32 kAppFlagsResourceID			= 1;
57static const int32 kSupportedTypesResourceID	= 1;
58static const int32 kMiniIconResourceID			= 101;
59static const int32 kLargeIconResourceID			= 101;
60static const int32 kIconResourceID				= 101;
61static const int32 kVersionInfoResourceID		= 1;
62static const int32 kMiniIconForTypeResourceID	= 0;
63static const int32 kLargeIconForTypeResourceID	= 0;
64static const int32 kIconForTypeResourceID		= 0;
65static 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)
71extern const uint32 MINI_ICON_TYPE, LARGE_ICON_TYPE;
72const uint32 MINI_ICON_TYPE = 'MICN';
73const uint32 LARGE_ICON_TYPE = 'ICON';
74
75
76BAppFileInfo::BAppFileInfo()
77	:
78	fResources(NULL),
79	fWhere(B_USE_BOTH_LOCATIONS)
80{
81}
82
83
84BAppFileInfo::BAppFileInfo(BFile* file)
85	:
86	fResources(NULL),
87	fWhere(B_USE_BOTH_LOCATIONS)
88{
89	SetTo(file);
90}
91
92
93BAppFileInfo::~BAppFileInfo()
94{
95	delete fResources;
96}
97
98
99status_t
100BAppFileInfo::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
155status_t
156BAppFileInfo::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
179status_t
180BAppFileInfo::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
204status_t
205BAppFileInfo::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
228status_t
229BAppFileInfo::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
253status_t
254BAppFileInfo::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
278status_t
279BAppFileInfo::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
296status_t
297BAppFileInfo::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
316status_t
317BAppFileInfo::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
332status_t
333BAppFileInfo::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
347status_t
348BAppFileInfo::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
370status_t
371BAppFileInfo::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 0
427		if (updateMimeDB && error == B_OK && mimeType.IsInstalled())
428			error = mimeType.SetSupportedTypes(types, syncAll);
429#endif
430	}
431	return error;
432}
433
434
435status_t
436BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
437{
438	return SetSupportedTypes(types, true, syncAll);
439}
440
441
442status_t
443BAppFileInfo::SetSupportedTypes(const BMessage* types)
444{
445	return SetSupportedTypes(types, true, false);
446}
447
448
449bool
450BAppFileInfo::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
476bool
477BAppFileInfo::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
499status_t
500BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
501{
502	return GetIconForType(NULL, icon, which);
503}
504
505
506status_t
507BAppFileInfo::GetIcon(uint8** data, size_t* size) const
508{
509	return GetIconForType(NULL, data, size);
510}
511
512
513status_t
514BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB)
515{
516	return SetIconForType(NULL, icon, which, updateMimeDB);
517}
518
519
520status_t
521BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
522{
523	return SetIconForType(NULL, icon, which, true);
524}
525
526
527status_t
528BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB)
529{
530	return SetIconForType(NULL, data, size, updateMimeDB);
531}
532
533
534status_t
535BAppFileInfo::SetIcon(const uint8* data, size_t size)
536{
537	return SetIconForType(NULL, data, size, true);
538}
539
540
541status_t
542BAppFileInfo::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
588status_t
589BAppFileInfo::SetVersionInfo(const version_info* info, version_kind kind)
590{
591	// check initialization
592	status_t error = B_OK;
593	if (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
641status_t
642BAppFileInfo::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
756status_t
757BAppFileInfo::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
789status_t
790BAppFileInfo::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
878status_t
879BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
880	icon_size which)
881{
882	return SetIconForType(type, icon, which, true);
883}
884
885
886status_t
887BAppFileInfo::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
930status_t
931BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size)
932{
933	return SetIconForType(type, data, size, true);
934}
935
936
937void
938BAppFileInfo::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
947bool
948BAppFileInfo::IsUsingAttributes() const
949{
950	return (fWhere & B_USE_ATTRIBUTES) != 0;
951}
952
953
954bool
955BAppFileInfo::IsUsingResources() const
956{
957	return (fWhere & B_USE_RESOURCES) != 0;
958}
959
960
961// FBC
962void BAppFileInfo::_ReservedAppFileInfo1() {}
963void BAppFileInfo::_ReservedAppFileInfo2() {}
964void BAppFileInfo::_ReservedAppFileInfo3() {}
965
966
967BAppFileInfo&
968BAppFileInfo::operator=(const BAppFileInfo&)
969{
970	return *this;
971}
972
973
974BAppFileInfo::BAppFileInfo(const BAppFileInfo&)
975{
976}
977
978
979status_t
980BAppFileInfo::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
994status_t
995BAppFileInfo::_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
1090status_t
1091BAppFileInfo::_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
1127status_t
1128BAppFileInfo::_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