# define UNISTR_FROM_STRING_EXPLICIT explicit
#endif
+#include <assert.h>
#include "parse.h"
#include "errmsg.h"
#include "uhash.h"
#include "reslist.h"
#include "rbt_pars.h"
#include "genrb.h"
+#include "unicode/stringpiece.h"
+#include "unicode/unistr.h"
#include "unicode/ustring.h"
#include "unicode/uscript.h"
#include "unicode/utf16.h"
#include "unicode/putil.h"
+#include "charstr.h"
#include "collationbuilder.h"
#include "collationdata.h"
#include "collationdatareader.h"
#define OPENSQBRACKET 0x005B
#define CLOSESQBRACKET 0x005D
+using icu::CharString;
+using icu::LocalMemory;
using icu::LocalPointer;
+using icu::LocalUCHARBUFPointer;
+using icu::StringPiece;
using icu::UnicodeString;
struct Lookahead
return result;
}
-static struct SResource* dependencyArray = NULL;
+static ArrayResource* dependencyArray = NULL;
static struct SResource *
parseDependency(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
}
elem = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, comment, status);
- array_add(dependencyArray, elem, status);
+ dependencyArray->add(elem);
if (U_FAILURE(*status))
{
namespace {
static struct SResource* resLookup(struct SResource* res, const char* key){
- struct SResource *current = NULL;
- struct SResTable *list;
- if (res == res_none()) {
+ if (res == res_none() || !res->isTable()) {
return NULL;
}
- list = &(res->u.fTable);
-
- current = list->fFirst;
+ TableResource *list = static_cast<TableResource *>(res);
+ SResource *current = list->fFirst;
while (current != NULL) {
if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), key) == 0) {
return current;
const char *localeID, const char *collationType,
UnicodeString &rules,
const char *& /*errorReason*/, UErrorCode &errorCode) {
- struct SRBRoot *data = NULL;
- UCHARBUF *ucbuf = NULL;
- int localeLength = strlen(localeID);
- char* filename = (char*)uprv_malloc(localeLength+5);
- char *inputDirBuf = NULL;
- char *openFileName = NULL;
- const char* cp = "";
- int32_t i = 0;
- int32_t dirlen = 0;
- int32_t filelen = 0;
- struct SResource* root;
- struct SResource* collations;
- struct SResource* collation;
- struct SResource* sequence;
-
- memcpy(filename, localeID, localeLength);
- for(i = 0; i < localeLength; i++){
+ CharString filename(localeID, errorCode);
+ for(int32_t i = 0; i < filename.length(); i++){
if(filename[i] == '-'){
- filename[i] = '_';
+ filename.data()[i] = '_';
}
}
- filename[localeLength] = '.';
- filename[localeLength+1] = 't';
- filename[localeLength+2] = 'x';
- filename[localeLength+3] = 't';
- filename[localeLength+4] = 0;
-
-
+ filename.append(".txt", errorCode);
if (U_FAILURE(errorCode)) {
return;
}
- if(filename==NULL){
- errorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }else{
- filelen = (int32_t)uprv_strlen(filename);
- }
+ CharString inputDirBuf;
+ CharString openFileName;
if(inputDir == NULL) {
- const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR);
- openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
- openFileName[0] = '\0';
+ const char *filenameBegin = uprv_strrchr(filename.data(), U_FILE_SEP_CHAR);
if (filenameBegin != NULL) {
/*
* When a filename ../../../data/root.txt is specified,
* This is very important when the resource file includes
* another file, like UCARules.txt or thaidict.brk.
*/
- int32_t filenameSize = (int32_t)(filenameBegin - filename + 1);
- inputDirBuf = (char *)uprv_malloc(filenameSize);
-
- /* test for NULL */
- if(inputDirBuf == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- goto finish;
- }
-
- uprv_strncpy(inputDirBuf, filename, filenameSize);
- inputDirBuf[filenameSize - 1] = 0;
- inputDir = inputDirBuf;
- dirlen = (int32_t)uprv_strlen(inputDir);
+ StringPiece dir = filename.toStringPiece();
+ const char *filenameLimit = filename.data() + filename.length();
+ dir.remove_suffix((int32_t)(filenameLimit - filenameBegin));
+ inputDirBuf.append(dir, errorCode);
+ inputDir = inputDirBuf.data();
}
}else{
- dirlen = (int32_t)uprv_strlen(inputDir);
-
- if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
- openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
-
- /* test for NULL */
- if(openFileName == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- goto finish;
- }
+ int32_t dirlen = (int32_t)uprv_strlen(inputDir);
- openFileName[0] = '\0';
+ if((filename[0] != U_FILE_SEP_CHAR) && (inputDir[dirlen-1] !='.')) {
/*
* append the input dir to openFileName if the first char in
- * filename is not file seperation char and the last char input directory is not '.'.
+ * filename is not file separator char and the last char input directory is not '.'.
* This is to support :
* genrb -s. /home/icu/data
* genrb -s. icu/data
* user should use
* genrb -s. icu/data --- start from CWD and look in icu/data dir
*/
- if( (filename[0] != U_FILE_SEP_CHAR) && (inputDir[dirlen-1] !='.')){
- uprv_strcpy(openFileName, inputDir);
- openFileName[dirlen] = U_FILE_SEP_CHAR;
+ openFileName.append(inputDir, dirlen, errorCode);
+ if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
+ openFileName.append(U_FILE_SEP_CHAR, errorCode);
}
- openFileName[dirlen + 1] = '\0';
- } else {
- openFileName = (char *) uprv_malloc(dirlen + filelen + 1);
-
- /* test for NULL */
- if(openFileName == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- goto finish;
- }
-
- uprv_strcpy(openFileName, inputDir);
-
}
}
- uprv_strcat(openFileName, filename);
- /* printf("%s\n", openFileName); */
- errorCode = U_ZERO_ERROR;
- ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, &errorCode);
-
+ openFileName.append(filename, errorCode);
+ if(U_FAILURE(errorCode)) {
+ return;
+ }
+ // printf("GenrbImporter::getRules(%s, %s) reads %s\n", localeID, collationType, openFileName.data());
+ const char* cp = "";
+ LocalUCHARBUFPointer ucbuf(
+ ucbuf_open(openFileName.data(), &cp, getShowWarning(), TRUE, &errorCode));
if(errorCode == U_FILE_ACCESS_ERROR) {
-
- fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName);
- goto finish;
+ fprintf(stderr, "couldn't open file %s\n", openFileName.data());
+ return;
}
- if (ucbuf == NULL || U_FAILURE(errorCode)) {
- fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName == NULL ? filename : openFileName,u_errorName(errorCode));
- goto finish;
+ if (ucbuf.isNull() || U_FAILURE(errorCode)) {
+ fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName.data(), u_errorName(errorCode));
+ return;
}
/* Parse the data into an SRBRoot */
- data = parse(ucbuf, inputDir, outputDir, filename, FALSE, FALSE, &errorCode);
+ struct SRBRoot *data =
+ parse(ucbuf.getAlias(), inputDir, outputDir, filename.data(), FALSE, FALSE, &errorCode);
if (U_FAILURE(errorCode)) {
- goto finish;
+ return;
}
- root = data->fRoot;
- collations = resLookup(root, "collations");
+ struct SResource *root = data->fRoot;
+ struct SResource *collations = resLookup(root, "collations");
if (collations != NULL) {
- collation = resLookup(collations, collationType);
+ struct SResource *collation = resLookup(collations, collationType);
if (collation != NULL) {
- sequence = resLookup(collation, "Sequence");
- if (sequence != NULL) {
+ struct SResource *sequence = resLookup(collation, "Sequence");
+ if (sequence != NULL && sequence->isString()) {
// No string pointer aliasing so that we need not hold onto the resource bundle.
- rules.setTo(sequence->u.fString.fChars, sequence->u.fString.fLength);
+ StringResource *sr = static_cast<StringResource *>(sequence);
+ rules = sr->fString;
}
}
}
-
-finish:
- if (inputDirBuf != NULL) {
- uprv_free(inputDirBuf);
- }
-
- if (openFileName != NULL) {
- uprv_free(openFileName);
- }
-
- if(ucbuf) {
- ucbuf_close(ucbuf);
- }
}
// Quick-and-dirty escaping function.
#endif // !UCONFIG_NO_COLLATION
-static struct SResource *
-addCollation(ParseState* state, struct SResource *result, const char *collationType,
+static TableResource *
+addCollation(ParseState* state, TableResource *result, const char *collationType,
uint32_t startline, UErrorCode *status)
{
// TODO: Use LocalPointer for result, or make caller close it when there is a failure.
{
// Ignore the parsed resources, continue parsing.
}
- else if (uprv_strcmp(subtag, "Version") == 0)
+ else if (uprv_strcmp(subtag, "Version") == 0 && member->isString())
{
+ StringResource *sr = static_cast<StringResource *>(member);
char ver[40];
- int32_t length = member->u.fString.fLength;
+ int32_t length = sr->length();
- if (length >= (int32_t) sizeof(ver))
+ if (length >= UPRV_LENGTHOF(ver))
{
- length = (int32_t) sizeof(ver) - 1;
+ length = UPRV_LENGTHOF(ver) - 1;
}
- u_UCharsToChars(member->u.fString.fChars, ver, length + 1); /* +1 for copying NULL */
+ sr->fString.extract(0, length, ver, UPRV_LENGTHOF(ver), US_INV);
u_versionFromString(version, ver);
- table_add(result, member, line, status);
+ result->add(member, line, *status);
member = NULL;
}
else if(uprv_strcmp(subtag, "%%CollationBin")==0)
{
/* discard duplicate %%CollationBin if any*/
}
- else if (uprv_strcmp(subtag, "Sequence") == 0)
+ else if (uprv_strcmp(subtag, "Sequence") == 0 && member->isString())
{
- rules.setTo(member->u.fString.fChars, member->u.fString.fLength);
+ StringResource *sr = static_cast<StringResource *>(member);
+ rules = sr->fString;
haveRules = TRUE;
// Defer building the collator until we have seen
// all sub-elements of the collation table, including the Version.
/* in order to achieve smaller data files, we can direct genrb */
/* to omit collation rules */
if(!state->omitCollationRules) {
- table_add(result, member, line, status);
+ result->add(member, line, *status);
member = NULL;
}
}
else // Just copy non-special items.
{
- table_add(result, member, line, status);
+ result->add(member, line, *status);
member = NULL;
}
res_close(member); // TODO: use LocalPointer
escape(parseError.postContext, postBuffer);
error(line, " error context: \"...%s\" ! \"%s...\"", preBuffer, postBuffer);
}
- if(isStrict()) {
+ if(isStrict() || t.isNull()) {
*status = intStatus;
res_close(result);
return NULL;
}
}
struct SResource *collationBin = bin_open(state->bundle, "%%CollationBin", totalSize, dest, NULL, NULL, status);
- table_add(result, collationBin, line, status);
+ result->add(collationBin, line, *status);
if (U_FAILURE(*status)) {
res_close(result);
return NULL;
static struct SResource *
parseCollationElements(ParseState* state, char *tag, uint32_t startline, UBool newCollation, UErrorCode *status)
{
- struct SResource *result = NULL;
+ TableResource *result = NULL;
struct SResource *member = NULL;
- struct SResource *collationRes = NULL;
struct UString *tokenValue;
struct UString comment;
enum ETokenType token;
return NULL;
}
- table_add(result, member, line, status);
+ result->add(member, line, *status);
}
else
{
/* then, we cannot handle aliases */
if(token == TOK_OPEN_BRACE) {
token = getToken(state, &tokenValue, &comment, &line, status);
+ TableResource *collationRes;
if (keepCollationType(subtag)) {
collationRes = table_open(state->bundle, subtag, NULL, status);
} else {
// need to parse the collation data regardless
collationRes = addCollation(state, collationRes, subtag, startline, status);
if (collationRes != NULL) {
- table_add(result, collationRes, startline, status);
+ result->add(collationRes, startline, *status);
}
} else if(token == TOK_COLON) { /* right now, we'll just try to see if we have aliases */
/* we could have a table too */
return NULL;
}
- table_add(result, member, line, status);
+ result->add(member, line, *status);
} else {
res_close(result);
*status = U_INVALID_FORMAT_ERROR;
/* Necessary, because CollationElements requires the bundle->fRoot member to be present which,
if this weren't special-cased, wouldn't be set until the entire file had been processed. */
static struct SResource *
-realParseTable(ParseState* state, struct SResource *table, char *tag, uint32_t startline, UErrorCode *status)
+realParseTable(ParseState* state, TableResource *table, char *tag, uint32_t startline, UErrorCode *status)
{
struct SResource *member = NULL;
struct UString *tokenValue=NULL;
return NULL;
}
- table_add(table, member, line, status);
+ table->add(member, line, *status);
if (U_FAILURE(*status))
{
static struct SResource *
parseTable(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
{
- struct SResource *result;
-
if (tag != NULL && uprv_strcmp(tag, "CollationElements") == 0)
{
return parseCollationElements(state, tag, startline, FALSE, status);
printf(" table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
}
- result = table_open(state->bundle, tag, comment, status);
+ TableResource *result = table_open(state->bundle, tag, comment, status);
if (result == NULL || U_FAILURE(*status))
{
static struct SResource *
parseArray(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
{
- struct SResource *result = NULL;
struct SResource *member = NULL;
struct UString *tokenValue;
struct UString memberComments;
enum ETokenType token;
UBool readToken = FALSE;
- result = array_open(state->bundle, tag, comment, status);
+ ArrayResource *result = array_open(state->bundle, tag, comment, status);
if (result == NULL || U_FAILURE(*status))
{
return NULL;
}
- array_add(result, member, status);
-
- if (U_FAILURE(*status))
- {
- res_close(result);
- return NULL;
- }
+ result->add(member);
/* eat optional comma if present */
token = peekToken(state, 0, NULL, NULL, NULL, status);
static struct SResource *
parseIntVector(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
{
- struct SResource *result = NULL;
enum ETokenType token;
char *string;
int32_t value;
uint32_t len;
struct UString memberComments;
- result = intvector_open(state->bundle, tag, comment, status);
+ IntVectorResource *result = intvector_open(state->bundle, tag, comment, status);
if (result == NULL || U_FAILURE(*status))
{
if(len==uprv_strlen(string))
{
- intvector_add(result, value, status);
+ result->add(value, *status);
uprv_free(string);
token = peekToken(state, 0, NULL, NULL, NULL, status);
}
static struct SResource *
parseBinary(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
{
- struct SResource *result = NULL;
- uint8_t *value;
- char *string;
- char toConv[3] = {'\0', '\0', '\0'};
- uint32_t count;
- uint32_t i;
- uint32_t line;
- char *stopstring;
- uint32_t len;
-
- string = getInvariantString(state, &line, NULL, status);
-
- if (string == NULL || U_FAILURE(*status))
+ uint32_t line;
+ LocalMemory<char> string(getInvariantString(state, &line, NULL, status));
+ if (string.isNull() || U_FAILURE(*status))
{
return NULL;
}
expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
-
if (U_FAILURE(*status))
{
- uprv_free(string);
return NULL;
}
printf(" binary %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
}
- count = (uint32_t)uprv_strlen(string);
+ uint32_t count = (uint32_t)uprv_strlen(string.getAlias());
if (count > 0){
if((count % 2)==0){
- value = static_cast<uint8_t *>(uprv_malloc(sizeof(uint8_t) * count));
-
- if (value == NULL)
+ LocalMemory<uint8_t> value;
+ if (value.allocateInsteadAndCopy(count) == NULL)
{
- uprv_free(string);
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- for (i = 0; i < count; i += 2)
+ char toConv[3] = {'\0', '\0', '\0'};
+ for (uint32_t i = 0; i < count; i += 2)
{
toConv[0] = string[i];
toConv[1] = string[i + 1];
+ char *stopstring;
value[i >> 1] = (uint8_t) uprv_strtoul(toConv, &stopstring, 16);
- len=(uint32_t)(stopstring-toConv);
+ uint32_t len=(uint32_t)(stopstring-toConv);
- if(len!=uprv_strlen(toConv))
+ if(len!=2)
{
- uprv_free(string);
*status=U_INVALID_CHAR_FOUND;
return NULL;
}
}
- result = bin_open(state->bundle, tag, (i >> 1), value,NULL, comment, status);
-
- uprv_free(value);
+ return bin_open(state->bundle, tag, count >> 1, value.getAlias(), NULL, comment, status);
}
else
{
*status = U_INVALID_CHAR_FOUND;
- uprv_free(string);
- error(line, "Encountered invalid binary string");
+ error(line, "Encountered invalid binary value (length is odd)");
return NULL;
}
}
else
{
- result = bin_open(state->bundle, tag, 0, NULL, "",comment,status);
- warning(startline, "Encountered empty binary tag");
+ warning(startline, "Encountered empty binary value");
+ return bin_open(state->bundle, tag, 0, NULL, "", comment, status);
}
- uprv_free(string);
-
- return result;
}
static struct SResource *
static struct SResource *
parseImport(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
{
- struct SResource *result;
- FileStream *file;
- int32_t len;
- uint8_t *data;
- char *filename;
uint32_t line;
- char *fullname = NULL;
- filename = getInvariantString(state, &line, NULL, status);
-
+ LocalMemory<char> filename(getInvariantString(state, &line, NULL, status));
if (U_FAILURE(*status))
{
return NULL;
if (U_FAILURE(*status))
{
- uprv_free(filename);
return NULL;
}
}
/* Open the input file for reading */
- if (state->inputdir == NULL)
- {
-#if 1
- /*
- * Always save file file name, even if there's
- * no input directory specified. MIGHT BREAK SOMETHING
- */
- int32_t filenameLength = uprv_strlen(filename);
-
- fullname = (char *) uprv_malloc(filenameLength + 1);
- uprv_strcpy(fullname, filename);
-#endif
-
- file = T_FileStream_open(filename, "rb");
+ CharString fullname;
+ if (state->inputdir != NULL) {
+ fullname.append(state->inputdir, *status);
}
- else
- {
-
- int32_t count = (int32_t)uprv_strlen(filename);
-
- if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
- {
- fullname = (char *) uprv_malloc(state->inputdirLength + count + 2);
-
- /* test for NULL */
- if(fullname == NULL)
- {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
- uprv_strcpy(fullname, state->inputdir);
-
- fullname[state->inputdirLength] = U_FILE_SEP_CHAR;
- fullname[state->inputdirLength + 1] = '\0';
-
- uprv_strcat(fullname, filename);
- }
- else
- {
- fullname = (char *) uprv_malloc(state->inputdirLength + count + 1);
-
- /* test for NULL */
- if(fullname == NULL)
- {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
- uprv_strcpy(fullname, state->inputdir);
- uprv_strcat(fullname, filename);
- }
-
- file = T_FileStream_open(fullname, "rb");
-
+ fullname.appendPathPart(filename.getAlias(), *status);
+ if (U_FAILURE(*status)) {
+ return NULL;
}
+ FileStream *file = T_FileStream_open(fullname.data(), "rb");
if (file == NULL)
{
- error(line, "couldn't open input file %s", filename);
+ error(line, "couldn't open input file %s", filename.getAlias());
*status = U_FILE_ACCESS_ERROR;
return NULL;
}
- len = T_FileStream_size(file);
- data = (uint8_t*)uprv_malloc(len * sizeof(uint8_t));
- /* test for NULL */
- if(data == NULL)
+ int32_t len = T_FileStream_size(file);
+ LocalMemory<uint8_t> data;
+ if(data.allocateInsteadAndCopy(len) == NULL)
{
*status = U_MEMORY_ALLOCATION_ERROR;
T_FileStream_close (file);
return NULL;
}
- /* int32_t numRead = */ T_FileStream_read (file, data, len);
+ /* int32_t numRead = */ T_FileStream_read(file, data.getAlias(), len);
T_FileStream_close (file);
- result = bin_open(state->bundle, tag, len, data, fullname, comment, status);
-
- uprv_free(data);
- uprv_free(filename);
- uprv_free(fullname);
-
- return result;
+ return bin_open(state->bundle, tag, len, data.getAlias(), fullname.data(), comment, status);
}
static struct SResource *
ustr_init(&comment);
expect(&state, TOK_STRING, &tokenValue, &comment, NULL, status);
- state.bundle = bundle_open(&comment, FALSE, status);
+ state.bundle = new SRBRoot(&comment, FALSE, *status);
if (state.bundle == NULL || U_FAILURE(*status))
{
}
- bundle_setlocale(state.bundle, tokenValue->fChars, status);
+ state.bundle->setLocale(tokenValue->fChars, *status);
/* The following code is to make Empty bundle work no matter with :table specifer or not */
token = getToken(&state, NULL, NULL, &line, status);
if (U_FAILURE(*status))
{
- bundle_close(state.bundle, status);
+ delete state.bundle;
return NULL;
}
* This is the same as a regular table, but also sets the
* URES_ATT_NO_FALLBACK flag in indexes[URES_INDEX_ATTRIBUTES] .
*/
- state.bundle->noFallback=TRUE;
+ state.bundle->fNoFallback=TRUE;
}
/* top-level tables need not handle special table names like "collations" */
- realParseTable(&state, state.bundle->fRoot, NULL, line, status);
+ assert(!state.bundle->fIsPoolBundle);
+ assert(state.bundle->fRoot->fType == URES_TABLE);
+ TableResource *rootTable = static_cast<TableResource *>(state.bundle->fRoot);
+ realParseTable(&state, rootTable, NULL, line, status);
if(dependencyArray!=NULL){
- table_add(state.bundle->fRoot, dependencyArray, 0, status);
+ rootTable->add(dependencyArray, 0, *status);
dependencyArray = NULL;
}
if (U_FAILURE(*status))
{
- bundle_close(state.bundle, status);
+ delete state.bundle;
res_close(dependencyArray);
return NULL;
}