]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/tools/genrb/parse.cpp
ICU-491.11.1.tar.gz
[apple/icu.git] / icuSources / tools / genrb / parse.cpp
diff --git a/icuSources/tools/genrb/parse.cpp b/icuSources/tools/genrb/parse.cpp
new file mode 100644 (file)
index 0000000..b9e393c
--- /dev/null
@@ -0,0 +1,2155 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1998-2012, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*
+* File parse.cpp
+*
+* Modification History:
+*
+*   Date          Name          Description
+*   05/26/99     stephen       Creation.
+*   02/25/00     weiv          Overhaul to write udata
+*   5/10/01      Ram           removed ustdio dependency
+*   06/10/2001  Dominic Ludlam <dom@recoil.org> Rewritten
+*******************************************************************************
+*/
+
+#include "ucol_imp.h"
+#include "parse.h"
+#include "errmsg.h"
+#include "uhash.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uinvchar.h"
+#include "read.h"
+#include "ustr.h"
+#include "reslist.h"
+#include "rbt_pars.h"
+#include "genrb.h"
+#include "unicode/ustring.h"
+#include "unicode/uscript.h"
+#include "unicode/putil.h"
+#include <stdio.h>
+
+/* Number of tokens to read ahead of the current stream position */
+#define MAX_LOOKAHEAD   3
+
+#define CR               0x000D
+#define LF               0x000A
+#define SPACE            0x0020
+#define TAB              0x0009
+#define ESCAPE           0x005C
+#define HASH             0x0023
+#define QUOTE            0x0027
+#define ZERO             0x0030
+#define STARTCOMMAND     0x005B
+#define ENDCOMMAND       0x005D
+#define OPENSQBRACKET    0x005B
+#define CLOSESQBRACKET   0x005D
+
+struct Lookahead
+{
+     enum   ETokenType type;
+     struct UString    value;
+     struct UString    comment;
+     uint32_t          line;
+};
+
+/* keep in sync with token defines in read.h */
+const char *tokenNames[TOK_TOKEN_COUNT] =
+{
+     "string",             /* A string token, such as "MonthNames" */
+     "'{'",                 /* An opening brace character */
+     "'}'",                 /* A closing brace character */
+     "','",                 /* A comma */
+     "':'",                 /* A colon */
+
+     "<end of file>",     /* End of the file has been reached successfully */
+     "<end of line>"
+};
+
+/* Just to store "TRUE" */
+static const UChar trueValue[] = {0x0054, 0x0052, 0x0055, 0x0045, 0x0000};
+
+typedef struct {
+    struct Lookahead  lookahead[MAX_LOOKAHEAD + 1];
+    uint32_t          lookaheadPosition;
+    UCHARBUF         *buffer;
+    struct SRBRoot *bundle;
+    const char     *inputdir;
+    uint32_t        inputdirLength;
+    const char     *outputdir;
+    uint32_t        outputdirLength;
+    UBool           makeBinaryCollation;
+} ParseState;
+
+static UBool gOmitCollationRules  = FALSE;
+
+typedef struct SResource *
+ParseResourceFunction(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status);
+
+static struct SResource *parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status);
+
+/* The nature of the lookahead buffer:
+   There are MAX_LOOKAHEAD + 1 slots, used as a circular buffer.  This provides
+   MAX_LOOKAHEAD lookahead tokens and a slot for the current token and value.
+   When getToken is called, the current pointer is moved to the next slot and the
+   old slot is filled with the next token from the reader by calling getNextToken.
+   The token values are stored in the slot, which means that token values don't
+   survive a call to getToken, ie.
+
+   UString *value;
+
+   getToken(&value, NULL, status);
+   getToken(NULL,   NULL, status);       bad - value is now a different string
+*/
+static void
+initLookahead(ParseState* state, UCHARBUF *buf, UErrorCode *status)
+{
+    static uint32_t initTypeStrings = 0;
+    uint32_t i;
+
+    if (!initTypeStrings)
+    {
+        initTypeStrings = 1;
+    }
+
+    state->lookaheadPosition   = 0;
+    state->buffer              = buf;
+
+    resetLineNumber();
+
+    for (i = 0; i < MAX_LOOKAHEAD; i++)
+    {
+        state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status);
+        if (U_FAILURE(*status))
+        {
+            return;
+        }
+    }
+
+    *status = U_ZERO_ERROR;
+}
+
+static void
+cleanupLookahead(ParseState* state)
+{
+    uint32_t i;
+    for (i = 0; i < MAX_LOOKAHEAD; i++)
+    {
+        ustr_deinit(&state->lookahead[i].value);
+        ustr_deinit(&state->lookahead[i].comment);
+    }
+
+}
+
+static enum ETokenType
+getToken(ParseState* state, struct UString **tokenValue, struct UString* comment, uint32_t *linenumber, UErrorCode *status)
+{
+    enum ETokenType result;
+    uint32_t          i;
+
+    result = state->lookahead[state->lookaheadPosition].type;
+
+    if (tokenValue != NULL)
+    {
+        *tokenValue = &state->lookahead[state->lookaheadPosition].value;
+    }
+
+    if (linenumber != NULL)
+    {
+        *linenumber = state->lookahead[state->lookaheadPosition].line;
+    }
+
+    if (comment != NULL)
+    {
+        ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status);
+    }
+
+    i = (state->lookaheadPosition + MAX_LOOKAHEAD) % (MAX_LOOKAHEAD + 1);
+    state->lookaheadPosition = (state->lookaheadPosition + 1) % (MAX_LOOKAHEAD + 1);
+    ustr_setlen(&state->lookahead[i].comment, 0, status);
+    ustr_setlen(&state->lookahead[i].value, 0, status);
+    state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status);
+
+    /* printf("getToken, returning %s\n", tokenNames[result]); */
+
+    return result;
+}
+
+static enum ETokenType
+peekToken(ParseState* state, uint32_t lookaheadCount, struct UString **tokenValue, uint32_t *linenumber, struct UString *comment, UErrorCode *status)
+{
+    uint32_t i = (state->lookaheadPosition + lookaheadCount) % (MAX_LOOKAHEAD + 1);
+
+    if (U_FAILURE(*status))
+    {
+        return TOK_ERROR;
+    }
+
+    if (lookaheadCount >= MAX_LOOKAHEAD)
+    {
+        *status = U_INTERNAL_PROGRAM_ERROR;
+        return TOK_ERROR;
+    }
+
+    if (tokenValue != NULL)
+    {
+        *tokenValue = &state->lookahead[i].value;
+    }
+
+    if (linenumber != NULL)
+    {
+        *linenumber = state->lookahead[i].line;
+    }
+
+    if(comment != NULL){
+        ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status);
+    }
+
+    return state->lookahead[i].type;
+}
+
+static void
+expect(ParseState* state, enum ETokenType expectedToken, struct UString **tokenValue, struct UString *comment, uint32_t *linenumber, UErrorCode *status)
+{
+    uint32_t        line;
+
+    enum ETokenType token = getToken(state, tokenValue, comment, &line, status);
+
+    if (linenumber != NULL)
+    {
+        *linenumber = line;
+    }
+
+    if (U_FAILURE(*status))
+    {
+        return;
+    }
+
+    if (token != expectedToken)
+    {
+        *status = U_INVALID_FORMAT_ERROR;
+        error(line, "expecting %s, got %s", tokenNames[expectedToken], tokenNames[token]);
+    }
+    else
+    {
+        *status = U_ZERO_ERROR;
+    }
+}
+
+static char *getInvariantString(ParseState* state, uint32_t *line, struct UString *comment, UErrorCode *status)
+{
+    struct UString *tokenValue;
+    char           *result;
+    uint32_t        count;
+
+    expect(state, TOK_STRING, &tokenValue, comment, line, status);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+    count = u_strlen(tokenValue->fChars);
+    if(!uprv_isInvariantUString(tokenValue->fChars, count)) {
+        *status = U_INVALID_FORMAT_ERROR;
+        error(*line, "invariant characters required for table keys, binary data, etc.");
+        return NULL;
+    }
+
+    result = reinterpret_cast<char *>(uprv_malloc(count+1));
+
+    if (result == NULL)
+    {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+
+    u_UCharsToChars(tokenValue->fChars, result, count+1);
+    return result;
+}
+
+static struct SResource *
+parseUCARules(ParseState* state, char *tag, uint32_t startline, const struct UString* /*comment*/, UErrorCode *status)
+{
+    struct SResource *result = NULL;
+    struct UString   *tokenValue;
+    FileStream       *file          = NULL;
+    char              filename[256] = { '\0' };
+    char              cs[128]       = { '\0' };
+    uint32_t          line;
+    int               len=0;
+    UBool quoted = FALSE;
+    UCHARBUF *ucbuf=NULL;
+    UChar32   c     = 0;
+    const char* cp  = NULL;
+    UChar *pTarget     = NULL;
+    UChar *target      = NULL;
+    UChar *targetLimit = NULL;
+    int32_t size = 0;
+
+    expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
+
+    if(isVerbose()){
+        printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    /* make the filename including the directory */
+    if (state->inputdir != NULL)
+    {
+        uprv_strcat(filename, state->inputdir);
+
+        if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
+        {
+            uprv_strcat(filename, U_FILE_SEP_STRING);
+        }
+    }
+
+    u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    uprv_strcat(filename, cs);
+
+    if(gOmitCollationRules) {
+        return res_none();
+    }
+
+    ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status);
+
+    if (U_FAILURE(*status)) {
+        error(line, "An error occured while opening the input file %s\n", filename);
+        return NULL;
+    }
+
+    /* We allocate more space than actually required
+    * since the actual size needed for storing UChars
+    * is not known in UTF-8 byte stream
+    */
+    size        = ucbuf_size(ucbuf) + 1;
+    pTarget     = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * size);
+    uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR);
+    target      = pTarget;
+    targetLimit = pTarget+size;
+
+    /* read the rules into the buffer */
+    while (target < targetLimit)
+    {
+        c = ucbuf_getc(ucbuf, status);
+        if(c == QUOTE) {
+            quoted = (UBool)!quoted;
+        }
+        /* weiv (06/26/2002): adding the following:
+         * - preserving spaces in commands [...]
+         * - # comments until the end of line
+         */
+        if (c == STARTCOMMAND && !quoted)
+        {
+            /* preserve commands
+             * closing bracket will be handled by the
+             * append at the end of the loop
+             */
+            while(c != ENDCOMMAND) {
+                U_APPEND_CHAR32(c, target,len);
+                c = ucbuf_getc(ucbuf, status);
+            }
+        }
+        else if (c == HASH && !quoted) {
+            /* skip comments */
+            while(c != CR && c != LF) {
+                c = ucbuf_getc(ucbuf, status);
+            }
+            continue;
+        }
+        else if (c == ESCAPE)
+        {
+            c = unescape(ucbuf, status);
+
+            if (c == (UChar32)U_ERR)
+            {
+                uprv_free(pTarget);
+                T_FileStream_close(file);
+                return NULL;
+            }
+        }
+        else if (!quoted && (c == SPACE || c == TAB || c == CR || c == LF))
+        {
+            /* ignore spaces carriage returns
+            * and line feed unless in the form \uXXXX
+            */
+            continue;
+        }
+
+        /* Append UChar * after dissembling if c > 0xffff*/
+        if (c != (UChar32)U_EOF)
+        {
+            U_APPEND_CHAR32(c, target,len);
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    /* terminate the string */
+    if(target < targetLimit){
+        *target = 0x0000;
+    }
+
+    result = string_open(state->bundle, tag, pTarget, (int32_t)(target - pTarget), NULL, status);
+
+
+    ucbuf_close(ucbuf);
+    uprv_free(pTarget);
+    T_FileStream_close(file);
+
+    return result;
+}
+
+static struct SResource *
+parseTransliterator(ParseState* state, char *tag, uint32_t startline, const struct UString* /*comment*/, UErrorCode *status)
+{
+    struct SResource *result = NULL;
+    struct UString   *tokenValue;
+    FileStream       *file          = NULL;
+    char              filename[256] = { '\0' };
+    char              cs[128]       = { '\0' };
+    uint32_t          line;
+    UCHARBUF *ucbuf=NULL;
+    const char* cp  = NULL;
+    UChar *pTarget     = NULL;
+    const UChar *pSource     = NULL;
+    int32_t size = 0;
+
+    expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
+
+    if(isVerbose()){
+        printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    /* make the filename including the directory */
+    if (state->inputdir != NULL)
+    {
+        uprv_strcat(filename, state->inputdir);
+
+        if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
+        {
+            uprv_strcat(filename, U_FILE_SEP_STRING);
+        }
+    }
+
+    u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    uprv_strcat(filename, cs);
+
+
+    ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status);
+
+    if (U_FAILURE(*status)) {
+        error(line, "An error occured while opening the input file %s\n", filename);
+        return NULL;
+    }
+
+    /* We allocate more space than actually required
+    * since the actual size needed for storing UChars
+    * is not known in UTF-8 byte stream
+    */
+    pSource = ucbuf_getBuffer(ucbuf, &size, status);
+    pTarget     = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (size + 1));
+    uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR);
+
+#if !UCONFIG_NO_TRANSLITERATION
+    size = utrans_stripRules(pSource, size, pTarget, status);
+#else
+    size = 0;
+    fprintf(stderr, " Warning: writing empty transliteration data ( UCONFIG_NO_TRANSLITERATION ) \n");
+#endif
+    result = string_open(state->bundle, tag, pTarget, size, NULL, status);
+
+    ucbuf_close(ucbuf);
+    uprv_free(pTarget);
+    T_FileStream_close(file);
+
+    return result;
+}
+static struct SResource* dependencyArray = NULL;
+
+static struct SResource *
+parseDependency(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
+{
+    struct SResource *result = NULL;
+    struct SResource *elem = NULL;
+    struct UString   *tokenValue;
+    uint32_t          line;
+    char              filename[256] = { '\0' };
+    char              cs[128]       = { '\0' };
+    
+    expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
+
+    if(isVerbose()){
+        printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    /* make the filename including the directory */
+    if (state->outputdir != NULL)
+    {
+        uprv_strcat(filename, state->outputdir);
+
+        if (state->outputdir[state->outputdirLength - 1] != U_FILE_SEP_CHAR)
+        {
+            uprv_strcat(filename, U_FILE_SEP_STRING);
+        }
+    }
+    
+    u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    uprv_strcat(filename, cs);
+    if(!T_FileStream_file_exists(filename)){
+        if(isStrict()){
+            error(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename);
+        }else{
+            warning(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename);       
+        }
+    }
+    if(dependencyArray==NULL){
+        dependencyArray = array_open(state->bundle, "%%DEPENDENCY", NULL, status);
+    }
+    if(tag!=NULL){
+        result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
+    }
+    elem = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, comment, status);
+
+    array_add(dependencyArray, elem, status);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+    return result;
+}
+static struct SResource *
+parseString(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
+{
+    struct UString   *tokenValue;
+    struct SResource *result = NULL;
+
+/*    if (tag != NULL && uprv_strcmp(tag, "%%UCARULES") == 0)
+    {
+        return parseUCARules(tag, startline, status);
+    }*/
+    if(isVerbose()){
+        printf(" string %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+    expect(state, TOK_STRING, &tokenValue, NULL, NULL, status);
+
+    if (U_SUCCESS(*status))
+    {
+        /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
+        doesn't survive expect either) */
+
+        result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
+        if(U_SUCCESS(*status) && result) {
+            expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+            if (U_FAILURE(*status))
+            {
+                res_close(result);
+                return NULL;
+            }
+        }
+    }
+
+    return result;
+}
+
+static struct SResource *
+parseAlias(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
+{
+    struct UString   *tokenValue;
+    struct SResource *result  = NULL;
+
+    expect(state, TOK_STRING, &tokenValue, NULL, NULL, status);
+
+    if(isVerbose()){
+        printf(" alias %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    if (U_SUCCESS(*status))
+    {
+        /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
+        doesn't survive expect either) */
+
+        result = alias_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
+
+        expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+    }
+
+    return result;
+}
+
+typedef struct{
+    const char* inputDir;
+    const char* outputDir;
+} GenrbData;
+
+static struct SResource* resLookup(struct SResource* res, const char* key){
+    struct SResource *current = NULL;
+    struct SResTable *list;
+    if (res == res_none()) {
+        return NULL;
+    }
+
+    list = &(res->u.fTable);
+
+    current = list->fFirst;
+    while (current != NULL) {
+        if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), key) == 0) {
+            return current;
+        }
+        current = current->fNext;
+    }
+    return NULL;
+}
+
+static const UChar* importFromDataFile(void* context, const char* locale, const char* type, int32_t* pLength, UErrorCode* status){
+    struct SRBRoot *data         = NULL;
+    UCHARBUF       *ucbuf        = NULL;
+    GenrbData* genrbdata = (GenrbData*) context;
+    int localeLength = strlen(locale);
+    char* filename = (char*)uprv_malloc(localeLength+5);
+    char           *inputDirBuf  = NULL;
+    char           *openFileName = NULL;
+    const char* cp = "";
+    UChar* urules = NULL;
+    int32_t urulesLength = 0;
+    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, locale, localeLength);
+    for(i = 0; i < localeLength; i++){
+        if(filename[i] == '-'){
+            filename[i] = '_';
+        }
+    }
+    filename[localeLength]   = '.';
+    filename[localeLength+1] = 't';
+    filename[localeLength+2] = 'x';
+    filename[localeLength+3] = 't';
+    filename[localeLength+4] = 0;
+
+
+    if (status==NULL || U_FAILURE(*status)) {
+        return NULL;
+    }
+    if(filename==NULL){
+        *status=U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }else{
+        filelen = (int32_t)uprv_strlen(filename);
+    }
+    if(genrbdata->inputDir == NULL) {
+        const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR);
+        openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
+        openFileName[0] = '\0';
+        if (filenameBegin != NULL) {
+            /*
+             * When a filename ../../../data/root.txt is specified,
+             * we presume that the input directory is ../../../data
+             * 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 = uprv_strncpy((char *)uprv_malloc(filenameSize), filename, filenameSize);
+
+            /* test for NULL */
+            if(inputDirBuf == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto finish;
+            }
+
+            inputDirBuf[filenameSize - 1] = 0;
+            genrbdata->inputDir = inputDirBuf;
+            dirlen  = (int32_t)uprv_strlen(genrbdata->inputDir);
+        }
+    }else{
+        dirlen  = (int32_t)uprv_strlen(genrbdata->inputDir);
+
+        if(genrbdata->inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
+            openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
+
+            /* test for NULL */
+            if(openFileName == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto finish;
+            }
+
+            openFileName[0] = '\0';
+            /*
+             * 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 '.'.
+             * This is to support :
+             * genrb -s. /home/icu/data
+             * genrb -s. icu/data
+             * The user cannot mix notations like
+             * genrb -s. /icu/data --- the absolute path specified. -s redundant
+             * user should use
+             * genrb -s. icu/data  --- start from CWD and look in icu/data dir
+             */
+            if( (filename[0] != U_FILE_SEP_CHAR) && (genrbdata->inputDir[dirlen-1] !='.')){
+                uprv_strcpy(openFileName, genrbdata->inputDir);
+                openFileName[dirlen]     = U_FILE_SEP_CHAR;
+            }
+            openFileName[dirlen + 1] = '\0';
+        } else {
+            openFileName = (char *) uprv_malloc(dirlen + filelen + 1);
+
+            /* test for NULL */
+            if(openFileName == NULL) {
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                goto finish;
+            }
+
+            uprv_strcpy(openFileName, genrbdata->inputDir);
+
+        }
+    }
+    uprv_strcat(openFileName, filename);
+    /* printf("%s\n", openFileName);  */
+    *status = U_ZERO_ERROR;
+    ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, status);
+
+    if(*status == U_FILE_ACCESS_ERROR) {
+
+        fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName);
+        goto finish;
+    }
+    if (ucbuf == NULL || U_FAILURE(*status)) {
+        fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName == NULL ? filename : openFileName,u_errorName(*status));
+        goto finish;
+    }
+
+    /* Parse the data into an SRBRoot */
+    data = parse(ucbuf, genrbdata->inputDir, genrbdata->outputDir, FALSE, status);
+
+    root = data->fRoot;
+    collations = resLookup(root, "collations");
+    if (collations != NULL) {
+      collation = resLookup(collations, type);
+      if (collation != NULL) {
+        sequence = resLookup(collation, "Sequence");
+        if (sequence != NULL) {
+          urules = sequence->u.fString.fChars;
+          urulesLength = sequence->u.fString.fLength;
+          *pLength = urulesLength;
+        }
+      }
+    }
+
+finish:
+    if (inputDirBuf != NULL) {
+        uprv_free(inputDirBuf);
+    }
+
+    if (openFileName != NULL) {
+        uprv_free(openFileName);
+    }
+
+    if(ucbuf) {
+        ucbuf_close(ucbuf);
+    }
+
+    return urules;
+}
+
+// Quick-and-dirty escaping function.
+// Assumes that we are on an ASCII-based platform.
+static void
+escape(const UChar *s, char *buffer) {
+    int32_t length = u_strlen(s);
+    int32_t i = 0;
+    for (;;) {
+        UChar32 c;
+        U16_NEXT(s, i, length, c);
+        if (c == 0) {
+            *buffer = 0;
+            return;
+        } else if (0x20 <= c && c <= 0x7e) {
+            // printable ASCII
+            *buffer++ = (char)c;  // assumes ASCII-based platform
+        } else {
+            buffer += sprintf(buffer, "\\u%04X", (int)c);
+        }
+    }
+}
+
+static struct SResource *
+addCollation(ParseState* state, struct SResource  *result, uint32_t startline, UErrorCode *status)
+{
+    struct SResource  *member = NULL;
+    struct UString    *tokenValue;
+    struct UString     comment;
+    enum   ETokenType  token;
+    char               subtag[1024];
+    UVersionInfo       version;
+    uint32_t           line;
+    GenrbData genrbdata;
+    /* '{' . (name resource)* '}' */
+    version[0]=0; version[1]=0; version[2]=0; version[3]=0;
+
+    for (;;)
+    {
+        ustr_init(&comment);
+        token = getToken(state, &tokenValue, &comment, &line, status);
+
+        if (token == TOK_CLOSE_BRACE)
+        {
+            return result;
+        }
+
+        if (token != TOK_STRING)
+        {
+            res_close(result);
+            *status = U_INVALID_FORMAT_ERROR;
+
+            if (token == TOK_EOF)
+            {
+                error(startline, "unterminated table");
+            }
+            else
+            {
+                error(line, "Unexpected token %s", tokenNames[token]);
+            }
+
+            return NULL;
+        }
+
+        u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        member = parseResource(state, subtag, NULL, status);
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        if (uprv_strcmp(subtag, "Version") == 0)
+        {
+            char     ver[40];
+            int32_t length = member->u.fString.fLength;
+
+            if (length >= (int32_t) sizeof(ver))
+            {
+                length = (int32_t) sizeof(ver) - 1;
+            }
+
+            u_UCharsToChars(member->u.fString.fChars, ver, length + 1); /* +1 for copying NULL */
+            u_versionFromString(version, ver);
+
+            table_add(result, member, line, status);
+
+        }
+        else if (uprv_strcmp(subtag, "Override") == 0)
+        {
+            // UBool override = (u_strncmp(member->u.fString.fChars, trueValue, u_strlen(trueValue)) == 0);
+            table_add(result, member, line, status);
+
+        }
+        else if(uprv_strcmp(subtag, "%%CollationBin")==0)
+        {
+            /* discard duplicate %%CollationBin if any*/
+        }
+        else if (uprv_strcmp(subtag, "Sequence") == 0)
+        {
+#if UCONFIG_NO_COLLATION || UCONFIG_NO_FILE_IO
+            warning(line, "Not building collation elements because of UCONFIG_NO_COLLATION and/or UCONFIG_NO_FILE_IO, see uconfig.h");
+#else
+            if(state->makeBinaryCollation) {
+
+                /* do the collation elements */
+                int32_t     len   = 0;
+                uint8_t   *data  = NULL;
+                UCollator *coll  = NULL;
+                int32_t reorderCodes[USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)];
+                int32_t reorderCodeCount;
+                int32_t reorderCodeIndex;
+                UParseError parseError;
+
+                genrbdata.inputDir = state->inputdir;
+                genrbdata.outputDir = state->outputdir;
+
+                UErrorCode intStatus = U_ZERO_ERROR;
+                uprv_memset(&parseError, 0, sizeof(parseError));
+                coll = ucol_openRulesForImport(member->u.fString.fChars, member->u.fString.fLength,
+                                               UCOL_OFF, UCOL_DEFAULT_STRENGTH,&parseError, importFromDataFile, &genrbdata, &intStatus);
+
+                if (U_SUCCESS(intStatus) && coll != NULL)
+                {
+                    len = ucol_cloneBinary(coll, NULL, 0, &intStatus);
+                    data = (uint8_t *)uprv_malloc(len);
+                    intStatus = U_ZERO_ERROR;
+                    len = ucol_cloneBinary(coll, data, len, &intStatus);
+                    /*data = ucol_cloneRuleData(coll, &len, &intStatus);*/
+
+                    /* tailoring rules version */
+                    /* This is wrong! */
+                    /*coll->dataInfo.dataVersion[1] = version[0];*/
+                    /* Copy tailoring version. Builder version already */
+                    /* set in ucol_openRules */
+                    ((UCATableHeader *)data)->version[1] = version[0];
+                    ((UCATableHeader *)data)->version[2] = version[1];
+                    ((UCATableHeader *)data)->version[3] = version[2];
+
+                    if (U_SUCCESS(intStatus) && data != NULL)
+                    {
+                        struct SResource *collationBin = bin_open(state->bundle, "%%CollationBin", len, data, NULL, NULL, status);
+                        table_add(result, collationBin, line, status);
+                        uprv_free(data);
+
+                        reorderCodeCount = ucol_getReorderCodes(
+                            coll, reorderCodes, USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST), &intStatus);
+                        if (U_SUCCESS(intStatus) && reorderCodeCount > 0) {
+                            struct SResource *reorderCodeRes = intvector_open(state->bundle, "%%ReorderCodes", NULL, status);
+                            for (reorderCodeIndex = 0; reorderCodeIndex < reorderCodeCount; reorderCodeIndex++) {
+                                intvector_add(reorderCodeRes, reorderCodes[reorderCodeIndex], status);
+                            }
+                            table_add(result, reorderCodeRes, line, status);
+                        }
+                    }
+                    else
+                    {
+                        warning(line, "could not obtain rules from collator");
+                        if(isStrict()){
+                            *status = U_INVALID_FORMAT_ERROR;
+                            return NULL;
+                        }
+                    }
+
+                    ucol_close(coll);
+                }
+                else
+                {
+                    if(intStatus == U_FILE_ACCESS_ERROR) {
+                        error(startline, "Collation could not be built- U_FILE_ACCESS_ERROR. Make sure ICU's data has been built and is loading properly.");
+                        *status = intStatus;
+                        return NULL;
+                    }
+                    char preBuffer[100], postBuffer[100];
+                    escape(parseError.preContext, preBuffer);
+                    escape(parseError.postContext, postBuffer);
+                    warning(line,
+                            "%%%%CollationBin could not be constructed from CollationElements\n"
+                            "  check context, check that the FractionalUCA.txt UCA version "
+                            "matches the current UCD version\n"
+                            "  UErrorCode=%s  UParseError={ line=%d offset=%d pre=<> post=<> }",
+                            u_errorName(intStatus),
+                            parseError.line,
+                            parseError.offset,
+                            preBuffer,
+                            postBuffer);
+                    if(isStrict()){
+                        *status = intStatus;
+                        return NULL;
+                    }
+                }
+            } else {
+                if(isVerbose()) {
+                    printf("Not building Collation binary\n");
+                }
+            }
+#endif
+            /* in order to achieve smaller data files, we can direct genrb */
+            /* to omit collation rules */
+            if(gOmitCollationRules) {
+                bundle_closeString(state->bundle, member);
+            } else {
+                table_add(result, member, line, status);
+            }
+        }
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+    }
+
+    // Reached the end without a TOK_CLOSE_BRACE.  Should be an error.
+    *status = U_INTERNAL_PROGRAM_ERROR;
+    return NULL;
+}
+
+static struct SResource *
+parseCollationElements(ParseState* state, char *tag, uint32_t startline, UBool newCollation, UErrorCode *status)
+{
+    struct SResource  *result = NULL;
+    struct SResource  *member = NULL;
+    struct SResource  *collationRes = NULL;
+    struct UString    *tokenValue;
+    struct UString     comment;
+    enum   ETokenType  token;
+    char               subtag[1024], typeKeyword[1024];
+    uint32_t           line;
+
+    result = table_open(state->bundle, tag, NULL, status);
+
+    if (result == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    if(isVerbose()){
+        printf(" collation elements %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+    if(!newCollation) {
+        return addCollation(state, result, startline, status);
+    }
+    else {
+        for(;;) {
+            ustr_init(&comment);
+            token = getToken(state, &tokenValue, &comment, &line, status);
+
+            if (token == TOK_CLOSE_BRACE)
+            {
+                return result;
+            }
+
+            if (token != TOK_STRING)
+            {
+                res_close(result);
+                *status = U_INVALID_FORMAT_ERROR;
+
+                if (token == TOK_EOF)
+                {
+                    error(startline, "unterminated table");
+                }
+                else
+                {
+                    error(line, "Unexpected token %s", tokenNames[token]);
+                }
+
+                return NULL;
+            }
+
+            u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
+
+            if (U_FAILURE(*status))
+            {
+                res_close(result);
+                return NULL;
+            }
+
+            if (uprv_strcmp(subtag, "default") == 0)
+            {
+                member = parseResource(state, subtag, NULL, status);
+
+                if (U_FAILURE(*status))
+                {
+                    res_close(result);
+                    return NULL;
+                }
+
+                table_add(result, member, line, status);
+            }
+            else
+            {
+                token = peekToken(state, 0, &tokenValue, &line, &comment, status);
+                /* this probably needs to be refactored or recursively use the parser */
+                /* first we assume that our collation table won't have the explicit type */
+                /* then, we cannot handle aliases */
+                if(token == TOK_OPEN_BRACE) {
+                    token = getToken(state, &tokenValue, &comment, &line, status);
+                    collationRes = table_open(state->bundle, subtag, NULL, status);
+                    collationRes = addCollation(state, collationRes, startline, status); /* need to parse the collation data regardless */
+                    if (gIncludeUnihanColl || uprv_strcmp(subtag, "unihan") != 0) {
+                        table_add(result, 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 */
+                    token = peekToken(state, 1, &tokenValue, &line, &comment, status);
+                    u_UCharsToChars(tokenValue->fChars, typeKeyword, u_strlen(tokenValue->fChars) + 1);
+                    if(uprv_strcmp(typeKeyword, "alias") == 0) {
+                        member = parseResource(state, subtag, NULL, status);
+                        if (U_FAILURE(*status))
+                        {
+                            res_close(result);
+                            return NULL;
+                        }
+
+                        table_add(result, member, line, status);
+                    } else {
+                        res_close(result);
+                        *status = U_INVALID_FORMAT_ERROR;
+                        return NULL;
+                    }
+                } else {
+                    res_close(result);
+                    *status = U_INVALID_FORMAT_ERROR;
+                    return NULL;
+                }
+            }
+
+            /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
+
+            /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
+
+            if (U_FAILURE(*status))
+            {
+                res_close(result);
+                return NULL;
+            }
+        }
+    }
+}
+
+/* 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)
+{
+    struct SResource  *member = NULL;
+    struct UString    *tokenValue=NULL;
+    struct UString    comment;
+    enum   ETokenType token;
+    char              subtag[1024];
+    uint32_t          line;
+    UBool             readToken = FALSE;
+
+    /* '{' . (name resource)* '}' */
+
+    if(isVerbose()){
+        printf(" parsing table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+    for (;;)
+    {
+        ustr_init(&comment);
+        token = getToken(state, &tokenValue, &comment, &line, status);
+
+        if (token == TOK_CLOSE_BRACE)
+        {
+            if (!readToken) {
+                warning(startline, "Encountered empty table");
+            }
+            return table;
+        }
+
+        if (token != TOK_STRING)
+        {
+            *status = U_INVALID_FORMAT_ERROR;
+
+            if (token == TOK_EOF)
+            {
+                error(startline, "unterminated table");
+            }
+            else
+            {
+                error(line, "unexpected token %s", tokenNames[token]);
+            }
+
+            return NULL;
+        }
+
+        if(uprv_isInvariantUString(tokenValue->fChars, -1)) {
+            u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
+        } else {
+            *status = U_INVALID_FORMAT_ERROR;
+            error(line, "invariant characters required for table keys");
+            return NULL;
+        }
+
+        if (U_FAILURE(*status))
+        {
+            error(line, "parse error. Stopped parsing tokens with %s", u_errorName(*status));
+            return NULL;
+        }
+
+        member = parseResource(state, subtag, &comment, status);
+
+        if (member == NULL || U_FAILURE(*status))
+        {
+            error(line, "parse error. Stopped parsing resource with %s", u_errorName(*status));
+            return NULL;
+        }
+
+        table_add(table, member, line, status);
+
+        if (U_FAILURE(*status))
+        {
+            error(line, "parse error. Stopped parsing table with %s", u_errorName(*status));
+            return NULL;
+        }
+        readToken = TRUE;
+        ustr_deinit(&comment);
+   }
+
+    /* not reached */
+    /* A compiler warning will appear if all paths don't contain a return statement. */
+/*     *status = U_INTERNAL_PROGRAM_ERROR;
+     return NULL;*/
+}
+
+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);
+    }
+    if (tag != NULL && uprv_strcmp(tag, "collations") == 0)
+    {
+        return parseCollationElements(state, tag, startline, TRUE, status);
+    }
+    if(isVerbose()){
+        printf(" table %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    result = table_open(state->bundle, tag, comment, status);
+
+    if (result == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    return realParseTable(state, result, tag, startline,  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);
+
+    if (result == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+    if(isVerbose()){
+        printf(" array %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    ustr_init(&memberComments);
+
+    /* '{' . resource [','] '}' */
+    for (;;)
+    {
+        /* reset length */
+        ustr_setlen(&memberComments, 0, status);
+
+        /* check for end of array, but don't consume next token unless it really is the end */
+        token = peekToken(state, 0, &tokenValue, NULL, &memberComments, status);
+
+
+        if (token == TOK_CLOSE_BRACE)
+        {
+            getToken(state, NULL, NULL, NULL, status);
+            if (!readToken) {
+                warning(startline, "Encountered empty array");
+            }
+            break;
+        }
+
+        if (token == TOK_EOF)
+        {
+            res_close(result);
+            *status = U_INVALID_FORMAT_ERROR;
+            error(startline, "unterminated array");
+            return NULL;
+        }
+
+        /* string arrays are a special case */
+        if (token == TOK_STRING)
+        {
+            getToken(state, &tokenValue, &memberComments, NULL, status);
+            member = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, &memberComments, status);
+        }
+        else
+        {
+            member = parseResource(state, NULL, &memberComments, status);
+        }
+
+        if (member == NULL || U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        array_add(result, member, status);
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        /* eat optional comma if present */
+        token = peekToken(state, 0, NULL, NULL, NULL, status);
+
+        if (token == TOK_COMMA)
+        {
+            getToken(state, NULL, NULL, NULL, status);
+        }
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+        readToken = TRUE;
+    }
+
+    ustr_deinit(&memberComments);
+    return result;
+}
+
+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;
+    UBool              readToken = FALSE;
+    char              *stopstring;
+    uint32_t           len;
+    struct UString     memberComments;
+
+    result = intvector_open(state->bundle, tag, comment, status);
+
+    if (result == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+    if(isVerbose()){
+        printf(" vector %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+    ustr_init(&memberComments);
+    /* '{' . string [','] '}' */
+    for (;;)
+    {
+        ustr_setlen(&memberComments, 0, status);
+
+        /* check for end of array, but don't consume next token unless it really is the end */
+        token = peekToken(state, 0, NULL, NULL,&memberComments, status);
+
+        if (token == TOK_CLOSE_BRACE)
+        {
+            /* it's the end, consume the close brace */
+            getToken(state, NULL, NULL, NULL, status);
+            if (!readToken) {
+                warning(startline, "Encountered empty int vector");
+            }
+            ustr_deinit(&memberComments);
+            return result;
+        }
+
+        string = getInvariantString(state, NULL, NULL, status);
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        /* For handling illegal char in the Intvector */
+        value = uprv_strtoul(string, &stopstring, 0);/* make intvector support decimal,hexdigit,octal digit ranging from -2^31-2^32-1*/
+        len=(uint32_t)(stopstring-string);
+
+        if(len==uprv_strlen(string))
+        {
+            intvector_add(result, value, status);
+            uprv_free(string);
+            token = peekToken(state, 0, NULL, NULL, NULL, status);
+        }
+        else
+        {
+            uprv_free(string);
+            *status=U_INVALID_CHAR_FOUND;
+        }
+
+        if (U_FAILURE(*status))
+        {
+            res_close(result);
+            return NULL;
+        }
+
+        /* the comma is optional (even though it is required to prevent the reader from concatenating
+        consecutive entries) so that a missing comma on the last entry isn't an error */
+        if (token == TOK_COMMA)
+        {
+            getToken(state, NULL, NULL, NULL, status);
+        }
+        readToken = TRUE;
+    }
+
+    /* not reached */
+    /* A compiler warning will appear if all paths don't contain a return statement. */
+/*    intvector_close(result, status);
+    *status = U_INTERNAL_PROGRAM_ERROR;
+    return NULL;*/
+}
+
+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))
+    {
+        return NULL;
+    }
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        uprv_free(string);
+        return NULL;
+    }
+
+    if(isVerbose()){
+        printf(" binary %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    count = (uint32_t)uprv_strlen(string);
+    if (count > 0){
+        if((count % 2)==0){
+            value = reinterpret_cast<uint8_t *>(uprv_malloc(sizeof(uint8_t) * count));
+
+            if (value == NULL)
+            {
+                uprv_free(string);
+                *status = U_MEMORY_ALLOCATION_ERROR;
+                return NULL;
+            }
+
+            for (i = 0; i < count; i += 2)
+            {
+                toConv[0] = string[i];
+                toConv[1] = string[i + 1];
+
+                value[i >> 1] = (uint8_t) uprv_strtoul(toConv, &stopstring, 16);
+                len=(uint32_t)(stopstring-toConv);
+
+                if(len!=uprv_strlen(toConv))
+                {
+                    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);
+        }
+        else
+        {
+            *status = U_INVALID_CHAR_FOUND;
+            uprv_free(string);
+            error(line, "Encountered invalid binary string");
+            return NULL;
+        }
+    }
+    else
+    {
+        result = bin_open(state->bundle, tag, 0, NULL, "",comment,status);
+        warning(startline, "Encountered empty binary tag");
+    }
+    uprv_free(string);
+
+    return result;
+}
+
+static struct SResource *
+parseInteger(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
+{
+    struct SResource *result = NULL;
+    int32_t           value;
+    char             *string;
+    char             *stopstring;
+    uint32_t          len;
+
+    string = getInvariantString(state, NULL, NULL, status);
+
+    if (string == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        uprv_free(string);
+        return NULL;
+    }
+
+    if(isVerbose()){
+        printf(" integer %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    if (uprv_strlen(string) <= 0)
+    {
+        warning(startline, "Encountered empty integer. Default value is 0.");
+    }
+
+    /* Allow integer support for hexdecimal, octal digit and decimal*/
+    /* and handle illegal char in the integer*/
+    value = uprv_strtoul(string, &stopstring, 0);
+    len=(uint32_t)(stopstring-string);
+    if(len==uprv_strlen(string))
+    {
+        result = int_open(state->bundle, tag, value, comment, status);
+    }
+    else
+    {
+        *status=U_INVALID_CHAR_FOUND;
+    }
+    uprv_free(string);
+
+    return result;
+}
+
+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);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        uprv_free(filename);
+        return NULL;
+    }
+
+    if(isVerbose()){
+        printf(" import %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    /* 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");
+    }
+    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");
+
+    }
+
+    if (file == NULL)
+    {
+        error(line, "couldn't open input file %s", filename);
+        *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)
+    {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        T_FileStream_close (file);
+        return NULL;
+    }
+
+    /* int32_t numRead = */ T_FileStream_read  (file, data, 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;
+}
+
+static struct SResource *
+parseInclude(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
+{
+    struct SResource *result;
+    int32_t           len=0;
+    char             *filename;
+    uint32_t          line;
+    UChar *pTarget     = NULL;
+
+    UCHARBUF *ucbuf;
+    char     *fullname = NULL;
+    int32_t  count     = 0;
+    const char* cp = NULL;
+    const UChar* uBuffer = NULL;
+
+    filename = getInvariantString(state, &line, NULL, status);
+    count     = (int32_t)uprv_strlen(filename);
+
+    if (U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+    expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
+
+    if (U_FAILURE(*status))
+    {
+        uprv_free(filename);
+        return NULL;
+    }
+
+    if(isVerbose()){
+        printf(" include %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    fullname = (char *) uprv_malloc(state->inputdirLength + count + 2);
+    /* test for NULL */
+    if(fullname == NULL)
+    {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        uprv_free(filename);
+        return NULL;
+    }
+
+    if(state->inputdir!=NULL){
+        if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
+        {
+
+            uprv_strcpy(fullname, state->inputdir);
+
+            fullname[state->inputdirLength]      = U_FILE_SEP_CHAR;
+            fullname[state->inputdirLength + 1] = '\0';
+
+            uprv_strcat(fullname, filename);
+        }
+        else
+        {
+            uprv_strcpy(fullname, state->inputdir);
+            uprv_strcat(fullname, filename);
+        }
+    }else{
+        uprv_strcpy(fullname,filename);
+    }
+
+    ucbuf = ucbuf_open(fullname, &cp,getShowWarning(),FALSE,status);
+
+    if (U_FAILURE(*status)) {
+        error(line, "couldn't open input file %s\n", filename);
+        return NULL;
+    }
+
+    uBuffer = ucbuf_getBuffer(ucbuf,&len,status);
+    result = string_open(state->bundle, tag, uBuffer, len, comment, status);
+
+    uprv_free(pTarget);
+
+    uprv_free(filename);
+    uprv_free(fullname);
+
+    return result;
+}
+
+
+
+
+
+U_STRING_DECL(k_type_string,    "string",    6);
+U_STRING_DECL(k_type_binary,    "binary",    6);
+U_STRING_DECL(k_type_bin,       "bin",       3);
+U_STRING_DECL(k_type_table,     "table",     5);
+U_STRING_DECL(k_type_table_no_fallback,     "table(nofallback)",         17);
+U_STRING_DECL(k_type_int,       "int",       3);
+U_STRING_DECL(k_type_integer,   "integer",   7);
+U_STRING_DECL(k_type_array,     "array",     5);
+U_STRING_DECL(k_type_alias,     "alias",     5);
+U_STRING_DECL(k_type_intvector, "intvector", 9);
+U_STRING_DECL(k_type_import,    "import",    6);
+U_STRING_DECL(k_type_include,   "include",   7);
+U_STRING_DECL(k_type_reserved,  "reserved",  8);
+
+/* Various non-standard processing plugins that create one or more special resources. */
+U_STRING_DECL(k_type_plugin_uca_rules,      "process(uca_rules)",        18);
+U_STRING_DECL(k_type_plugin_collation,      "process(collation)",        18);
+U_STRING_DECL(k_type_plugin_transliterator, "process(transliterator)",   23);
+U_STRING_DECL(k_type_plugin_dependency,     "process(dependency)",       19);
+
+typedef enum EResourceType
+{
+    RT_UNKNOWN,
+    RT_STRING,
+    RT_BINARY,
+    RT_TABLE,
+    RT_TABLE_NO_FALLBACK,
+    RT_INTEGER,
+    RT_ARRAY,
+    RT_ALIAS,
+    RT_INTVECTOR,
+    RT_IMPORT,
+    RT_INCLUDE,
+    RT_PROCESS_UCA_RULES,
+    RT_PROCESS_COLLATION,
+    RT_PROCESS_TRANSLITERATOR,
+    RT_PROCESS_DEPENDENCY,
+    RT_RESERVED
+} EResourceType;
+
+static struct {
+    const char *nameChars;   /* only used for debugging */
+    const UChar *nameUChars;
+    ParseResourceFunction *parseFunction;
+} gResourceTypes[] = {
+    {"Unknown", NULL, NULL},
+    {"string", k_type_string, parseString},
+    {"binary", k_type_binary, parseBinary},
+    {"table", k_type_table, parseTable},
+    {"table(nofallback)", k_type_table_no_fallback, NULL}, /* parseFunction will never be called */
+    {"integer", k_type_integer, parseInteger},
+    {"array", k_type_array, parseArray},
+    {"alias", k_type_alias, parseAlias},
+    {"intvector", k_type_intvector, parseIntVector},
+    {"import", k_type_import, parseImport},
+    {"include", k_type_include, parseInclude},
+    {"process(uca_rules)", k_type_plugin_uca_rules, parseUCARules},
+    {"process(collation)", k_type_plugin_collation, NULL /* not implemented yet */},
+    {"process(transliterator)", k_type_plugin_transliterator, parseTransliterator},
+    {"process(dependency)", k_type_plugin_dependency, parseDependency},
+    {"reserved", NULL, NULL}
+};
+
+void initParser(UBool omitCollationRules)
+{
+    U_STRING_INIT(k_type_string,    "string",    6);
+    U_STRING_INIT(k_type_binary,    "binary",    6);
+    U_STRING_INIT(k_type_bin,       "bin",       3);
+    U_STRING_INIT(k_type_table,     "table",     5);
+    U_STRING_INIT(k_type_table_no_fallback,     "table(nofallback)",         17);
+    U_STRING_INIT(k_type_int,       "int",       3);
+    U_STRING_INIT(k_type_integer,   "integer",   7);
+    U_STRING_INIT(k_type_array,     "array",     5);
+    U_STRING_INIT(k_type_alias,     "alias",     5);
+    U_STRING_INIT(k_type_intvector, "intvector", 9);
+    U_STRING_INIT(k_type_import,    "import",    6);
+    U_STRING_INIT(k_type_reserved,  "reserved",  8);
+    U_STRING_INIT(k_type_include,   "include",   7);
+
+    U_STRING_INIT(k_type_plugin_uca_rules,      "process(uca_rules)",        18);
+    U_STRING_INIT(k_type_plugin_collation,      "process(collation)",        18);
+    U_STRING_INIT(k_type_plugin_transliterator, "process(transliterator)",   23);
+    U_STRING_INIT(k_type_plugin_dependency,     "process(dependency)",       19);
+
+    gOmitCollationRules = omitCollationRules;
+}
+
+static inline UBool isTable(enum EResourceType type) {
+    return (UBool)(type==RT_TABLE || type==RT_TABLE_NO_FALLBACK);
+}
+
+static enum EResourceType
+parseResourceType(ParseState* state, UErrorCode *status)
+{
+    struct UString        *tokenValue;
+    struct UString        comment;
+    enum   EResourceType  result = RT_UNKNOWN;
+    uint32_t              line=0;
+    ustr_init(&comment);
+    expect(state, TOK_STRING, &tokenValue, &comment, &line, status);
+
+    if (U_FAILURE(*status))
+    {
+        return RT_UNKNOWN;
+    }
+
+    *status = U_ZERO_ERROR;
+
+    /* Search for normal types */
+    result=RT_UNKNOWN;
+    while ((result=(EResourceType)(result+1)) < RT_RESERVED) {
+        if (u_strcmp(tokenValue->fChars, gResourceTypes[result].nameUChars) == 0) {
+            break;
+        }
+    }
+    /* Now search for the aliases */
+    if (u_strcmp(tokenValue->fChars, k_type_int) == 0) {
+        result = RT_INTEGER;
+    }
+    else if (u_strcmp(tokenValue->fChars, k_type_bin) == 0) {
+        result = RT_BINARY;
+    }
+    else if (result == RT_RESERVED) {
+        char tokenBuffer[1024];
+        u_austrncpy(tokenBuffer, tokenValue->fChars, sizeof(tokenBuffer));
+        tokenBuffer[sizeof(tokenBuffer) - 1] = 0;
+        *status = U_INVALID_FORMAT_ERROR;
+        error(line, "unknown resource type '%s'", tokenBuffer);
+    }
+
+    return result;
+}
+
+/* parse a non-top-level resource */
+static struct SResource *
+parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status)
+{
+    enum   ETokenType      token;
+    enum   EResourceType  resType = RT_UNKNOWN;
+    ParseResourceFunction *parseFunction = NULL;
+    struct UString        *tokenValue;
+    uint32_t                 startline;
+    uint32_t                 line;
+
+
+    token = getToken(state, &tokenValue, NULL, &startline, status);
+
+    if(isVerbose()){
+        printf(" resource %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
+    }
+
+    /* name . [ ':' type ] '{' resource '}' */
+    /* This function parses from the colon onwards.  If the colon is present, parse the
+    type then try to parse a resource of that type.  If there is no explicit type,
+    work it out using the lookahead tokens. */
+    switch (token)
+    {
+    case TOK_EOF:
+        *status = U_INVALID_FORMAT_ERROR;
+        error(startline, "Unexpected EOF encountered");
+        return NULL;
+
+    case TOK_ERROR:
+        *status = U_INVALID_FORMAT_ERROR;
+        return NULL;
+
+    case TOK_COLON:
+        resType = parseResourceType(state, status);
+        expect(state, TOK_OPEN_BRACE, &tokenValue, NULL, &startline, status);
+
+        if (U_FAILURE(*status))
+        {
+            return NULL;
+        }
+
+        break;
+
+    case TOK_OPEN_BRACE:
+        break;
+
+    default:
+        *status = U_INVALID_FORMAT_ERROR;
+        error(startline, "syntax error while reading a resource, expected '{' or ':'");
+        return NULL;
+    }
+
+
+    if (resType == RT_UNKNOWN)
+    {
+        /* No explicit type, so try to work it out.  At this point, we've read the first '{'.
+        We could have any of the following:
+        { {         => array (nested)
+        { :/}       => array
+        { string ,  => string array
+
+        { string {  => table
+
+        { string :/{    => table
+        { string }      => string
+        */
+
+        token = peekToken(state, 0, NULL, &line, NULL,status);
+
+        if (U_FAILURE(*status))
+        {
+            return NULL;
+        }
+
+        if (token == TOK_OPEN_BRACE || token == TOK_COLON ||token ==TOK_CLOSE_BRACE )
+        {
+            resType = RT_ARRAY;
+        }
+        else if (token == TOK_STRING)
+        {
+            token = peekToken(state, 1, NULL, &line, NULL, status);
+
+            if (U_FAILURE(*status))
+            {
+                return NULL;
+            }
+
+            switch (token)
+            {
+            case TOK_COMMA:         resType = RT_ARRAY;  break;
+            case TOK_OPEN_BRACE:    resType = RT_TABLE;  break;
+            case TOK_CLOSE_BRACE:   resType = RT_STRING; break;
+            case TOK_COLON:         resType = RT_TABLE;  break;
+            default:
+                *status = U_INVALID_FORMAT_ERROR;
+                error(line, "Unexpected token after string, expected ',', '{' or '}'");
+                return NULL;
+            }
+        }
+        else
+        {
+            *status = U_INVALID_FORMAT_ERROR;
+            error(line, "Unexpected token after '{'");
+            return NULL;
+        }
+
+        /* printf("Type guessed as %s\n", resourceNames[resType]); */
+    } else if(resType == RT_TABLE_NO_FALLBACK) {
+        *status = U_INVALID_FORMAT_ERROR;
+        error(startline, "error: %s resource type not valid except on top bundle level", gResourceTypes[resType].nameChars);
+        return NULL;
+    }
+
+
+    /* We should now know what we need to parse next, so call the appropriate parser
+    function and return. */
+    parseFunction = gResourceTypes[resType].parseFunction;
+    if (parseFunction != NULL) {
+        return parseFunction(state, tag, startline, comment, status);
+    }
+    else {
+        *status = U_INTERNAL_PROGRAM_ERROR;
+        error(startline, "internal error: %s resource type found and not handled", gResourceTypes[resType].nameChars);
+    }
+
+    return NULL;
+}
+
+/* parse the top-level resource */
+struct SRBRoot *
+parse(UCHARBUF *buf, const char *inputDir, const char *outputDir, UBool makeBinaryCollation,
+      UErrorCode *status)
+{
+    struct UString    *tokenValue;
+    struct UString    comment;
+    uint32_t           line;
+    enum EResourceType bundleType;
+    enum ETokenType    token;
+    ParseState state;
+    uint32_t i;
+
+
+    for (i = 0; i < MAX_LOOKAHEAD + 1; i++)
+    {
+        ustr_init(&state.lookahead[i].value);
+        ustr_init(&state.lookahead[i].comment);
+    }
+
+    initLookahead(&state, buf, status);
+
+    state.inputdir       = inputDir;
+    state.inputdirLength = (state.inputdir != NULL) ? (uint32_t)uprv_strlen(state.inputdir) : 0;
+    state.outputdir       = outputDir;
+    state.outputdirLength = (state.outputdir != NULL) ? (uint32_t)uprv_strlen(state.outputdir) : 0;
+    state.makeBinaryCollation = makeBinaryCollation;
+
+    ustr_init(&comment);
+    expect(&state, TOK_STRING, &tokenValue, &comment, NULL, status);
+
+    state.bundle = bundle_open(&comment, FALSE, status);
+
+    if (state.bundle == NULL || U_FAILURE(*status))
+    {
+        return NULL;
+    }
+
+
+    bundle_setlocale(state.bundle, 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(token==TOK_COLON) {
+        *status=U_ZERO_ERROR;
+        bundleType=parseResourceType(&state, status);
+
+        if(isTable(bundleType))
+        {
+            expect(&state, TOK_OPEN_BRACE, NULL, NULL, &line, status);
+        }
+        else
+        {
+            *status=U_PARSE_ERROR;
+             error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
+        }
+    }
+    else
+    {
+        /* not a colon */
+        if(token==TOK_OPEN_BRACE)
+        {
+            *status=U_ZERO_ERROR;
+            bundleType=RT_TABLE;
+        }
+        else
+        {
+            /* neither colon nor open brace */
+            *status=U_PARSE_ERROR;
+            bundleType=RT_UNKNOWN;
+            error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status));
+        }
+    }
+
+    if (U_FAILURE(*status))
+    {
+        bundle_close(state.bundle, status);
+        return NULL;
+    }
+
+    if(bundleType==RT_TABLE_NO_FALLBACK) {
+        /*
+         * Parse a top-level table with the table(nofallback) declaration.
+         * 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;
+    }
+    /* top-level tables need not handle special table names like "collations" */
+    realParseTable(&state, state.bundle->fRoot, NULL, line, status);
+    if(dependencyArray!=NULL){
+        table_add(state.bundle->fRoot, dependencyArray, 0, status);
+        dependencyArray = NULL;
+    }
+   if (U_FAILURE(*status))
+    {
+        bundle_close(state.bundle, status);
+        res_close(dependencyArray);
+        return NULL;
+    }
+
+    if (getToken(&state, NULL, NULL, &line, status) != TOK_EOF)
+    {
+        warning(line, "extraneous text after resource bundle (perhaps unmatched braces)");
+        if(isStrict()){
+            *status = U_INVALID_FORMAT_ERROR;
+            return NULL;
+        }
+    }
+
+    cleanupLookahead(&state);
+    ustr_deinit(&comment);
+    return state.bundle;
+}