BPicture: Fix archive constructor.
[haiku.git] / src / kits / locale / HashMapCatalog.cpp
blob1681fefc343323c855a37d12b7426953ff246d8e
1 /*
2 * Copyright 2009, Adrien Destugues, pulkomandy@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <HashMapCatalog.h>
9 #include <ByteOrder.h>
11 #include <stdlib.h>
14 namespace BPrivate {
18 * This is the standard implementation of a localization catalog, using a hash
19 * map. This class is abstract, you need to inherit it and provide methodes for
20 * reading and writing the catalog to a file. Classes doing that are
21 * HashMapCatalog and PlainTextCatalog.
22 * If you ever need to create a catalog not built around an hash map, inherit
23 * BCatalogData instead. Note that in this case you will not be able to use our
24 * development tools anymore.
28 CatKey::CatKey(const char *str, const char *ctx, const char *cmt)
30 fString(str),
31 fContext(ctx),
32 fComment(cmt),
33 fFlags(0)
35 fHashVal = HashFun(fString.String(),0);
36 fHashVal = HashFun(fContext.String(),fHashVal);
37 fHashVal = HashFun(fComment.String(),fHashVal);
41 CatKey::CatKey(uint32 id)
43 fHashVal(id),
44 fFlags(0)
49 CatKey::CatKey()
51 fHashVal(0),
52 fFlags(0)
57 bool
58 CatKey::operator== (const CatKey& right) const
60 // Two keys are equal if their hashval and key (string,context,comment)
61 // are equal (testing only the hash would not filter out collisions):
62 return fHashVal == right.fHashVal
63 && fString == right.fString
64 && fContext == right.fContext
65 && fComment == right.fComment;
69 bool
70 CatKey::operator!= (const CatKey& right) const
72 // Two keys are equal if their hashval and key (string,context,comment)
73 // are equal (testing only the hash would not filter out collisions):
74 return fHashVal != right.fHashVal
75 || fString != right.fString
76 || fContext != right.fContext
77 || fComment != right.fComment;
81 status_t
82 CatKey::GetStringParts(BString* str, BString* ctx, BString* cmt) const
84 if (str) *str = fString;
85 if (ctx) *ctx = fContext;
86 if (cmt) *cmt = fComment;
88 return B_OK;
92 uint32
93 CatKey::HashFun(const char* s, int startValue) {
94 unsigned long h = startValue;
95 for ( ; *s; ++s)
96 h = 5 * h + *s;
98 // Add 1 to differenciate ("ab","cd","ef") from ("abcd","e","f")
99 h = 5 * h + 1;
101 return size_t(h);
105 // HashMapCatalog
108 void
109 HashMapCatalog::MakeEmpty()
111 fCatMap.Clear();
115 int32
116 HashMapCatalog::CountItems() const
118 return fCatMap.Size();
122 const char *
123 HashMapCatalog::GetString(const char *string, const char *context,
124 const char *comment)
126 CatKey key(string, context, comment);
127 return GetString(key);
131 const char *
132 HashMapCatalog::GetString(uint32 id)
134 CatKey key(id);
135 return GetString(key);
139 const char *
140 HashMapCatalog::GetString(const CatKey& key)
142 BString value = fCatMap.Get(key);
143 if (value.Length() == 0)
144 return NULL;
145 else
146 return value.String();
150 static status_t
151 parseQuotedChars(BString& stringToParse)
153 char* in = stringToParse.LockBuffer(0);
154 if (in == NULL)
155 return B_ERROR;
156 char* out = in;
157 int newLength = 0;
158 bool quoted = false;
160 while (*in != 0) {
161 if (quoted) {
162 if (*in == 'n')
163 *out = '\n';
164 else if (*in == 't')
165 *out = '\t';
166 else if (*in == '"')
167 *out = '"';
168 else if (*in == 'x') {
169 if (in[1] == '\0' || in[2] == '\0')
170 break;
171 // Parse the 2-digit hex integer that follows
172 char tmp[3];
173 tmp[0] = in[1];
174 tmp[1] = in[2];
175 tmp[2] = '\0';
176 unsigned int hexchar = strtoul(tmp, NULL, 16);
177 *out = hexchar;
178 // skip the number
179 in += 2;
180 } else {
181 // drop quote from unknown quoting-sequence:
182 *out = *in ;
184 quoted = false;
185 out++;
186 newLength++;
187 } else {
188 quoted = (*in == '\\');
189 if (!quoted) {
190 *out = *in;
191 out++;
192 newLength++;
195 in++;
197 *out = '\0';
198 stringToParse.UnlockBuffer(newLength);
200 return B_OK;
204 status_t
205 HashMapCatalog::SetString(const char *string, const char *translated,
206 const char *context, const char *comment)
208 BString stringCopy(string);
209 status_t result = parseQuotedChars(stringCopy);
210 if (result != B_OK)
211 return result;
213 BString translatedCopy(translated);
214 if ((result = parseQuotedChars(translatedCopy)) != B_OK)
215 return result;
217 BString commentCopy(comment);
218 if ((result = parseQuotedChars(commentCopy)) != B_OK)
219 return result;
221 CatKey key(stringCopy.String(), context, commentCopy.String());
222 return fCatMap.Put(key, translatedCopy.String());
223 // overwrite existing element
227 status_t
228 HashMapCatalog::SetString(int32 id, const char *translated)
230 BString translatedCopy(translated);
231 status_t result = parseQuotedChars(translatedCopy);
232 if (result != B_OK)
233 return result;
234 CatKey key(id);
235 return fCatMap.Put(key, translatedCopy.String());
236 // overwrite existing element
240 status_t
241 HashMapCatalog::SetString(const CatKey& key, const char *translated)
243 BString translatedCopy(translated);
244 status_t result = parseQuotedChars(translatedCopy);
245 if (result != B_OK)
246 return result;
247 return fCatMap.Put(key, translatedCopy.String());
248 // overwrite existing element
253 * computes a checksum (we call it fingerprint) on all the catalog-keys. We do
254 * not include the values, since we want catalogs for different languages of the
255 * same app to have the same fingerprint, since we use it to separate different
256 * catalog-versions. We use a simple sum because there is no well known
257 * checksum algorithm that gives the same result if the string are sorted in the
258 * wrong order, and this does happen, as an hash map is an unsorted container.
260 uint32
261 HashMapCatalog::ComputeFingerprint() const
263 uint32 checksum = 0;
265 int32 hash;
266 CatMap::Iterator iter = fCatMap.GetIterator();
267 CatMap::Entry entry;
268 while (iter.HasNext())
270 entry = iter.Next();
271 hash = B_HOST_TO_LENDIAN_INT32(entry.key.fHashVal);
272 checksum += hash;
274 return checksum;
278 void
279 HashMapCatalog::UpdateFingerprint()
281 fFingerprint = ComputeFingerprint();
285 } // namespace BPrivate