xref: /haiku/src/kits/storage/mime/MimeInfoUpdater.cpp (revision 040a81419dda83d1014e9dc94936a4cb3f027303)
1 /*
2  * Copyright 2002-2013, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Tyler Dauwalder
7  *		Jonas Sundström, jonas@kirilla.com
8  *		Michael Lotz, mmlr@mlotz.ch
9  *		Ingo Weinhold, ingo_weinhold@gmx.de
10  */
11 
12 
13 #include <mime/MimeInfoUpdater.h>
14 
15 #include <stdlib.h>
16 
17 #include <AppFileInfo.h>
18 #include <Bitmap.h>
19 #include <File.h>
20 #include <fs_attr.h>
21 #include <MimeType.h>
22 #include <String.h>
23 
24 #include <AutoLocker.h>
25 #include <mime/Database.h>
26 #include <mime/database_support.h>
27 
28 
29 static const char *kAppFlagsAttribute = "BEOS:APP_FLAGS";
30 
31 
32 static status_t
33 update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite,
34 	const char *type, BBitmap &icon, icon_size iconSize)
35 {
36 	status_t err = appFileInfoRead.GetIconForType(type, &icon, iconSize);
37 	if (err == B_OK)
38 		err = appFileInfoWrite.SetIconForType(type, &icon, iconSize);
39 	else if (err == B_ENTRY_NOT_FOUND)
40 		err = appFileInfoWrite.SetIconForType(type, NULL, iconSize);
41 	return err;
42 }
43 
44 
45 static status_t
46 update_icon(BAppFileInfo &appFileInfoRead, BAppFileInfo &appFileInfoWrite,
47 	const char *type)
48 {
49 	uint8* data = NULL;
50 	size_t size = 0;
51 
52 	status_t err = appFileInfoRead.GetIconForType(type, &data, &size);
53 	if (err == B_OK)
54 		err = appFileInfoWrite.SetIconForType(type, data, size);
55 	else if (err == B_ENTRY_NOT_FOUND)
56 		err = appFileInfoWrite.SetIconForType(type, NULL, size);
57 
58 	free(data);
59 
60 	return err;
61 }
62 
63 
64 static bool
65 is_shared_object_mime_type(const BString &type)
66 {
67 	return type.ICompare(B_APP_MIME_TYPE) == 0;
68 }
69 
70 
71 namespace BPrivate {
72 namespace Storage {
73 namespace Mime {
74 
75 
76 MimeInfoUpdater::MimeInfoUpdater(Database* database,
77 	DatabaseLocker* databaseLocker, int32 force)
78 	:
79 	MimeEntryProcessor(database, databaseLocker, force)
80 {
81 }
82 
83 
84 MimeInfoUpdater::~MimeInfoUpdater()
85 {
86 }
87 
88 
89 status_t
90 MimeInfoUpdater::Do(const entry_ref& entry, bool* _entryIsDir)
91 {
92 	bool updateType = false;
93 	bool updateAppInfo = false;
94 	BNode node;
95 
96 	status_t err = node.SetTo(&entry);
97 	if (!err && _entryIsDir)
98 		*_entryIsDir = node.IsDirectory();
99 	if (!err) {
100 		// If not forced, only update if the entry has no file type attribute
101 		attr_info info;
102 		if (fForce == B_UPDATE_MIME_INFO_FORCE_UPDATE_ALL
103 			|| node.GetAttrInfo(kFileTypeAttr, &info) == B_ENTRY_NOT_FOUND) {
104 			updateType = true;
105 		}
106 		updateAppInfo = (updateType
107 			|| fForce == B_UPDATE_MIME_INFO_FORCE_KEEP_TYPE);
108 	}
109 
110 	// guess the MIME type
111 	BString type;
112 	if (!err && (updateType || updateAppInfo)) {
113 		AutoLocker<DatabaseLocker> databaseLocker(fDatabaseLocker);
114 		err = fDatabase->GuessMimeType(&entry, &type);
115 	}
116 
117 	// update the MIME type
118 	if (!err && updateType) {
119 		ssize_t len = type.Length() + 1;
120 		ssize_t bytes = node.WriteAttr(kFileTypeAttr, kFileTypeType, 0, type,
121 			len);
122 		if (bytes < B_OK)
123 			err = bytes;
124 		else
125 			err = (bytes != len ? (status_t)B_FILE_ERROR : (status_t)B_OK);
126 	}
127 
128 	// update the app file info attributes, if this is a shared object
129 	BFile file;
130 	BAppFileInfo appFileInfoRead;
131 	BAppFileInfo appFileInfoWrite;
132 	if (!err && updateAppInfo && node.IsFile()
133 		&& is_shared_object_mime_type(type)
134 		&& file.SetTo(&entry, B_READ_WRITE) == B_OK
135 		&& appFileInfoRead.SetTo(&file) == B_OK
136 		&& appFileInfoWrite.SetTo(&file) == B_OK) {
137 
138 		// we read from resources and write to attributes
139 		appFileInfoRead.SetInfoLocation(B_USE_RESOURCES);
140 		appFileInfoWrite.SetInfoLocation(B_USE_ATTRIBUTES);
141 
142 		// signature
143 		char signature[B_MIME_TYPE_LENGTH];
144 		err = appFileInfoRead.GetSignature(signature);
145 		if (err == B_OK)
146 			err = appFileInfoWrite.SetSignature(signature);
147 		else if (err == B_ENTRY_NOT_FOUND)
148 			err = appFileInfoWrite.SetSignature(NULL);
149 		if (err != B_OK)
150 			return err;
151 
152 		// catalog entry
153 		char catalogEntry[B_MIME_TYPE_LENGTH * 3];
154 		err = appFileInfoRead.GetCatalogEntry(catalogEntry);
155 		if (err == B_OK)
156 			err = appFileInfoWrite.SetCatalogEntry(catalogEntry);
157 		else if (err == B_ENTRY_NOT_FOUND)
158 			err = appFileInfoWrite.SetCatalogEntry(NULL);
159 		if (err != B_OK)
160 			return err;
161 
162 		// app flags
163 		uint32 appFlags;
164 		err = appFileInfoRead.GetAppFlags(&appFlags);
165 		if (err == B_OK) {
166 			err = appFileInfoWrite.SetAppFlags(appFlags);
167 		} else if (err == B_ENTRY_NOT_FOUND) {
168 			file.RemoveAttr(kAppFlagsAttribute);
169 			err = B_OK;
170 		}
171 		if (err != B_OK)
172 			return err;
173 
174 		// supported types
175 		BMessage supportedTypes;
176 		bool hasSupportedTypes = false;
177 		err = appFileInfoRead.GetSupportedTypes(&supportedTypes);
178 		if (err == B_OK) {
179 			err = appFileInfoWrite.SetSupportedTypes(&supportedTypes);
180 			hasSupportedTypes = true;
181 		} else if (err == B_ENTRY_NOT_FOUND)
182 			err = appFileInfoWrite.SetSupportedTypes(NULL);
183 		if (err != B_OK)
184 			return err;
185 
186 		// vector icon
187 		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL);
188 		if (err != B_OK)
189 			return err;
190 
191 		// small icon
192 		BBitmap smallIcon(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK,
193 			B_CMAP8);
194 		if (smallIcon.InitCheck() != B_OK)
195 			return smallIcon.InitCheck();
196 		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, smallIcon,
197 			B_MINI_ICON);
198 		if (err != B_OK)
199 			return err;
200 
201 		// large icon
202 		BBitmap largeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK,
203 			B_CMAP8);
204 		if (largeIcon.InitCheck() != B_OK)
205 			return largeIcon.InitCheck();
206 		err = update_icon(appFileInfoRead, appFileInfoWrite, NULL, largeIcon,
207 			B_LARGE_ICON);
208 		if (err != B_OK)
209 			return err;
210 
211 		// version infos
212 		const version_kind versionKinds[]
213 			= {B_APP_VERSION_KIND, B_SYSTEM_VERSION_KIND};
214 		for (int i = 0; i < 2; i++) {
215 			version_kind kind = versionKinds[i];
216 			version_info versionInfo;
217 			err = appFileInfoRead.GetVersionInfo(&versionInfo, kind);
218 			if (err == B_OK)
219 				err = appFileInfoWrite.SetVersionInfo(&versionInfo, kind);
220 			else if (err == B_ENTRY_NOT_FOUND)
221 				err = appFileInfoWrite.SetVersionInfo(NULL, kind);
222 			if (err != B_OK)
223 				return err;
224 		}
225 
226 		// icons for supported types
227 		if (hasSupportedTypes) {
228 			const char *supportedType;
229 			for (int32 i = 0;
230 				 supportedTypes.FindString("types", i, &supportedType) == B_OK;
231 				 i++) {
232 				// vector icon
233 				err = update_icon(appFileInfoRead, appFileInfoWrite,
234 					supportedType);
235 				if (err != B_OK)
236 					return err;
237 
238 				// small icon
239 				err = update_icon(appFileInfoRead, appFileInfoWrite,
240 					supportedType, smallIcon, B_MINI_ICON);
241 				if (err != B_OK)
242 					return err;
243 
244 				// large icon
245 				err = update_icon(appFileInfoRead, appFileInfoWrite,
246 					supportedType, largeIcon, B_LARGE_ICON);
247 				if (err != B_OK)
248 					return err;
249 			}
250 		}
251 	}
252 
253 	return err;
254 }
255 
256 
257 } // namespace Mime
258 } // namespace Storage
259 } // namespace BPrivate
260