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