blob: 618dbb58808c9048c4560b82ff65bf1ff38023e8 [file] [log] [blame]
Adrien Destugues374c6dc2015-01-11 16:37:56 +01001/*
2** Copyright 2009-2015 Adrien Destugues, pulkomandy@pulkomandy.tk.
3** Distributed under the terms of the MIT License.
4*/
5
6#include "AmigaCatalog.h"
7
8#include <iostream>
9#include <memory>
10#include <new>
11
12#include <Application.h>
13#include <Directory.h>
14#include <File.h>
15#include <FindDirectory.h>
16#include <fs_attr.h>
17#include <Mime.h>
18#include <Path.h>
19#include <Resources.h>
20#include <Roster.h>
21#include <StackOrHeapArray.h>
22#include <String.h>
23
24#include <LocaleRoster.h>
25#include <Catalog.h>
26
27
28class BMessage;
29
30
31using BPrivate::HashMapCatalog;
32using BPrivate::AmigaCatalog;
33
34
35/* This add-on implements reading of Amiga catalog files. These are IFF files
36 * of type CTLG and used to localize Amiga applications. In most cases you
37 * should use the Haiku standard catalogs instead, unless:
38 * - You are porting an application from Amiga and want to use the same locale
39 * files
40 * - You want to use ID-based string lookup instead of string-to-string, for
41 * performance reasons.
42 */
43
44
45static const char *kCatFolder = "Catalogs/";
46static const char *kCatExtension = ".catalog";
47
48const char *AmigaCatalog::kCatMimeType
49 = "locale/x-vnd.Be.locale-catalog.amiga";
50
51static int16 kCatArchiveVersion = 1;
52 // version of the catalog archive structure, bump this if you change it!
53
54
55/*
56 * constructs a AmigaCatalog with given signature and language and reads
57 * the catalog from disk.
58 * InitCheck() will be B_OK if catalog could be loaded successfully, it will
59 * give an appropriate error-code otherwise.
60 */
61AmigaCatalog::AmigaCatalog(const char *signature, const char *language,
62 uint32 fingerprint)
63 :
64 HashMapCatalog(signature, language, fingerprint)
65{
66 // give highest priority to catalog living in sub-folder of app's folder:
67 app_info appInfo;
68 be_app->GetAppInfo(&appInfo);
69 node_ref nref;
70 nref.device = appInfo.ref.device;
71 nref.node = appInfo.ref.directory;
72 BDirectory appDir(&nref);
73 BString catalogName(kCatFolder);
74 catalogName << fLanguageName
75 << "/" << fSignature
76 << kCatExtension;
77 BPath catalogPath(&appDir, catalogName.String());
78 status_t status = ReadFromFile(catalogPath.Path());
79
80 if (status != B_OK) {
81 // look in common-etc folder (/boot/home/config/etc):
82 BPath commonEtcPath;
83 find_directory(B_USER_ETC_DIRECTORY, &commonEtcPath);
84 if (commonEtcPath.InitCheck() == B_OK) {
85 catalogName = BString(commonEtcPath.Path())
86 << kCatFolder << fLanguageName
87 << "/" << fSignature
88 << kCatExtension;
89 status = ReadFromFile(catalogName.String());
90 }
91 }
92
93 if (status != B_OK) {
94 // look in system-etc folder (/boot/beos/etc):
95 BPath systemEtcPath;
96 find_directory(B_SYSTEM_ETC_DIRECTORY, &systemEtcPath);
97 if (systemEtcPath.InitCheck() == B_OK) {
98 catalogName = BString(systemEtcPath.Path())
99 << kCatFolder << fLanguageName
100 << "/" << fSignature
101 << kCatExtension;
102 status = ReadFromFile(catalogName.String());
103 }
104 }
105
106 fInitCheck = status;
107}
108
109
110/*
111 * constructs an empty AmigaCatalog with given sig and language.
112 * This is used for editing/testing purposes.
113 * InitCheck() will always be B_OK.
114 */
115AmigaCatalog::AmigaCatalog(const char *path, const char *signature,
116 const char *language)
117 :
118 HashMapCatalog(signature, language, 0),
119 fPath(path)
120{
121 fInitCheck = B_OK;
122}
123
124
125AmigaCatalog::~AmigaCatalog()
126{
127}
128
129
130status_t
131AmigaCatalog::ReadFromFile(const char *path)
132{
133 if (!path)
134 path = fPath.String();
135
136 BFile source(path, B_READ_ONLY);
137 if (source.InitCheck() != B_OK)
138 return source.InitCheck();
139
140 // Now read all the data from the file
141
142 int32 tmp;
143 source.Read(&tmp, sizeof(tmp)); // IFF header
144 if (ntohl(tmp) != 'FORM')
145 return B_BAD_DATA;
146
147 int32 dataSize;
148 source.Read(&dataSize, sizeof(dataSize)); // File size
149 dataSize = ntohl(dataSize);
150 source.Read(&tmp, sizeof(tmp)); // File type
151 if (ntohl(tmp) != 'CTLG')
152 return B_BAD_DATA;
153
154 dataSize -= 4; // Type is included in data size.
155
156 while(dataSize > 0) {
157 int32 chunkID, chunkSize;
158 source.Read(&chunkID, sizeof(chunkID));
159 source.Read(&chunkSize, sizeof(chunkSize));
160 chunkSize = ntohl(chunkSize);
161
162 // Round to word
163 if (chunkSize & 1) chunkSize++;
164
165 BStackOrHeapArray<char, 256> chunkData(chunkSize);
166 source.Read(chunkData, chunkSize);
167
168 chunkID = ntohl(chunkID);
169
170 switch(chunkID) {
171 case 'FVER': // Version
172 fSignature = chunkData;
173 break;
174 case 'LANG': // Language
175 fLanguageName = chunkData;
176 break;
177
178 case 'STRS': // Catalog strings
179 {
180 BMemoryIO strings(chunkData, chunkSize);
181 int32 strID, strLen;
182 puts("");
183
184 while (strings.Position() < chunkSize) {
185 strings.Read(&strID, sizeof(strID));
186 strings.Read(&strLen, sizeof(strLen));
187 strID = ntohl(strID);
188 strLen = ntohl(strLen);
189 if (strLen & 3) {
190 strLen &= ~3;
191 strLen += 4;
192 }
193 char strVal[strLen];
194 strings.Read(strVal, strLen);
195
196 SetString(strID, strVal);
197 }
198 break;
199 }
200
201 case 'CSET': // Unknown/unused
202 default:
203 break;
204 }
205
206 dataSize -= chunkSize + 8;
207 }
208
209 fPath = path;
210 fFingerprint = ComputeFingerprint();
211 return B_OK;
212}
213
214
215status_t
216AmigaCatalog::WriteToFile(const char *path)
217{
218 return B_NOT_SUPPORTED;
219}
220
221
222/*
223 * writes mimetype, language-name and signature of catalog into the
224 * catalog-file.
225 */
226void
227AmigaCatalog::UpdateAttributes(BFile& catalogFile)
228{
229 static const int bufSize = 256;
230 char buf[bufSize];
231 uint32 temp;
232 if (catalogFile.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, &buf, bufSize)
233 <= 0
234 || strcmp(kCatMimeType, buf) != 0) {
235 catalogFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0,
236 kCatMimeType, strlen(kCatMimeType)+1);
237 }
238 if (catalogFile.ReadAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0,
239 &buf, bufSize) <= 0
240 || fLanguageName != buf) {
241 catalogFile.WriteAttr(BLocaleRoster::kCatLangAttr, B_STRING_TYPE, 0,
242 fLanguageName.String(), fLanguageName.Length()+1);
243 }
244 if (catalogFile.ReadAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0,
245 &buf, bufSize) <= 0
246 || fSignature != buf) {
247 catalogFile.WriteAttr(BLocaleRoster::kCatSigAttr, B_STRING_TYPE, 0,
248 fSignature.String(), fSignature.Length()+1);
249 }
250 if (catalogFile.ReadAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE,
251 0, &temp, sizeof(uint32)) <= 0) {
252 catalogFile.WriteAttr(BLocaleRoster::kCatFingerprintAttr, B_UINT32_TYPE,
253 0, &fFingerprint, sizeof(uint32));
254 }
255}
256
257
258void
259AmigaCatalog::UpdateAttributes(const char* path)
260{
261 BEntry entry(path);
262 BFile node(&entry, B_READ_WRITE);
263 UpdateAttributes(node);
264}
265
266
267BCatalogData *
268AmigaCatalog::Instantiate(const char *signature, const char *language,
269 uint32 fingerprint)
270{
271 AmigaCatalog *catalog
272 = new(std::nothrow) AmigaCatalog(signature, language, fingerprint);
273 if (catalog && catalog->InitCheck() != B_OK) {
274 delete catalog;
275 return NULL;
276 }
277 return catalog;
278}
279
280
281extern "C" BCatalogData *
282instantiate_catalog(const char *signature, const char *language,
283 uint32 fingerprint)
284{
285 AmigaCatalog *catalog
286 = new(std::nothrow) AmigaCatalog(signature, language, fingerprint);
287 if (catalog && catalog->InitCheck() != B_OK) {
288 delete catalog;
289 return NULL;
290 }
291 return catalog;
292}
293
294
295extern "C" BCatalogData *
296create_catalog(const char *signature, const char *language)
297{
298 AmigaCatalog *catalog
299 = new(std::nothrow) AmigaCatalog("emptycat", signature, language);
300 return catalog;
301}
302
303
304extern "C" status_t
305get_available_languages(BMessage* availableLanguages,
306 const char* sigPattern = NULL, const char* langPattern = NULL,
307 int32 fingerprint = 0)
308{
309 // TODO
310 return B_ERROR;
311}
312
313
314uint8 gCatalogAddOnPriority = 80;