headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / storage / ResourceStrings.cpp
blob8ee53189704463187f7bcc98092bd1b1fc7c9504
1 //----------------------------------------------------------------------
2 // This software is part of the OpenBeOS distribution and is covered
3 // by the MIT License.
4 //---------------------------------------------------------------------
5 /*!
6 \file ResourceStrings.cpp
7 BResourceStrings implementation.
8 */
10 #include <ResourceStrings.h>
12 #include <new>
13 #include <stdlib.h>
14 #include <string.h>
16 #include <Entry.h>
17 #include <File.h>
18 #include <Resources.h>
19 #include <String.h>
21 #include <AppMisc.h>
23 using namespace std;
26 // constructor
27 /*! \brief Creates an object initialized to the application's string resources.
29 BResourceStrings::BResourceStrings()
30 : _string_lock(),
31 _init_error(),
32 fFileRef(),
33 fResources(NULL),
34 fHashTable(NULL),
35 fHashTableSize(0),
36 fStringCount(0)
38 SetStringFile(NULL);
41 // constructor
42 /*! \brief Creates an object initialized to the string resources of the
43 file referred to by the supplied entry_ref.
44 \param ref the entry_ref referring to the resource file
46 BResourceStrings::BResourceStrings(const entry_ref &ref)
47 : _string_lock(),
48 _init_error(),
49 fFileRef(),
50 fResources(NULL),
51 fHashTable(NULL),
52 fHashTableSize(0),
53 fStringCount(0)
55 SetStringFile(&ref);
58 // destructor
59 /*! \brief Frees all resources associated with the BResourceStrings object.
61 BResourceStrings::~BResourceStrings()
63 _string_lock.Lock();
64 _Cleanup();
67 // InitCheck
68 /*! \brief Returns the status of the last initialization via contructor or
69 SetStringFile().
70 \return \c B_OK, if the object is properly initialized, an error code
71 otherwise.
73 status_t
74 BResourceStrings::InitCheck()
76 return _init_error;
79 // NewString
80 /*! \brief Finds and returns a copy of the string identified by the supplied
81 ID.
82 The caller is responsible for deleting the returned BString object.
83 \param id the ID of the requested string
84 \return
85 - A string object containing the requested string,
86 - \c NULL, if the object is not properly initialized or there is no string
87 with ID \a id.
89 BString *
90 BResourceStrings::NewString(int32 id)
92 // _string_lock.Lock();
93 BString *result = NULL;
94 if (const char *str = FindString(id))
95 result = new(nothrow) BString(str);
96 // _string_lock.Unlock();
97 return result;
100 // FindString
101 /*! \brief Finds and returns the string identified by the supplied ID.
102 The caller must not free the returned string. It belongs to the
103 BResourceStrings object and is valid until the object is destroyed or set
104 to another file.
105 \param id the ID of the requested string
106 \return
107 - The requested string,
108 - \c NULL, if the object is not properly initialized or there is no string
109 with ID \a id.
111 const char *
112 BResourceStrings::FindString(int32 id)
114 _string_lock.Lock();
115 const char *result = NULL;
116 if (InitCheck() == B_OK) {
117 if (_string_id_hash *entry = _FindString(id))
118 result = entry->data;
120 _string_lock.Unlock();
121 return result;
124 // SetStringFile
125 /*! \brief Re-initialized the BResourceStrings object to the file referred to
126 by the supplied entry_ref.
127 If the supplied entry_ref is \c NULL, the object is initialized to the
128 application file.
129 \param ref the entry_ref referring to the resource file
131 status_t
132 BResourceStrings::SetStringFile(const entry_ref *ref)
134 _string_lock.Lock();
135 // cleanup
136 _Cleanup();
137 // get the ref (if NULL, take the application)
138 status_t error = B_OK;
139 entry_ref fileRef;
140 if (ref) {
141 fileRef = *ref;
142 fFileRef = *ref;
143 } else
144 error = BPrivate::get_app_ref(&fileRef);
145 // get the BResources
146 if (error == B_OK) {
147 BFile file(&fileRef, B_READ_ONLY);
148 error = file.InitCheck();
149 if (error == B_OK) {
150 fResources = new(nothrow) BResources;
151 if (fResources)
152 error = fResources->SetTo(&file);
153 else
154 error = B_NO_MEMORY;
157 // read the strings
158 if (error == B_OK) {
159 // count them first
160 fStringCount = 0;
161 int32 id;
162 const char *name;
163 size_t length;
164 while (fResources->GetResourceInfo(RESOURCE_TYPE, fStringCount, &id,
165 &name, &length)) {
166 fStringCount++;
168 // allocate a hash table with a nice size
169 // I don't have a heuristic at hand, so let's simply take the count.
170 error = _Rehash(fStringCount);
171 // load the resources
172 for (int32 i = 0; error == B_OK && i < fStringCount; i++) {
173 if (!fResources->GetResourceInfo(RESOURCE_TYPE, i, &id, &name,
174 &length)) {
175 error = B_ERROR;
177 if (error == B_OK) {
178 const void *data
179 = fResources->LoadResource(RESOURCE_TYPE, id, &length);
180 if (data) {
181 _string_id_hash *entry = NULL;
182 if (length == 0)
183 entry = _AddString(NULL, id, false);
184 else
185 entry = _AddString((char*)data, id, false);
186 if (!entry)
187 error = B_ERROR;
188 } else
189 error = B_ERROR;
193 // if something went wrong, cleanup the mess
194 if (error != B_OK)
195 _Cleanup();
196 _init_error = error;
197 _string_lock.Unlock();
198 return error;
201 // GetStringFile
202 /*! \brief Returns an entry_ref referring to the resource file, the object is
203 currently initialized to.
204 \param outRef a pointer to an entry_ref variable to be initialized to the
205 requested entry_ref
206 \return
207 - \c B_OK: Everything went fine.
208 - \c B_BAD_VALUE: \c NULL \a outRef.
209 - other error codes
211 status_t
212 BResourceStrings::GetStringFile(entry_ref *outRef)
214 status_t error = (outRef ? B_OK : B_BAD_VALUE);
215 if (error == B_OK)
216 error = InitCheck();
217 if (error == B_OK) {
218 if (fFileRef == entry_ref())
219 error = B_ENTRY_NOT_FOUND;
220 else
221 *outRef = fFileRef;
223 return error;
227 // _Cleanup
228 /*! \brief Frees all resources associated with this object and sets all
229 member variables to harmless values.
231 void
232 BResourceStrings::_Cleanup()
234 // _string_lock.Lock();
235 _MakeEmpty();
236 delete[] fHashTable;
237 fHashTable = NULL;
238 delete fResources;
239 fResources = NULL;
240 fFileRef = entry_ref();
241 fHashTableSize = 0;
242 fStringCount = 0;
243 _init_error = B_OK;
244 // _string_lock.Unlock();
247 // _MakeEmpty
248 /*! \brief Empties the id->string hash table.
250 void
251 BResourceStrings::_MakeEmpty()
253 if (fHashTable) {
254 for (int32 i = 0; i < fHashTableSize; i++) {
255 while (_string_id_hash *entry = fHashTable[i]) {
256 fHashTable[i] = entry->next;
257 delete entry;
260 fStringCount = 0;
264 // _Rehash
265 /*! \brief Resizes the id->string hash table to the supplied size.
266 \param newSize the new hash table size
267 \return
268 - \c B_OK: Everything went fine.
269 - \c B_NO_MEMORY: Insuffient memory.
271 status_t
272 BResourceStrings::_Rehash(int32 newSize)
274 status_t error = B_OK;
275 if (newSize > 0 && newSize != fHashTableSize) {
276 // alloc a new table and fill it with NULL
277 _string_id_hash **newHashTable
278 = new(nothrow) _string_id_hash*[newSize];
279 if (newHashTable) {
280 memset(newHashTable, 0, sizeof(_string_id_hash*) * newSize);
281 // move the entries to the new table
282 if (fHashTable && fHashTableSize > 0 && fStringCount > 0) {
283 for (int32 i = 0; i < fHashTableSize; i++) {
284 while (_string_id_hash *entry = fHashTable[i]) {
285 fHashTable[i] = entry->next;
286 int32 newPos = entry->id % newSize;
287 entry->next = newHashTable[newPos];
288 newHashTable[newPos] = entry;
292 // set the new table
293 delete[] fHashTable;
294 fHashTable = newHashTable;
295 fHashTableSize = newSize;
296 } else
297 error = B_NO_MEMORY;
299 return error;
302 // _AddString
303 /*! \brief Adds an entry to the id->string hash table.
304 If there is already a string with the given ID, it will be replaced.
305 \param str the string
306 \param id the id of the string
307 \param wasMalloced if \c true, the object will be responsible for
308 free()ing the supplied string
309 \return the hash table entry or \c NULL, if something went wrong
311 BResourceStrings::_string_id_hash *
312 BResourceStrings::_AddString(char *str, int32 id, bool wasMalloced)
314 _string_id_hash *entry = NULL;
315 if (fHashTable && fHashTableSize > 0)
316 entry = new(nothrow) _string_id_hash;
317 if (entry) {
318 entry->assign_string(str, false);
319 entry->id = id;
320 entry->data_alloced = wasMalloced;
321 int32 pos = id % fHashTableSize;
322 entry->next = fHashTable[pos];
323 fHashTable[pos] = entry;
325 return entry;
328 // _FindString
329 /*! \brief Returns the hash table entry for a given ID.
330 \param id the ID
331 \return the hash table entry or \c NULL, if there is no entry with this ID
333 BResourceStrings::_string_id_hash *
334 BResourceStrings::_FindString(int32 id)
336 _string_id_hash *entry = NULL;
337 if (fHashTable && fHashTableSize > 0) {
338 int32 pos = id % fHashTableSize;
339 entry = fHashTable[pos];
340 while (entry != NULL && entry->id != id)
341 entry = entry->next;
343 return entry;
347 // FBC
348 status_t BResourceStrings::_Reserved_ResourceStrings_0(void *) { return 0; }
349 status_t BResourceStrings::_Reserved_ResourceStrings_1(void *) { return 0; }
350 status_t BResourceStrings::_Reserved_ResourceStrings_2(void *) { return 0; }
351 status_t BResourceStrings::_Reserved_ResourceStrings_3(void *) { return 0; }
352 status_t BResourceStrings::_Reserved_ResourceStrings_4(void *) { return 0; }
353 status_t BResourceStrings::_Reserved_ResourceStrings_5(void *) { return 0; }
356 // _string_id_hash
358 // constructor
359 /*! \brief Creates an uninitialized hash table entry.
361 BResourceStrings::_string_id_hash::_string_id_hash()
362 : next(NULL),
363 id(0),
364 data(NULL),
365 data_alloced(false)
369 // destructor
370 /*! \brief Frees all resources associated with this object.
371 Only if \c data_alloced is \c true, the string will be free()d.
373 BResourceStrings::_string_id_hash::~_string_id_hash()
375 if (data_alloced)
376 free(data);
379 // assign_string
380 /*! \brief Sets the string of the hash table entry.
381 \param str the string
382 \param makeCopy If \c true, the supplied string is copied and the copy
383 will be freed on destruction. If \c false, the entry points to the
384 supplied string. It will not be freed() on destruction.
386 void
387 BResourceStrings::_string_id_hash::assign_string(const char *str,
388 bool makeCopy)
390 if (data_alloced)
391 free(data);
392 data = NULL;
393 data_alloced = false;
394 if (str) {
395 if (makeCopy) {
396 data = strdup(str);
397 data_alloced = true;
398 } else
399 data = const_cast<char*>(str);