vfs: check userland buffers before reading them.
[haiku.git] / src / kits / storage / mime / SupportingApps.cpp
blob495f06e1824b1dff25ae2c13c4d3b8717f9ead6d
1 /*
2 * Copyright 2002-2006, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Tyler Dauwalder
7 * Ingo Weinhold, bonefish@users.sf.net
8 * Axel Dörfler, axeld@pinc-software.de
9 */
12 #include <mime/SupportingApps.h>
14 #include <stdio.h>
16 #include <new>
17 #include <iostream>
19 #include <Directory.h>
20 #include <Message.h>
21 #include <MimeType.h>
22 #include <Path.h>
23 #include <String.h>
25 #include <mime/database_support.h>
26 #include <mime/DatabaseDirectory.h>
27 #include <mime/DatabaseLocation.h>
28 #include <storage_support.h>
31 #define DBG(x) x
32 //#define DBG(x)
33 #define OUT printf
35 namespace BPrivate {
36 namespace Storage {
37 namespace Mime {
39 /*!
40 \class SupportingApps
41 \brief Supporting apps information for the entire database
44 // Constructor
45 //! Constructs a new SupportingApps object
46 SupportingApps::SupportingApps(DatabaseLocation* databaseLocation)
48 fDatabaseLocation(databaseLocation),
49 fHaveDoneFullBuild(false)
53 // Destructor
54 //! Destroys the SupportingApps object
55 SupportingApps::~SupportingApps()
59 // GetSupportingApps
60 /*! \brief Returns a list of signatures of supporting applications for the
61 given type in the pre-allocated \c BMessage pointed to by \c apps.
63 See \c BMimeType::GetSupportingApps() for more information.
65 status_t
66 SupportingApps::GetSupportingApps(const char *type, BMessage *apps)
68 status_t err = type && apps ? B_OK : B_BAD_VALUE;
69 // See if we need to do our initial build still
70 if (!err && !fHaveDoneFullBuild)
71 err = BuildSupportingAppsTable();
73 if (!err) {
74 // Clear the message, as we're just going to add to it
75 apps->MakeEmpty();
77 BMimeType mime(type);
78 err = mime.InitCheck();
79 if (!err) {
80 if (mime.IsSupertypeOnly()) {
81 // Add the apps that support this supertype (plus their count)
82 std::set<std::string> &superApps = fSupportingApps[type];
83 int32 count = 0;
84 std::set<std::string>::const_iterator i;
85 for (i = superApps.begin(); i != superApps.end() && !err; i++) {
86 err = apps->AddString(kApplicationsField, (*i).c_str());
87 count++;
89 if (!err)
90 err = apps->AddInt32(kSupportingAppsSuperCountField, count);
91 } else {
92 // Add the apps that support this subtype (plus their count)
93 std::set<std::string> &subApps = fSupportingApps[type];
94 int32 count = 0;
95 std::set<std::string>::const_iterator i;
96 for (i = subApps.begin(); i != subApps.end() && !err; i++) {
97 err = apps->AddString(kApplicationsField, (*i).c_str());
98 count++;
100 if (!err)
101 err = apps->AddInt32(kSupportingAppsSubCountField, count);
103 // Now add any apps that support the supertype, but not the
104 // subtype (plus their count).
105 BMimeType superMime;
106 err = mime.GetSupertype(&superMime);
107 if (!err)
108 err = superMime.InitCheck();
109 if (!err) {
110 std::set<std::string> &superApps = fSupportingApps[superMime.Type()];
111 count = 0;
112 for (i = superApps.begin(); i != superApps.end() && !err; i++) {
113 if (subApps.find(*i) == subApps.end()) {
114 err = apps->AddString(kApplicationsField, (*i).c_str());
115 count++;
118 if (!err)
119 err = apps->AddInt32(kSupportingAppsSuperCountField, count);
124 return err;
127 // SetSupportedTypes
128 /*! \brief Sets the list of supported types for the given application and
129 updates the supporting apps mappings.
131 All types listed as being supported types will including the given
132 app signature in their list of supporting apps following this call.
134 If \a fullSync is true, all types previously but no longer supported
135 by this application with no longer list this application as a
136 supporting app.
138 If \a fullSync is false, said previously supported types will be
139 saved to a "stranded types" mapping and appropriately synchronized
140 the next time SetSupportedTypes() is called with a \c true \a fullSync
141 parameter.
143 The stranded types mapping is properly maintained even in the event
144 of types being removed and then re-added to the list of supporting
145 types with consecutive \c false \a fullSync parameters.
147 \param app The application whose supported types you are setting
148 \param types Pointer to a \c BMessage containing an array of supported
149 mime types in its \c Mime::kTypesField field.
150 \param fullSync If \c true, \c app is removed as a supporting application
151 for any types for which it is no longer a supporting application
152 (including types which were removed as supporting types with
153 previous callsto SetSupportedTypes(..., false)). If \c false,
154 said mappings are not updated until the next SetSupportedTypes(..., true)
155 call.
157 status_t
158 SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool fullSync)
160 status_t err = app && types ? B_OK : B_BAD_VALUE;
161 if (!fHaveDoneFullBuild)
162 return err;
164 std::set<std::string> oldTypes;
165 std::set<std::string> &newTypes = fSupportedTypes[app];
166 std::set<std::string> &strandedTypes = fStrandedTypes[app];
167 // Make a copy of the previous types if we're doing a full sync
168 if (!err) {
169 oldTypes = newTypes;
171 // Read through the list of new supported types, creating the new
172 // supported types list and adding the app as a supporting app for
173 // each type.
174 newTypes.clear();
175 const char *type;
176 for (int32 i = 0; types->FindString(kTypesField, i, &type) == B_OK;
177 i++) {
178 newTypes.insert(type);
179 AddSupportingApp(type, app);
182 // Update the list of stranded types by removing any types that are newly
183 // re-supported and adding any types that are newly un-supported
184 for (std::set<std::string>::const_iterator i = newTypes.begin();
185 i != newTypes.end(); i++) {
186 strandedTypes.erase(*i);
188 for (std::set<std::string>::const_iterator i = oldTypes.begin();
189 i != oldTypes.end(); i++) {
190 if (newTypes.find(*i) == newTypes.end())
191 strandedTypes.insert(*i);
194 // Now, if we're doing a full sync, remove the app as a supporting
195 // app for any of its stranded types and then clear said list of
196 // stranded types.
197 if (fullSync) {
198 for (std::set<std::string>::const_iterator i = strandedTypes.begin();
199 i != strandedTypes.end(); i++) {
200 RemoveSupportingApp((*i).c_str(), app);
202 strandedTypes.clear();
205 return err;
209 /*! \brief Clears the given application's supported types list and optionally
210 removes the application from each of said types' supporting apps list.
211 \param app The application whose supported types you are clearing
212 \param fullSync See SupportingApps::SetSupportedTypes()
214 status_t
215 SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync)
217 BMessage types;
218 return SetSupportedTypes(app, &types, fullSync);
221 // AddSupportingApp
222 /*! \brief Adds the given application signature to the set of supporting
223 apps for the given type.
225 \param type The full mime type
226 \param app The full application signature (i.e. "application/app-subtype")
227 \return
228 - B_OK: success, even if the app was already in the supporting apps list
229 - "error code": failure
231 status_t
232 SupportingApps::AddSupportingApp(const char *type, const char *app)
234 status_t err = type && app ? B_OK : B_BAD_VALUE;
235 if (!err)
236 fSupportingApps[type].insert(app);
237 return err;
240 // RemoveSupportingApp
241 /*! \brief Removes the given application signature from the set of supporting
242 apps for the given type.
244 \param type The full mime type
245 \param app The full application signature (i.e. "application/app-subtype")
246 \return
247 - B_OK: success, even if the app was not found in the supporting apps list
248 - "error code": failure
250 status_t
251 SupportingApps::RemoveSupportingApp(const char *type, const char *app)
253 status_t err = type && app ? B_OK : B_BAD_VALUE;
254 if (!err)
255 fSupportingApps[type].erase(app);
256 return err;
259 // BuildSupportingAppsTable
260 /*! \brief Crawls the mime database and builds a list of supporting application
261 signatures for every supported type.
263 status_t
264 SupportingApps::BuildSupportingAppsTable()
266 fSupportedTypes.clear();
267 fSupportingApps.clear();
268 fStrandedTypes.clear();
270 DatabaseDirectory dir;
271 status_t status = dir.Init(fDatabaseLocation, "application");
273 // Build the supporting apps table based on the mime database
274 if (status == B_OK) {
275 dir.Rewind();
277 // Handle each application type
278 while (true) {
279 entry_ref ref;
280 status = dir.GetNextRef(&ref);
281 if (status < B_OK) {
282 // If we've come to the end of list, it's not an error
283 if (status == B_ENTRY_NOT_FOUND)
284 status = B_OK;
285 break;
288 // read application signature from file
289 BString appSignature;
290 BNode node(&ref);
291 if (node.InitCheck() == B_OK && node.ReadAttrString(kTypeAttr,
292 &appSignature) >= B_OK) {
293 // Read in the list of supported types
294 BMessage msg;
295 if (fDatabaseLocation->ReadMessageAttribute(appSignature,
296 kSupportedTypesAttr, msg) == B_OK) {
297 // Iterate through the supported types, adding them to the list of
298 // supported types for the application and adding the application's
299 // signature to the list of supporting apps for each type
300 BString type;
301 std::set<std::string> &supportedTypes = fSupportedTypes[appSignature.String()];
302 for (int i = 0; msg.FindString(kTypesField, i, &type) == B_OK; i++) {
303 type.ToLower();
304 // MIME types are case insensitive, so we lowercase everything
305 supportedTypes.insert(type.String());
306 AddSupportingApp(type.String(), appSignature.String());
313 if (status == B_OK)
314 fHaveDoneFullBuild = true;
315 else
316 DBG(OUT("SupportingApps::BuildSupportingAppsTable() failed: %s\n", strerror(status)));
318 return status;
321 } // namespace Mime
322 } // namespace Storage
323 } // namespace BPrivate