HaikuDepot: notify work status from main window
[haiku.git] / src / tools / locale / PlainTextCatalog.cpp
blob6f89a374d9c2c6e1c29a3e429c3312ec92a1a0d6
1 /*
2 ** Copyright 2009 Adrien Destugues, pulkomandy@gmail.com. All rights reserved.
3 ** Distributed under the terms of the MIT License.
4 */
6 #include <PlainTextCatalog.h>
8 #include <assert.h>
9 #include <cstdio>
10 #include <iostream>
11 #include <fstream>
12 #include <memory>
13 #include <new>
14 #include <sstream>
15 #include <string>
17 #include <syslog.h>
19 #include <Application.h>
20 #include <Directory.h>
21 #include <File.h>
22 #include <FindDirectory.h>
23 #include <fs_attr.h>
24 #include <Message.h>
25 #include <Mime.h>
26 #include <Path.h>
27 #include <Resources.h>
28 #include <Roster.h>
29 #include <String.h>
31 #include <Catalog.h>
34 using BPrivate::PlainTextCatalog;
35 using std::auto_ptr;
36 using std::min;
37 using std::max;
38 using std::pair;
42 * This file implements the plain text catalog-type for the Haiku
43 * locale kit. It is not meant to be used in applications like other add ons,
44 * but only as a way to get an easy to translate file for developers.
48 namespace BPrivate {
51 const char *PlainTextCatalog::kCatMimeType
52 = "locale/x-vnd.Be.locale-catalog.plaintext";
54 static int16 kCatArchiveVersion = 1;
55 // version of the catalog archive structure, bump this if you change it!
58 // Note: \xNN is not replaced back, so you get the unescaped value in the catkey
59 // file. This is fine for regular unicode chars (B_UTF8_ELLIPSIS) but may be
60 // dangerous if you use \x10 as a newline...
61 void
62 escapeQuotedChars(BString& stringToEscape)
64 stringToEscape.ReplaceAll("\\", "\\\\");
65 stringToEscape.ReplaceAll("\n", "\\n");
66 stringToEscape.ReplaceAll("\t", "\\t");
67 stringToEscape.ReplaceAll("\"", "\\\"");
72 * constructs a PlainTextCatalog with given signature and language and reads
73 * the catalog from disk.
74 * InitCheck() will be B_OK if catalog could be loaded successfully, it will
75 * give an appropriate error-code otherwise.
77 PlainTextCatalog::PlainTextCatalog(const entry_ref &signature,
78 const char *language, uint32 fingerprint)
80 HashMapCatalog("", language, fingerprint)
82 // Look for the catalog in the directory we are going to use
83 // This constructor is not used so lets disable that...
85 fInitCheck = B_NOT_SUPPORTED;
86 fprintf(stderr,
87 "trying to load plaintext-catalog(lang=%s) results in %s\n",
88 language, strerror(fInitCheck));
93 * constructs an empty PlainTextCatalog with given sig and language.
94 * This is used for editing/testing purposes.
95 * InitCheck() will always be B_OK.
97 PlainTextCatalog::PlainTextCatalog(const char *path, const char *signature,
98 const char *language)
100 HashMapCatalog(signature, language, 0),
101 fPath(path)
103 fInitCheck = B_OK;
107 PlainTextCatalog::~PlainTextCatalog()
112 status_t
113 PlainTextCatalog::ReadFromFile(const char *path)
115 std::fstream catalogFile;
116 std::string currentItem;
118 if (!path)
119 path = fPath.String();
121 catalogFile.open(path, std::fstream::in);
122 if (!catalogFile.is_open()) {
123 fprintf(stderr, "couldn't open catalog at %s\n", path);
124 return B_ENTRY_NOT_FOUND;
127 // Now read all the data from the file
129 // The first line holds some info about the catalog :
130 // ArchiveVersion \t LanguageName \t AppSignature \t FingerPrint
131 if (std::getline(catalogFile, currentItem, '\t').good()) {
132 // Get the archive version
133 int arcver= -1;
134 std::istringstream ss(currentItem);
135 ss >> arcver;
136 if (ss.fail()) {
137 // can't convert to int
138 fprintf(stderr,
139 "Unable to extract archive version ( string: %s ) from %s\n",
140 currentItem.c_str(), path);
141 return B_ERROR;
144 if (arcver != kCatArchiveVersion) {
145 // wrong version
146 fprintf(stderr,
147 "Wrong archive version ! Got %d instead of %d from %s\n", arcver,
148 kCatArchiveVersion, path);
149 return B_ERROR;
151 } else {
152 fprintf(stderr, "Unable to read from catalog %s\n", path);
153 return B_ERROR;
156 if (std::getline(catalogFile, currentItem, '\t').good()) {
157 // Get the language
158 fLanguageName = currentItem.c_str() ;
159 } else {
160 fprintf(stderr, "Unable to get language from %s\n", path);
161 return B_ERROR;
164 if (std::getline(catalogFile, currentItem, '\t').good()) {
165 // Get the signature
166 fSignature = currentItem.c_str() ;
167 } else {
168 fprintf(stderr, "Unable to get signature from %s\n", path);
169 return B_ERROR;
172 if (std::getline(catalogFile, currentItem).good()) {
173 // Get the fingerprint
174 std::istringstream ss(currentItem);
175 uint32 foundFingerprint;
176 ss >> foundFingerprint;
177 if (ss.fail()) {
178 fprintf(stderr, "Unable to get fingerprint (%s) from %s\n",
179 currentItem.c_str(), path);
180 return B_ERROR;
183 if (fFingerprint == 0)
184 fFingerprint = foundFingerprint;
186 if (fFingerprint != foundFingerprint) {
187 return B_MISMATCHED_VALUES;
189 } else {
190 fprintf(stderr, "Unable to get fingerprint from %s\n", path);
191 return B_ERROR;
194 // We managed to open the file, so we remember it's the one we are using
195 fPath = path;
196 // fprintf(stderr, "LocaleKit Plaintext: found catalog at %s\n", path);
198 std::string originalString;
199 std::string context;
200 std::string comment;
201 std::string translated;
203 while (std::getline(catalogFile, originalString,'\t').good()) {
204 // Each line is : "original string \t context \t comment \t translation"
206 if (!std::getline(catalogFile, context,'\t').good()) {
207 fprintf(stderr, "Unable to get context for string %s from %s\n",
208 originalString.c_str(), path);
209 return B_ERROR;
212 if (!std::getline(catalogFile, comment,'\t').good()) {
213 fprintf(stderr, "Unable to get comment for string %s from %s\n",
214 originalString.c_str(), path);
215 return B_ERROR;
218 if (!std::getline(catalogFile, translated).good()) {
219 fprintf(stderr,
220 "Unable to get translated text for string %s from %s\n",
221 originalString.c_str(), path);
222 return B_ERROR;
225 // We could do that :
226 // SetString(key, translated.c_str());
227 // but we want to keep the strings in the new catkey. Hash collisions
228 // happen, you know. (and CatKey::== will fail)
229 SetString(originalString.c_str(), translated.c_str(), context.c_str(),
230 comment.c_str());
233 catalogFile.close();
235 #if 0
236 uint32 checkFP = ComputeFingerprint();
237 if (fFingerprint != checkFP) {
238 fprintf(stderr, "plaintext-catalog(sig=%s, lang=%s) "
239 "has wrong fingerprint after load (%u instead of %u). "
240 "The catalog data may be corrupted, so this catalog is "
241 "skipped.\n",
242 fSignature.String(), fLanguageName.String(), checkFP,
243 fFingerprint);
244 return B_BAD_DATA;
246 #endif
248 // some information living in member variables needs to be copied
249 // to attributes. Although these attributes should have been written
250 // when creating the catalog, we make sure that they exist there:
251 UpdateAttributes(path);
252 return B_OK;
256 status_t
257 PlainTextCatalog::WriteToFile(const char *path)
259 BString textContent;
260 BFile catalogFile;
262 if (path)
263 fPath = path;
264 status_t res = catalogFile.SetTo(fPath.String(),
265 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
266 if (res != B_OK)
267 return res;
269 UpdateFingerprint();
270 // make sure we have the correct fingerprint before we flatten it
272 textContent << kCatArchiveVersion << "\t" << fLanguageName.String() << "\t"
273 << fSignature.String() << "\t" << fFingerprint << "\n";
275 res = catalogFile.Write(textContent.String(),textContent.Length());
276 if (res != textContent.Length())
277 return res;
279 CatMap::Iterator iter = fCatMap.GetIterator();
280 CatMap::Entry entry;
281 BString original;
282 BString comment;
283 BString translated;
285 while (iter.HasNext()) {
286 entry = iter.Next();
287 original = entry.key.fString;
288 comment = entry.key.fComment;
289 translated = entry.value;
291 escapeQuotedChars(original);
292 escapeQuotedChars(comment);
293 escapeQuotedChars(translated);
295 textContent.Truncate(0);
296 textContent << original.String() << "\t"
297 << entry.key.fContext.String() << "\t"
298 << comment << "\t"
299 << translated.String() << "\n";
300 res = catalogFile.Write(textContent.String(),textContent.Length());
301 if (res != textContent.Length())
302 return res;
305 // set mimetype-, language- and signature-attributes:
306 UpdateAttributes(catalogFile);
308 return B_OK;
313 * writes mimetype, language-name and signature of catalog into the
314 * catalog-file.
316 void
317 PlainTextCatalog::UpdateAttributes(BFile& catalogFile)
319 // useless on the build-tool-side
323 void
324 PlainTextCatalog::UpdateAttributes(const char* path)
326 BEntry entry(path);
327 BFile node(&entry, B_READ_WRITE);
328 UpdateAttributes(node);
332 BCatalogData *
333 PlainTextCatalog::Instantiate(const entry_ref &owner, const char *language,
334 uint32 fingerprint)
336 PlainTextCatalog *catalog
337 = new(std::nothrow) PlainTextCatalog(owner, language, fingerprint);
338 if (catalog && catalog->InitCheck() != B_OK) {
339 delete catalog;
340 return NULL;
342 return catalog;
346 } // namespace BPrivate
349 extern "C" BCatalogData *
350 instantiate_catalog(const entry_ref &owner, const char *language,
351 uint32 fingerprint)
353 return PlainTextCatalog::Instantiate(owner, language, fingerprint);
357 extern "C" BCatalogData *
358 create_catalog(const char *signature, const char *language)
360 PlainTextCatalog *catalog
361 = new(std::nothrow) PlainTextCatalog("emptycat", signature, language);
362 return catalog;
366 uint8 gCatalogAddOnPriority = 99;
367 // give low priority to this add on, we don't want it to be actually used