xref: /haiku/src/kits/storage/mime/database_support.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 /*!
6 	\file database_support.cpp
7 	Private mime database functions and constants
8 */
9 
10 #include <DataIO.h>
11 #include <Directory.h>
12 #include <Entry.h>
13 #include <Message.h>
14 #include <Node.h>
15 #include <Path.h>
16 #include <storage_support.h>
17 #include <TypeConstants.h>
18 
19 #include <fs_attr.h>	// For struct attr_info
20 #include <new>			// For new(nothrow)
21 #include <stdio.h>
22 #include <string>
23 
24 #include "mime/database_support.h"
25 
26 //#define DBG(x) x
27 #define DBG(x)
28 #define OUT printf
29 
30 // icon types (which really ought to be publicly or semi-publicly declared somewhere...)
31 enum {
32 	B_MINI_ICON_TYPE	= 'MICN',
33 	B_LARGE_ICON_TYPE	= 'ICON',
34 };
35 
36 namespace BPrivate {
37 namespace Storage {
38 namespace Mime {
39 
40 //const std::string kDatabaseDir					= "/boot/home/config/settings/beos_mime";
41 const std::string kDatabaseDir 					= "/boot/home/config/settings/obos_mime";
42 const std::string kApplicationDatabaseDir		= kDatabaseDir + "/application";
43 
44 #define ATTR_PREFIX "META:"
45 #define MINI_ICON_ATTR_PREFIX ATTR_PREFIX "M:"
46 #define LARGE_ICON_ATTR_PREFIX ATTR_PREFIX "L:"
47 
48 const char *kMiniIconAttrPrefix		= MINI_ICON_ATTR_PREFIX;
49 const char *kLargeIconAttrPrefix	= LARGE_ICON_ATTR_PREFIX;
50 
51 // attribute names
52 const char *kFileTypeAttr			= "BEOS:TYPE";
53 const char *kTypeAttr				= ATTR_PREFIX "TYPE";
54 const char *kAppHintAttr			= ATTR_PREFIX "PPATH";
55 const char *kAttrInfoAttr			= ATTR_PREFIX "ATTR_INFO";
56 const char *kShortDescriptionAttr	= ATTR_PREFIX "S:DESC";
57 const char *kLongDescriptionAttr	= ATTR_PREFIX "L:DESC";
58 const char *kFileExtensionsAttr		= ATTR_PREFIX "EXTENS";
59 const char *kMiniIconAttr			= MINI_ICON_ATTR_PREFIX "STD_ICON";
60 const char *kLargeIconAttr			= LARGE_ICON_ATTR_PREFIX "STD_ICON";
61 const char *kPreferredAppAttr		= ATTR_PREFIX "PREF_APP";
62 const char *kSnifferRuleAttr		= ATTR_PREFIX "SNIFF_RULE";
63 const char *kSupportedTypesAttr		= ATTR_PREFIX "FILE_TYPES";
64 
65 // attribute data types (as used in the R5 database)
66 const int32 kFileTypeType			= 'MIMS';	// B_MIME_STRING_TYPE
67 const int32 kTypeType				= B_STRING_TYPE;
68 const int32 kAppHintType			= 'MPTH';
69 const int32 kAttrInfoType			= B_MESSAGE_TYPE;
70 const int32 kShortDescriptionType	= 'MSDC';
71 const int32 kLongDescriptionType	= 'MLDC';
72 const int32 kFileExtensionsType		= B_MESSAGE_TYPE;
73 const int32 kMiniIconType			= B_MINI_ICON_TYPE;
74 const int32 kLargeIconType			= B_LARGE_ICON_TYPE;
75 const int32 kPreferredAppType		= 'MSIG';
76 const int32 kSnifferRuleType		= B_STRING_TYPE;
77 const int32 kSupportedTypesType		= B_MESSAGE_TYPE;
78 
79 // Message fields
80 const char *kApplicationsField				= "applications";
81 const char *kExtensionsField				= "extensions";
82 const char *kSupertypesField				= "super_types";
83 const char *kSupportingAppsSubCountField	= "be:sub";
84 const char *kSupportingAppsSuperCountField	= "be:super";
85 const char *kTypesField						= "types";
86 
87 // Mime types
88 const char *kGenericFileType	= "application/octet-stream";
89 const char *kDirectoryType		= "application/x-vnd.Be-directory";
90 const char *kSymlinkType		= "application/x-vnd.Be-symlink";
91 const char *kMetaMimeType		= "application/x-vnd.Be-meta-mime";
92 
93 // Error codes
94 const status_t kMimeGuessFailureError	= B_ERRORS_END+1;
95 
96 // type_to_filename
97 //! Converts the given MIME type to an absolute path in the MIME database.
98 std::string
99 type_to_filename(const char *type)
100 {
101 	return kDatabaseDir + "/" + BPrivate::Storage::to_lower(type);
102 }
103 
104 // open_type
105 /*! \brief Opens a BNode on the given type, failing if the type has no
106            corresponding file in the database.
107 	\param type The MIME type to open
108 	\param result Pointer to a pre-allocated BNode into which
109 	              is opened on the given MIME type
110 */
111 status_t
112 open_type(const char *type, BNode *result)
113 {
114 	status_t err = (type && result ? B_OK : B_BAD_VALUE);
115 	if (!err)
116 		err = result->SetTo(type_to_filename(type).c_str());
117 	return err;
118 }
119 
120 // open_or_create_type
121 /*! \brief Opens a BNode on the given type, creating a node of the
122 	       appropriate flavor if necessary.
123 
124 	All MIME types are converted to lowercase for use in the filesystem.
125 	\param type The MIME type to open
126 	\param result Pointer to a pre-allocated BNode into which
127 	              is opened on the given MIME type
128 */
129 status_t
130 open_or_create_type(const char *type, BNode *result, bool *didCreate)
131 {
132 	if (didCreate)
133 		*didCreate = false;
134 	std::string filename;
135 	std::string typeLower = BPrivate::Storage::to_lower(type);
136 	status_t err = (type && result ? B_OK : B_BAD_VALUE);
137 	if (!err) {
138 		filename = type_to_filename(type);
139 		err = result->SetTo(filename.c_str());
140 	}
141 	if (err == B_ENTRY_NOT_FOUND) {
142 		// Figure out what type of node we need to create
143 		// + Supertype == directory
144 		// + Non-supertype == file
145 		uint32 pos = typeLower.find_first_of('/');
146 		if (pos == std::string::npos) {
147 			// Supertype == directory
148 			BDirectory parent(kDatabaseDir.c_str());
149 			err = parent.InitCheck();
150 			if (!err)
151 				err = parent.CreateDirectory(typeLower.c_str(), NULL);
152 		} else {
153 			// Non-supertype == file
154 			std::string super(typeLower, 0, pos);
155 			std::string sub(typeLower, pos+1);
156 			BDirectory parent((kDatabaseDir + "/" + super).c_str());
157 			err = parent.InitCheck();
158 			if (!err)
159 				err = parent.CreateFile(sub.c_str(), NULL);
160 		}
161 		// Now try opening again
162 		err = result->SetTo(filename.c_str());
163 		if (!err && didCreate)
164 			*didCreate = true;
165 	}
166 	return err;
167 }
168 
169 // read_mime_attr
170 /*! \brief Reads up to \c len bytes of the given data from the given attribute
171 	       for the given MIME type.
172 
173 	If no entry for the given type exists in the database, the function fails,
174 	and the contents of \c data are undefined.
175 
176 	\param type The MIME type
177 	\param attr The attribute name
178 	\param data Pointer to a memory buffer into which the data should be copied
179 	\param len The maximum number of bytes to read
180 	\param datatype The expected data type
181 	\return If successful, the number of bytes read is returned, otherwise, an
182 	        error code is returned.
183 */
184 ssize_t
185 read_mime_attr(const char *type, const char *attr, void *data,
186 	size_t len, type_code datatype)
187 {
188 	BNode node;
189 	ssize_t err = (type && attr && data ? B_OK : B_BAD_VALUE);
190 	if (!err)
191 		err = open_type(type, &node);
192 	if (!err)
193 		err = node.ReadAttr(attr, datatype, 0, data, len);
194 	return err;
195 }
196 
197 // read_mime_attr_message
198 /*! \brief Reads a flattened BMessage from the given attribute of the given
199 	MIME type.
200 
201 	If no entry for the given type exists in the database, or if the data
202 	stored in the attribute is not a flattened BMessage, the function fails
203 	and the contents of \c msg are undefined.
204 
205 	\param type The MIME type
206 	\param attr The attribute name
207 	\param data Pointer to a pre-allocated BMessage into which the attribute
208 			    data is unflattened.
209 */
210 status_t
211 read_mime_attr_message(const char *type, const char *attr, BMessage *msg)
212 {
213 	BNode node;
214 	attr_info info;
215 	char *buffer = NULL;
216 	ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE);
217 	if (!err)
218 		err = open_type(type, &node);
219 	if (!err)
220 		err = node.GetAttrInfo(attr, &info);
221 	if (!err)
222 		err = info.type == B_MESSAGE_TYPE ? B_OK : B_BAD_VALUE;
223 	if (!err) {
224 		buffer = new(std::nothrow) char[info.size];
225 		if (!buffer)
226 			err = B_NO_MEMORY;
227 	}
228 	if (!err)
229 		err = node.ReadAttr(attr, B_MESSAGE_TYPE, 0, buffer, info.size);
230 	if (err >= 0)
231 		err = err == info.size ? (status_t)B_OK : (status_t)B_FILE_ERROR;
232 	if (!err)
233 		err = msg->Unflatten(buffer);
234 	delete [] buffer;
235 	return err;
236 }
237 
238 // read_mime_attr_string
239 /*! \brief Reads a BString from the given attribute of the given
240 	MIME type.
241 
242 	If no entry for the given type exists in the database, the function fails
243 	and the contents of \c str are undefined.
244 
245 	\param type The MIME type
246 	\param attr The attribute name
247 	\param str Pointer to a pre-allocated BString into which the attribute
248 			   data stored.
249 */
250 status_t
251 read_mime_attr_string(const char *type, const char *attr, BString *str)
252 {
253 	BNode node;
254 	status_t err = (type && attr && str ? B_OK : B_BAD_VALUE);
255 	if (!err)
256 		err = open_type(type, &node);
257 	if (!err)
258 		err = node.ReadAttrString(attr, str);
259 	return err;
260 }
261 
262 // write_mime_attr
263 /*! \brief Writes \c len bytes of the given data to the given attribute
264 	       for the given MIME type.
265 
266 	If no entry for the given type exists in the database, it is created.
267 
268 	\param type The MIME type
269 	\param attr The attribute name
270 	\param data Pointer to the data to write
271 	\param len The number of bytes to write
272 	\param datatype The data type of the given data
273 */
274 status_t
275 write_mime_attr(const char *type, const char *attr, const void *data,
276 	size_t len, type_code datatype, bool *didCreate)
277 {
278 	BNode node;
279 	status_t err = (type && attr && data ? B_OK : B_BAD_VALUE);
280 	if (!err)
281 		err = open_or_create_type(type, &node, didCreate);
282 	if (!err) {
283 		ssize_t bytes = node.WriteAttr(attr, datatype, 0, data, len);
284 		if (bytes < B_OK)
285 			err = bytes;
286 		else
287 			err = (bytes != (ssize_t)len ? (status_t)B_FILE_ERROR : (status_t)B_OK);
288 	}
289 	return err;
290 }
291 
292 // write_mime_attr_message
293 /*! \brief Flattens the given \c BMessage and writes it to the given attribute
294 	       of the given MIME type.
295 
296 	If no entry for the given type exists in the database, it is created.
297 
298 	\param type The MIME type
299 	\param attr The attribute name
300 	\param msg The BMessage to flatten and write
301 */
302 status_t
303 write_mime_attr_message(const char *type, const char *attr, const BMessage *msg, bool *didCreate)
304 {
305 	BNode node;
306 	BMallocIO data;
307 	ssize_t bytes;
308 	ssize_t err = (type && attr && msg ? B_OK : B_BAD_VALUE);
309 	if (!err)
310 		err = data.SetSize(msg->FlattenedSize());
311 	if (!err)
312 		err = msg->Flatten(&data, &bytes);
313 	if (!err)
314 		err = bytes == msg->FlattenedSize() ? B_OK : B_ERROR;
315 	if (!err)
316 		err = open_or_create_type(type, &node, didCreate);
317 	if (!err)
318 		err = node.WriteAttr(attr, B_MESSAGE_TYPE, 0, data.Buffer(), data.BufferLength());
319 	if (err >= 0)
320 		err = err == (ssize_t)data.BufferLength() ? (ssize_t)B_OK : (ssize_t)B_FILE_ERROR;
321 	return err;
322 }
323 
324 // delete_attribute
325 //! Deletes the given attribute for the given type
326 /*!
327 	\param type The mime type
328 	\param attr The attribute name
329 	\return
330     - B_OK: success
331     - B_ENTRY_NOT_FOUND: no such type or attribute
332     - "error code": failure
333 */
334 status_t
335 delete_attribute(const char *type, const char *attr)
336 {
337 	status_t err = type ? B_OK : B_BAD_VALUE;
338 	BNode node;
339 	if (!err)
340 		err = open_type(type, &node);
341 	if (!err)
342 		err = node.RemoveAttr(attr);
343 	return err;
344 }
345 
346 
347 
348 } // namespace Mime
349 } // namespace Storage
350 } // namespace BPrivate
351 
352