]> git.saurik.com Git - apple/icu.git/blame_incremental - icuSources/tools/genrb/parse.c
ICU-6.2.15.tar.gz
[apple/icu.git] / icuSources / tools / genrb / parse.c
... / ...
CommitLineData
1/*
2*******************************************************************************
3*
4* Copyright (C) 1998-2004, 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 "unicode/ustring.h"
32#include "unicode/putil.h"
33
34/* Number of tokens to read ahead of the current stream position */
35#define MAX_LOOKAHEAD 3
36
37#define U_ICU_UNIDATA "unidata"
38#define CR 0x000D
39#define LF 0x000A
40#define SPACE 0x0020
41#define TAB 0x0009
42#define ESCAPE 0x005C
43#define HASH 0x0023
44#define QUOTE 0x0027
45#define STARTCOMMAND 0x005B
46#define ENDCOMMAND 0x005D
47
48U_STRING_DECL(k_type_string, "string", 6);
49U_STRING_DECL(k_type_binary, "binary", 6);
50U_STRING_DECL(k_type_bin, "bin", 3);
51U_STRING_DECL(k_type_table, "table", 5);
52U_STRING_DECL(k_type_int, "int", 3);
53U_STRING_DECL(k_type_integer, "integer", 7);
54U_STRING_DECL(k_type_array, "array", 5);
55U_STRING_DECL(k_type_alias, "alias", 5);
56U_STRING_DECL(k_type_intvector, "intvector", 9);
57U_STRING_DECL(k_type_import, "import", 6);
58U_STRING_DECL(k_type_include, "include", 7);
59U_STRING_DECL(k_type_reserved, "reserved", 8);
60
61enum EResourceType
62{
63 RT_UNKNOWN,
64 RT_STRING,
65 RT_BINARY,
66 RT_TABLE,
67 RT_INTEGER,
68 RT_ARRAY,
69 RT_ALIAS,
70 RT_INTVECTOR,
71 RT_IMPORT,
72 RT_INCLUDE,
73 RT_RESERVED
74};
75
76/* only used for debugging */
77const char *resourceNames[] =
78{
79 "Unknown",
80 "String",
81 "Binary",
82 "Table",
83 "Integer",
84 "Array",
85 "Alias",
86 "Int vector",
87 "Import",
88 "Include",
89 "Reserved",
90};
91
92struct Lookahead
93{
94 enum ETokenType type;
95 struct UString value;
96 struct UString comment;
97 uint32_t line;
98};
99
100/* keep in sync with token defines in read.h */
101const char *tokenNames[TOK_TOKEN_COUNT] =
102{
103 "string", /* A string token, such as "MonthNames" */
104 "'{'", /* An opening brace character */
105 "'}'", /* A closing brace character */
106 "','", /* A comma */
107 "':'", /* A colon */
108
109 "<end of file>", /* End of the file has been reached successfully */
110 "<end of line>"
111};
112
113/* Just to store "TRUE" */
114static const UChar trueValue[] = {0x0054, 0x0052, 0x0055, 0x0045, 0x0000};
115
116static struct Lookahead lookahead[MAX_LOOKAHEAD + 1];
117static uint32_t lookaheadPosition;
118static UCHARBUF *buffer;
119
120static struct SRBRoot *bundle;
121static const char *inputdir;
122static uint32_t inputdirLength;
123
124static UBool gMakeBinaryCollation = TRUE;
125
126static struct SResource *parseResource(char *tag, const struct UString *comment, UErrorCode *status);
127
128void initParser(UBool makeBinaryCollation)
129{
130 uint32_t i;
131
132 U_STRING_INIT(k_type_string, "string", 6);
133 U_STRING_INIT(k_type_binary, "binary", 6);
134 U_STRING_INIT(k_type_bin, "bin", 3);
135 U_STRING_INIT(k_type_table, "table", 5);
136 U_STRING_INIT(k_type_int, "int", 3);
137 U_STRING_INIT(k_type_integer, "integer", 7);
138 U_STRING_INIT(k_type_array, "array", 5);
139 U_STRING_INIT(k_type_alias, "alias", 5);
140 U_STRING_INIT(k_type_intvector, "intvector", 9);
141 U_STRING_INIT(k_type_import, "import", 6);
142 U_STRING_INIT(k_type_reserved, "reserved", 8);
143 U_STRING_INIT(k_type_include, "include", 7);
144 for (i = 0; i < MAX_LOOKAHEAD + 1; i++)
145 {
146 ustr_init(&lookahead[i].value);
147 }
148 gMakeBinaryCollation = makeBinaryCollation;
149}
150
151/* The nature of the lookahead buffer:
152 There are MAX_LOOKAHEAD + 1 slots, used as a circular buffer. This provides
153 MAX_LOOKAHEAD lookahead tokens and a slot for the current token and value.
154 When getToken is called, the current pointer is moved to the next slot and the
155 old slot is filled with the next token from the reader by calling getNextToken.
156 The token values are stored in the slot, which means that token values don't
157 survive a call to getToken, ie.
158
159 UString *value;
160
161 getToken(&value, NULL, status);
162 getToken(NULL, NULL, status); bad - value is now a different string
163*/
164static void
165initLookahead(UCHARBUF *buf, UErrorCode *status)
166{
167 static uint32_t initTypeStrings = 0;
168 uint32_t i;
169
170 if (!initTypeStrings)
171 {
172 initTypeStrings = 1;
173 }
174
175 lookaheadPosition = 0;
176 buffer = buf;
177
178 resetLineNumber();
179
180 for (i = 0; i < MAX_LOOKAHEAD; i++)
181 {
182 lookahead[i].type = getNextToken(buffer, &lookahead[i].value, &lookahead[i].line, &lookahead[i].comment, status);
183 if (U_FAILURE(*status))
184 {
185 return;
186 }
187 }
188
189 *status = U_ZERO_ERROR;
190}
191
192static enum ETokenType
193getToken(struct UString **tokenValue, struct UString* comment, uint32_t *linenumber, UErrorCode *status)
194{
195 enum ETokenType result;
196 uint32_t i;
197
198 result = lookahead[lookaheadPosition].type;
199
200 if (tokenValue != NULL)
201 {
202 *tokenValue = &lookahead[lookaheadPosition].value;
203 }
204
205 if (linenumber != NULL)
206 {
207 *linenumber = lookahead[lookaheadPosition].line;
208 }
209
210 if (comment != NULL)
211 {
212 ustr_cpy(comment, &(lookahead[lookaheadPosition].comment), status);
213 }
214
215 i = (lookaheadPosition + MAX_LOOKAHEAD) % (MAX_LOOKAHEAD + 1);
216 lookaheadPosition = (lookaheadPosition + 1) % (MAX_LOOKAHEAD + 1);
217 ustr_setlen(&lookahead[i].comment, 0, status);
218 ustr_setlen(&lookahead[i].value, 0, status);
219 lookahead[i].type = getNextToken(buffer, &lookahead[i].value, &lookahead[i].line, &lookahead[i].comment, status);
220
221 /* printf("getToken, returning %s\n", tokenNames[result]); */
222
223 return result;
224}
225
226static enum ETokenType
227peekToken(uint32_t lookaheadCount, struct UString **tokenValue, uint32_t *linenumber, struct UString *comment, UErrorCode *status)
228{
229 uint32_t i = (lookaheadPosition + lookaheadCount) % (MAX_LOOKAHEAD + 1);
230
231 if (U_FAILURE(*status))
232 {
233 return TOK_ERROR;
234 }
235
236 if (lookaheadCount >= MAX_LOOKAHEAD)
237 {
238 *status = U_INTERNAL_PROGRAM_ERROR;
239 return TOK_ERROR;
240 }
241
242 if (tokenValue != NULL)
243 {
244 *tokenValue = &lookahead[i].value;
245 }
246
247 if (linenumber != NULL)
248 {
249 *linenumber = lookahead[i].line;
250 }
251
252 if(comment != NULL){
253 ustr_cpy(comment, &(lookahead[lookaheadPosition].comment), status);
254 }
255
256 return lookahead[i].type;
257}
258
259static void
260expect(enum ETokenType expectedToken, struct UString **tokenValue, struct UString *comment, uint32_t *linenumber, UErrorCode *status)
261{
262 uint32_t line;
263
264 enum ETokenType token = getToken(tokenValue, comment, &line, status);
265
266 if (U_FAILURE(*status))
267 {
268 return;
269 }
270
271 if (linenumber != NULL)
272 {
273 *linenumber = line;
274 }
275
276 if (token != expectedToken)
277 {
278 *status = U_INVALID_FORMAT_ERROR;
279 error(line, "expecting %s, got %s", tokenNames[expectedToken], tokenNames[token]);
280 }
281 else /* "else" is added by Jing/GCL */
282 {
283 *status = U_ZERO_ERROR;
284 }
285}
286
287static char *getInvariantString(uint32_t *line, struct UString *comment, UErrorCode *status)
288{
289 struct UString *tokenValue;
290 char *result;
291 uint32_t count;
292
293 expect(TOK_STRING, &tokenValue, comment, line, status);
294
295 if (U_FAILURE(*status))
296 {
297 return NULL;
298 }
299
300 count = u_strlen(tokenValue->fChars);
301 if(!uprv_isInvariantUString(tokenValue->fChars, count)) {
302 *status = U_INVALID_FORMAT_ERROR;
303 error(*line, "invariant characters required for table keys, binary data, etc.");
304 return NULL;
305 }
306
307 result = uprv_malloc(count+1);
308
309 if (result == NULL)
310 {
311 *status = U_MEMORY_ALLOCATION_ERROR;
312 return NULL;
313 }
314
315 u_UCharsToChars(tokenValue->fChars, result, count+1);
316 return result;
317}
318
319static enum EResourceType
320parseResourceType(UErrorCode *status)
321{
322 struct UString *tokenValue;
323 struct UString comment;
324 enum EResourceType result = RT_UNKNOWN;
325 uint32_t line=0;
326 ustr_init(&comment);
327 expect(TOK_STRING, &tokenValue, &comment, &line, status);
328
329 if (U_FAILURE(*status))
330 {
331 return RT_UNKNOWN;
332 }
333
334 *status = U_ZERO_ERROR;
335
336 if (u_strcmp(tokenValue->fChars, k_type_string) == 0) {
337 result = RT_STRING;
338 } else if (u_strcmp(tokenValue->fChars, k_type_array) == 0) {
339 result = RT_ARRAY;
340 } else if (u_strcmp(tokenValue->fChars, k_type_alias) == 0) {
341 result = RT_ALIAS;
342 } else if (u_strcmp(tokenValue->fChars, k_type_table) == 0) {
343 result = RT_TABLE;
344 } else if (u_strcmp(tokenValue->fChars, k_type_binary) == 0) {
345 result = RT_BINARY;
346 } else if (u_strcmp(tokenValue->fChars, k_type_bin) == 0) {
347 result = RT_BINARY;
348 } else if (u_strcmp(tokenValue->fChars, k_type_int) == 0) {
349 result = RT_INTEGER;
350 } else if (u_strcmp(tokenValue->fChars, k_type_integer) == 0) {
351 result = RT_INTEGER;
352 } else if (u_strcmp(tokenValue->fChars, k_type_intvector) == 0) {
353 result = RT_INTVECTOR;
354 } else if (u_strcmp(tokenValue->fChars, k_type_import) == 0) {
355 result = RT_IMPORT;
356 } else if (u_strcmp(tokenValue->fChars, k_type_include) == 0) {
357 result = RT_INCLUDE;
358 } else if (u_strcmp(tokenValue->fChars, k_type_reserved) == 0) {
359 result = RT_RESERVED;
360 } else {
361 char tokenBuffer[1024];
362 u_austrncpy(tokenBuffer, tokenValue->fChars, sizeof(tokenBuffer));
363 tokenBuffer[sizeof(tokenBuffer) - 1] = 0;
364 *status = U_INVALID_FORMAT_ERROR;
365 error(line, "unknown resource type '%s'", tokenBuffer);
366 }
367
368 return result;
369}
370
371static struct SResource *
372parseUCARules(char *tag, uint32_t startline, UErrorCode *status)
373{
374 struct SResource *result = NULL;
375 struct UString *tokenValue;
376 struct UString comment;
377 FileStream *file = NULL;
378 char filename[256] = { '\0' };
379 char cs[128] = { '\0' };
380 uint32_t line;
381 int len=0;
382 UBool quoted = FALSE;
383 UCHARBUF *ucbuf=NULL;
384 UChar32 c = 0;
385 const char* cp = NULL;
386 UChar *pTarget = NULL;
387 UChar *target = NULL;
388 UChar *targetLimit = NULL;
389 int32_t size = 0;
390
391 ustr_init(&comment);
392 expect(TOK_STRING, &tokenValue, &comment, &line, status);
393
394 if(isVerbose()){
395 printf(" %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
396 }
397
398 if (U_FAILURE(*status))
399 {
400 return NULL;
401 }
402 /* make the filename including the directory */
403 if (inputdir != NULL)
404 {
405 uprv_strcat(filename, inputdir);
406
407 if (inputdir[inputdirLength - 1] != U_FILE_SEP_CHAR)
408 {
409 uprv_strcat(filename, U_FILE_SEP_STRING);
410 }
411 }
412
413 u_UCharsToChars(tokenValue->fChars, cs, tokenValue->fLength);
414
415 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
416
417 if (U_FAILURE(*status))
418 {
419 return NULL;
420 }
421 uprv_strcat(filename,"..");
422 uprv_strcat(filename,U_FILE_SEP_STRING);
423 uprv_strcat(filename, U_ICU_UNIDATA);
424 uprv_strcat(filename, U_FILE_SEP_STRING);
425 uprv_strcat(filename, cs);
426
427
428 ucbuf = ucbuf_open(filename, &cp, getShowWarning(),FALSE, status);
429
430 if (U_FAILURE(*status)) {
431 error(line, "An error occured while opening the input file %s\n", filename);
432 return NULL;
433 }
434
435 /* We allocate more space than actually required
436 * since the actual size needed for storing UChars
437 * is not known in UTF-8 byte stream
438 */
439 size = ucbuf_size(ucbuf);
440 pTarget = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * size);
441 uprv_memset(pTarget, 0, size*U_SIZEOF_UCHAR);
442 target = pTarget;
443 targetLimit = pTarget+size;
444
445 /* read the rules into the buffer */
446 while (target < targetLimit)
447 {
448 c = ucbuf_getc(ucbuf, status);
449 if(c == QUOTE) {
450 quoted = (UBool)!quoted;
451 }
452 /* weiv (06/26/2002): adding the following:
453 * - preserving spaces in commands [...]
454 * - # comments until the end of line
455 */
456 if (c == STARTCOMMAND && !quoted)
457 {
458 /* preserve commands
459 * closing bracket will be handled by the
460 * append at the end of the loop
461 */
462 while(c != ENDCOMMAND) {
463 U_APPEND_CHAR32(c, target,len);
464 c = ucbuf_getc(ucbuf, status);
465 }
466 } else if (c == HASH && !quoted) {
467 /* skip comments */
468 while(c != CR && c != LF) {
469 c = ucbuf_getc(ucbuf, status);
470 }
471 continue;
472 } else if (c == ESCAPE)
473 {
474 c = unescape(ucbuf, status);
475
476 if (c == U_ERR)
477 {
478 uprv_free(pTarget);
479 T_FileStream_close(file);
480 return NULL;
481 }
482 }
483 else if (!quoted && (c == SPACE || c == TAB || c == CR || c == LF))
484 {
485 /* ignore spaces carriage returns
486 * and line feed unless in the form \uXXXX
487 */
488 continue;
489 }
490
491 /* Append UChar * after dissembling if c > 0xffff*/
492 if (c != U_EOF)
493 {
494 U_APPEND_CHAR32(c, target,len);
495 }
496 else
497 {
498 break;
499 }
500 }
501
502 /* terminate the string */
503 if(target < targetLimit){
504 *target = 0x0000;
505 }
506
507 result = string_open(bundle, tag, pTarget, (int32_t)(target - pTarget), NULL, status);
508
509
510 ucbuf_close(ucbuf);
511 uprv_free(pTarget);
512 T_FileStream_close(file);
513
514 return result;
515}
516
517static struct SResource *
518parseString(char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
519{
520 struct UString *tokenValue;
521 struct SResource *result = NULL;
522
523 if (tag != NULL && uprv_strcmp(tag, "%%UCARULES") == 0)
524 {
525 return parseUCARules(tag, startline, status);
526 }
527 if(isVerbose()){
528 printf(" string %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
529 }
530 expect(TOK_STRING, &tokenValue, NULL, NULL, status);
531
532 if (U_SUCCESS(*status))
533 {
534 /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
535 doesn't survive expect either) */
536
537 result = string_open(bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
538 if(U_SUCCESS(*status) && result) {
539 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
540
541 if (U_FAILURE(*status))
542 {
543 string_close(result, status);
544 return NULL;
545 }
546 }
547 }
548
549 return result;
550}
551
552static struct SResource *
553parseAlias(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
554{
555 struct UString *tokenValue;
556 struct SResource *result = NULL;
557
558 expect(TOK_STRING, &tokenValue, NULL, NULL, status);
559
560 if(isVerbose()){
561 printf(" alias %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
562 }
563
564 if (U_SUCCESS(*status))
565 {
566 /* create the string now - tokenValue doesn't survive a call to getToken (and therefore
567 doesn't survive expect either) */
568
569 result = alias_open(bundle, tag, tokenValue->fChars, tokenValue->fLength, comment, status);
570
571 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
572
573 if (U_FAILURE(*status))
574 {
575 alias_close(result, status);
576 return NULL;
577 }
578 }
579
580 return result;
581}
582
583static struct SResource *
584addCollation(struct SResource *result, uint32_t startline, UErrorCode *status)
585{
586 struct SResource *member = NULL;
587 struct UString *tokenValue;
588 struct UString comment;
589 enum ETokenType token;
590 char subtag[1024];
591 UVersionInfo version;
592 UBool override = FALSE;
593 uint32_t line;
594 /* '{' . (name resource)* '}' */
595 version[0]=0; version[1]=0; version[2]=0; version[3]=0;
596
597 for (;;)
598 {
599 ustr_init(&comment);
600 token = getToken(&tokenValue, &comment, &line, status);
601
602 if (token == TOK_CLOSE_BRACE)
603 {
604 return result;
605 }
606
607 if (token != TOK_STRING)
608 {
609 table_close(result, status);
610 *status = U_INVALID_FORMAT_ERROR;
611
612 if (token == TOK_EOF)
613 {
614 error(startline, "unterminated table");
615 }
616 else
617 {
618 error(line, "Unexpected token %s", tokenNames[token]);
619 }
620
621 return NULL;
622 }
623
624 u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
625
626 if (U_FAILURE(*status))
627 {
628 table_close(result, status);
629 return NULL;
630 }
631
632 member = parseResource(subtag, NULL, status);
633
634 if (U_FAILURE(*status))
635 {
636 table_close(result, status);
637 return NULL;
638 }
639
640 if (uprv_strcmp(subtag, "Version") == 0)
641 {
642 char ver[40];
643 int32_t length = member->u.fString.fLength;
644
645 if (length >= (int32_t) sizeof(ver))
646 {
647 length = (int32_t) sizeof(ver) - 1;
648 }
649
650 u_UCharsToChars(member->u.fString.fChars, ver, length + 1); /* +1 for copying NULL */
651 u_versionFromString(version, ver);
652
653 table_add(result, member, line, status);
654
655 }
656 else if (uprv_strcmp(subtag, "Override") == 0)
657 {
658 override = FALSE;
659
660 if (u_strncmp(member->u.fString.fChars, trueValue, u_strlen(trueValue)) == 0)
661 {
662 override = TRUE;
663 }
664 table_add(result, member, line, status);
665
666 }
667 else if(uprv_strcmp(subtag, "%%CollationBin")==0)
668 {
669 /* discard duplicate %%CollationBin if any*/
670 }
671 else if (uprv_strcmp(subtag, "Sequence") == 0)
672 {
673#if UCONFIG_NO_COLLATION
674 warning(line, "Not building collation elements because of UCONFIG_NO_COLLATION, see uconfig.h");
675#else
676 /* first we add the "Sequence", so that we always have rules */
677 table_add(result, member, line, status);
678 if(gMakeBinaryCollation) {
679 UErrorCode intStatus = U_ZERO_ERROR;
680
681 /* do the collation elements */
682 int32_t len = 0;
683 uint8_t *data = NULL;
684 UCollator *coll = NULL;
685 UParseError parseError;
686 /* add sequence */
687 /*table_add(result, member, line, status);*/
688
689 coll = ucol_openRules(member->u.fString.fChars, member->u.fString.fLength,
690 UCOL_OFF, UCOL_DEFAULT_STRENGTH,&parseError, &intStatus);
691
692 if (U_SUCCESS(intStatus) && coll != NULL)
693 {
694 len = ucol_cloneBinary(coll, NULL, 0, &intStatus);
695 data = (uint8_t *)uprv_malloc(len);
696 len = ucol_cloneBinary(coll, data, len, &intStatus);
697 /*data = ucol_cloneRuleData(coll, &len, &intStatus);*/
698
699 /* tailoring rules version */
700 /* This is wrong! */
701 /*coll->dataInfo.dataVersion[1] = version[0];*/
702 /* Copy tailoring version. Builder version already */
703 /* set in ucol_openRules */
704 ((UCATableHeader *)data)->version[1] = version[0];
705 ((UCATableHeader *)data)->version[2] = version[1];
706 ((UCATableHeader *)data)->version[3] = version[2];
707
708 if (U_SUCCESS(intStatus) && data != NULL)
709 {
710 member = bin_open(bundle, "%%CollationBin", len, data, NULL, NULL, status);
711 /*table_add(bundle->fRoot, member, line, status);*/
712 table_add(result, member, line, status);
713 uprv_free(data);
714 }
715 else
716 {
717 warning(line, "could not obtain rules from collator");
718 if(isStrict()){
719 *status = U_INVALID_FORMAT_ERROR;
720 return NULL;
721 }
722 }
723
724 ucol_close(coll);
725 }
726 else
727 {
728 warning(line, "%%Collation could not be constructed from CollationElements - check context!");
729 if(isStrict()){
730 *status = intStatus;
731 return NULL;
732 }
733 }
734 } else {
735 if(isVerbose()) {
736 printf("Not building Collation binary\n");
737 }
738 }
739#endif
740 }
741
742 /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
743
744 /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
745
746 if (U_FAILURE(*status))
747 {
748 table_close(result, status);
749 return NULL;
750 }
751 }
752
753 /* not reached */
754 /* A compiler warning will appear if all paths don't contain a return statement. */
755/* *status = U_INTERNAL_PROGRAM_ERROR;
756 return NULL;*/
757}
758
759static struct SResource *
760parseCollationElements(char *tag, uint32_t startline, UBool newCollation, UErrorCode *status)
761{
762 struct SResource *result = NULL;
763 struct SResource *member = NULL;
764 struct SResource *collationRes = NULL;
765 struct UString *tokenValue;
766 struct UString comment;
767 enum ETokenType token;
768 char subtag[1024], typeKeyword[1024];
769 uint32_t line;
770
771 result = table_open(bundle, tag, NULL, status);
772
773 if (result == NULL || U_FAILURE(*status))
774 {
775 return NULL;
776 }
777 if(isVerbose()){
778 printf(" collation elements %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
779 }
780 if(!newCollation) {
781 return addCollation(result, startline, status);
782 } else {
783 for(;;) {
784 ustr_init(&comment);
785 token = getToken(&tokenValue, &comment, &line, status);
786
787 if (token == TOK_CLOSE_BRACE)
788 {
789 return result;
790 }
791
792 if (token != TOK_STRING)
793 {
794 table_close(result, status);
795 *status = U_INVALID_FORMAT_ERROR;
796
797 if (token == TOK_EOF)
798 {
799 error(startline, "unterminated table");
800 }
801 else
802 {
803 error(line, "Unexpected token %s", tokenNames[token]);
804 }
805
806 return NULL;
807 }
808
809 u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
810
811 if (U_FAILURE(*status))
812 {
813 table_close(result, status);
814 return NULL;
815 }
816
817 if (uprv_strcmp(subtag, "default") == 0)
818 {
819 member = parseResource(subtag, NULL, status);
820
821 if (U_FAILURE(*status))
822 {
823 table_close(result, status);
824 return NULL;
825 }
826
827 table_add(result, member, line, status);
828 }
829 else
830 {
831 token = peekToken(0, &tokenValue, &line, &comment, status);
832 /* this probably needs to be refactored or recursively use the parser */
833 /* first we assume that our collation table won't have the explicit type */
834 /* then, we cannot handle aliases */
835 if(token == TOK_OPEN_BRACE) {
836 token = getToken(&tokenValue, &comment, &line, status);
837 collationRes = table_open(bundle, subtag, NULL, status);
838 table_add(result, addCollation(collationRes, startline, status), startline, status);
839 } else if(token == TOK_COLON) { /* right now, we'll just try to see if we have aliases */
840 /* we could have a table too */
841 token = peekToken(1, &tokenValue, &line, &comment, status);
842 u_UCharsToChars(tokenValue->fChars, typeKeyword, u_strlen(tokenValue->fChars) + 1);
843 if(uprv_strcmp(typeKeyword, "alias") == 0) {
844 member = parseResource(subtag, NULL, status);
845
846 if (U_FAILURE(*status))
847 {
848 table_close(result, status);
849 return NULL;
850 }
851
852 table_add(result, member, line, status);
853 } else {
854 *status = U_INVALID_FORMAT_ERROR;
855 return NULL;
856 }
857 } else {
858 *status = U_INVALID_FORMAT_ERROR;
859 return NULL;
860 }
861 }
862
863 /*member = string_open(bundle, subtag, tokenValue->fChars, tokenValue->fLength, status);*/
864
865 /*expect(TOK_CLOSE_BRACE, NULL, NULL, status);*/
866
867 if (U_FAILURE(*status))
868 {
869 table_close(result, status);
870 return NULL;
871 }
872
873 }
874 }
875}
876
877/* Necessary, because CollationElements requires the bundle->fRoot member to be present which,
878 if this weren't special-cased, wouldn't be set until the entire file had been processed. */
879static struct SResource *
880realParseTable(struct SResource *table, char *tag, uint32_t startline, UErrorCode *status)
881{
882 struct SResource *member = NULL;
883 struct UString *tokenValue=NULL;
884 struct UString comment;
885 enum ETokenType token;
886 char subtag[1024];
887 uint32_t line;
888 UBool readToken = FALSE;
889
890 /* '{' . (name resource)* '}' */
891 if(isVerbose()){
892 printf(" parsing table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
893 }
894 for (;;)
895 {
896 ustr_init(&comment);
897 token = getToken(&tokenValue, &comment, &line, status);
898
899 if (token == TOK_CLOSE_BRACE)
900 {
901 if (!readToken) {
902 warning(startline, "Encountered empty table");
903 }
904 return table;
905 }
906
907 if (token != TOK_STRING)
908 {
909 table_close(table, status);
910 *status = U_INVALID_FORMAT_ERROR;
911
912 if (token == TOK_EOF)
913 {
914 error(startline, "unterminated table");
915 }
916 else
917 {
918 error(line, "unexpected token %s", tokenNames[token]);
919 }
920
921 return NULL;
922 }
923
924 if(uprv_isInvariantUString(tokenValue->fChars, -1)) {
925 u_UCharsToChars(tokenValue->fChars, subtag, u_strlen(tokenValue->fChars) + 1);
926 } else {
927 *status = U_INVALID_FORMAT_ERROR;
928 error(line, "invariant characters required for table keys");
929 table_close(table, status);
930 return NULL;
931 }
932
933 if (U_FAILURE(*status))
934 {
935 error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
936 table_close(table, status);
937 return NULL;
938 }
939
940 member = parseResource(subtag, &comment, status);
941
942 if (member == NULL || U_FAILURE(*status))
943 {
944 error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
945 table_close(table, status);
946 return NULL;
947 }
948
949 table_add(table, member, line, status);
950
951 if (U_FAILURE(*status))
952 {
953 error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
954 table_close(table, status);
955 return NULL;
956 }
957 readToken = TRUE;
958 }
959
960 /* not reached */
961 /* A compiler warning will appear if all paths don't contain a return statement. */
962/* *status = U_INTERNAL_PROGRAM_ERROR;
963 return NULL;*/
964}
965
966static struct SResource *
967parseTable(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
968{
969 struct SResource *result;
970
971 if (tag != NULL && uprv_strcmp(tag, "CollationElements") == 0)
972 {
973 return parseCollationElements(tag, startline, FALSE, status);
974 }
975 if (tag != NULL && uprv_strcmp(tag, "collations") == 0)
976 {
977 return parseCollationElements(tag, startline, TRUE, status);
978 }
979 if(isVerbose()){
980 printf(" table %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
981 }
982
983 result = table_open(bundle, tag, comment, status);
984
985 if (result == NULL || U_FAILURE(*status))
986 {
987 return NULL;
988 }
989
990 return realParseTable(result, tag, startline, status);
991}
992
993static struct SResource *
994parseArray(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
995{
996 struct SResource *result = NULL;
997 struct SResource *member = NULL;
998 struct UString *tokenValue;
999 struct UString memberComments;
1000 enum ETokenType token;
1001 UBool readToken = FALSE;
1002
1003 result = array_open(bundle, tag, comment, status);
1004
1005 if (result == NULL || U_FAILURE(*status))
1006 {
1007 return NULL;
1008 }
1009 if(isVerbose()){
1010 printf(" array %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1011 }
1012
1013 ustr_init(&memberComments);
1014
1015 /* '{' . resource [','] '}' */
1016 for (;;)
1017 {
1018 /* reset length */
1019 ustr_setlen(&memberComments, 0, status);
1020
1021 /* check for end of array, but don't consume next token unless it really is the end */
1022 token = peekToken(0, &tokenValue, NULL, &memberComments, status);
1023
1024
1025 if (token == TOK_CLOSE_BRACE)
1026 {
1027 getToken(NULL, NULL, NULL, status);
1028 if (!readToken) {
1029 warning(startline, "Encountered empty array");
1030 }
1031 break;
1032 }
1033
1034 if (token == TOK_EOF)
1035 {
1036 array_close(result, status);
1037 *status = U_INVALID_FORMAT_ERROR;
1038 error(startline, "unterminated array");
1039 return NULL;
1040 }
1041
1042 /* string arrays are a special case */
1043 if (token == TOK_STRING)
1044 {
1045 getToken(&tokenValue, &memberComments, NULL, status);
1046 member = string_open(bundle, NULL, tokenValue->fChars, tokenValue->fLength, &memberComments, status);
1047 }
1048 else
1049 {
1050 member = parseResource(NULL, &memberComments, status);
1051 }
1052
1053 if (member == NULL || U_FAILURE(*status))
1054 {
1055 array_close(result, status);
1056 return NULL;
1057 }
1058
1059 array_add(result, member, status);
1060
1061 if (U_FAILURE(*status))
1062 {
1063 array_close(result, status);
1064 return NULL;
1065 }
1066
1067 /* eat optional comma if present */
1068 token = peekToken(0, NULL, NULL, NULL, status);
1069
1070 if (token == TOK_COMMA)
1071 {
1072 getToken(NULL, NULL, NULL, status);
1073 }
1074
1075 if (U_FAILURE(*status))
1076 {
1077 array_close(result, status);
1078 return NULL;
1079 }
1080 readToken = TRUE;
1081 }
1082
1083 return result;
1084}
1085
1086static struct SResource *
1087parseIntVector(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1088{
1089 struct SResource *result = NULL;
1090 enum ETokenType token;
1091 char *string;
1092 int32_t value;
1093 UBool readToken = FALSE;
1094 /* added by Jing/GCL */
1095 char *stopstring;
1096 uint32_t len;
1097 struct UString memberComments;
1098
1099 result = intvector_open(bundle, tag, comment, status);
1100
1101 if (result == NULL || U_FAILURE(*status))
1102 {
1103 return NULL;
1104 }
1105
1106 if(isVerbose()){
1107 printf(" vector %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1108 }
1109 ustr_init(&memberComments);
1110 /* '{' . string [','] '}' */
1111 for (;;)
1112 {
1113 ustr_setlen(&memberComments, 0, status);
1114
1115 /* check for end of array, but don't consume next token unless it really is the end */
1116 token = peekToken(0, NULL, NULL,&memberComments, status);
1117
1118 if (token == TOK_CLOSE_BRACE)
1119 {
1120 /* it's the end, consume the close brace */
1121 getToken(NULL, NULL, NULL, status);
1122 if (!readToken) {
1123 warning(startline, "Encountered empty int vector");
1124 }
1125 return result;
1126 }
1127
1128 string = getInvariantString(NULL, NULL, status);
1129
1130 if (U_FAILURE(*status))
1131 {
1132 intvector_close(result, status);
1133 return NULL;
1134 }
1135 /* Commented by Jing/GCL */
1136 /*value = uprv_strtol(string, NULL, 10);
1137 intvector_add(result, value, status);
1138
1139 uprv_free(string);
1140
1141 token = peekToken(0, NULL, NULL, status);*/
1142
1143 /* The following is added by Jing/GCL to handle illegal char in the Intvector */
1144 value = uprv_strtoul(string, &stopstring, 0);/* make intvector support decimal,hexdigit,octal digit ranging from -2^31-2^32-1*/
1145 len=(uint32_t)(stopstring-string);
1146
1147 if(len==uprv_strlen(string))
1148 {
1149 intvector_add(result, value, status);
1150 uprv_free(string);
1151 token = peekToken(0, NULL, NULL, NULL, status);
1152 }
1153 else
1154 {
1155 uprv_free(string);
1156 *status=U_INVALID_CHAR_FOUND;
1157 }
1158 /* The above is added by Jing/GCL */
1159
1160 if (U_FAILURE(*status))
1161 {
1162 intvector_close(result, status);
1163 return NULL;
1164 }
1165
1166 /* the comma is optional (even though it is required to prevent the reader from concatenating
1167 consecutive entries) so that a missing comma on the last entry isn't an error */
1168 if (token == TOK_COMMA)
1169 {
1170 getToken(NULL, NULL, NULL, status);
1171 }
1172 readToken = TRUE;
1173 }
1174
1175 /* not reached */
1176 /* A compiler warning will appear if all paths don't contain a return statement. */
1177/* intvector_close(result, status);
1178 *status = U_INTERNAL_PROGRAM_ERROR;
1179 return NULL;*/
1180}
1181
1182static struct SResource *
1183parseBinary(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1184{
1185 struct SResource *result = NULL;
1186 uint8_t *value;
1187 char *string;
1188 char toConv[3] = {'\0', '\0', '\0'};
1189 uint32_t count;
1190 uint32_t i;
1191 uint32_t line;
1192 /* added by Jing/GCL */
1193 char *stopstring;
1194 uint32_t len;
1195
1196 string = getInvariantString(&line, NULL, status);
1197
1198 if (string == NULL || U_FAILURE(*status))
1199 {
1200 return NULL;
1201 }
1202
1203 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1204
1205 if (U_FAILURE(*status))
1206 {
1207 uprv_free(string);
1208 return NULL;
1209 }
1210
1211 if(isVerbose()){
1212 printf(" binary %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1213 }
1214
1215 count = (uint32_t)uprv_strlen(string);
1216 if (count > 0){
1217 if((count % 2)==0){
1218 value = uprv_malloc(sizeof(uint8_t) * count);
1219
1220 if (value == NULL)
1221 {
1222 uprv_free(string);
1223 *status = U_MEMORY_ALLOCATION_ERROR;
1224 return NULL;
1225 }
1226
1227 for (i = 0; i < count; i += 2)
1228 {
1229 toConv[0] = string[i];
1230 toConv[1] = string[i + 1];
1231
1232 value[i >> 1] = (uint8_t) uprv_strtoul(toConv, &stopstring, 16);
1233 len=(uint32_t)(stopstring-toConv);
1234
1235 if(len!=uprv_strlen(toConv))
1236 {
1237 uprv_free(string);
1238 *status=U_INVALID_CHAR_FOUND;
1239 return NULL;
1240 }
1241 }
1242
1243 result = bin_open(bundle, tag, (i >> 1), value,NULL, comment, status);
1244
1245 uprv_free(value);
1246 }
1247 else
1248 {
1249 *status = U_INVALID_CHAR_FOUND;
1250 uprv_free(string);
1251 error(line, "Encountered invalid binary string");
1252 return NULL;
1253 }
1254 }
1255 else
1256 {
1257 result = bin_open(bundle, tag, 0, NULL, "",comment,status);
1258 warning(startline, "Encountered empty binary tag");
1259 }
1260 uprv_free(string);
1261
1262 return result;
1263}
1264
1265static struct SResource *
1266parseInteger(char *tag, uint32_t startline, const struct UString *comment, UErrorCode *status)
1267{
1268 struct SResource *result = NULL;
1269 int32_t value;
1270 char *string;
1271 /* added by Jing/GCL */
1272 char *stopstring;
1273 uint32_t len;
1274
1275 string = getInvariantString(NULL, NULL, status);
1276
1277 if (string == NULL || U_FAILURE(*status))
1278 {
1279 return NULL;
1280 }
1281
1282 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1283
1284 if (U_FAILURE(*status))
1285 {
1286 uprv_free(string);
1287 return NULL;
1288 }
1289
1290 if(isVerbose()){
1291 printf(" integer %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1292 }
1293
1294 if (uprv_strlen(string) <= 0)
1295 {
1296 warning(startline, "Encountered empty integer. Default value is 0.");
1297 }
1298
1299 /* commented by Jing/GCL */
1300 /* value = uprv_strtol(string, NULL, 10);*/
1301 /* result = int_open(bundle, tag, value, status);*/
1302 /* The following is added by Jing/GCL*/
1303 /* to make integer support hexdecimal, octal digit and decimal*/
1304 /* to handle illegal char in the integer*/
1305 value = uprv_strtoul(string, &stopstring, 0);
1306 len=(uint32_t)(stopstring-string);
1307 if(len==uprv_strlen(string))
1308 {
1309 result = int_open(bundle, tag, value, comment, status);
1310 }
1311 else
1312 {
1313 *status=U_INVALID_CHAR_FOUND;
1314 }
1315 uprv_free(string);
1316
1317 return result;
1318}
1319
1320static struct SResource *
1321parseImport(char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
1322{
1323 struct SResource *result;
1324 FileStream *file;
1325 int32_t len;
1326 uint8_t *data;
1327 char *filename;
1328 uint32_t line;
1329 char *fullname = NULL;
1330 int32_t numRead = 0;
1331 filename = getInvariantString(&line, NULL, status);
1332
1333 if (U_FAILURE(*status))
1334 {
1335 return NULL;
1336 }
1337
1338 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1339
1340 if (U_FAILURE(*status))
1341 {
1342 uprv_free(filename);
1343 return NULL;
1344 }
1345
1346 if(isVerbose()){
1347 printf(" import %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1348 }
1349
1350 /* Open the input file for reading */
1351 if (inputdir == NULL)
1352 {
1353 file = T_FileStream_open(filename, "rb");
1354 }
1355 else
1356 {
1357
1358 int32_t count = (int32_t)uprv_strlen(filename);
1359
1360 if (inputdir[inputdirLength - 1] != U_FILE_SEP_CHAR)
1361 {
1362 fullname = (char *) uprv_malloc(inputdirLength + count + 2);
1363
1364 /* test for NULL */
1365 if(fullname == NULL)
1366 {
1367 *status = U_MEMORY_ALLOCATION_ERROR;
1368 return NULL;
1369 }
1370
1371 uprv_strcpy(fullname, inputdir);
1372
1373 fullname[inputdirLength] = U_FILE_SEP_CHAR;
1374 fullname[inputdirLength + 1] = '\0';
1375
1376 uprv_strcat(fullname, filename);
1377 }
1378 else
1379 {
1380 fullname = (char *) uprv_malloc(inputdirLength + count + 1);
1381
1382 /* test for NULL */
1383 if(fullname == NULL)
1384 {
1385 *status = U_MEMORY_ALLOCATION_ERROR;
1386 return NULL;
1387 }
1388
1389 uprv_strcpy(fullname, inputdir);
1390 uprv_strcat(fullname, filename);
1391 }
1392
1393 file = T_FileStream_open(fullname, "rb");
1394
1395 }
1396
1397 if (file == NULL)
1398 {
1399 error(line, "couldn't open input file %s", filename);
1400 *status = U_FILE_ACCESS_ERROR;
1401 return NULL;
1402 }
1403
1404 len = T_FileStream_size(file);
1405 data = (uint8_t*)uprv_malloc(len * sizeof(uint8_t));
1406 /* test for NULL */
1407 if(data == NULL)
1408 {
1409 *status = U_MEMORY_ALLOCATION_ERROR;
1410 T_FileStream_close (file);
1411 return NULL;
1412 }
1413
1414 numRead = T_FileStream_read (file, data, len);
1415 T_FileStream_close (file);
1416
1417 result = bin_open(bundle, tag, len, data, fullname, comment, status);
1418
1419 uprv_free(data);
1420 uprv_free(filename);
1421 uprv_free(fullname);
1422
1423 return result;
1424}
1425
1426static struct SResource *
1427parseInclude(char *tag, uint32_t startline, const struct UString* comment, UErrorCode *status)
1428{
1429 struct SResource *result;
1430 int32_t len=0;
1431 char *filename;
1432 uint32_t line;
1433 UChar *pTarget = NULL;
1434
1435 UCHARBUF *ucbuf;
1436 char *fullname = NULL;
1437 int32_t count = 0;
1438 const char* cp = NULL;
1439 const UChar* uBuffer = NULL;
1440
1441 filename = getInvariantString(&line, NULL, status);
1442 count = (int32_t)uprv_strlen(filename);
1443
1444 if (U_FAILURE(*status))
1445 {
1446 return NULL;
1447 }
1448
1449 expect(TOK_CLOSE_BRACE, NULL, NULL, NULL, status);
1450
1451 if (U_FAILURE(*status))
1452 {
1453 uprv_free(filename);
1454 return NULL;
1455 }
1456
1457 if(isVerbose()){
1458 printf(" include %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1459 }
1460
1461 fullname = (char *) uprv_malloc(inputdirLength + count + 2);
1462 /* test for NULL */
1463 if(fullname == NULL)
1464 {
1465 *status = U_MEMORY_ALLOCATION_ERROR;
1466 uprv_free(filename);
1467 return NULL;
1468 }
1469
1470 if(inputdir!=NULL){
1471 if (inputdir[inputdirLength - 1] != U_FILE_SEP_CHAR)
1472 {
1473
1474 uprv_strcpy(fullname, inputdir);
1475
1476 fullname[inputdirLength] = U_FILE_SEP_CHAR;
1477 fullname[inputdirLength + 1] = '\0';
1478
1479 uprv_strcat(fullname, filename);
1480 }
1481 else
1482 {
1483 uprv_strcpy(fullname, inputdir);
1484 uprv_strcat(fullname, filename);
1485 }
1486 }else{
1487 uprv_strcpy(fullname,filename);
1488 }
1489
1490 ucbuf = ucbuf_open(fullname, &cp,getShowWarning(),FALSE,status);
1491
1492 if (U_FAILURE(*status)) {
1493 error(line, "couldn't open input file %s\n", filename);
1494 return NULL;
1495 }
1496
1497 uBuffer = ucbuf_getBuffer(ucbuf,&len,status);
1498 result = string_open(bundle, tag, uBuffer, len, comment, status);
1499
1500 uprv_free(pTarget);
1501
1502 uprv_free(filename);
1503 uprv_free(fullname);
1504
1505 return result;
1506}
1507
1508static struct SResource *
1509parseResource(char *tag, const struct UString *comment, UErrorCode *status)
1510{
1511 enum ETokenType token;
1512 enum EResourceType resType = RT_UNKNOWN;
1513 struct UString *tokenValue;
1514 uint32_t startline;
1515 uint32_t line;
1516
1517 token = getToken(&tokenValue, NULL, &startline, status);
1518
1519 if(isVerbose()){
1520 printf(" resource %s at line %i \n", (tag == NULL) ? "(null)" : tag, (int)startline);
1521 }
1522
1523 /* name . [ ':' type ] '{' resource '}' */
1524 /* This function parses from the colon onwards. If the colon is present, parse the
1525 type then try to parse a resource of that type. If there is no explicit type,
1526 work it out using the lookahead tokens. */
1527 switch (token)
1528 {
1529 case TOK_EOF:
1530 *status = U_INVALID_FORMAT_ERROR;
1531 error(startline, "Unexpected EOF encountered");
1532 return NULL;
1533
1534 case TOK_ERROR:
1535 *status = U_INVALID_FORMAT_ERROR;
1536 return NULL;
1537
1538 case TOK_COLON:
1539 resType = parseResourceType(status);
1540 expect(TOK_OPEN_BRACE, &tokenValue, NULL, &startline, status);
1541
1542 if (U_FAILURE(*status))
1543 {
1544 return NULL;
1545 }
1546
1547 break;
1548
1549 case TOK_OPEN_BRACE:
1550 break;
1551
1552 default:
1553 *status = U_INVALID_FORMAT_ERROR;
1554 error(startline, "syntax error while reading a resource, expected '{' or ':'");
1555 return NULL;
1556 }
1557
1558 if (resType == RT_UNKNOWN)
1559 {
1560 /* No explicit type, so try to work it out. At this point, we've read the first '{'.
1561 We could have any of the following:
1562 { { => array (nested)
1563 { :/} => array
1564 { string , => string array
1565
1566 commented by Jing/GCL
1567 { string { => table
1568
1569 added by Jing/GCL
1570
1571 { string :/{ => table
1572 { string } => string
1573 */
1574
1575 token = peekToken(0, NULL, &line, NULL,status);
1576
1577 if (U_FAILURE(*status))
1578 {
1579 return NULL;
1580 }
1581
1582 /* Commented by Jing/GCL */
1583 /* if (token == TOK_OPEN_BRACE || token == TOK_COLON )*/
1584 if (token == TOK_OPEN_BRACE || token == TOK_COLON ||token ==TOK_CLOSE_BRACE )
1585 {
1586 resType = RT_ARRAY;
1587 }
1588 else if (token == TOK_STRING)
1589 {
1590 token = peekToken(1, NULL, &line, NULL, status);
1591
1592 if (U_FAILURE(*status))
1593 {
1594 return NULL;
1595 }
1596
1597 switch (token)
1598 {
1599 case TOK_COMMA: resType = RT_ARRAY; break;
1600 case TOK_OPEN_BRACE: resType = RT_TABLE; break;
1601 case TOK_CLOSE_BRACE: resType = RT_STRING; break;
1602 /* added by Jing/GCL to make table work when :table is omitted */
1603 case TOK_COLON: resType = RT_TABLE; break;
1604 default:
1605 *status = U_INVALID_FORMAT_ERROR;
1606 error(line, "Unexpected token after string, expected ',', '{' or '}'");
1607 return NULL;
1608 }
1609 }
1610 else
1611 {
1612 *status = U_INVALID_FORMAT_ERROR;
1613 error(line, "Unexpected token after '{'");
1614 return NULL;
1615 }
1616
1617 /* printf("Type guessed as %s\n", resourceNames[resType]); */
1618 }
1619
1620 /* We should now know what we need to parse next, so call the appropriate parser
1621 function and return. */
1622 switch (resType)
1623 {
1624 case RT_STRING: return parseString (tag, startline, comment, status);
1625 case RT_TABLE: return parseTable (tag, startline, comment, status);
1626 case RT_ARRAY: return parseArray (tag, startline, comment, status);
1627 case RT_ALIAS: return parseAlias (tag, startline, comment, status);
1628 case RT_BINARY: return parseBinary (tag, startline, comment, status);
1629 case RT_INTEGER: return parseInteger (tag, startline, comment, status);
1630 case RT_IMPORT: return parseImport (tag, startline, comment, status);
1631 case RT_INCLUDE: return parseInclude (tag, startline, comment, status);
1632 case RT_INTVECTOR: return parseIntVector (tag, startline, comment, status);
1633
1634 default:
1635 *status = U_INTERNAL_PROGRAM_ERROR;
1636 error(startline, "internal error: unknown resource type found and not handled");
1637 }
1638
1639 return NULL;
1640}
1641
1642struct SRBRoot *
1643parse(UCHARBUF *buf, const char *currentInputDir, UErrorCode *status)
1644{
1645 struct UString *tokenValue;
1646 struct UString comment;
1647 uint32_t line;
1648 /* added by Jing/GCL */
1649 enum EResourceType bundleType;
1650 enum ETokenType token;
1651
1652 initLookahead(buf, status);
1653
1654 inputdir = currentInputDir;
1655 inputdirLength = (inputdir != NULL) ? (uint32_t)uprv_strlen(inputdir) : 0;
1656
1657 ustr_init(&comment);
1658 expect(TOK_STRING, &tokenValue, &comment, NULL, status);
1659
1660 bundle = bundle_open(&comment, status);
1661
1662 if (bundle == NULL || U_FAILURE(*status))
1663 {
1664 return NULL;
1665 }
1666
1667
1668 bundle_setlocale(bundle, tokenValue->fChars, status);
1669 /* Commented by Jing/GCL */
1670 /* expect(TOK_OPEN_BRACE, NULL, &line, status); */
1671 /* The following code is to make Empty bundle work no matter with :table specifer or not */
1672 token = getToken(NULL, NULL, &line, status);
1673
1674 if(token==TOK_COLON)
1675 {
1676 *status=U_ZERO_ERROR;
1677 }
1678 else
1679 {
1680 *status=U_PARSE_ERROR;
1681 }
1682
1683 if(U_SUCCESS(*status)){
1684
1685 bundleType=parseResourceType(status);
1686
1687 if(bundleType==RT_TABLE)
1688 {
1689 expect(TOK_OPEN_BRACE, NULL, NULL, &line, status);
1690 }
1691 else
1692 {
1693 *status=U_PARSE_ERROR;
1694 error(line, "parse error. Stopped parsing with %s", u_errorName(*status));
1695 }
1696 }
1697 else
1698 {
1699 if(token==TOK_OPEN_BRACE)
1700 {
1701 *status=U_ZERO_ERROR;
1702 }
1703 else
1704 {
1705 error(line, "parse error, did not find open-brace '{' or colon ':', stopped with %s", u_errorName(*status));
1706 }
1707 }
1708 /* The above is added by Jing/GCL */
1709
1710 if (U_FAILURE(*status))
1711 {
1712 bundle_close(bundle, status);
1713 return NULL;
1714 }
1715
1716 realParseTable(bundle->fRoot, NULL, line, status);
1717
1718 if (U_FAILURE(*status))
1719 {
1720 bundle_close(bundle, status);
1721 return NULL;
1722 }
1723
1724 if (getToken(NULL, NULL, &line, status) != TOK_EOF)
1725 {
1726 warning(line, "extraneous text after resource bundle (perhaps unmatched braces)");
1727 if(isStrict()){
1728 *status = U_INVALID_FORMAT_ERROR;
1729 return NULL;
1730 }
1731 }
1732
1733 return bundle;
1734}