1/*
2 * Copyright 2002-2007, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 */
8
9
10/*!
11	\file database_access.cpp
12	Mime database atomic read functions
13*/
14
15#include <Bitmap.h>
16#include <Entry.h>
17#include <Directory.h>
18#include <IconUtils.h>
19#include <Message.h>
20#include <mime/database_support.h>
21#include <Node.h>
22#include <Path.h>
23#include <RegistrarDefs.h>
24#include <String.h>
25#include <storage_support.h>
26
27#include <fs_attr.h>	// For struct attr_info
28#include <iostream>
29#include <new>			// For new(nothrow)
30#include <stdio.h>
31#include <string>
32
33#include "mime/database_access.h"
34
35#define DBG(x) x
36//#define DBG(x)
37#define OUT printf
38
39namespace BPrivate {
40namespace Storage {
41namespace Mime {
42
43
44/*! \brief Fetches the application hint for the given MIME type.
45
46	The entry_ref pointed to by \c ref must be pre-allocated.
47
48	\param type The MIME type of interest
49	\param ref Pointer to a pre-allocated \c entry_ref struct into
50	           which the location of the hint application is copied.
51
52	\return
53	- \c B_OK: Success
54	- \c B_ENTRY_NOT_FOUND: No app hint exists for the given type
55	- "error code": Failure
56*/
57status_t
58get_app_hint(const char *type, entry_ref *ref)
59{
60	if (type == NULL || ref == NULL)
61		return B_BAD_VALUE;
62
63	char path[B_PATH_NAME_LENGTH];
64	BEntry entry;
65	ssize_t status = read_mime_attr(type, kAppHintAttr, path,
66		B_PATH_NAME_LENGTH, kAppHintType);
67
68	if (status >= B_OK)
69		status = entry.SetTo(path);
70	if (status == B_OK)
71		status = entry.GetRef(ref);
72
73	return status;
74}
75
76
77/*! \brief Fetches from the MIME database a BMessage describing the attributes
78	typically associated with files of the given MIME type
79
80	The attribute information is returned in a pre-allocated BMessage pointed to by
81	the \c info parameter (note that the any prior contents of the message
82	will be destroyed). Please see BMimeType::SetAttrInfo() for a description
83	of the expected format of such a message.
84
85	\param info Pointer to a pre-allocated BMessage into which information about
86	            the MIME type's associated file attributes is stored.
87	\return
88	- \c B_OK: Success
89	- "error code": Failure
90*/
91status_t
92get_attr_info(const char *type, BMessage *info)
93{
94	status_t err = read_mime_attr_message(type, kAttrInfoAttr, info);
95	if (err == B_ENTRY_NOT_FOUND) {
96		// return an empty message
97		info->MakeEmpty();
98		err = B_OK;
99	}
100	if (err == B_OK) {
101		info->what = 233;
102			// Don't know why, but that's what R5 does.
103		err = info->AddString("type", type);
104	}
105	return err;
106}
107
108
109/*!	\brief Fetches the short description for the given MIME type.
110
111	The string pointed to by \c description must be long enough to
112	hold the short description; a length of \c B_MIME_TYPE_LENGTH is
113	recommended.
114
115	\param type The MIME type of interest
116	\param description Pointer to a pre-allocated string into which the short
117	                   description is copied. If the function fails, the contents
118	                   of the string are undefined.
119
120	\return
121	- \c B_OK: Success
122	- \c B_ENTRY_NOT_FOUND: No short description exists for the given type
123	- "error code": Failure
124*/
125status_t
126get_short_description(const char *type, char *description)
127{
128///	DBG(OUT("Mime::Database::get_short_description()\n"));
129	ssize_t err = read_mime_attr(type, kShortDescriptionAttr, description,
130		B_MIME_TYPE_LENGTH, kShortDescriptionType);
131	return err >= 0 ? B_OK : err ;
132}
133
134// get_long_description
135//!	Fetches the long description for the given MIME type.
136/*!	The string pointed to by \c description must be long enough to
137	hold the long description; a length of \c B_MIME_TYPE_LENGTH is
138	recommended.
139
140	\param type The MIME type of interest
141	\param description Pointer to a pre-allocated string into which the long
142	                   description is copied. If the function fails, the contents
143	                   of the string are undefined.
144
145	\return
146	- \c B_OK: Success
147	- \c B_ENTRY_NOT_FOUND: No long description exists for the given type
148	- "error code": Failure
149*/
150status_t
151get_long_description(const char *type, char *description)
152{
153//	DBG(OUT("Mime::Database::get_long_description()\n"));
154	ssize_t err = read_mime_attr(type, kLongDescriptionAttr, description,
155		B_MIME_TYPE_LENGTH, kLongDescriptionType);
156	return err >= 0 ? B_OK : err ;
157}
158
159
160/*!	\brief Fetches a BMessage describing the MIME type's associated filename
161	extensions
162
163	The list of extensions is returned in a pre-allocated BMessage pointed to
164	by the \c extensions parameter (note that the any prior contents of the
165	message will be destroyed). Please see BMimeType::GetFileExtensions() for
166	a description of the message format.
167
168	\param extensions Pointer to a pre-allocated BMessage into which the MIME
169	                  type's associated file extensions will be stored.
170	\return
171	- \c B_OK: Success
172	- "error code": Failure
173*/
174status_t
175get_file_extensions(const char *type, BMessage *extensions)
176{
177	status_t err = read_mime_attr_message(type, kFileExtensionsAttr, extensions);
178	if (err == B_ENTRY_NOT_FOUND) {
179		// return an empty message
180		extensions->MakeEmpty();
181		err = B_OK;
182	}
183	if (err == B_OK) {
184		extensions->what = 234;	// Don't know why, but that's what R5 does.
185		err = extensions->AddString("type", type);
186	}
187	return err;
188}
189
190
191/*!	\brief Fetches the icon of given size associated with the given MIME type
192
193	The bitmap pointed to by \c icon must be of the proper size (\c 32x32
194	for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and color depth
195	(\c B_CMAP8).
196
197	\param type The mime type
198	\param icon Pointer to a pre-allocated bitmap of proper dimensions and color depth
199	\param size The size icon you're interested in (\c B_LARGE_ICON or \c B_MINI_ICON)
200*/
201status_t
202get_icon(const char *type, BBitmap *icon, icon_size which)
203{
204	return get_icon_for_type(type, NULL, icon, which);
205}
206
207// get_icon
208//! Fetches the vector icon associated with the given MIME type
209/*  \param type The mime type
210	\param data Pointer in which the allocated icon data is returned. You need to
211				free the buffer once you're done with it.
212	\param size Pointer in which the size of the icon data is returned.
213*/
214status_t
215get_icon(const char *type, uint8** data, size_t* size)
216{
217	return get_icon_for_type(type, NULL, data, size);
218}
219
220// get_icon_for_type
221/*! \brief Fetches the large or mini icon used by an application of this type for files of the
222	given type.
223
224	The type of the \c BMimeType object is not required to actually be a subtype of
225	\c "application/"; that is the intended use however, and calling \c get_icon_for_type()
226	on a non-application type will likely return \c B_ENTRY_NOT_FOUND.
227
228	The icon is copied into the \c BBitmap pointed to by \c icon. The bitmap must
229	be the proper size: \c 32x32 for the large icon, \c 16x16 for the mini icon.
230
231	\param type The MIME type
232	\param fileType Pointer to a pre-allocated string containing the MIME type whose
233					custom icon you wish to fetch. If NULL, works just like get_icon().
234	\param icon Pointer to a pre-allocated \c BBitmap of proper size and colorspace into
235				which the icon is copied.
236	\param icon_size Value that specifies which icon to return. Currently \c B_LARGE_ICON
237					 and \c B_MINI_ICON are supported.
238	\return
239	- \c B_OK: Success
240	- \c B_ENTRY_NOT_FOUND: No icon of the given size exists for the given type
241	- "error code": Failure
242
243*/
244status_t
245get_icon_for_type(const char* type, const char* fileType, BBitmap* icon,
246	icon_size which)
247{
248	if (!type || !icon)
249		return B_BAD_VALUE;
250
251	// open the node for the given type
252	BNode node;
253	ssize_t err = open_type(type, &node);
254	if (err < B_OK)
255		return (status_t)err;
256
257	// construct our attribute name
258	std::string vectorIconAttrName;
259	std::string smallIconAttrName;
260	std::string largeIconAttrName;
261
262	if (fileType) {
263		std::string lowerCaseFileType = BPrivate::Storage::to_lower(fileType);
264
265		vectorIconAttrName = kIconAttrPrefix + lowerCaseFileType;
266		smallIconAttrName = kMiniIconAttrPrefix + lowerCaseFileType;
267		largeIconAttrName = kLargeIconAttrPrefix + lowerCaseFileType;
268	} else {
269		vectorIconAttrName = kIconAttr;
270		smallIconAttrName = kMiniIconAttr;
271		largeIconAttrName = kLargeIconAttr;
272	}
273
274	return BIconUtils::GetIcon(&node, vectorIconAttrName.c_str(),
275		smallIconAttrName.c_str(), largeIconAttrName.c_str(),
276		which, icon);
277
278
279//	ssize_t err = type && icon ? B_OK : B_BAD_VALUE;
280//
281//	// Figure out what kind of data we *should* find
282//	uint32 attrType = 0;
283//	ssize_t attrSize = 0;
284//	BRect bounds;
285//
286//	if (!err) {
287//		switch (which) {
288//			case B_MINI_ICON:
289//				bounds.Set(0, 0, 15, 15);
290//				attrType = kMiniIconType;
291//				attrSize = 16 * 16;
292//				break;
293//			case B_LARGE_ICON:
294//				bounds.Set(0, 0, 31, 31);
295//				attrType = kLargeIconType;
296//				attrSize = 32 * 32;
297//				break;
298//			default:
299//				err = B_BAD_VALUE;
300//				break;
301//		}
302//	}
303//	// Construct our attribute name
304//	std::string attr;
305//	if (fileType) {
306//		attr = (which == B_MINI_ICON
307//	              ? kMiniIconAttrPrefix
308//	                : kLargeIconAttrPrefix)
309//	                  + BPrivate::Storage::to_lower(fileType);
310//	} else {
311//		attr = (which == B_MINI_ICON) ? kMiniIconAttr : kLargeIconAttr;
312//	}
313//	// Check the icon and attribute to see if they match
314//	if (!err) {
315//		err = (icon->InitCheck() == B_OK
316//				&& icon->Bounds() == bounds) ? B_OK : B_BAD_VALUE;
317//	}
318//
319//	BNode node;
320//	if (!err)
321//		err = open_type(type, &node);
322//
323//	attr_info info;
324//	if (!err)
325//		err = node.GetAttrInfo(attr.c_str(), &info);
326//
327//	if (!err)
328//		err = (attrType == info.type && attrSize == info.size) ? B_OK : B_BAD_VALUE;
329//	// read the attribute
330//	if (!err) {
331//		bool otherColorSpace = (icon->ColorSpace() != B_CMAP8);
332//		char *buffer = NULL;
333//		if (otherColorSpace) {
334//			// other color space than stored in attribute
335//			buffer = new(std::nothrow) char[attrSize];
336//			if (!buffer)
337//				err = B_NO_MEMORY;
338//			if (!err)
339//				err = node.ReadAttr(attr.c_str(), attrType, 0, buffer, attrSize);
340//		} else {
341//			// same color space, just read direct
342//			err = node.ReadAttr(attr.c_str(), attrType, 0, icon->Bits(), attrSize);
343//		}
344//		if (err >= 0)
345//			err = (err == attrSize) ? (status_t)B_OK : (status_t)B_FILE_ERROR;
346//		if (otherColorSpace) {
347//			if (!err) {
348//				err = icon->ImportBits(buffer, attrSize, B_ANY_BYTES_PER_ROW,
349//									   0, B_CMAP8);
350//			}
351//			delete[] buffer;
352//		}
353//	}
354//
355//	return err;
356}
357
358// get_icon_for_type
359/*! \brief Fetches the vector icon used by an application of this type for files of the
360	given type.
361
362	The type of the \c BMimeType object is not required to actually be a subtype of
363	\c "application/"; that is the intended use however, and calling \c get_icon_for_type()
364	on a non-application type will likely return \c B_ENTRY_NOT_FOUND.
365
366	The icon data is allocated and returned in \a data.
367
368	\param type The MIME type
369	\param fileType Pointer to a pre-allocated string containing the MIME type whose
370					custom icon you wish to fetch. If NULL, works just like get_icon().
371	\param data Pointer in which the icon data is returned on success.
372	\param size Pointer in which the size of the icon data is returned.
373	\return
374	- \c B_OK: Success
375	- \c B_ENTRY_NOT_FOUND: No vector icon exists for the given type
376	- "error code": Failure
377
378*/
379status_t
380get_icon_for_type(const char* type, const char* fileType, uint8** data,
381				  size_t* size)
382{
383	if (!type || !data || !size)
384		return B_BAD_VALUE;
385
386	// open the node for the given type
387	BNode node;
388	ssize_t err = open_type(type, &node);
389	if (err < B_OK)
390		return (status_t)err;
391
392	// construct our attribute name
393	std::string iconAttrName;
394
395	if (fileType)
396		iconAttrName = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType);
397	else
398		iconAttrName = kIconAttr;
399
400	// get info about attribute for that name
401	attr_info info;
402	if (!err)
403		err = node.GetAttrInfo(iconAttrName.c_str(), &info);
404
405	// validate attribute type
406	if (!err)
407		err = (info.type == B_VECTOR_ICON_TYPE) ? B_OK : B_BAD_VALUE;
408
409	// allocate a buffer and read the attribute data into it
410	if (!err) {
411		uint8* buffer = new(std::nothrow) uint8[info.size];
412		if (!buffer)
413			err = B_NO_MEMORY;
414		if (!err) {
415			err = node.ReadAttr(iconAttrName.c_str(), B_VECTOR_ICON_TYPE,
416								0, buffer, info.size);
417		}
418
419		if (err >= 0)
420			err = (err == info.size) ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR;
421
422		if (!err) {
423			// success, set data pointer and size
424			*data = buffer;
425			*size = info.size;
426		} else {
427			delete[] buffer;
428		}
429	}
430
431	return err;
432}
433
434
435/*!	\brief Fetches signature of the MIME type's preferred application for the
436	given action.
437
438	The string pointed to by \c signature must be long enough to
439	hold the short description; a length of \c B_MIME_TYPE_LENGTH is
440	recommended.
441
442	Currently, the only supported app verb is \c B_OPEN.
443
444	\param type The MIME type of interest
445	\param description Pointer to a pre-allocated string into which the
446		preferred application's signature is copied. If the function fails,
447		the contents of the string are undefined.
448	\param verb \c The action of interest
449
450	\return
451	- \c B_OK: Success
452	- \c B_ENTRY_NOT_FOUND: No such preferred application exists
453	- "error code": Failure
454*/
455status_t
456get_preferred_app(const char *type, char *signature, app_verb verb = B_OPEN)
457{
458	// Since B_OPEN is the currently the only app_verb, it is essentially ignored
459	ssize_t err = read_mime_attr(type, kPreferredAppAttr, signature,
460		B_MIME_TYPE_LENGTH, kPreferredAppType);
461	return err >= 0 ? B_OK : err ;
462}
463
464
465/*! \brief Fetches the sniffer rule for the given MIME type.
466	\param type The MIME type of interest
467	\param result Pointer to a pre-allocated BString into which the type's
468	              sniffer rule is copied.
469	\return
470	- \c B_OK: Success
471	- \c B_ENTRY_NOT_FOUND: No such preferred application exists
472	- "error code": Failure
473*/
474status_t
475get_sniffer_rule(const char *type, BString *result)
476{
477	return read_mime_attr_string(type, kSnifferRuleAttr, result);
478}
479
480
481status_t
482get_supported_types(const char *type, BMessage *types)
483{
484	status_t err = read_mime_attr_message(type, kSupportedTypesAttr, types);
485	if (err == B_ENTRY_NOT_FOUND) {
486		// return an empty message
487		types->MakeEmpty();
488		err = B_OK;
489	}
490	if (err == B_OK) {
491		types->what = 0;
492		err = types->AddString("type", type);
493	}
494	return err;
495}
496
497
498//! Checks if the given MIME type is present in the database
499bool
500is_installed(const char *type)
501{
502	BNode node;
503	return open_type(type, &node) == B_OK;
504}
505
506
507/*! \brief Returns properly formatted raw bitmap data, ready to be shipped off
508	to the hacked up 4-parameter version of Database::SetIcon()
509
510	This function exists as something of a hack until an OBOS::BBitmap
511	implementation is available. It takes the given bitmap, converts it to the
512	B_CMAP8 color space if necessary and able, and returns said bitmap data in
513	a newly allocated array pointed to by the pointer that's pointed to by
514	\c data. The length of the array is stored in the integer pointed to by
515	\c dataSize. The array is allocated with \c new[], and it's your
516	responsibility to \c delete[] it when you're finished.
517*/
518status_t
519get_icon_data(const BBitmap *icon, icon_size which, void **data,
520	int32 *dataSize)
521{
522	if (icon == NULL || data == NULL || dataSize == 0
523		|| icon->InitCheck() != B_OK)
524		return B_BAD_VALUE;
525
526	BRect bounds;
527	BBitmap *icon8 = NULL;
528	void *srcData = NULL;
529	bool otherColorSpace = false;
530
531	// Figure out what kind of data we *should* have
532	switch (which) {
533		case B_MINI_ICON:
534			bounds.Set(0, 0, 15, 15);
535			break;
536		case B_LARGE_ICON:
537			bounds.Set(0, 0, 31, 31);
538			break;
539		default:
540			return B_BAD_VALUE;
541	}
542
543	// Check the icon
544	status_t err = icon->Bounds() == bounds ? B_OK : B_BAD_VALUE;
545
546	// Convert to B_CMAP8 if necessary
547	if (!err) {
548		otherColorSpace = (icon->ColorSpace() != B_CMAP8);
549		if (otherColorSpace) {
550			icon8 = new(std::nothrow) BBitmap(bounds, B_BITMAP_NO_SERVER_LINK,
551				B_CMAP8);
552			if (!icon8)
553				err = B_NO_MEMORY;
554			if (!err)
555				err = icon8->ImportBits(icon);
556			if (!err) {
557				srcData = icon8->Bits();
558				*dataSize = icon8->BitsLength();
559			}
560		} else {
561			srcData = icon->Bits();
562			*dataSize = icon->BitsLength();
563		}
564	}
565
566	// Alloc a new data buffer
567	if (!err) {
568		*data = new(std::nothrow) char[*dataSize];
569		if (!*data)
570			err = B_NO_MEMORY;
571	}
572
573	// Copy the data into it.
574	if (!err)
575		memcpy(*data, srcData, *dataSize);
576	if (otherColorSpace)
577		delete icon8;
578	return err;
579}
580
581} // namespace Mime
582} // namespace Storage
583} // namespace BPrivate
584
585