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 (updateMimeDB && error == B_OK && mimeType.IsInstalled())
427			error = mimeType.SetSupportedTypes(types, syncAll);
428	}
429	return error;
430}
431
432
433status_t
434BAppFileInfo::SetSupportedTypes(const BMessage* types, bool syncAll)
435{
436	return SetSupportedTypes(types, true, syncAll);
437}
438
439
440status_t
441BAppFileInfo::SetSupportedTypes(const BMessage* types)
442{
443	return SetSupportedTypes(types, true, false);
444}
445
446
447bool
448BAppFileInfo::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
474bool
475BAppFileInfo::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
497status_t
498BAppFileInfo::GetIcon(BBitmap* icon, icon_size which) const
499{
500	return GetIconForType(NULL, icon, which);
501}
502
503
504status_t
505BAppFileInfo::GetIcon(uint8** data, size_t* size) const
506{
507	return GetIconForType(NULL, data, size);
508}
509
510
511status_t
512BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which, bool updateMimeDB)
513{
514	return SetIconForType(NULL, icon, which, updateMimeDB);
515}
516
517
518status_t
519BAppFileInfo::SetIcon(const BBitmap* icon, icon_size which)
520{
521	return SetIconForType(NULL, icon, which, true);
522}
523
524
525status_t
526BAppFileInfo::SetIcon(const uint8* data, size_t size, bool updateMimeDB)
527{
528	return SetIconForType(NULL, data, size, updateMimeDB);
529}
530
531
532status_t
533BAppFileInfo::SetIcon(const uint8* data, size_t size)
534{
535	return SetIconForType(NULL, data, size, true);
536}
537
538
539status_t
540BAppFileInfo::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
586status_t
587BAppFileInfo::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
639status_t
640BAppFileInfo::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
754status_t
755BAppFileInfo::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
787status_t
788BAppFileInfo::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
874status_t
875BAppFileInfo::SetIconForType(const char* type, const BBitmap* icon,
876	icon_size which)
877{
878	return SetIconForType(type, icon, which, true);
879}
880
881
882status_t
883BAppFileInfo::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
924status_t
925BAppFileInfo::SetIconForType(const char* type, const uint8* data, size_t size)
926{
927	return SetIconForType(type, data, size, true);
928}
929
930
931void
932BAppFileInfo::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
941bool
942BAppFileInfo::IsUsingAttributes() const
943{
944	return (fWhere & B_USE_ATTRIBUTES) != 0;
945}
946
947
948bool
949BAppFileInfo::IsUsingResources() const
950{
951	return (fWhere & B_USE_RESOURCES) != 0;
952}
953
954
955// FBC
956void BAppFileInfo::_ReservedAppFileInfo1() {}
957void BAppFileInfo::_ReservedAppFileInfo2() {}
958void BAppFileInfo::_ReservedAppFileInfo3() {}
959
960
961#ifdef _BEOS_R5_COMPATIBLE_
962//!	Privatized assignment operator to prevent usage.
963BAppFileInfo&
964BAppFileInfo::operator=(const BAppFileInfo&)
965{
966	return *this;
967}
968
969
970//! Privatized copy constructor to prevent usage.
971BAppFileInfo::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*/
990status_t
991BAppFileInfo::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*/
1030status_t
1031BAppFileInfo::_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*/
1146status_t
1147BAppFileInfo::_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*/
1198status_t
1199BAppFileInfo::_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