#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);
}
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();
}
status_t
BResourceStrings::InitCheck()
{
return _init_error;
}
BString *
BResourceStrings::NewString(int32 id)
{
BString *result = NULL;
if (const char *str = FindString(id))
result = new(nothrow) BString(str);
return result;
}
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;
}
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;
}
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;
}
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;
}
}
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;
}
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;
}
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)
{
}
BResourceStrings::_string_id_hash::~_string_id_hash()
{
if (data_alloced)
free(data);
}
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);
}
}