• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 *******************************************************************************
3 *
4 *   Copyright (C) 1998-2010, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 *******************************************************************************
8 *
9 * File parse.c
10 *
11 * Modification History:
12 *
13 *   Date          Name          Description
14 *   05/26/99     stephen       Creation.
15 *   02/25/00     weiv          Overhaul to write udata
16 *   5/10/01      Ram           removed ustdio dependency
17 *   06/10/2001  Dominic Ludlam <dom@recoil.org> Rewritten
18 *******************************************************************************
19 */
20 
21 #include "ucol_imp.h"
22 #include "parse.h"
23 #include "errmsg.h"
24 #include "uhash.h"
25 #include "cmemory.h"
26 #include "cstring.h"
27 #include "uinvchar.h"
28 #include "read.h"
29 #include "ustr.h"
30 #include "reslist.h"
31 #include "rbt_pars.h"
32 #include "genrb.h"
33 #include "unicode/ustring.h"
34 #include "unicode/uscript.h"
35 #include "unicode/putil.h"
36 #include <stdio.h>
37 
38 extern UBool gIncludeUnihanColl;
39 
40 /* Number of tokens to read ahead of the current stream position */
41 #define MAX_LOOKAHEAD   3
42 
43 #define CR               0x000D
44 #define LF               0x000A
45 #define SPACE            0x0020
46 #define TAB              0x0009
47 #define ESCAPE           0x005C
48 #define HASH             0x0023
49 #define QUOTE            0x0027
50 #define ZERO             0x0030
51 #define STARTCOMMAND     0x005B
52 #define ENDCOMMAND       0x005D
53 #define OPENSQBRACKET    0x005B
54 #define CLOSESQBRACKET   0x005D
55 
56 struct Lookahead
57 {
58      enum   ETokenType type;
59      struct UString    value;
60      struct UString    comment;
61      uint32_t          line;
62 };
63 
64 /* keep in sync with token defines in read.h */
65 const char *tokenNames[TOK_TOKEN_COUNT] =
66 {
67      "string",             /* A string token, such as "MonthNames" */
68      "'{'",                 /* An opening brace character */
69      "'}'",                 /* A closing brace character */
70      "','",                 /* A comma */
71      "':'",                 /* A colon */
72 
73      "<end of file>",     /* End of the file has been reached successfully */
74      "<end of line>"
75 };
76 
77 /* Just to store "TRUE" */
78 static const UChar trueValue[] = {0x0054, 0x0052, 0x0055, 0x0045, 0x0000};
79 
80 typedef struct {
81     struct Lookahead  lookahead[MAX_LOOKAHEAD + 1];
82     uint32_t          lookaheadPosition;
83     UCHARBUF         *buffer;
84     struct SRBRoot *bundle;
85     const char     *inputdir;
86     uint32_t        inputdirLength;
87     const char     *outputdir;
88     uint32_t        outputdirLength;
89 } ParseState;
90 
91 static UBool gMakeBinaryCollation = TRUE;
92 static UBool gOmitCollationRules  = FALSE;
93 
94 typedef struct SResource *
95 ParseResourceFunction(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status);
96 
97 static struct SResource *parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status);
98 
99 /* The nature of the lookahead buffer:
100    There are MAX_LOOKAHEAD + 1 slots, used as a circular buffer.  This provides
101    MAX_LOOKAHEAD lookahead tokens and a slot for the current token and value.
102    When getToken is called, the current pointer is moved to the next slot and the
103    old slot is filled with the next token from the reader by calling getNextToken.
104    The token values are stored in the slot, which means that token values don't
105    survive a call to getToken, ie.
106 
107    UString *value;
108 
109    getToken(&value, NULL, status);
110    getToken(NULL,   NULL, status);       bad - value is now a different string
111 */
112 static void
initLookahead(ParseState * state,UCHARBUF * buf,UErrorCode * status)113 initLookahead(ParseState* state, UCHARBUF *buf, UErrorCode *status)
114 {
115     static uint32_t initTypeStrings = 0;
116     uint32_t i;
117 
118     if (!initTypeStrings)
119     {
120         initTypeStrings = 1;
121     }
122 
123     state->lookaheadPosition   = 0;
124     state->buffer              = buf;
125 
126     resetLineNumber();
127 
128     for (i = 0; i < MAX_LOOKAHEAD; i++)
129     {
130         state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status);
131         if (U_FAILURE(*status))
132         {
133             return;
134         }
135     }
136 
137     *status = U_ZERO_ERROR;
138 }
139 
140 static void
cleanupLookahead(ParseState * state)141 cleanupLookahead(ParseState* state)
142 {
143     uint32_t i;
144     for (i = 0; i < MAX_LOOKAHEAD; i++)
145     {
146         ustr_deinit(&state->lookahead[i].value);
147         ustr_deinit(&state->lookahead[i].comment);
148     }
149 
150 }
151 
152 static enum ETokenType
getToken(ParseState * state,struct UString ** tokenValue,struct UString * comment,uint32_t * linenumber,UErrorCode * status)153 getToken(ParseState* state, struct UString **tokenValue, struct UString* comment, uint32_t *linenumber, UErrorCode *status)
154 {
155     enum ETokenType result;
156     uint32_t          i;
157 
158     result = state->lookahead[state->lookaheadPosition].type;
159 
160     if (tokenValue != NULL)
161     {
162         *tokenValue = &state->lookahead[state->lookaheadPosition].value;
163     }
164 
165     if (linenumber != NULL)
166     {
167         *linenumber = state->lookahead[state->lookaheadPosition].line;
168     }
169 
170     if (comment != NULL)
171     {
172         ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status);
173     }
174 
175     i = (state->lookaheadPosition + MAX_LOOKAHEAD) % (MAX_LOOKAHEAD + 1);
176     state->lookaheadPosition = (state->lookaheadPosition + 1) % (MAX_LOOKAHEAD + 1);
177     ustr_setlen(&state->lookahead[i].comment, 0, status);
178     ustr_setlen(&state->lookahead[i].value, 0, status);
179     state->lookahead[i].type = getNextToken(state->buffer, &state->lookahead[i].value, &state->lookahead[i].line, &state->lookahead[i].comment, status);
180 
181     /* printf("getToken, returning %s\n", tokenNames[result]); */
182 
183     return result;
184 }
185 
186 static enum ETokenType
peekToken(ParseState * state,uint32_t lookaheadCount,struct UString ** tokenValue,uint32_t * linenumber,struct UString * comment,UErrorCode * status)187 peekToken(ParseState* state, uint32_t lookaheadCount, struct UString **tokenValue, uint32_t *linenumber, struct UString *comment, UErrorCode *status)
188 {
189     uint32_t i = (state->lookaheadPosition + lookaheadCount) % (MAX_LOOKAHEAD + 1);
190 
191     if (U_FAILURE(*status))
192     {
193         return TOK_ERROR;
194     }
195 
196     if (lookaheadCount >= MAX_LOOKAHEAD)
197     {
198         *status = U_INTERNAL_PROGRAM_ERROR;
199         return TOK_ERROR;
200     }
201 
202     if (tokenValue != NULL)
203     {
204         *tokenValue = &state->lookahead[i].value;
205     }
206 
207     if (linenumber != NULL)
208     {
209         *linenumber = state->lookahead[i].line;
210     }
211 
212     if(comment != NULL){
213         ustr_cpy(comment, &(state->lookahead[state->lookaheadPosition].comment), status);
214     }
215 
216     return state->lookahead[i].type;
217 }
218 
219 static void
expect(ParseState * state,enum ETokenType expectedToken,struct UString ** tokenValue,struct UString * comment,uint32_t * linenumber,UErrorCode * status)220 expect(ParseState* state, enum ETokenType expectedToken, struct UString **tokenValue, struct UString *comment, uint32_t *linenumber, UErrorCode *status)
221 {
222     uint32_t        line;
223 
224     enum ETokenType token = getToken(state, tokenValue, comment, &line, status);
225 
226     if (linenumber != NULL)
227     {
228         *linenumber = line;
229     }
230 
231     if (U_FAILURE(*status))
232     {
233         return;
234     }
235 
236     if (token != expectedToken)
237     {
238         *status = U_INVALID_FORMAT_ERROR;
239         error(line, "expecting %s, got %s", tokenNames[expectedToken], tokenNames[token]);
240     }
241     else
242     {
243         *status = U_ZERO_ERROR;
244     }
245 }
246 
getInvariantString(ParseState * state,uint32_t * line,struct UString * comment,UErrorCode * status)247 static char *getInvariantString(ParseState* state, uint32_t *line, struct UString *comment, UErrorCode *status)
248 {
249     struct UString *tokenValue;
250     char           *result;
251     uint32_t        count;
252 
253     expect(state, TOK_STRING, &tokenValue, comment, line, status);
254 
255     if (U_FAILURE(*status))
256     {
257         return NULL;
258     }
259 
260     count = u_strlen(tokenValue->fChars);
261     if(!uprv_isInvariantUString(tokenValue->fChars, count)) {
262         *status = U_INVALID_FORMAT_ERROR;
263         error(*line, "invariant characters required for table keys, binary data, etc.");
264         return NULL;
265     }
266 
267     result = uprv_malloc(count+1);
268 
269     if (result == NULL)
270     {
271         *status = U_MEMORY_ALLOCATION_ERROR;
272         return NULL;
273     }
274 
275     u_UCharsToChars(tokenValue->fChars, result, count+1);
276     return result;
277 }
278 
279 static struct SResource *
parseUCARules(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)280 parseUCARules(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
281 {
282     struct SResource *result = NULL;
283     struct UString   *tokenValue;
284     FileStream       *file          = NULL;
285     char              filename[256] = { '\0' };
286     char              cs[128]       = { '\0' };
287     uint32_t          line;
288     int               len=0;
289     UBool quoted = FALSE;
290     UCHARBUF *ucbuf=NULL;
291     UChar32   c     = 0;
292     const char* cp  = NULL;
293     UChar *pTarget     = NULL;
294     UChar *target      = NULL;
295     UChar *targetLimit = NULL;
296     int32_t size = 0;
297 
298     expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
299 
300     if(isVerbose()){
301         printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
302     }
303 
304     if (U_FAILURE(*status))
305     {
306         return NULL;
307     }
308     /* make the filename including the directory */
309     if (state->inputdir != NULL)
310     {
311         uprv_strcat(filename, state->inputdir);
312 
313         if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
314         {
315             uprv_strcat(filename, U_FILE_SEP_STRING);
316         }
317     }
318 
319     u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
320 
321     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
322 
323     if (U_FAILURE(*status))
324     {
325         return NULL;
326     }
327     uprv_strcat(filename, cs);
328 
329     if(gOmitCollationRules) {
330         return res_none();
331     }
332 
333     ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status);
334 
335     if (U_FAILURE(*status)) {
336         error(line, "An error occured while opening the input file %s\n", filename);
337         return NULL;
338     }
339 
340     /* We allocate more space than actually required
341     * since the actual size needed for storing UChars
342     * is not known in UTF-8 byte stream
343     */
344     size        = ucbuf_size(ucbuf) + 1;
345     pTarget     = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * size);
346     uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR);
347     target      = pTarget;
348     targetLimit = pTarget+size;
349 
350     /* read the rules into the buffer */
351     while (target < targetLimit)
352     {
353         c = ucbuf_getc(ucbuf, status);
354         if(c == QUOTE) {
355             quoted = (UBool)!quoted;
356         }
357         /* weiv (06/26/2002): adding the following:
358          * - preserving spaces in commands [...]
359          * - # comments until the end of line
360          */
361         if (c == STARTCOMMAND && !quoted)
362         {
363             /* preserve commands
364              * closing bracket will be handled by the
365              * append at the end of the loop
366              */
367             while(c != ENDCOMMAND) {
368                 U_APPEND_CHAR32(c, target,len);
369                 c = ucbuf_getc(ucbuf, status);
370             }
371         }
372         else if (c == HASH && !quoted) {
373             /* skip comments */
374             while(c != CR && c != LF) {
375                 c = ucbuf_getc(ucbuf, status);
376             }
377             continue;
378         }
379         else if (c == ESCAPE)
380         {
381             c = unescape(ucbuf, status);
382 
383             if (c == U_ERR)
384             {
385                 uprv_free(pTarget);
386                 T_FileStream_close(file);
387                 return NULL;
388             }
389         }
390         else if (!quoted && (c == SPACE || c == TAB || c == CR || c == LF))
391         {
392             /* ignore spaces carriage returns
393             * and line feed unless in the form \uXXXX
394             */
395             continue;
396         }
397 
398         /* Append UChar * after dissembling if c > 0xffff*/
399         if (c != U_EOF)
400         {
401             U_APPEND_CHAR32(c, target,len);
402         }
403         else
404         {
405             break;
406         }
407     }
408 
409     /* terminate the string */
410     if(target < targetLimit){
411         *target = 0x0000;
412     }
413 
414     result = string_open(state->bundle, tag, pTarget, (int32_t)(target - pTarget), NULL, status);
415 
416 
417     ucbuf_close(ucbuf);
418     uprv_free(pTarget);
419     T_FileStream_close(file);
420 
421     return result;
422 }
423 
424 static struct SResource *
parseTransliterator(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)425 parseTransliterator(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
426 {
427     struct SResource *result = NULL;
428     struct UString   *tokenValue;
429     FileStream       *file          = NULL;
430     char              filename[256] = { '\0' };
431     char              cs[128]       = { '\0' };
432     uint32_t          line;
433     UCHARBUF *ucbuf=NULL;
434     const char* cp  = NULL;
435     UChar *pTarget     = NULL;
436     const UChar *pSource     = NULL;
437     int32_t size = 0;
438 
439     expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
440 
441     if(isVerbose()){
442         printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
443     }
444 
445     if (U_FAILURE(*status))
446     {
447         return NULL;
448     }
449     /* make the filename including the directory */
450     if (state->inputdir != NULL)
451     {
452         uprv_strcat(filename, state->inputdir);
453 
454         if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
455         {
456             uprv_strcat(filename, U_FILE_SEP_STRING);
457         }
458     }
459 
460     u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
461 
462     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
463 
464     if (U_FAILURE(*status))
465     {
466         return NULL;
467     }
468     uprv_strcat(filename, cs);
469 
470 
471     ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status);
472 
473     if (U_FAILURE(*status)) {
474         error(line, "An error occured while opening the input file %s\n", filename);
475         return NULL;
476     }
477 
478     /* We allocate more space than actually required
479     * since the actual size needed for storing UChars
480     * is not known in UTF-8 byte stream
481     */
482     pSource = ucbuf_getBuffer(ucbuf, &size, status);
483     pTarget     = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (size + 1));
484     uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR);
485 
486 #if !UCONFIG_NO_TRANSLITERATION
487     size = utrans_stripRules(pSource, size, pTarget, status);
488 #else
489     size = 0;
490     fprintf(stderr, " Warning: writing empty transliteration data ( UCONFIG_NO_TRANSLITERATION ) \n");
491 #endif
492     result = string_open(state->bundle, tag, pTarget, size, NULL, status);
493 
494     ucbuf_close(ucbuf);
495     uprv_free(pTarget);
496     T_FileStream_close(file);
497 
498     return result;
499 }
500 static struct SResource* dependencyArray = NULL;
501 
502 static struct SResource *
parseDependency(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)503 parseDependency(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
504 {
505     struct SResource *result = NULL;
506     struct SResource *elem = NULL;
507     struct UString   *tokenValue;
508     uint32_t          line;
509     char              filename[256] = { '\0' };
510     char              cs[128]       = { '\0' };
511 
512     expect(state, TOK_STRING, &tokenValue, NULL, &line, status);
513 
514     if(isVerbose()){
515         printf(" %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
516     }
517 
518     if (U_FAILURE(*status))
519     {
520         return NULL;
521     }
522     /* make the filename including the directory */
523     if (state->outputdir != NULL)
524     {
525         uprv_strcat(filename, state->outputdir);
526 
527         if (state->outputdir[state->outputdirLength - 1] != U_FILE_SEP_CHAR)
528         {
529             uprv_strcat(filename, U_FILE_SEP_STRING);
530         }
531     }
532 
533     u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
534 
535     if (U_FAILURE(*status))
536     {
537         return NULL;
538     }
539     uprv_strcat(filename, cs);
540     if(!T_FileStream_file_exists(filename)){
541         if(isStrict()){
542             error(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename);
543         }else{
544             warning(line, "The dependency file %s does not exist. Please make sure it exists.\n",filename);
545         }
546     }
547     if(dependencyArray==NULL){
548         dependencyArray = array_open(state->bundle, "%%DEPENDENCY", NULL, status);
549     }
550     if(tag!=NULL){
551         result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
552     }
553     elem = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, comment, status);
554 
555     array_add(dependencyArray, elem, status);
556 
557     if (U_FAILURE(*status))
558     {
559         return NULL;
560     }
561     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
562     return result;
563 }
564 static struct SResource *
parseString(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)565 parseString(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
566 {
567     struct UString   *tokenValue;
568     struct SResource *result = NULL;
569 
570 /*    if (tag != NULL && uprv_strcmp(tag, "%%UCARULES") == 0)
571     {
572         return parseUCARules(tag, startline, status);
573     }*/
574     if(isVerbose()){
575         printf(" string %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
576     }
577     expect(state, TOK_STRING, &tokenValue, NULL, NULL, status);
578 
579     if (U_SUCCESS(*status))
580     {
581         /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
582         doesn't survive expect either) */
583 
584         result = string_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
585         if(U_SUCCESS(*status) && result) {
586             expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
587 
588             if (U_FAILURE(*status))
589             {
590                 res_close(result);
591                 return NULL;
592             }
593         }
594     }
595 
596     return result;
597 }
598 
599 static struct SResource *
parseAlias(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)600 parseAlias(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
601 {
602     struct UString   *tokenValue;
603     struct SResource *result  = NULL;
604 
605     expect(state, TOK_STRING, &tokenValue, NULL, NULL, status);
606 
607     if(isVerbose()){
608         printf(" alias %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
609     }
610 
611     if (U_SUCCESS(*status))
612     {
613         /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
614         doesn't survive expect either) */
615 
616         result = alias_open(state->bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
617 
618         expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
619 
620         if (U_FAILURE(*status))
621         {
622             res_close(result);
623             return NULL;
624         }
625     }
626 
627     return result;
628 }
629 
630 typedef struct{
631     const char* inputDir;
632     const char* outputDir;
633 } GenrbData;
634 
resLookup(struct SResource * res,const char * key)635 static struct SResource* resLookup(struct SResource* res, const char* key){
636     struct SResource *current = NULL;
637     struct SResTable *list;
638     if (res == res_none()) {
639         return NULL;
640     }
641 
642     list = &(res->u.fTable);
643 
644     current = list->fFirst;
645     while (current != NULL) {
646         if (uprv_strcmp(((list->fRoot->fKeys) + (current->fKey)), key) == 0) {
647             return current;
648         }
649         current = current->fNext;
650     }
651     return NULL;
652 }
653 
importFromDataFile(void * context,const char * locale,const char * type,int32_t * pLength,UErrorCode * status)654 static const UChar* importFromDataFile(void* context, const char* locale, const char* type, int32_t* pLength, UErrorCode* status){
655     struct SRBRoot *data         = NULL;
656     UCHARBUF       *ucbuf        = NULL;
657     GenrbData* genrbdata = (GenrbData*) context;
658     int localeLength = strlen(locale);
659     char* filename = (char*)uprv_malloc(localeLength+5);
660     char           *inputDirBuf  = NULL;
661     char           *openFileName = NULL;
662     const char* cp = "";
663     UChar* urules = NULL;
664     int32_t urulesLength = 0;
665     int32_t i = 0;
666     int32_t dirlen  = 0;
667     int32_t filelen = 0;
668     struct SResource* root;
669     struct SResource* collations;
670     struct SResource* collation;
671     struct SResource* sequence;
672 
673     memcpy(filename, locale, localeLength);
674     for(i = 0; i < localeLength; i++){
675         if(filename[i] == '-'){
676             filename[i] = '_';
677         }
678     }
679     filename[localeLength]   = '.';
680     filename[localeLength+1] = 't';
681     filename[localeLength+2] = 'x';
682     filename[localeLength+3] = 't';
683     filename[localeLength+4] = 0;
684 
685 
686     if (status==NULL || U_FAILURE(*status)) {
687         return NULL;
688     }
689     if(filename==NULL){
690         *status=U_ILLEGAL_ARGUMENT_ERROR;
691         return NULL;
692     }else{
693         filelen = (int32_t)uprv_strlen(filename);
694     }
695     if(genrbdata->inputDir == NULL) {
696         const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR);
697         openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
698         openFileName[0] = '\0';
699         if (filenameBegin != NULL) {
700             /*
701              * When a filename ../../../data/root.txt is specified,
702              * we presume that the input directory is ../../../data
703              * This is very important when the resource file includes
704              * another file, like UCARules.txt or thaidict.brk.
705              */
706             int32_t filenameSize = (int32_t)(filenameBegin - filename + 1);
707             inputDirBuf = uprv_strncpy((char *)uprv_malloc(filenameSize), filename, filenameSize);
708 
709             /* test for NULL */
710             if(inputDirBuf == NULL) {
711                 *status = U_MEMORY_ALLOCATION_ERROR;
712                 goto finish;
713             }
714 
715             inputDirBuf[filenameSize - 1] = 0;
716             genrbdata->inputDir = inputDirBuf;
717             dirlen  = (int32_t)uprv_strlen(genrbdata->inputDir);
718         }
719     }else{
720         dirlen  = (int32_t)uprv_strlen(genrbdata->inputDir);
721 
722         if(genrbdata->inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
723             openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
724 
725             /* test for NULL */
726             if(openFileName == NULL) {
727                 *status = U_MEMORY_ALLOCATION_ERROR;
728                 goto finish;
729             }
730 
731             openFileName[0] = '\0';
732             /*
733              * append the input dir to openFileName if the first char in
734              * filename is not file seperation char and the last char input directory is  not '.'.
735              * This is to support :
736              * genrb -s. /home/icu/data
737              * genrb -s. icu/data
738              * The user cannot mix notations like
739              * genrb -s. /icu/data --- the absolute path specified. -s redundant
740              * user should use
741              * genrb -s. icu/data  --- start from CWD and look in icu/data dir
742              */
743             if( (filename[0] != U_FILE_SEP_CHAR) && (genrbdata->inputDir[dirlen-1] !='.')){
744                 uprv_strcpy(openFileName, genrbdata->inputDir);
745                 openFileName[dirlen]     = U_FILE_SEP_CHAR;
746             }
747             openFileName[dirlen + 1] = '\0';
748         } else {
749             openFileName = (char *) uprv_malloc(dirlen + filelen + 1);
750 
751             /* test for NULL */
752             if(openFileName == NULL) {
753                 *status = U_MEMORY_ALLOCATION_ERROR;
754                 goto finish;
755             }
756 
757             uprv_strcpy(openFileName, genrbdata->inputDir);
758 
759         }
760     }
761     uprv_strcat(openFileName, filename);
762     /* printf("%s\n", openFileName);  */
763     *status = U_ZERO_ERROR;
764     ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, status);
765 
766     if(*status == U_FILE_ACCESS_ERROR) {
767 
768         fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName);
769         goto finish;
770     }
771     if (ucbuf == NULL || U_FAILURE(*status)) {
772         fprintf(stderr, "An error occured processing file %s. Error: %s\n", openFileName == NULL ? filename : openFileName,u_errorName(*status));
773         goto finish;
774     }
775 
776     /* Parse the data into an SRBRoot */
777     data = parse(ucbuf, genrbdata->inputDir, genrbdata->outputDir, status);
778 
779     root = data->fRoot;
780     collations = resLookup(root, "collations");
781     collation = resLookup(collations, type);
782     sequence = resLookup(collation, "Sequence");
783     urules = sequence->u.fString.fChars;
784     urulesLength = sequence->u.fString.fLength;
785     *pLength = urulesLength;
786 
787 finish:
788 
789     if (inputDirBuf != NULL) {
790         uprv_free(inputDirBuf);
791     }
792 
793     if (openFileName != NULL) {
794         uprv_free(openFileName);
795     }
796 
797     if(ucbuf) {
798         ucbuf_close(ucbuf);
799     }
800 
801     return urules;
802 }
803 
804 static struct SResource *
addCollation(ParseState * state,struct SResource * result,uint32_t startline,UErrorCode * status)805 addCollation(ParseState* state, struct SResource  *result, uint32_t startline, UErrorCode *status)
806 {
807     struct SResource  *member = NULL;
808     struct UString    *tokenValue;
809     struct UString     comment;
810     enum   ETokenType  token;
811     char               subtag[1024];
812     UVersionInfo       version;
813     UBool              override = FALSE;
814     uint32_t           line;
815     GenrbData genrbdata;
816     /* '{' . (name resource)* '}' */
817     version[0]=0; version[1]=0; version[2]=0; version[3]=0;
818 
819     for (;;)
820     {
821         ustr_init(&comment);
822         token = getToken(state, &tokenValue, &comment, &line, status);
823 
824         if (token == TOK_CLOSE_BRACE)
825         {
826             return result;
827         }
828 
829         if (token != TOK_STRING)
830         {
831             res_close(result);
832             *status = U_INVALID_FORMAT_ERROR;
833 
834             if (token == TOK_EOF)
835             {
836                 error(startline, "unterminated table");
837             }
838             else
839             {
840                 error(line, "Unexpected token %s", tokenNames[token]);
841             }
842 
843             return NULL;
844         }
845 
846         u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
847 
848         if (U_FAILURE(*status))
849         {
850             res_close(result);
851             return NULL;
852         }
853 
854         member = parseResource(state, subtag, NULL, status);
855 
856         if (U_FAILURE(*status))
857         {
858             res_close(result);
859             return NULL;
860         }
861 
862         if (uprv_strcmp(subtag, "Version") == 0)
863         {
864             char     ver[40];
865             int32_t length = member->u.fString.fLength;
866 
867             if (length >= (int32_t) sizeof(ver))
868             {
869                 length = (int32_t) sizeof(ver) - 1;
870             }
871 
872             u_UCharsToChars(member->u.fString.fChars, ver, length + 1); /* +1 for copying NULL */
873             u_versionFromString(version, ver);
874 
875             table_add(result, member, line, status);
876 
877         }
878         else if (uprv_strcmp(subtag, "Override") == 0)
879         {
880             override = FALSE;
881 
882             if (u_strncmp(member->u.fString.fChars, trueValue, u_strlen(trueValue)) == 0)
883             {
884                 override = TRUE;
885             }
886             table_add(result, member, line, status);
887 
888         }
889         else if(uprv_strcmp(subtag, "%%CollationBin")==0)
890         {
891             /* discard duplicate %%CollationBin if any*/
892         }
893         else if (uprv_strcmp(subtag, "Sequence") == 0)
894         {
895 #if UCONFIG_NO_COLLATION || UCONFIG_NO_FILE_IO
896             warning(line, "Not building collation elements because of UCONFIG_NO_COLLATION and/or UCONFIG_NO_FILE_IO, see uconfig.h");
897 #else
898             if(gMakeBinaryCollation) {
899                 UErrorCode intStatus = U_ZERO_ERROR;
900 
901                 /* do the collation elements */
902                 int32_t     len   = 0;
903                 uint8_t   *data  = NULL;
904                 UCollator *coll  = NULL;
905                 int32_t reorderCodes[USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST)];
906                 uint32_t reorderCodeCount;
907                 int32_t reorderCodeIndex;
908                 UParseError parseError;
909 
910                 genrbdata.inputDir = state->inputdir;
911                 genrbdata.outputDir = state->outputdir;
912 
913                 coll = ucol_openRulesForImport(member->u.fString.fChars, member->u.fString.fLength,
914                                                UCOL_OFF, UCOL_DEFAULT_STRENGTH,&parseError, importFromDataFile, &genrbdata, &intStatus);
915 
916                 if (U_SUCCESS(intStatus) && coll != NULL)
917                 {
918                     len = ucol_cloneBinary(coll, NULL, 0, &intStatus);
919                     data = (uint8_t *)uprv_malloc(len);
920                     intStatus = U_ZERO_ERROR;
921                     len = ucol_cloneBinary(coll, data, len, &intStatus);
922                     /*data = ucol_cloneRuleData(coll, &len, &intStatus);*/
923 
924                     /* tailoring rules version */
925                     /* This is wrong! */
926                     /*coll->dataInfo.dataVersion[1] = version[0];*/
927                     /* Copy tailoring version. Builder version already */
928                     /* set in ucol_openRules */
929                     ((UCATableHeader *)data)->version[1] = version[0];
930                     ((UCATableHeader *)data)->version[2] = version[1];
931                     ((UCATableHeader *)data)->version[3] = version[2];
932 
933                     if (U_SUCCESS(intStatus) && data != NULL)
934                     {
935                         struct SResource *collationBin = bin_open(state->bundle, "%%CollationBin", len, data, NULL, NULL, status);
936                         table_add(result, collationBin, line, status);
937                         uprv_free(data);
938 
939                         reorderCodeCount = ucol_getReorderCodes(
940                             coll, reorderCodes, USCRIPT_CODE_LIMIT + (UCOL_REORDER_CODE_LIMIT - UCOL_REORDER_CODE_FIRST), &intStatus);
941                         if (U_SUCCESS(intStatus) && reorderCodeCount > 0) {
942                             struct SResource *reorderCodeRes = intvector_open(state->bundle, "%%ReorderCodes", NULL, status);
943                             for (reorderCodeIndex = 0; reorderCodeIndex < reorderCodeCount; reorderCodeIndex++) {
944                                 intvector_add(reorderCodeRes, reorderCodes[reorderCodeIndex], status);
945                             }
946                             table_add(result, reorderCodeRes, line, status);
947                         }
948                     }
949                     else
950                     {
951                         warning(line, "could not obtain rules from collator");
952                         if(isStrict()){
953                             *status = U_INVALID_FORMAT_ERROR;
954                             return NULL;
955                         }
956                     }
957 
958                     ucol_close(coll);
959                 }
960                 else
961                 {
962                     if(intStatus == U_FILE_ACCESS_ERROR) {
963                       error(startline, "Collation could not be built- U_FILE_ACCESS_ERROR. Make sure ICU's data has been built and is loading properly.");
964                       *status = intStatus;
965                       return NULL;
966                     }
967                     warning(line, "%%Collation could not be constructed from CollationElements - check context!");
968                     if(isStrict()){
969                         *status = intStatus;
970                         return NULL;
971                     }
972                 }
973             } else {
974                 if(isVerbose()) {
975                     printf("Not building Collation binary\n");
976                 }
977             }
978 #endif
979             /* in order to achieve smaller data files, we can direct genrb */
980             /* to omit collation rules */
981             if(gOmitCollationRules) {
982                 bundle_closeString(state->bundle, member);
983             } else {
984                 table_add(result, member, line, status);
985             }
986         }
987 
988         /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
989 
990         /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
991 
992         if (U_FAILURE(*status))
993         {
994             res_close(result);
995             return NULL;
996         }
997     }
998 
999     /* not reached */
1000     /* A compiler warning will appear if all paths don't contain a return statement. */
1001 /*    *status = U_INTERNAL_PROGRAM_ERROR;
1002     return NULL;*/
1003 }
1004 
1005 static struct SResource *
parseCollationElements(ParseState * state,char * tag,uint32_t startline,UBool newCollation,UErrorCode * status)1006 parseCollationElements(ParseState* state, char *tag, uint32_t startline, UBool newCollation, UErrorCode *status)
1007 {
1008     struct SResource  *result = NULL;
1009     struct SResource  *member = NULL;
1010     struct SResource  *collationRes = NULL;
1011     struct UString    *tokenValue;
1012     struct UString     comment;
1013     enum   ETokenType  token;
1014     char               subtag[1024], typeKeyword[1024];
1015     uint32_t           line;
1016 
1017     result = table_open(state->bundle, tag, NULL, status);
1018 
1019     if (result == NULL || U_FAILURE(*status))
1020     {
1021         return NULL;
1022     }
1023     if(isVerbose()){
1024         printf(" collation elements %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1025     }
1026     if(!newCollation) {
1027         return addCollation(state, result, startline, status);
1028     }
1029     else {
1030         for(;;) {
1031             ustr_init(&comment);
1032             token = getToken(state, &tokenValue, &comment, &line, status);
1033 
1034             if (token == TOK_CLOSE_BRACE)
1035             {
1036                 return result;
1037             }
1038 
1039             if (token != TOK_STRING)
1040             {
1041                 res_close(result);
1042                 *status = U_INVALID_FORMAT_ERROR;
1043 
1044                 if (token == TOK_EOF)
1045                 {
1046                     error(startline, "unterminated table");
1047                 }
1048                 else
1049                 {
1050                     error(line, "Unexpected token %s", tokenNames[token]);
1051                 }
1052 
1053                 return NULL;
1054             }
1055 
1056             u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
1057 
1058             if (U_FAILURE(*status))
1059             {
1060                 res_close(result);
1061                 return NULL;
1062             }
1063 
1064             if (uprv_strcmp(subtag, "default") == 0)
1065             {
1066                 member = parseResource(state, subtag, NULL, status);
1067 
1068                 if (U_FAILURE(*status))
1069                 {
1070                     res_close(result);
1071                     return NULL;
1072                 }
1073 
1074                 table_add(result, member, line, status);
1075             }
1076             else
1077             {
1078                 token = peekToken(state, 0, &tokenValue, &line, &comment, status);
1079                 /* this probably needs to be refactored or recursively use the parser */
1080                 /* first we assume that our collation table won't have the explicit type */
1081                 /* then, we cannot handle aliases */
1082                 if(token == TOK_OPEN_BRACE) {
1083                     token = getToken(state, &tokenValue, &comment, &line, status);
1084                     collationRes = table_open(state->bundle, subtag, NULL, status);
1085                     collationRes = addCollation(state, collationRes, startline, status); /* need to parse the collation data regardless */
1086                     if (gIncludeUnihanColl || uprv_strcmp(subtag, "unihan") != 0) {
1087                         table_add(result, collationRes, startline, status);
1088                     }
1089                 } else if(token == TOK_COLON) { /* right now, we'll just try to see if we have aliases */
1090                     /* we could have a table too */
1091                     token = peekToken(state, 1, &tokenValue, &line, &comment, status);
1092                     u_UCharsToChars(tokenValue->fChars, typeKeyword, u_strlen(tokenValue->fChars) + 1);
1093                     if(uprv_strcmp(typeKeyword, "alias") == 0) {
1094                         member = parseResource(state, subtag, NULL, status);
1095 
1096                         if (U_FAILURE(*status))
1097                         {
1098                             res_close(result);
1099                             return NULL;
1100                         }
1101 
1102                         table_add(result, member, line, status);
1103                     } else {
1104                         res_close(result);
1105                         *status = U_INVALID_FORMAT_ERROR;
1106                         return NULL;
1107                     }
1108                 } else {
1109                     res_close(result);
1110                     *status = U_INVALID_FORMAT_ERROR;
1111                     return NULL;
1112                 }
1113             }
1114 
1115             /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
1116 
1117             /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
1118 
1119             if (U_FAILURE(*status))
1120             {
1121                 res_close(result);
1122                 return NULL;
1123             }
1124         }
1125     }
1126 }
1127 
1128 /* Necessary, because CollationElements requires the bundle->fRoot member to be present which,
1129    if this weren't special-cased, wouldn't be set until the entire file had been processed. */
1130 static struct SResource *
realParseTable(ParseState * state,struct SResource * table,char * tag,uint32_t startline,UErrorCode * status)1131 realParseTable(ParseState* state, struct SResource *table, char *tag, uint32_t startline, UErrorCode *status)
1132 {
1133     struct SResource  *member = NULL;
1134     struct UString    *tokenValue=NULL;
1135     struct UString    comment;
1136     enum   ETokenType token;
1137     char              subtag[1024];
1138     uint32_t          line;
1139     UBool             readToken = FALSE;
1140 
1141     /* '{' . (name resource)* '}' */
1142     if(isVerbose()){
1143         printf(" parsing table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1144     }
1145     for (;;)
1146     {
1147         ustr_init(&comment);
1148         token = getToken(state, &tokenValue, &comment, &line, status);
1149 
1150         if (token == TOK_CLOSE_BRACE)
1151         {
1152             if (!readToken) {
1153                 warning(startline, "Encountered empty table");
1154             }
1155             return table;
1156         }
1157 
1158         if (token != TOK_STRING)
1159         {
1160             *status = U_INVALID_FORMAT_ERROR;
1161 
1162             if (token == TOK_EOF)
1163             {
1164                 error(startline, "unterminated table");
1165             }
1166             else
1167             {
1168                 error(line, "unexpected token %s", tokenNames[token]);
1169             }
1170 
1171             return NULL;
1172         }
1173 
1174         if(uprv_isInvariantUString(tokenValue->fChars, -1)) {
1175             u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
1176         } else {
1177             *status = U_INVALID_FORMAT_ERROR;
1178             error(line, "invariant characters required for table keys");
1179             return NULL;
1180         }
1181 
1182         if (U_FAILURE(*status))
1183         {
1184             error(line, "parse error. Stopped parsing tokens with %s", u_errorName(*status));
1185             return NULL;
1186         }
1187 
1188         member = parseResource(state, subtag, &comment, status);
1189 
1190         if (member == NULL || U_FAILURE(*status))
1191         {
1192             error(line, "parse error. Stopped parsing resource with %s", u_errorName(*status));
1193             return NULL;
1194         }
1195 
1196         table_add(table, member, line, status);
1197 
1198         if (U_FAILURE(*status))
1199         {
1200             error(line, "parse error. Stopped parsing table with %s", u_errorName(*status));
1201             return NULL;
1202         }
1203         readToken = TRUE;
1204         ustr_deinit(&comment);
1205     }
1206 
1207     /* not reached */
1208     /* A compiler warning will appear if all paths don't contain a return statement. */
1209 /*     *status = U_INTERNAL_PROGRAM_ERROR;
1210      return NULL;*/
1211 }
1212 
1213 static struct SResource *
parseTable(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1214 parseTable(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1215 {
1216     struct SResource *result;
1217 
1218     if (tag != NULL && uprv_strcmp(tag, "CollationElements") == 0)
1219     {
1220         return parseCollationElements(state, tag, startline, FALSE, status);
1221     }
1222     if (tag != NULL && uprv_strcmp(tag, "collations") == 0)
1223     {
1224         return parseCollationElements(state, tag, startline, TRUE, status);
1225     }
1226     if(isVerbose()){
1227         printf(" table %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1228     }
1229 
1230     result = table_open(state->bundle, tag, comment, status);
1231 
1232     if (result == NULL || U_FAILURE(*status))
1233     {
1234         return NULL;
1235     }
1236 
1237     return realParseTable(state, result, tag, startline,  status);
1238 }
1239 
1240 static struct SResource *
parseArray(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1241 parseArray(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1242 {
1243     struct SResource  *result = NULL;
1244     struct SResource  *member = NULL;
1245     struct UString    *tokenValue;
1246     struct UString    memberComments;
1247     enum   ETokenType token;
1248     UBool             readToken = FALSE;
1249 
1250     result = array_open(state->bundle, tag, comment, status);
1251 
1252     if (result == NULL || U_FAILURE(*status))
1253     {
1254         return NULL;
1255     }
1256     if(isVerbose()){
1257         printf(" array %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1258     }
1259 
1260     ustr_init(&memberComments);
1261 
1262     /* '{' . resource [','] '}' */
1263     for (;;)
1264     {
1265         /* reset length */
1266         ustr_setlen(&memberComments, 0, status);
1267 
1268         /* check for end of array, but don't consume next token unless it really is the end */
1269         token = peekToken(state, 0, &tokenValue, NULL, &memberComments, status);
1270 
1271 
1272         if (token == TOK_CLOSE_BRACE)
1273         {
1274             getToken(state, NULL, NULL, NULL, status);
1275             if (!readToken) {
1276                 warning(startline, "Encountered empty array");
1277             }
1278             break;
1279         }
1280 
1281         if (token == TOK_EOF)
1282         {
1283             res_close(result);
1284             *status = U_INVALID_FORMAT_ERROR;
1285             error(startline, "unterminated array");
1286             return NULL;
1287         }
1288 
1289         /* string arrays are a special case */
1290         if (token == TOK_STRING)
1291         {
1292             getToken(state, &tokenValue, &memberComments, NULL, status);
1293             member = string_open(state->bundle, NULL, tokenValue->fChars, tokenValue->fLength, &memberComments, status);
1294         }
1295         else
1296         {
1297             member = parseResource(state, NULL, &memberComments, status);
1298         }
1299 
1300         if (member == NULL || U_FAILURE(*status))
1301         {
1302             res_close(result);
1303             return NULL;
1304         }
1305 
1306         array_add(result, member, status);
1307 
1308         if (U_FAILURE(*status))
1309         {
1310             res_close(result);
1311             return NULL;
1312         }
1313 
1314         /* eat optional comma if present */
1315         token = peekToken(state, 0, NULL, NULL, NULL, status);
1316 
1317         if (token == TOK_COMMA)
1318         {
1319             getToken(state, NULL, NULL, NULL, status);
1320         }
1321 
1322         if (U_FAILURE(*status))
1323         {
1324             res_close(result);
1325             return NULL;
1326         }
1327         readToken = TRUE;
1328     }
1329 
1330     ustr_deinit(&memberComments);
1331     return result;
1332 }
1333 
1334 static struct SResource *
parseIntVector(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1335 parseIntVector(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1336 {
1337     struct SResource  *result = NULL;
1338     enum   ETokenType  token;
1339     char              *string;
1340     int32_t            value;
1341     UBool              readToken = FALSE;
1342     char              *stopstring;
1343     uint32_t           len;
1344     struct UString     memberComments;
1345 
1346     result = intvector_open(state->bundle, tag, comment, status);
1347 
1348     if (result == NULL || U_FAILURE(*status))
1349     {
1350         return NULL;
1351     }
1352 
1353     if(isVerbose()){
1354         printf(" vector %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1355     }
1356     ustr_init(&memberComments);
1357     /* '{' . string [','] '}' */
1358     for (;;)
1359     {
1360         ustr_setlen(&memberComments, 0, status);
1361 
1362         /* check for end of array, but don't consume next token unless it really is the end */
1363         token = peekToken(state, 0, NULL, NULL,&memberComments, status);
1364 
1365         if (token == TOK_CLOSE_BRACE)
1366         {
1367             /* it's the end, consume the close brace */
1368             getToken(state, NULL, NULL, NULL, status);
1369             if (!readToken) {
1370                 warning(startline, "Encountered empty int vector");
1371             }
1372             ustr_deinit(&memberComments);
1373             return result;
1374         }
1375 
1376         string = getInvariantString(state, NULL, NULL, status);
1377 
1378         if (U_FAILURE(*status))
1379         {
1380             res_close(result);
1381             return NULL;
1382         }
1383 
1384         /* For handling illegal char in the Intvector */
1385         value = uprv_strtoul(string, &stopstring, 0);/* make intvector support decimal,hexdigit,octal digit ranging from -2^31-2^32-1*/
1386         len=(uint32_t)(stopstring-string);
1387 
1388         if(len==uprv_strlen(string))
1389         {
1390             intvector_add(result, value, status);
1391             uprv_free(string);
1392             token = peekToken(state, 0, NULL, NULL, NULL, status);
1393         }
1394         else
1395         {
1396             uprv_free(string);
1397             *status=U_INVALID_CHAR_FOUND;
1398         }
1399 
1400         if (U_FAILURE(*status))
1401         {
1402             res_close(result);
1403             return NULL;
1404         }
1405 
1406         /* the comma is optional (even though it is required to prevent the reader from concatenating
1407         consecutive entries) so that a missing comma on the last entry isn't an error */
1408         if (token == TOK_COMMA)
1409         {
1410             getToken(state, NULL, NULL, NULL, status);
1411         }
1412         readToken = TRUE;
1413     }
1414 
1415     /* not reached */
1416     /* A compiler warning will appear if all paths don't contain a return statement. */
1417 /*    intvector_close(result, status);
1418     *status = U_INTERNAL_PROGRAM_ERROR;
1419     return NULL;*/
1420 }
1421 
1422 static struct SResource *
parseBinary(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1423 parseBinary(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1424 {
1425     struct SResource *result = NULL;
1426     uint8_t          *value;
1427     char             *string;
1428     char              toConv[3] = {'\0', '\0', '\0'};
1429     uint32_t          count;
1430     uint32_t          i;
1431     uint32_t          line;
1432     char             *stopstring;
1433     uint32_t          len;
1434 
1435     string = getInvariantString(state, &line, NULL, status);
1436 
1437     if (string == NULL || U_FAILURE(*status))
1438     {
1439         return NULL;
1440     }
1441 
1442     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1443 
1444     if (U_FAILURE(*status))
1445     {
1446         uprv_free(string);
1447         return NULL;
1448     }
1449 
1450     if(isVerbose()){
1451         printf(" binary %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1452     }
1453 
1454     count = (uint32_t)uprv_strlen(string);
1455     if (count > 0){
1456         if((count % 2)==0){
1457             value = uprv_malloc(sizeof(uint8_t) * count);
1458 
1459             if (value == NULL)
1460             {
1461                 uprv_free(string);
1462                 *status = U_MEMORY_ALLOCATION_ERROR;
1463                 return NULL;
1464             }
1465 
1466             for (i = 0; i < count; i += 2)
1467             {
1468                 toConv[0] = string[i];
1469                 toConv[1] = string[i + 1];
1470 
1471                 value[i >> 1] = (uint8_t) uprv_strtoul(toConv, &stopstring, 16);
1472                 len=(uint32_t)(stopstring-toConv);
1473 
1474                 if(len!=uprv_strlen(toConv))
1475                 {
1476                     uprv_free(string);
1477                     *status=U_INVALID_CHAR_FOUND;
1478                     return NULL;
1479                 }
1480             }
1481 
1482             result = bin_open(state->bundle, tag, (i >> 1), value,NULL, comment, status);
1483 
1484             uprv_free(value);
1485         }
1486         else
1487         {
1488             *status = U_INVALID_CHAR_FOUND;
1489             uprv_free(string);
1490             error(line, "Encountered invalid binary string");
1491             return NULL;
1492         }
1493     }
1494     else
1495     {
1496         result = bin_open(state->bundle, tag, 0, NULL, "",comment,status);
1497         warning(startline, "Encountered empty binary tag");
1498     }
1499     uprv_free(string);
1500 
1501     return result;
1502 }
1503 
1504 static struct SResource *
parseInteger(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1505 parseInteger(ParseState* state, char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1506 {
1507     struct SResource *result = NULL;
1508     int32_t           value;
1509     char             *string;
1510     char             *stopstring;
1511     uint32_t          len;
1512 
1513     string = getInvariantString(state, NULL, NULL, status);
1514 
1515     if (string == NULL || U_FAILURE(*status))
1516     {
1517         return NULL;
1518     }
1519 
1520     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1521 
1522     if (U_FAILURE(*status))
1523     {
1524         uprv_free(string);
1525         return NULL;
1526     }
1527 
1528     if(isVerbose()){
1529         printf(" integer %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1530     }
1531 
1532     if (uprv_strlen(string) <= 0)
1533     {
1534         warning(startline, "Encountered empty integer. Default value is 0.");
1535     }
1536 
1537     /* Allow integer support for hexdecimal, octal digit and decimal*/
1538     /* and handle illegal char in the integer*/
1539     value = uprv_strtoul(string, &stopstring, 0);
1540     len=(uint32_t)(stopstring-string);
1541     if(len==uprv_strlen(string))
1542     {
1543         result = int_open(state->bundle, tag, value, comment, status);
1544     }
1545     else
1546     {
1547         *status=U_INVALID_CHAR_FOUND;
1548     }
1549     uprv_free(string);
1550 
1551     return result;
1552 }
1553 
1554 static struct SResource *
parseImport(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1555 parseImport(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
1556 {
1557     struct SResource *result;
1558     FileStream       *file;
1559     int32_t           len;
1560     uint8_t          *data;
1561     char             *filename;
1562     uint32_t          line;
1563     char     *fullname = NULL;
1564     int32_t numRead = 0;
1565     filename = getInvariantString(state, &line, NULL, status);
1566 
1567     if (U_FAILURE(*status))
1568     {
1569         return NULL;
1570     }
1571 
1572     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1573 
1574     if (U_FAILURE(*status))
1575     {
1576         uprv_free(filename);
1577         return NULL;
1578     }
1579 
1580     if(isVerbose()){
1581         printf(" import %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1582     }
1583 
1584     /* Open the input file for reading */
1585     if (state->inputdir == NULL)
1586     {
1587 #if 1
1588         /*
1589          * Always save file file name, even if there's
1590          * no input directory specified. MIGHT BREAK SOMETHING
1591          */
1592         int32_t filenameLength = uprv_strlen(filename);
1593 
1594         fullname = (char *) uprv_malloc(filenameLength + 1);
1595         uprv_strcpy(fullname, filename);
1596 #endif
1597 
1598         file = T_FileStream_open(filename, "rb");
1599     }
1600     else
1601     {
1602 
1603         int32_t  count     = (int32_t)uprv_strlen(filename);
1604 
1605         if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
1606         {
1607             fullname = (char *) uprv_malloc(state->inputdirLength + count + 2);
1608 
1609             /* test for NULL */
1610             if(fullname == NULL)
1611             {
1612                 *status = U_MEMORY_ALLOCATION_ERROR;
1613                 return NULL;
1614             }
1615 
1616             uprv_strcpy(fullname, state->inputdir);
1617 
1618             fullname[state->inputdirLength]      = U_FILE_SEP_CHAR;
1619             fullname[state->inputdirLength + 1] = '\0';
1620 
1621             uprv_strcat(fullname, filename);
1622         }
1623         else
1624         {
1625             fullname = (char *) uprv_malloc(state->inputdirLength + count + 1);
1626 
1627             /* test for NULL */
1628             if(fullname == NULL)
1629             {
1630                 *status = U_MEMORY_ALLOCATION_ERROR;
1631                 return NULL;
1632             }
1633 
1634             uprv_strcpy(fullname, state->inputdir);
1635             uprv_strcat(fullname, filename);
1636         }
1637 
1638         file = T_FileStream_open(fullname, "rb");
1639 
1640     }
1641 
1642     if (file == NULL)
1643     {
1644         error(line, "couldn't open input file %s", filename);
1645         *status = U_FILE_ACCESS_ERROR;
1646         return NULL;
1647     }
1648 
1649     len  = T_FileStream_size(file);
1650     data = (uint8_t*)uprv_malloc(len * sizeof(uint8_t));
1651     /* test for NULL */
1652     if(data == NULL)
1653     {
1654         *status = U_MEMORY_ALLOCATION_ERROR;
1655         T_FileStream_close (file);
1656         return NULL;
1657     }
1658 
1659     numRead = T_FileStream_read  (file, data, len);
1660     T_FileStream_close (file);
1661 
1662     result = bin_open(state->bundle, tag, len, data, fullname, comment, status);
1663 
1664     uprv_free(data);
1665     uprv_free(filename);
1666     uprv_free(fullname);
1667 
1668     return result;
1669 }
1670 
1671 static struct SResource *
parseInclude(ParseState * state,char * tag,uint32_t startline,const struct UString * comment,UErrorCode * status)1672 parseInclude(ParseState* state, char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
1673 {
1674     struct SResource *result;
1675     int32_t           len=0;
1676     char             *filename;
1677     uint32_t          line;
1678     UChar *pTarget     = NULL;
1679 
1680     UCHARBUF *ucbuf;
1681     char     *fullname = NULL;
1682     int32_t  count     = 0;
1683     const char* cp = NULL;
1684     const UChar* uBuffer = NULL;
1685 
1686     filename = getInvariantString(state, &line, NULL, status);
1687     count     = (int32_t)uprv_strlen(filename);
1688 
1689     if (U_FAILURE(*status))
1690     {
1691         return NULL;
1692     }
1693 
1694     expect(state, TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1695 
1696     if (U_FAILURE(*status))
1697     {
1698         uprv_free(filename);
1699         return NULL;
1700     }
1701 
1702     if(isVerbose()){
1703         printf(" include %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1704     }
1705 
1706     fullname = (char *) uprv_malloc(state->inputdirLength + count + 2);
1707     /* test for NULL */
1708     if(fullname == NULL)
1709     {
1710         *status = U_MEMORY_ALLOCATION_ERROR;
1711         uprv_free(filename);
1712         return NULL;
1713     }
1714 
1715     if(state->inputdir!=NULL){
1716         if (state->inputdir[state->inputdirLength - 1] != U_FILE_SEP_CHAR)
1717         {
1718 
1719             uprv_strcpy(fullname, state->inputdir);
1720 
1721             fullname[state->inputdirLength]      = U_FILE_SEP_CHAR;
1722             fullname[state->inputdirLength + 1] = '\0';
1723 
1724             uprv_strcat(fullname, filename);
1725         }
1726         else
1727         {
1728             uprv_strcpy(fullname, state->inputdir);
1729             uprv_strcat(fullname, filename);
1730         }
1731     }else{
1732         uprv_strcpy(fullname,filename);
1733     }
1734 
1735     ucbuf = ucbuf_open(fullname, &cp,getShowWarning(),FALSE,status);
1736 
1737     if (U_FAILURE(*status)) {
1738         error(line, "couldn't open input file %s\n", filename);
1739         return NULL;
1740     }
1741 
1742     uBuffer = ucbuf_getBuffer(ucbuf,&len,status);
1743     result = string_open(state->bundle, tag, uBuffer, len, comment, status);
1744 
1745     uprv_free(pTarget);
1746 
1747     uprv_free(filename);
1748     uprv_free(fullname);
1749 
1750     return result;
1751 }
1752 
1753 
1754 
1755 
1756 
1757 U_STRING_DECL(k_type_string,    "string",    6);
1758 U_STRING_DECL(k_type_binary,    "binary",    6);
1759 U_STRING_DECL(k_type_bin,       "bin",       3);
1760 U_STRING_DECL(k_type_table,     "table",     5);
1761 U_STRING_DECL(k_type_table_no_fallback,     "table(nofallback)",         17);
1762 U_STRING_DECL(k_type_int,       "int",       3);
1763 U_STRING_DECL(k_type_integer,   "integer",   7);
1764 U_STRING_DECL(k_type_array,     "array",     5);
1765 U_STRING_DECL(k_type_alias,     "alias",     5);
1766 U_STRING_DECL(k_type_intvector, "intvector", 9);
1767 U_STRING_DECL(k_type_import,    "import",    6);
1768 U_STRING_DECL(k_type_include,   "include",   7);
1769 U_STRING_DECL(k_type_reserved,  "reserved",  8);
1770 
1771 /* Various non-standard processing plugins that create one or more special resources. */
1772 U_STRING_DECL(k_type_plugin_uca_rules,      "process(uca_rules)",        18);
1773 U_STRING_DECL(k_type_plugin_collation,      "process(collation)",        18);
1774 U_STRING_DECL(k_type_plugin_transliterator, "process(transliterator)",   23);
1775 U_STRING_DECL(k_type_plugin_dependency,     "process(dependency)",       19);
1776 
1777 typedef enum EResourceType
1778 {
1779     RT_UNKNOWN,
1780     RT_STRING,
1781     RT_BINARY,
1782     RT_TABLE,
1783     RT_TABLE_NO_FALLBACK,
1784     RT_INTEGER,
1785     RT_ARRAY,
1786     RT_ALIAS,
1787     RT_INTVECTOR,
1788     RT_IMPORT,
1789     RT_INCLUDE,
1790     RT_PROCESS_UCA_RULES,
1791     RT_PROCESS_COLLATION,
1792     RT_PROCESS_TRANSLITERATOR,
1793     RT_PROCESS_DEPENDENCY,
1794     RT_RESERVED
1795 } EResourceType;
1796 
1797 static struct {
1798     const char *nameChars;   /* only used for debugging */
1799     const UChar *nameUChars;
1800     ParseResourceFunction *parseFunction;
1801 } gResourceTypes[] = {
1802     {"Unknown", NULL, NULL},
1803     {"string", k_type_string, parseString},
1804     {"binary", k_type_binary, parseBinary},
1805     {"table", k_type_table, parseTable},
1806     {"table(nofallback)", k_type_table_no_fallback, NULL}, /* parseFunction will never be called */
1807     {"integer", k_type_integer, parseInteger},
1808     {"array", k_type_array, parseArray},
1809     {"alias", k_type_alias, parseAlias},
1810     {"intvector", k_type_intvector, parseIntVector},
1811     {"import", k_type_import, parseImport},
1812     {"include", k_type_include, parseInclude},
1813     {"process(uca_rules)", k_type_plugin_uca_rules, parseUCARules},
1814     {"process(collation)", k_type_plugin_collation, NULL /* not implemented yet */},
1815     {"process(transliterator)", k_type_plugin_transliterator, parseTransliterator},
1816     {"process(dependency)", k_type_plugin_dependency, parseDependency},
1817     {"reserved", NULL, NULL}
1818 };
1819 
initParser(UBool omitBinaryCollation,UBool omitCollationRules)1820 void initParser(UBool omitBinaryCollation, UBool omitCollationRules)
1821 {
1822     U_STRING_INIT(k_type_string,    "string",    6);
1823     U_STRING_INIT(k_type_binary,    "binary",    6);
1824     U_STRING_INIT(k_type_bin,       "bin",       3);
1825     U_STRING_INIT(k_type_table,     "table",     5);
1826     U_STRING_INIT(k_type_table_no_fallback,     "table(nofallback)",         17);
1827     U_STRING_INIT(k_type_int,       "int",       3);
1828     U_STRING_INIT(k_type_integer,   "integer",   7);
1829     U_STRING_INIT(k_type_array,     "array",     5);
1830     U_STRING_INIT(k_type_alias,     "alias",     5);
1831     U_STRING_INIT(k_type_intvector, "intvector", 9);
1832     U_STRING_INIT(k_type_import,    "import",    6);
1833     U_STRING_INIT(k_type_reserved,  "reserved",  8);
1834     U_STRING_INIT(k_type_include,   "include",   7);
1835 
1836     U_STRING_INIT(k_type_plugin_uca_rules,      "process(uca_rules)",        18);
1837     U_STRING_INIT(k_type_plugin_collation,      "process(collation)",        18);
1838     U_STRING_INIT(k_type_plugin_transliterator, "process(transliterator)",   23);
1839     U_STRING_INIT(k_type_plugin_dependency,     "process(dependency)",       19);
1840 
1841     gMakeBinaryCollation = !omitBinaryCollation;
1842     gOmitCollationRules = omitCollationRules;
1843 }
1844 
isTable(enum EResourceType type)1845 static U_INLINE UBool isTable(enum EResourceType type) {
1846     return (UBool)(type==RT_TABLE || type==RT_TABLE_NO_FALLBACK);
1847 }
1848 
1849 static enum EResourceType
parseResourceType(ParseState * state,UErrorCode * status)1850 parseResourceType(ParseState* state, UErrorCode *status)
1851 {
1852     struct UString        *tokenValue;
1853     struct UString        comment;
1854     enum   EResourceType  result = RT_UNKNOWN;
1855     uint32_t              line=0;
1856     ustr_init(&comment);
1857     expect(state, TOK_STRING, &tokenValue, &comment, &line, status);
1858 
1859     if (U_FAILURE(*status))
1860     {
1861         return RT_UNKNOWN;
1862     }
1863 
1864     *status = U_ZERO_ERROR;
1865 
1866     /* Search for normal types */
1867     result=RT_UNKNOWN;
1868     while (++result < RT_RESERVED) {
1869         if (u_strcmp(tokenValue->fChars, gResourceTypes[result].nameUChars) == 0) {
1870             break;
1871         }
1872     }
1873     /* Now search for the aliases */
1874     if (u_strcmp(tokenValue->fChars, k_type_int) == 0) {
1875         result = RT_INTEGER;
1876     }
1877     else if (u_strcmp(tokenValue->fChars, k_type_bin) == 0) {
1878         result = RT_BINARY;
1879     }
1880     else if (result == RT_RESERVED) {
1881         char tokenBuffer[1024];
1882         u_austrncpy(tokenBuffer, tokenValue->fChars, sizeof(tokenBuffer));
1883         tokenBuffer[sizeof(tokenBuffer) - 1] = 0;
1884         *status = U_INVALID_FORMAT_ERROR;
1885         error(line, "unknown resource type '%s'", tokenBuffer);
1886     }
1887 
1888     return result;
1889 }
1890 
1891 /* parse a non-top-level resource */
1892 static struct SResource *
parseResource(ParseState * state,char * tag,const struct UString * comment,UErrorCode * status)1893 parseResource(ParseState* state, char *tag, const struct UString *comment, UErrorCode *status)
1894 {
1895     enum   ETokenType      token;
1896     enum   EResourceType  resType = RT_UNKNOWN;
1897     ParseResourceFunction *parseFunction = NULL;
1898     struct UString        *tokenValue;
1899     uint32_t                 startline;
1900     uint32_t                 line;
1901 
1902     token = getToken(state, &tokenValue, NULL, &startline, status);
1903 
1904     if(isVerbose()){
1905         printf(" resource %s at line %i \n",  (tag == NULL) ? "(null)" : tag, (int)startline);
1906     }
1907 
1908     /* name . [ ':' type ] '{' resource '}' */
1909     /* This function parses from the colon onwards.  If the colon is present, parse the
1910     type then try to parse a resource of that type.  If there is no explicit type,
1911     work it out using the lookahead tokens. */
1912     switch (token)
1913     {
1914     case TOK_EOF:
1915         *status = U_INVALID_FORMAT_ERROR;
1916         error(startline, "Unexpected EOF encountered");
1917         return NULL;
1918 
1919     case TOK_ERROR:
1920         *status = U_INVALID_FORMAT_ERROR;
1921         return NULL;
1922 
1923     case TOK_COLON:
1924         resType = parseResourceType(state, status);
1925         expect(state, TOK_OPEN_BRACE, &tokenValue, NULL, &startline, status);
1926 
1927         if (U_FAILURE(*status))
1928         {
1929             return NULL;
1930         }
1931 
1932         break;
1933 
1934     case TOK_OPEN_BRACE:
1935         break;
1936 
1937     default:
1938         *status = U_INVALID_FORMAT_ERROR;
1939         error(startline, "syntax error while reading a resource, expected '{' or ':'");
1940         return NULL;
1941     }
1942 
1943     if (resType == RT_UNKNOWN)
1944     {
1945         /* No explicit type, so try to work it out.  At this point, we've read the first '{'.
1946         We could have any of the following:
1947         { {         => array (nested)
1948         { :/}       => array
1949         { string ,  => string array
1950 
1951         { string {  => table
1952 
1953         { string :/{    => table
1954         { string }      => string
1955         */
1956 
1957         token = peekToken(state, 0, NULL, &line, NULL,status);
1958 
1959         if (U_FAILURE(*status))
1960         {
1961             return NULL;
1962         }
1963 
1964         if (token == TOK_OPEN_BRACE || token == TOK_COLON ||token ==TOK_CLOSE_BRACE )
1965         {
1966             resType = RT_ARRAY;
1967         }
1968         else if (token == TOK_STRING)
1969         {
1970             token = peekToken(state, 1, NULL, &line, NULL, status);
1971 
1972             if (U_FAILURE(*status))
1973             {
1974                 return NULL;
1975             }
1976 
1977             switch (token)
1978             {
1979             case TOK_COMMA:         resType = RT_ARRAY;  break;
1980             case TOK_OPEN_BRACE:    resType = RT_TABLE;  break;
1981             case TOK_CLOSE_BRACE:   resType = RT_STRING; break;
1982             case TOK_COLON:         resType = RT_TABLE;  break;
1983             default:
1984                 *status = U_INVALID_FORMAT_ERROR;
1985                 error(line, "Unexpected token after string, expected ',', '{' or '}'");
1986                 return NULL;
1987             }
1988         }
1989         else
1990         {
1991             *status = U_INVALID_FORMAT_ERROR;
1992             error(line, "Unexpected token after '{'");
1993             return NULL;
1994         }
1995 
1996         /* printf("Type guessed as %s\n", resourceNames[resType]); */
1997     } else if(resType == RT_TABLE_NO_FALLBACK) {
1998         *status = U_INVALID_FORMAT_ERROR;
1999         error(startline, "error: %s resource type not valid except on top bundle level", gResourceTypes[resType].nameChars);
2000         return NULL;
2001     }
2002 
2003     /* We should now know what we need to parse next, so call the appropriate parser
2004     function and return. */
2005     parseFunction = gResourceTypes[resType].parseFunction;
2006     if (parseFunction != NULL) {
2007         return parseFunction(state, tag, startline, comment, status);
2008     }
2009     else {
2010         *status = U_INTERNAL_PROGRAM_ERROR;
2011         error(startline, "internal error: %s resource type found and not handled", gResourceTypes[resType].nameChars);
2012     }
2013 
2014     return NULL;
2015 }
2016 
2017 /* parse the top-level resource */
2018 struct SRBRoot *
parse(UCHARBUF * buf,const char * inputDir,const char * outputDir,UErrorCode * status)2019 parse(UCHARBUF *buf, const char *inputDir, const char *outputDir, UErrorCode *status)
2020 {
2021     struct UString    *tokenValue;
2022     struct UString    comment;
2023     uint32_t           line;
2024     enum EResourceType bundleType;
2025     enum ETokenType    token;
2026     ParseState state;
2027     uint32_t i;
2028     int encLength;
2029     char* enc;
2030     for (i = 0; i < MAX_LOOKAHEAD + 1; i++)
2031     {
2032         ustr_init(&state.lookahead[i].value);
2033         ustr_init(&state.lookahead[i].comment);
2034     }
2035 
2036     initLookahead(&state, buf, status);
2037 
2038     state.inputdir       = inputDir;
2039     state.inputdirLength = (state.inputdir != NULL) ? (uint32_t)uprv_strlen(state.inputdir) : 0;
2040     state.outputdir       = outputDir;
2041     state.outputdirLength = (state.outputdir != NULL) ? (uint32_t)uprv_strlen(state.outputdir) : 0;
2042 
2043     ustr_init(&comment);
2044     expect(&state, TOK_STRING, &tokenValue, &comment, NULL, status);
2045 
2046     state.bundle = bundle_open(&comment, FALSE, status);
2047 
2048     if (state.bundle == NULL || U_FAILURE(*status))
2049     {
2050         return NULL;
2051     }
2052 
2053 
2054     bundle_setlocale(state.bundle, tokenValue->fChars, status);
2055 
2056     /* The following code is to make Empty bundle work no matter with :table specifer or not */
2057     token = getToken(&state, NULL, NULL, &line, status);
2058     if(token==TOK_COLON) {
2059         *status=U_ZERO_ERROR;
2060         bundleType=parseResourceType(&state, status);
2061 
2062         if(isTable(bundleType))
2063         {
2064             expect(&state, TOK_OPEN_BRACE, NULL, NULL, &line, status);
2065         }
2066         else
2067         {
2068             *status=U_PARSE_ERROR;
2069             /* printf("asdsdweqdasdad\n"); */
2070 
2071             error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
2072         }
2073     }
2074     else
2075     {
2076         /* not a colon */
2077         if(token==TOK_OPEN_BRACE)
2078         {
2079             *status=U_ZERO_ERROR;
2080             bundleType=RT_TABLE;
2081         }
2082         else
2083         {
2084             /* neither colon nor open brace */
2085             *status=U_PARSE_ERROR;
2086             bundleType=RT_UNKNOWN;
2087             error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status));
2088         }
2089     }
2090 
2091     if (U_FAILURE(*status))
2092     {
2093         bundle_close(state.bundle, status);
2094         return NULL;
2095     }
2096 
2097     if(bundleType==RT_TABLE_NO_FALLBACK) {
2098         /*
2099          * Parse a top-level table with the table(nofallback) declaration.
2100          * This is the same as a regular table, but also sets the
2101          * URES_ATT_NO_FALLBACK flag in indexes[URES_INDEX_ATTRIBUTES] .
2102          */
2103         state.bundle->noFallback=TRUE;
2104     }
2105     /* top-level tables need not handle special table names like "collations" */
2106     realParseTable(&state, state.bundle->fRoot, NULL, line, status);
2107 
2108     if(dependencyArray!=NULL){
2109         table_add(state.bundle->fRoot, dependencyArray, 0, status);
2110         dependencyArray = NULL;
2111     }
2112     if (U_FAILURE(*status))
2113     {
2114         bundle_close(state.bundle, status);
2115         res_close(dependencyArray);
2116         return NULL;
2117     }
2118 
2119     if (getToken(&state, NULL, NULL, &line, status) != TOK_EOF)
2120     {
2121         warning(line, "extraneous text after resource bundle (perhaps unmatched braces)");
2122         if(isStrict()){
2123             *status = U_INVALID_FORMAT_ERROR;
2124             return NULL;
2125         }
2126     }
2127 
2128     cleanupLookahead(&state);
2129     ustr_deinit(&comment);
2130     return state.bundle;
2131 }
2132