\file ResourceStrings.cpp
BResourceStrings implementation.
*/
#include <ResourceStrings.h>
#include <new>
#include <stdlib.h>
#include <string.h>
#include <Entry.h>
#include <File.h>
#include <Resources.h>
#include <String.h>
#include <AppMisc.h>
using namespace std;
*/
BResourceStrings::BResourceStrings()
: _string_lock(),
_init_error(),
fFileRef(),
fResources(NULL),
fHashTable(NULL),
fHashTableSize(0),
fStringCount(0)
{
SetStringFile(NULL);
}
file referred to by the supplied entry_ref.
\param ref the entry_ref referring to the resource file
*/
BResourceStrings::BResourceStrings(const entry_ref &ref)
: _string_lock(),
_init_error(),
fFileRef(),
fResources(NULL),
fHashTable(NULL),
fHashTableSize(0),
fStringCount(0)
{
SetStringFile(&ref);
}
*/
BResourceStrings::~BResourceStrings()
{
_string_lock.Lock();
_Cleanup();
}
SetStringFile().
\return \c B_OK, if the object is properly initialized, an error code
otherwise.
*/
status_t
BResourceStrings::InitCheck()
{
return _init_error;
}
ID.
The caller is responsible for deleting the returned BString object.
\param id the ID of the requested string
\return
- A string object containing the requested string,
- \c NULL, if the object is not properly initialized or there is no string
with ID \a id.
*/
BString *
BResourceStrings::NewString(int32 id)
{
BString *result = NULL;
if (const char *str = FindString(id))
result = new(nothrow) BString(str);
return result;
}
The caller must not free the returned string. It belongs to the
BResourceStrings object and is valid until the object is destroyed or set
to another file.
\param id the ID of the requested string
\return
- The requested string,
- \c NULL, if the object is not properly initialized or there is no string
with ID \a id.
*/
const char *
BResourceStrings::FindString(int32 id)
{
_string_lock.Lock();
const char *result = NULL;
if (InitCheck() == B_OK) {
if (_string_id_hash *entry = _FindString(id))
result = entry->data;
}
_string_lock.Unlock();
return result;
}
by the supplied entry_ref.
If the supplied entry_ref is \c NULL, the object is initialized to the
application file.
\param ref the entry_ref referring to the resource file
*/
status_t
BResourceStrings::SetStringFile(const entry_ref *ref)
{
_string_lock.Lock();
_Cleanup();
status_t error = B_OK;
entry_ref fileRef;
if (ref) {
fileRef = *ref;
fFileRef = *ref;
} else
error = BPrivate::get_app_ref(&fileRef);
if (error == B_OK) {
BFile file(&fileRef, B_READ_ONLY);
error = file.InitCheck();
if (error == B_OK) {
fResources = new(nothrow) BResources;
if (fResources)
error = fResources->SetTo(&file);
else
error = B_NO_MEMORY;
}
}
if (error == B_OK) {
fStringCount = 0;
int32 id;
const char *name;
size_t length;
while (fResources->GetResourceInfo(RESOURCE_TYPE, fStringCount, &id,
&name, &length)) {
fStringCount++;
}
error = _Rehash(fStringCount);
for (int32 i = 0; error == B_OK && i < fStringCount; i++) {
if (!fResources->GetResourceInfo(RESOURCE_TYPE, i, &id, &name,
&length)) {
error = B_ERROR;
}
if (error == B_OK) {
const void *data
= fResources->LoadResource(RESOURCE_TYPE, id, &length);
if (data) {
_string_id_hash *entry = NULL;
if (length == 0)
entry = _AddString(NULL, id, false);
else
entry = _AddString((char*)data, id, false);
if (!entry)
error = B_ERROR;
} else
error = B_ERROR;
}
}
}
if (error != B_OK)
_Cleanup();
_init_error = error;
_string_lock.Unlock();
return error;
}
currently initialized to.
\param outRef a pointer to an entry_ref variable to be initialized to the
requested entry_ref
\return
- \c B_OK: Everything went fine.
- \c B_BAD_VALUE: \c NULL \a outRef.
- other error codes
*/
status_t
BResourceStrings::GetStringFile(entry_ref *outRef)
{
status_t error = (outRef ? B_OK : B_BAD_VALUE);
if (error == B_OK)
error = InitCheck();
if (error == B_OK) {
if (fFileRef == entry_ref())
error = B_ENTRY_NOT_FOUND;
else
*outRef = fFileRef;
}
return error;
}
member variables to harmless values.
*/
void
BResourceStrings::_Cleanup()
{
_MakeEmpty();
delete[] fHashTable;
fHashTable = NULL;
delete fResources;
fResources = NULL;
fFileRef = entry_ref();
fHashTableSize = 0;
fStringCount = 0;
_init_error = B_OK;
}
*/
void
BResourceStrings::_MakeEmpty()
{
if (fHashTable) {
for (int32 i = 0; i < fHashTableSize; i++) {
while (_string_id_hash *entry = fHashTable[i]) {
fHashTable[i] = entry->next;
delete entry;
}
}
fStringCount = 0;
}
}
\param newSize the new hash table size
\return
- \c B_OK: Everything went fine.
- \c B_NO_MEMORY: Insuffient memory.
*/
status_t
BResourceStrings::_Rehash(int32 newSize)
{
status_t error = B_OK;
if (newSize > 0 && newSize != fHashTableSize) {
_string_id_hash **newHashTable
= new(nothrow) _string_id_hash*[newSize];
if (newHashTable) {
memset(newHashTable, 0, sizeof(_string_id_hash*) * newSize);
if (fHashTable && fHashTableSize > 0 && fStringCount > 0) {
for (int32 i = 0; i < fHashTableSize; i++) {
while (_string_id_hash *entry = fHashTable[i]) {
fHashTable[i] = entry->next;
int32 newPos = entry->id % newSize;
entry->next = newHashTable[newPos];
newHashTable[newPos] = entry;
}
}
}
delete[] fHashTable;
fHashTable = newHashTable;
fHashTableSize = newSize;
} else
error = B_NO_MEMORY;
}
return error;
}
If there is already a string with the given ID, it will be replaced.
\param str the string
\param id the id of the string
\param wasMalloced if \c true, the object will be responsible for
free()ing the supplied string
\return the hash table entry or \c NULL, if something went wrong
*/
BResourceStrings::_string_id_hash *
BResourceStrings::_AddString(char *str, int32 id, bool wasMalloced)
{
_string_id_hash *entry = NULL;
if (fHashTable && fHashTableSize > 0)
entry = new(nothrow) _string_id_hash;
if (entry) {
entry->assign_string(str, false);
entry->id = id;
entry->data_alloced = wasMalloced;
int32 pos = id % fHashTableSize;
entry->next = fHashTable[pos];
fHashTable[pos] = entry;
}
return entry;
}
\param id the ID
\return the hash table entry or \c NULL, if there is no entry with this ID
*/
BResourceStrings::_string_id_hash *
BResourceStrings::_FindString(int32 id)
{
_string_id_hash *entry = NULL;
if (fHashTable && fHashTableSize > 0) {
int32 pos = id % fHashTableSize;
entry = fHashTable[pos];
while (entry != NULL && entry->id != id)
entry = entry->next;
}
return entry;
}
status_t BResourceStrings::_Reserved_ResourceStrings_0(void *) { return 0; }
status_t BResourceStrings::_Reserved_ResourceStrings_1(void *) { return 0; }
status_t BResourceStrings::_Reserved_ResourceStrings_2(void *) { return 0; }
status_t BResourceStrings::_Reserved_ResourceStrings_3(void *) { return 0; }
status_t BResourceStrings::_Reserved_ResourceStrings_4(void *) { return 0; }
status_t BResourceStrings::_Reserved_ResourceStrings_5(void *) { return 0; }
*/
BResourceStrings::_string_id_hash::_string_id_hash()
: next(NULL),
id(0),
data(NULL),
data_alloced(false)
{
}
Only if \c data_alloced is \c true, the string will be free()d.
*/
BResourceStrings::_string_id_hash::~_string_id_hash()
{
if (data_alloced)
free(data);
}
\param str the string
\param makeCopy If \c true, the supplied string is copied and the copy
will be freed on destruction. If \c false, the entry points to the
supplied string. It will not be freed() on destruction.
*/
void
BResourceStrings::_string_id_hash::assign_string(const char *str,
bool makeCopy)
{
if (data_alloced)
free(data);
data = NULL;
data_alloced = false;
if (str) {
if (makeCopy) {
data = strdup(str);
data_alloced = true;
} else
data = const_cast<char*>(str);
}
}