2 ** Copyright 2009 Adrien Destugues, pulkomandy@gmail.com. All rights reserved.
3 ** Distributed under the terms of the MIT License.
6 #include <PlainTextCatalog.h>
19 #include <Application.h>
20 #include <Directory.h>
22 #include <FindDirectory.h>
27 #include <Resources.h>
34 using BPrivate::PlainTextCatalog
;
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.
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...
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
;
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
,
100 HashMapCatalog(signature
, language
, 0),
107 PlainTextCatalog::~PlainTextCatalog()
113 PlainTextCatalog::ReadFromFile(const char *path
)
115 std::fstream catalogFile
;
116 std::string currentItem
;
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
134 std::istringstream
ss(currentItem
);
137 // can't convert to int
139 "Unable to extract archive version ( string: %s ) from %s\n",
140 currentItem
.c_str(), path
);
144 if (arcver
!= kCatArchiveVersion
) {
147 "Wrong archive version ! Got %d instead of %d from %s\n", arcver
,
148 kCatArchiveVersion
, path
);
152 fprintf(stderr
, "Unable to read from catalog %s\n", path
);
156 if (std::getline(catalogFile
, currentItem
, '\t').good()) {
158 fLanguageName
= currentItem
.c_str() ;
160 fprintf(stderr
, "Unable to get language from %s\n", path
);
164 if (std::getline(catalogFile
, currentItem
, '\t').good()) {
166 fSignature
= currentItem
.c_str() ;
168 fprintf(stderr
, "Unable to get signature from %s\n", path
);
172 if (std::getline(catalogFile
, currentItem
).good()) {
173 // Get the fingerprint
174 std::istringstream
ss(currentItem
);
175 uint32 foundFingerprint
;
176 ss
>> foundFingerprint
;
178 fprintf(stderr
, "Unable to get fingerprint (%s) from %s\n",
179 currentItem
.c_str(), path
);
183 if (fFingerprint
== 0)
184 fFingerprint
= foundFingerprint
;
186 if (fFingerprint
!= foundFingerprint
) {
187 return B_MISMATCHED_VALUES
;
190 fprintf(stderr
, "Unable to get fingerprint from %s\n", path
);
194 // We managed to open the file, so we remember it's the one we are using
196 // fprintf(stderr, "LocaleKit Plaintext: found catalog at %s\n", path);
198 std::string originalString
;
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
);
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
);
218 if (!std::getline(catalogFile
, translated
).good()) {
220 "Unable to get translated text for string %s from %s\n",
221 originalString
.c_str(), path
);
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(),
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 "
242 fSignature
.String(), fLanguageName
.String(), checkFP
,
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
);
257 PlainTextCatalog::WriteToFile(const char *path
)
264 status_t res
= catalogFile
.SetTo(fPath
.String(),
265 B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
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())
279 CatMap::Iterator iter
= fCatMap
.GetIterator();
285 while (iter
.HasNext()) {
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"
299 << translated
.String() << "\n";
300 res
= catalogFile
.Write(textContent
.String(),textContent
.Length());
301 if (res
!= textContent
.Length())
305 // set mimetype-, language- and signature-attributes:
306 UpdateAttributes(catalogFile
);
313 * writes mimetype, language-name and signature of catalog into the
317 PlainTextCatalog::UpdateAttributes(BFile
& catalogFile
)
319 // useless on the build-tool-side
324 PlainTextCatalog::UpdateAttributes(const char* path
)
327 BFile
node(&entry
, B_READ_WRITE
);
328 UpdateAttributes(node
);
333 PlainTextCatalog::Instantiate(const entry_ref
&owner
, const char *language
,
336 PlainTextCatalog
*catalog
337 = new(std::nothrow
) PlainTextCatalog(owner
, language
, fingerprint
);
338 if (catalog
&& catalog
->InitCheck() != B_OK
) {
346 } // namespace BPrivate
349 extern "C" BCatalogData
*
350 instantiate_catalog(const entry_ref
&owner
, const char *language
,
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
);
366 uint8 gCatalogAddOnPriority
= 99;
367 // give low priority to this add on, we don't want it to be actually used