blob: 0b585c7173e1bac50dee077a584a998559cfc455 [file] [log] [blame]
/*
*******************************************************************************
*
* Copyright (C) 2000, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
*
* File reslist.c
*
* Modification History:
*
* Date Name Description
* 02/21/00 weiv Creation.
*******************************************************************************
*/
#include "reslist.h"
#include "unewdata.h"
#include "unicode/ures.h"
#include "error.h"
#define BIN_ALIGNMENT 16
uint32_t res_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status);
static const UDataInfo dataInfo={
sizeof(UDataInfo),
0,
U_IS_BIG_ENDIAN,
U_CHARSET_FAMILY,
sizeof(UChar),
0,
0x52, 0x65, 0x73, 0x42, /* dataFormat="resb" */
1, 0, 0, 0, /* formatVersion */
1, 4, 0, 0 /* dataVersion take a look at version inside parsed resb*/
};
static uint8_t calcPadding(uint32_t size) {
/* returns space we need to pad */
return (uint8_t)((size%sizeof(uint32_t))?(sizeof(uint32_t)-(size%sizeof(uint32_t))):0);
}
/* Writing Functions */
static uint32_t string_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
udata_write32(mem, res->u.fString.fLength);
udata_writeUString(mem, res->u.fString.fChars, (res->u.fString.fLength)+1);
udata_writePadding(mem, calcPadding(res->fSize));
return usedOffset;
}
static uint32_t array_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
uint32_t i = 0;
uint32_t *resources = NULL;
struct SResource *current = NULL;
if(U_FAILURE(*status)) {
return 0;
}
if(res->u.fArray.fCount > 0) {
resources = (uint32_t *) uprv_malloc(sizeof(uint32_t)*res->u.fArray.fCount);
if (resources == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return 0;
}
current = res->u.fArray.fFirst;
i=0;
while(current != NULL) {
if(current->fType == RES_INT) {
*(resources+i) = (current->fType)<<28 | (current->u.fIntValue.fValue & 0xFFFFFFF);
} else if(current->fType == RES_BINARY) {
uint32_t uo = usedOffset;
usedOffset = res_write(mem, current, usedOffset, status);
*(resources+i) = (current->fType)<<28 | (usedOffset>>2) ;
usedOffset += (current->fSize) + calcPadding(current->fSize) - (usedOffset-uo);
} else {
usedOffset = res_write(mem, current, usedOffset, status);
*(resources+i) = (current->fType)<<28 | (usedOffset>>2);
usedOffset += (current->fSize) + calcPadding(current->fSize);
}
i++;
current = current->fNext;
}
/* usedOffset += res->fSize + pad; */
udata_write32(mem, res->u.fArray.fCount);
udata_writeBlock(mem, resources, sizeof(uint32_t)*res->u.fArray.fCount);
uprv_free(resources);
} else { /*table is empty*/
udata_write32(mem, 0);
}
return usedOffset;
}
static uint32_t intvector_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
return usedOffset;
}
static uint32_t bin_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
uint32_t pad = 0;
uint32_t extrapad = calcPadding(res->fSize);
uint32_t dataStart = usedOffset+sizeof(res->u.fBinaryValue.fLength);
if(dataStart%BIN_ALIGNMENT) {
pad = (BIN_ALIGNMENT-dataStart%BIN_ALIGNMENT);
udata_writePadding(mem, pad);
usedOffset += pad;
}
udata_write32(mem, res->u.fBinaryValue.fLength);
udata_writeBlock(mem, res->u.fBinaryValue.fData, res->u.fBinaryValue.fLength);
udata_writePadding(mem, (BIN_ALIGNMENT - pad + extrapad));
return usedOffset;
}
static uint32_t int_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
return usedOffset;
}
static uint32_t table_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
uint8_t pad = 0;
uint32_t i = 0;
uint16_t *keys = NULL;
uint32_t *resources = NULL;
struct SResource *current = NULL;
if(U_FAILURE(*status)) {
return 0;
}
pad = calcPadding(res->fSize);
if(res->u.fTable.fCount > 0) {
keys = (uint16_t *) uprv_malloc(sizeof(uint16_t)*res->u.fTable.fCount);
if (keys == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return 0;
}
resources = (uint32_t *) uprv_malloc(sizeof(uint32_t)*res->u.fTable.fCount);
if (resources == NULL) {
uprv_free(keys);
*status = U_MEMORY_ALLOCATION_ERROR;
return 0;
}
current = res->u.fTable.fFirst;
i=0;
while(current != NULL) {
*(keys+i) = (uint16_t)((current->fKey)+sizeof(uint32_t)); /*where the key is plus root pointer*/
if(current->fType == RES_INT) {
*(resources+i) = (current->fType)<<28 | (current->u.fIntValue.fValue & 0xFFFFFFF);
} else if(current->fType == RES_BINARY) {
uint32_t uo = usedOffset;
usedOffset = res_write(mem, current, usedOffset, status);
*(resources+i) = (current->fType)<<28 | (usedOffset>>2) ;
usedOffset += (current->fSize) + calcPadding(current->fSize) - (usedOffset-uo);
} else {
usedOffset = res_write(mem, current, usedOffset, status);
*(resources+i) = (current->fType)<<28 | (usedOffset>>2) ;
usedOffset += (current->fSize) + calcPadding(current->fSize);
}
i++;
current = current->fNext;
}
udata_write16(mem, res->u.fTable.fCount);
udata_writeBlock(mem, keys, sizeof(uint16_t)*res->u.fTable.fCount);
udata_writePadding(mem, pad);
udata_writeBlock(mem, resources, sizeof(uint32_t)*res->u.fTable.fCount);
uprv_free(keys);
uprv_free(resources);
} else { /*table is empty*/
udata_write16(mem, 0);
udata_writePadding(mem, pad);
}
return usedOffset;
}
uint32_t res_write(UNewDataMemory *mem, struct SResource *res,
uint32_t usedOffset, UErrorCode *status) {
if(U_FAILURE(*status)) {
return 0;
}
if(res != NULL) {
switch(res->fType) {
case RES_STRING:
return string_write(mem, res, usedOffset, status);
break;
case RES_INT_VECTOR:
return intvector_write(mem, res, usedOffset, status);
break;
case RES_BINARY:
return bin_write(mem, res, usedOffset, status);
break;
case RES_INT:
return int_write(mem, res, usedOffset, status);
break;
case RES_ARRAY:
return array_write(mem, res, usedOffset, status);
break;
case RES_TABLE :
return table_write(mem, res, usedOffset, status);
break;
default:
break;
}
}
*status = U_INTERNAL_PROGRAM_ERROR;
return 0;
}
/*void bundle_write(struct SRBRoot *bundle, const char *outputDir, const char *filename, UErrorCode *status) {*/
void bundle_write(struct SRBRoot *bundle, const char *outputDir, UErrorCode *status) {
UNewDataMemory *mem = NULL;
uint8_t pad = 0;
uint32_t root = 0;
uint32_t usedOffset = 0;
if(U_FAILURE(*status)) {
return;
}
mem = udata_create(outputDir, "res", bundle->fLocale, &dataInfo, U_COPYRIGHT_STRING, status);
/*mem = udata_create(outputDir, "res", filename, &dataInfo, U_COPYRIGHT_STRING, status);*/
pad = calcPadding(bundle->fKeyPoint);
usedOffset = sizeof(uint32_t) + bundle->fKeyPoint + pad ; /*this is how much root and keys are taking up*/
root = ((usedOffset + bundle->fRoot->u.fTable.fChildrenSize)>>2) | (RES_TABLE << 28); /* we're gonna put the main table at the end */
udata_write32(mem, root);
udata_writeBlock(mem, bundle->fKeys, bundle->fKeyPoint);
udata_writePadding(mem, pad);
usedOffset = res_write(mem, bundle->fRoot, usedOffset, status);
udata_finish(mem, status);
}
/* Opening Functions */
struct SResource* table_open(struct SRBRoot *bundle, char *tag, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_TABLE;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fNext = NULL;
res->fSize = sizeof(uint16_t);
res->u.fTable.fCount = 0;
res->u.fTable.fChildrenSize = 0;
res->u.fTable.fFirst = NULL;
res->u.fTable.fRoot = bundle;
return res;
}
struct SResource* array_open(struct SRBRoot *bundle, char *tag, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_ARRAY;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fNext = NULL;
res->fSize = sizeof(int32_t);
res->u.fArray.fCount = 0;
res->u.fArray.fChildrenSize = 0;
res->u.fArray.fFirst = NULL;
res->u.fArray.fLast = NULL;
return res;
}
struct SResource *string_open(struct SRBRoot *bundle, char *tag, UChar *value, int32_t len, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_STRING;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fNext = NULL;
res->u.fString.fLength = len;
res->u.fString.fChars = (UChar *)uprv_malloc(sizeof(UChar) * (len+1));
if(res->u.fString.fChars == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(res);
return NULL;
}
uprv_memcpy(res->u.fString.fChars, value, sizeof(UChar) * (len+1));
res->fSize = sizeof(int32_t) + sizeof(UChar) * (len+1);
return res;
}
struct SResource* intvector_open(struct SRBRoot *bundle, char *tag, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_ARRAY;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fNext = NULL;
res->fSize = sizeof(int32_t);
res->u.fIntVector.fCount = 0;
res->u.fIntVector.fArray = (uint32_t *)uprv_malloc(sizeof(uint32_t) * RESLIST_MAX_INT_VECTOR);
if(res->u.fIntVector.fArray == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(res);
return NULL;
}
return res;
}
struct SResource *int_open(struct SRBRoot *bundle, char *tag, int32_t value, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_INT;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fSize = 0;
res->fNext = NULL;
res->u.fIntValue.fValue = value;
return res;
}
struct SResource *bin_open(struct SRBRoot *bundle, const char *tag, uint32_t length, uint8_t *data, UErrorCode *status) {
struct SResource *res;
if(U_FAILURE(*status)) {
return NULL;
}
res = (struct SResource *)uprv_malloc(sizeof(struct SResource));
if(res == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
res->fType = RES_BINARY;
res->fKey = bundle_addtag(bundle, tag, status);
if(U_FAILURE(*status)) {
uprv_free(res);
return NULL;
}
res->fNext = NULL;
res->u.fBinaryValue.fLength = length;
res->u.fBinaryValue.fData = (uint8_t *)uprv_malloc(sizeof(uint8_t) * length);
if(res->u.fString.fChars == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(res);
return NULL;
}
uprv_memcpy(res->u.fBinaryValue.fData, data, length);
res->fSize = sizeof(int32_t) + sizeof(uint8_t) * length + BIN_ALIGNMENT;
return res;
}
struct SRBRoot *bundle_open(UErrorCode *status) {
struct SRBRoot *bundle = NULL;
if(U_FAILURE(*status)) {
return NULL;
}
bundle = (struct SRBRoot*) uprv_malloc(sizeof(struct SRBRoot));
if(bundle == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return 0;
}
bundle->fLocale = NULL;
bundle->fKeyPoint = 0;
bundle->fKeys = (char *) uprv_malloc(sizeof(char) * KEY_SPACE_SIZE);
if(bundle->fKeys == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(bundle);
return NULL;
}
bundle->fCount = 0;
bundle->fRoot = table_open(bundle, NULL, status);
if((bundle->fRoot == NULL) || (U_FAILURE(*status))) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(bundle->fKeys);
uprv_free(bundle);
return NULL;
}
/*
bundle->fRoot = (struct SResource*) uprv_malloc(sizeof(struct SResource));
if(bundle->fRoot == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(bundle->fKeys);
uprv_free(bundle);
return NULL;
}
bundle->fRoot->fType = RES_TABLE;
bundle->fRoot->fSize = sizeof(uint16_t);
bundle->fRoot->u.fTable.fCount = 0;
bundle->fRoot->u.fTable.fFirst = NULL;
bundle->fRoot->u.fTable.fRoot = bundle;
*/
return bundle;
}
/* Closing Functions */
void table_close(struct SResource *table, UErrorCode *status) {
struct SResource *current = NULL;
struct SResource *prev = NULL;
current = table->u.fTable.fFirst;
while(current!=NULL) {
prev = current;
current = current->fNext;
res_close(prev, status);
}
}
void array_close(struct SResource *array, UErrorCode *status) {
struct SResource *current = NULL;
struct SResource *prev = NULL;
current = array->u.fArray.fFirst;
while(current!=NULL) {
prev = current;
current = current->fNext;
res_close(prev, status);
}
}
void string_close(struct SResource *string, UErrorCode *status) {
if(string->u.fString.fChars != NULL) {
uprv_free(string->u.fString.fChars);
}
}
void intvector_close(struct SResource *intvector, UErrorCode *status) {
if(intvector->u.fIntVector.fArray != NULL) {
uprv_free(intvector->u.fIntVector.fArray);
}
}
void int_close(struct SResource *intres, UErrorCode *status) {
/* Intentionally left blank */
}
void bin_close(struct SResource *binres, UErrorCode *status) {
if(binres->u.fBinaryValue.fData != NULL) {
uprv_free(binres->u.fBinaryValue.fData);
}
}
void res_close(struct SResource *res, UErrorCode *status) {
if(res != NULL) {
switch(res->fType) {
case RES_STRING:
string_close(res, status);
break;
case RES_INT_VECTOR:
intvector_close(res, status);
break;
case RES_BINARY:
bin_close(res, status);
break;
case RES_INT:
int_close(res, status);
break;
case RES_ARRAY:
array_close(res, status);
break;
case RES_TABLE :
table_close(res, status);
break;
default:
/* Shouldn't happen */
break;
}
uprv_free(res);
}
}
void bundle_close(struct SRBRoot *bundle, UErrorCode *status) {
struct SResource *current = NULL;
struct SResource *prev = NULL;
if(bundle->fRoot!=NULL) {
current = bundle->fRoot->u.fTable.fFirst;
while(current!=NULL) {
prev = current;
current = current->fNext;
res_close(prev, status);
}
uprv_free(bundle->fRoot);
}
if(bundle->fLocale != NULL) {
uprv_free(bundle->fLocale);
}
if(bundle->fKeys != NULL) {
uprv_free(bundle->fKeys);
}
uprv_free(bundle);
}
/* Adding Functions */
void table_add(struct SResource *table, struct SResource *res, UErrorCode *status) {
struct SResource *current = NULL;
struct SResource *prev = NULL;
struct SResTable *list;
if(U_FAILURE(*status)) {
return;
}
/* here we need to traverse the list */
list = &(table->u.fTable);
++(list->fCount);
table->fSize += sizeof(uint32_t) + sizeof(uint16_t);
table->u.fTable.fChildrenSize += res->fSize + calcPadding(res->fSize);
if(res->fType == RES_TABLE) {
table->u.fTable.fChildrenSize += res->u.fTable.fChildrenSize;
} else if (res->fType == RES_ARRAY) {
table->u.fTable.fChildrenSize += res->u.fArray.fChildrenSize;
}
/* is list still empty? */
if(list->fFirst == NULL) {
list->fFirst = res;
res->fNext = NULL;
return;
} else {
current = list->fFirst;
}
while(current != NULL) {
if(uprv_strcmp(((list->fRoot->fKeys)+(current->fKey)), ((list->fRoot->fKeys)+(res->fKey)))<0) {
prev = current;
current = current->fNext;
} else if (uprv_strcmp(((list->fRoot->fKeys)+(current->fKey)), ((list->fRoot->fKeys)+(res->fKey)))>0) { /*we're either in front of list, or in middle*/
if(prev == NULL) { /*front of the list*/
list->fFirst = res;
} else { /*middle of the list*/
prev->fNext = res;
}
res->fNext = current;
return;
} else { /* Key already exists! ERROR! */
char msg[100]={ "duplicate key '" };
uprv_strcat(msg, (list->fRoot->fKeys)+(current->fKey));
uprv_strcat(msg, "' in table");
setErrorText(msg);
*status = U_UNSUPPORTED_ERROR;
return;
}
}
/* end of list */
prev->fNext = res;
res->fNext = NULL;
}
void array_add(struct SResource *array, struct SResource *res, UErrorCode *status) {
if(U_FAILURE(*status)) {
return;
}
if(array->u.fArray.fFirst == NULL) {
array->u.fArray.fFirst = res;
array->u.fArray.fLast = res;
} else {
array->u.fArray.fLast->fNext = res;
array->u.fArray.fLast = res;
}
(array->u.fArray.fCount)++;
array->fSize += sizeof(uint32_t);
array->u.fArray.fChildrenSize += res->fSize + calcPadding(res->fSize);
if(res->fType == RES_TABLE) {
array->u.fArray.fChildrenSize += res->u.fTable.fChildrenSize;
} else if (res->fType == RES_ARRAY) {
array->u.fArray.fChildrenSize += res->u.fArray.fChildrenSize;
}
}
void intvector_add(struct SResource *intvector, int32_t value, UErrorCode *status) {
if(U_FAILURE(*status)) {
return;
}
*(intvector->u.fIntVector.fArray+(intvector->u.fIntVector.fCount)) = value;
(intvector->u.fIntVector.fCount)++;
intvector->fSize += sizeof(uint32_t);
}
/* Misc Functions */
void bundle_setlocale(struct SRBRoot *bundle, UChar *locale, UErrorCode *status) {
if(U_FAILURE(*status)) {
return;
}
if (bundle->fLocale!=NULL) {
uprv_free(bundle->fLocale);
}
bundle->fLocale= (char*) uprv_malloc(sizeof(char) * (u_strlen(locale)+1));
if(bundle->fLocale == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return;
}
/*u_strcpy(bundle->fLocale, locale);*/
u_UCharsToChars(locale, bundle->fLocale, u_strlen(locale)+1);
}
uint16_t bundle_addtag(struct SRBRoot *bundle, const char *tag, UErrorCode *status) {
uint16_t keypos;
if(U_FAILURE(*status)) {
return (uint16_t)-1;
}
if(tag == NULL) {
return (uint16_t)-1;
}
keypos = bundle->fKeyPoint;
bundle->fKeyPoint += (uint16_t)(uprv_strlen(tag)+1);
if(bundle->fKeyPoint > KEY_SPACE_SIZE) {
*status = U_MEMORY_ALLOCATION_ERROR;
return (uint16_t)-1;
}
uprv_strcpy((bundle->fKeys)+keypos, tag);
return keypos;
}
struct SResource *table_get(struct SResource *table, char *key, UErrorCode *status) {
return NULL;
}