|  | /* | 
|  | ******************************************************************************* | 
|  | * | 
|  | *   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; | 
|  | } |