Home | History | Annotate | Download | only in genrb
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 1998-2016, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *
     11 * File genrb.cpp
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   05/25/99    stephen     Creation.
     17 *   5/10/01     Ram         removed ustdio dependency
     18 *******************************************************************************
     19 */
     20 
     21 #include <assert.h>
     22 #include "genrb.h"
     23 #include "unicode/localpointer.h"
     24 #include "unicode/uclean.h"
     25 #include "unicode/utf16.h"
     26 #include "charstr.h"
     27 #include "cmemory.h"
     28 #include "reslist.h"
     29 #include "ucmndata.h"  /* TODO: for reading the pool bundle */
     30 
     31 U_NAMESPACE_USE
     32 
     33 /* Protos */
     34 void  processFile(const char *filename, const char* cp, const char *inputDir, const char *outputDir,
     35                   const char *packageName,
     36                   SRBRoot *newPoolBundle, UBool omitBinaryCollation, UErrorCode &status);
     37 static char *make_res_filename(const char *filename, const char *outputDir,
     38                                const char *packageName, UErrorCode &status);
     39 
     40 /* File suffixes */
     41 #define RES_SUFFIX ".res"
     42 #define COL_SUFFIX ".col"
     43 
     44 const char *gCurrentFileName = NULL;
     45 #ifdef XP_MAC_CONSOLE
     46 #include <console.h>
     47 #endif
     48 
     49 void ResFile::close() {
     50     delete[] fBytes;
     51     fBytes = NULL;
     52     delete fStrings;
     53     fStrings = NULL;
     54 }
     55 
     56 enum
     57 {
     58     HELP1,
     59     HELP2,
     60     VERBOSE,
     61     QUIET,
     62     VERSION,
     63     SOURCEDIR,
     64     DESTDIR,
     65     ENCODING,
     66     ICUDATADIR,
     67     WRITE_JAVA,
     68     COPYRIGHT,
     69     JAVA_PACKAGE,
     70     BUNDLE_NAME,
     71     WRITE_XLIFF,
     72     STRICT,
     73     NO_BINARY_COLLATION,
     74     LANGUAGE,
     75     NO_COLLATION_RULES,
     76     FORMAT_VERSION,
     77     WRITE_POOL_BUNDLE,
     78     USE_POOL_BUNDLE,
     79     INCLUDE_UNIHAN_COLL
     80 };
     81 
     82 UOption options[]={
     83                       UOPTION_HELP_H,
     84                       UOPTION_HELP_QUESTION_MARK,
     85                       UOPTION_VERBOSE,
     86                       UOPTION_QUIET,
     87                       UOPTION_VERSION,
     88                       UOPTION_SOURCEDIR,
     89                       UOPTION_DESTDIR,
     90                       UOPTION_ENCODING,
     91                       UOPTION_ICUDATADIR,
     92                       UOPTION_WRITE_JAVA,
     93                       UOPTION_COPYRIGHT,
     94                       UOPTION_DEF("java-package", '\x01', UOPT_REQUIRES_ARG),
     95                       UOPTION_BUNDLE_NAME,
     96                       UOPTION_DEF("write-xliff", 'x', UOPT_OPTIONAL_ARG),
     97                       UOPTION_DEF("strict",    'k', UOPT_NO_ARG), /* 14 */
     98                       UOPTION_DEF("noBinaryCollation", 'C', UOPT_NO_ARG),/* 15 */
     99                       UOPTION_DEF("language",  'l', UOPT_REQUIRES_ARG), /* 16 */
    100                       UOPTION_DEF("omitCollationRules", 'R', UOPT_NO_ARG),/* 17 */
    101                       UOPTION_DEF("formatVersion", '\x01', UOPT_REQUIRES_ARG),/* 18 */
    102                       UOPTION_DEF("writePoolBundle", '\x01', UOPT_NO_ARG),/* 19 */
    103                       UOPTION_DEF("usePoolBundle", '\x01', UOPT_OPTIONAL_ARG),/* 20 */
    104                       UOPTION_DEF("includeUnihanColl", '\x01', UOPT_NO_ARG),/* 21 */ /* temporary, don't display in usage info */
    105                   };
    106 
    107 static     UBool       write_java = FALSE;
    108 static     UBool       write_xliff = FALSE;
    109 static     const char* outputEnc ="";
    110 
    111 static ResFile poolBundle;
    112 
    113 /*added by Jing*/
    114 static     const char* language = NULL;
    115 static     const char* xliffOutputFileName = NULL;
    116 int
    117 main(int argc,
    118      char* argv[])
    119 {
    120     UErrorCode  status    = U_ZERO_ERROR;
    121     const char *arg       = NULL;
    122     const char *outputDir = NULL; /* NULL = no output directory, use current */
    123     const char *inputDir  = NULL;
    124     const char *encoding  = "";
    125     int         i;
    126     UBool illegalArg = FALSE;
    127 
    128     U_MAIN_INIT_ARGS(argc, argv);
    129 
    130     options[JAVA_PACKAGE].value = "com.ibm.icu.impl.data";
    131     options[BUNDLE_NAME].value = "LocaleElements";
    132     argc = u_parseArgs(argc, argv, UPRV_LENGTHOF(options), options);
    133 
    134     /* error handling, printing usage message */
    135     if(argc<0) {
    136         fprintf(stderr, "%s: error in command line argument \"%s\"\n", argv[0], argv[-argc]);
    137         illegalArg = TRUE;
    138     } else if(argc<2) {
    139         illegalArg = TRUE;
    140     }
    141     if(options[WRITE_POOL_BUNDLE].doesOccur && options[USE_POOL_BUNDLE].doesOccur) {
    142         fprintf(stderr, "%s: cannot combine --writePoolBundle and --usePoolBundle\n", argv[0]);
    143         illegalArg = TRUE;
    144     }
    145     if(options[FORMAT_VERSION].doesOccur) {
    146         const char *s = options[FORMAT_VERSION].value;
    147         if(uprv_strlen(s) != 1 || (s[0] < '1' && '3' < s[0])) {
    148             fprintf(stderr, "%s: unsupported --formatVersion %s\n", argv[0], s);
    149             illegalArg = TRUE;
    150         } else if(s[0] == '1' &&
    151                   (options[WRITE_POOL_BUNDLE].doesOccur || options[USE_POOL_BUNDLE].doesOccur)
    152         ) {
    153             fprintf(stderr, "%s: cannot combine --formatVersion 1 with --writePoolBundle or --usePoolBundle\n", argv[0]);
    154             illegalArg = TRUE;
    155         } else {
    156             setFormatVersion(s[0] - '0');
    157         }
    158     }
    159 
    160     if((options[JAVA_PACKAGE].doesOccur || options[BUNDLE_NAME].doesOccur) &&
    161             !options[WRITE_JAVA].doesOccur) {
    162         fprintf(stderr,
    163                 "%s error: command line argument --java-package or --bundle-name "
    164                 "without --write-java\n",
    165                 argv[0]);
    166         illegalArg = TRUE;
    167     }
    168 
    169     if(options[VERSION].doesOccur) {
    170         fprintf(stderr,
    171                 "%s version %s (ICU version %s).\n"
    172                 "%s\n",
    173                 argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING);
    174         if(!illegalArg) {
    175             return U_ZERO_ERROR;
    176         }
    177     }
    178 
    179     if(illegalArg || options[HELP1].doesOccur || options[HELP2].doesOccur) {
    180         /*
    181          * Broken into chunks because the C89 standard says the minimum
    182          * required supported string length is 509 bytes.
    183          */
    184         fprintf(stderr,
    185                 "Usage: %s [OPTIONS] [FILES]\n"
    186                 "\tReads the list of resource bundle source files and creates\n"
    187                 "\tbinary version of resource bundles (.res files)\n",
    188                 argv[0]);
    189         fprintf(stderr,
    190                 "Options:\n"
    191                 "\t-h or -? or --help       this usage text\n"
    192                 "\t-q or --quiet            do not display warnings\n"
    193                 "\t-v or --verbose          print extra information when processing files\n"
    194                 "\t-V or --version          prints out version number and exits\n"
    195                 "\t-c or --copyright        include copyright notice\n");
    196         fprintf(stderr,
    197                 "\t-e or --encoding         encoding of source files\n"
    198                 "\t-d of --destdir          destination directory, followed by the path, defaults to %s\n"
    199                 "\t-s or --sourcedir        source directory for files followed by path, defaults to %s\n"
    200                 "\t-i or --icudatadir       directory for locating any needed intermediate data files,\n"
    201                 "\t                         followed by path, defaults to %s\n",
    202                 u_getDataDirectory(), u_getDataDirectory(), u_getDataDirectory());
    203         fprintf(stderr,
    204                 "\t-j or --write-java       write a Java ListResourceBundle for ICU4J, followed by optional encoding\n"
    205                 "\t                         defaults to ASCII and \\uXXXX format.\n"
    206                 "\t      --java-package     For --write-java: package name for writing the ListResourceBundle,\n"
    207                 "\t                         defaults to com.ibm.icu.impl.data\n");
    208         fprintf(stderr,
    209                 "\t-b or --bundle-name      For --write-java: root resource bundle name for writing the ListResourceBundle,\n"
    210                 "\t                         defaults to LocaleElements\n"
    211                 "\t-x or --write-xliff      write an XLIFF file for the resource bundle. Followed by\n"
    212                 "\t                         an optional output file name.\n"
    213                 "\t-k or --strict           use pedantic parsing of syntax\n"
    214                 /*added by Jing*/
    215                 "\t-l or --language         for XLIFF: language code compliant with BCP 47.\n");
    216         fprintf(stderr,
    217                 "\t-C or --noBinaryCollation  do not generate binary collation image;\n"
    218                 "\t                           makes .res file smaller but collator instantiation much slower;\n"
    219                 "\t                           maintains ability to get tailoring rules\n"
    220                 "\t-R or --omitCollationRules do not include collation (tailoring) rules;\n"
    221                 "\t                           makes .res file smaller and maintains collator instantiation speed\n"
    222                 "\t                           but tailoring rules will not be available (they are rarely used)\n");
    223         fprintf(stderr,
    224                 "\t      --formatVersion      write a .res file compatible with the requested formatVersion (single digit);\n"
    225                 "\t                           for example, --formatVersion 1\n");
    226         fprintf(stderr,
    227                 "\t      --writePoolBundle    write a pool.res file with all of the keys of all input bundles\n"
    228                 "\t      --usePoolBundle [path-to-pool.res]  point to keys from the pool.res keys pool bundle if they are available there;\n"
    229                 "\t                           makes .res files smaller but dependent on the pool bundle\n"
    230                 "\t                           (--writePoolBundle and --usePoolBundle cannot be combined)\n");
    231 
    232         return illegalArg ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
    233     }
    234 
    235     if(options[VERBOSE].doesOccur) {
    236         setVerbose(TRUE);
    237     }
    238 
    239     if(options[QUIET].doesOccur) {
    240         setShowWarning(FALSE);
    241     }
    242     if(options[STRICT].doesOccur) {
    243         setStrict(TRUE);
    244     }
    245     if(options[COPYRIGHT].doesOccur){
    246         setIncludeCopyright(TRUE);
    247     }
    248 
    249     if(options[SOURCEDIR].doesOccur) {
    250         inputDir = options[SOURCEDIR].value;
    251     }
    252 
    253     if(options[DESTDIR].doesOccur) {
    254         outputDir = options[DESTDIR].value;
    255     }
    256 
    257     if(options[ENCODING].doesOccur) {
    258         encoding = options[ENCODING].value;
    259     }
    260 
    261     if(options[ICUDATADIR].doesOccur) {
    262         u_setDataDirectory(options[ICUDATADIR].value);
    263     }
    264     /* Initialize ICU */
    265     u_init(&status);
    266     if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
    267         /* Note: u_init() will try to open ICU property data.
    268          *       failures here are expected when building ICU from scratch.
    269          *       ignore them.
    270         */
    271         fprintf(stderr, "%s: can not initialize ICU.  status = %s\n",
    272             argv[0], u_errorName(status));
    273         exit(1);
    274     }
    275     status = U_ZERO_ERROR;
    276     if(options[WRITE_JAVA].doesOccur) {
    277         write_java = TRUE;
    278         outputEnc = options[WRITE_JAVA].value;
    279     }
    280 
    281     if(options[WRITE_XLIFF].doesOccur) {
    282         write_xliff = TRUE;
    283         if(options[WRITE_XLIFF].value != NULL){
    284             xliffOutputFileName = options[WRITE_XLIFF].value;
    285         }
    286     }
    287 
    288     initParser();
    289 
    290     /*added by Jing*/
    291     if(options[LANGUAGE].doesOccur) {
    292         language = options[LANGUAGE].value;
    293     }
    294 
    295     LocalPointer<SRBRoot> newPoolBundle;
    296     if(options[WRITE_POOL_BUNDLE].doesOccur) {
    297         newPoolBundle.adoptInsteadAndCheckErrorCode(new SRBRoot(NULL, TRUE, status), status);
    298         if(U_FAILURE(status)) {
    299             fprintf(stderr, "unable to create an empty bundle for the pool keys: %s\n", u_errorName(status));
    300             return status;
    301         } else {
    302             const char *poolResName = "pool.res";
    303             char *nameWithoutSuffix = static_cast<char *>(uprv_malloc(uprv_strlen(poolResName) + 1));
    304             if (nameWithoutSuffix == NULL) {
    305                 fprintf(stderr, "out of memory error\n");
    306                 return U_MEMORY_ALLOCATION_ERROR;
    307             }
    308             uprv_strcpy(nameWithoutSuffix, poolResName);
    309             *uprv_strrchr(nameWithoutSuffix, '.') = 0;
    310             newPoolBundle->fLocale = nameWithoutSuffix;
    311         }
    312     }
    313 
    314     if(options[USE_POOL_BUNDLE].doesOccur) {
    315         const char *poolResName = "pool.res";
    316         FileStream *poolFile;
    317         int32_t poolFileSize;
    318         int32_t indexLength;
    319         /*
    320          * TODO: Consolidate inputDir/filename handling from main() and processFile()
    321          * into a common function, and use it here as well.
    322          * Try to create toolutil functions for dealing with dir/filenames and
    323          * loading ICU data files without udata_open().
    324          * Share code with icupkg?
    325          * Also, make_res_filename() seems to be unused. Review and remove.
    326          */
    327         CharString poolFileName;
    328         if (options[USE_POOL_BUNDLE].value!=NULL) {
    329             poolFileName.append(options[USE_POOL_BUNDLE].value, status);
    330         } else if (inputDir) {
    331             poolFileName.append(inputDir, status);
    332         }
    333         poolFileName.appendPathPart(poolResName, status);
    334         if (U_FAILURE(status)) {
    335             return status;
    336         }
    337         poolFile = T_FileStream_open(poolFileName.data(), "rb");
    338         if (poolFile == NULL) {
    339             fprintf(stderr, "unable to open pool bundle file %s\n", poolFileName.data());
    340             return 1;
    341         }
    342         poolFileSize = T_FileStream_size(poolFile);
    343         if (poolFileSize < 32) {
    344             fprintf(stderr, "the pool bundle file %s is too small\n", poolFileName.data());
    345             return 1;
    346         }
    347         poolBundle.fBytes = new uint8_t[(poolFileSize + 15) & ~15];
    348         if (poolFileSize > 0 && poolBundle.fBytes == NULL) {
    349             fprintf(stderr, "unable to allocate memory for the pool bundle file %s\n", poolFileName.data());
    350             return U_MEMORY_ALLOCATION_ERROR;
    351         }
    352 
    353         UDataSwapper *ds;
    354         const DataHeader *header;
    355         int32_t bytesRead = T_FileStream_read(poolFile, poolBundle.fBytes, poolFileSize);
    356         if (bytesRead != poolFileSize) {
    357             fprintf(stderr, "unable to read the pool bundle file %s\n", poolFileName.data());
    358             return 1;
    359         }
    360         /*
    361          * Swap the pool bundle so that a single checked-in file can be used.
    362          * The swapper functions also test that the data looks like
    363          * a well-formed .res file.
    364          */
    365         ds = udata_openSwapperForInputData(poolBundle.fBytes, bytesRead,
    366                                            U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &status);
    367         if (U_FAILURE(status)) {
    368             fprintf(stderr, "udata_openSwapperForInputData(pool bundle %s) failed: %s\n",
    369                     poolFileName.data(), u_errorName(status));
    370             return status;
    371         }
    372         ures_swap(ds, poolBundle.fBytes, bytesRead, poolBundle.fBytes, &status);
    373         udata_closeSwapper(ds);
    374         if (U_FAILURE(status)) {
    375             fprintf(stderr, "ures_swap(pool bundle %s) failed: %s\n",
    376                     poolFileName.data(), u_errorName(status));
    377             return status;
    378         }
    379         header = (const DataHeader *)poolBundle.fBytes;
    380         if (header->info.formatVersion[0] < 2) {
    381             fprintf(stderr, "invalid format of pool bundle file %s\n", poolFileName.data());
    382             return U_INVALID_FORMAT_ERROR;
    383         }
    384         const int32_t *pRoot = (const int32_t *)(
    385                 (const char *)header + header->dataHeader.headerSize);
    386         poolBundle.fIndexes = pRoot + 1;
    387         indexLength = poolBundle.fIndexes[URES_INDEX_LENGTH] & 0xff;
    388         if (indexLength <= URES_INDEX_POOL_CHECKSUM) {
    389             fprintf(stderr, "insufficient indexes[] in pool bundle file %s\n", poolFileName.data());
    390             return U_INVALID_FORMAT_ERROR;
    391         }
    392         int32_t keysBottom = 1 + indexLength;
    393         int32_t keysTop = poolBundle.fIndexes[URES_INDEX_KEYS_TOP];
    394         poolBundle.fKeys = (const char *)(pRoot + keysBottom);
    395         poolBundle.fKeysLength = (keysTop - keysBottom) * 4;
    396         poolBundle.fChecksum = poolBundle.fIndexes[URES_INDEX_POOL_CHECKSUM];
    397 
    398         for (i = 0; i < poolBundle.fKeysLength; ++i) {
    399             if (poolBundle.fKeys[i] == 0) {
    400                 ++poolBundle.fKeysCount;
    401             }
    402         }
    403 
    404         // 16BitUnits[] begins with strings-v2.
    405         // The strings-v2 may optionally be terminated by what looks like
    406         // an explicit string length that exceeds the number of remaining 16-bit units.
    407         int32_t stringUnitsLength = (poolBundle.fIndexes[URES_INDEX_16BIT_TOP] - keysTop) * 2;
    408         if (stringUnitsLength >= 2 && getFormatVersion() >= 3) {
    409             poolBundle.fStrings = new PseudoListResource(NULL, status);
    410             if (poolBundle.fStrings == NULL) {
    411                 fprintf(stderr, "unable to allocate memory for the pool bundle strings %s\n",
    412                         poolFileName.data());
    413                 return U_MEMORY_ALLOCATION_ERROR;
    414             }
    415             // The PseudoListResource constructor call did not allocate further memory.
    416             assert(U_SUCCESS(status));
    417             const UChar *p = (const UChar *)(pRoot + keysTop);
    418             int32_t remaining = stringUnitsLength;
    419             do {
    420                 int32_t first = *p;
    421                 int8_t numCharsForLength;
    422                 int32_t length;
    423                 if (!U16_IS_TRAIL(first)) {
    424                     // NUL-terminated
    425                     numCharsForLength = 0;
    426                     for (length = 0;
    427                          length < remaining && p[length] != 0;
    428                          ++length) {}
    429                 } else if (first < 0xdfef) {
    430                     numCharsForLength = 1;
    431                     length = first & 0x3ff;
    432                 } else if (first < 0xdfff && remaining >= 2) {
    433                     numCharsForLength = 2;
    434                     length = ((first - 0xdfef) << 16) | p[1];
    435                 } else if (first == 0xdfff && remaining >= 3) {
    436                     numCharsForLength = 3;
    437                     length = ((int32_t)p[1] << 16) | p[2];
    438                 } else {
    439                     break;  // overrun
    440                 }
    441                 // Check for overrun before changing remaining,
    442                 // so that it is always accurate after the loop body.
    443                 if ((numCharsForLength + length) >= remaining ||
    444                         p[numCharsForLength + length] != 0) {
    445                     break;  // overrun or explicitly terminated
    446                 }
    447                 int32_t poolStringIndex = stringUnitsLength - remaining;
    448                 // Maximum pool string index when suffix-sharing the last character.
    449                 int32_t maxStringIndex = poolStringIndex + numCharsForLength + length - 1;
    450                 if (maxStringIndex >= RES_MAX_OFFSET) {
    451                     // pool string index overrun
    452                     break;
    453                 }
    454                 p += numCharsForLength;
    455                 remaining -= numCharsForLength;
    456                 if (length != 0) {
    457                     StringResource *sr =
    458                             new StringResource(poolStringIndex, numCharsForLength,
    459                                                p, length, status);
    460                     if (sr == NULL) {
    461                         fprintf(stderr, "unable to allocate memory for a pool bundle string %s\n",
    462                                 poolFileName.data());
    463                         return U_MEMORY_ALLOCATION_ERROR;
    464                     }
    465                     poolBundle.fStrings->add(sr);
    466                     poolBundle.fStringIndexLimit = maxStringIndex + 1;
    467                     // The StringResource constructor did not allocate further memory.
    468                     assert(U_SUCCESS(status));
    469                 }
    470                 p += length + 1;
    471                 remaining -= length + 1;
    472             } while (remaining > 0);
    473             if (poolBundle.fStrings->fCount == 0) {
    474                 delete poolBundle.fStrings;
    475                 poolBundle.fStrings = NULL;
    476             }
    477         }
    478 
    479         T_FileStream_close(poolFile);
    480         setUsePoolBundle(TRUE);
    481         if (isVerbose() && poolBundle.fStrings != NULL) {
    482             printf("number of shared strings: %d\n", (int)poolBundle.fStrings->fCount);
    483             int32_t length = poolBundle.fStringIndexLimit + 1;  // incl. last NUL
    484             printf("16-bit units for strings: %6d = %6d bytes\n",
    485                    (int)length, (int)length * 2);
    486         }
    487     }
    488 
    489     if(!options[FORMAT_VERSION].doesOccur && getFormatVersion() == 3 &&
    490             poolBundle.fStrings == NULL &&
    491             !options[WRITE_POOL_BUNDLE].doesOccur) {
    492         // If we just default to formatVersion 3
    493         // but there are no pool bundle strings to share
    494         // and we do not write a pool bundle,
    495         // then write formatVersion 2 which is just as good.
    496         setFormatVersion(2);
    497     }
    498 
    499     if(options[INCLUDE_UNIHAN_COLL].doesOccur) {
    500         puts("genrb option --includeUnihanColl ignored: \n"
    501                 "CLDR 26/ICU 54 unihan data is small, except\n"
    502                 "the ucadata-unihan.icu version of the collation root data\n"
    503                 "is about 300kB larger than the ucadata-implicithan.icu version.");
    504     }
    505 
    506     if((argc-1)!=1) {
    507         printf("genrb number of files: %d\n", argc - 1);
    508     }
    509     /* generate the binary files */
    510     for(i = 1; i < argc; ++i) {
    511         status = U_ZERO_ERROR;
    512         arg    = getLongPathname(argv[i]);
    513 
    514         CharString theCurrentFileName;
    515         if (inputDir) {
    516             theCurrentFileName.append(inputDir, status);
    517         }
    518         theCurrentFileName.appendPathPart(arg, status);
    519         if (U_FAILURE(status)) {
    520             break;
    521         }
    522 
    523         gCurrentFileName = theCurrentFileName.data();
    524         if (isVerbose()) {
    525             printf("Processing file \"%s\"\n", theCurrentFileName.data());
    526         }
    527         processFile(arg, encoding, inputDir, outputDir, NULL,
    528                     newPoolBundle.getAlias(),
    529                     options[NO_BINARY_COLLATION].doesOccur, status);
    530     }
    531 
    532     poolBundle.close();
    533 
    534     if(U_SUCCESS(status) && options[WRITE_POOL_BUNDLE].doesOccur) {
    535         char outputFileName[256];
    536         newPoolBundle->write(outputDir, NULL, outputFileName, sizeof(outputFileName), status);
    537         if(U_FAILURE(status)) {
    538             fprintf(stderr, "unable to write the pool bundle: %s\n", u_errorName(status));
    539         }
    540     }
    541 
    542     u_cleanup();
    543 
    544     /* Dont return warnings as a failure */
    545     if (U_SUCCESS(status)) {
    546         return 0;
    547     }
    548 
    549     return status;
    550 }
    551 
    552 /* Process a file */
    553 void
    554 processFile(const char *filename, const char *cp,
    555             const char *inputDir, const char *outputDir, const char *packageName,
    556             SRBRoot *newPoolBundle,
    557             UBool omitBinaryCollation, UErrorCode &status) {
    558     LocalPointer<SRBRoot> data;
    559     UCHARBUF       *ucbuf        = NULL;
    560     char           *rbname       = NULL;
    561     char           *openFileName = NULL;
    562     char           *inputDirBuf  = NULL;
    563 
    564     char           outputFileName[256];
    565 
    566     int32_t dirlen  = 0;
    567     int32_t filelen = 0;
    568 
    569     if (U_FAILURE(status)) {
    570         return;
    571     }
    572     if(filename==NULL){
    573         status=U_ILLEGAL_ARGUMENT_ERROR;
    574         return;
    575     }else{
    576         filelen = (int32_t)uprv_strlen(filename);
    577     }
    578 
    579     if(inputDir == NULL) {
    580         const char *filenameBegin = uprv_strrchr(filename, U_FILE_SEP_CHAR);
    581         openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
    582         openFileName[0] = '\0';
    583         if (filenameBegin != NULL) {
    584             /*
    585              * When a filename ../../../data/root.txt is specified,
    586              * we presume that the input directory is ../../../data
    587              * This is very important when the resource file includes
    588              * another file, like UCARules.txt or thaidict.brk.
    589              */
    590             int32_t filenameSize = (int32_t)(filenameBegin - filename + 1);
    591             inputDirBuf = uprv_strncpy((char *)uprv_malloc(filenameSize), filename, filenameSize);
    592 
    593             /* test for NULL */
    594             if(inputDirBuf == NULL) {
    595                 status = U_MEMORY_ALLOCATION_ERROR;
    596                 goto finish;
    597             }
    598 
    599             inputDirBuf[filenameSize - 1] = 0;
    600             inputDir = inputDirBuf;
    601             dirlen  = (int32_t)uprv_strlen(inputDir);
    602         }
    603     }else{
    604         dirlen  = (int32_t)uprv_strlen(inputDir);
    605 
    606         if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) {
    607             openFileName = (char *) uprv_malloc(dirlen + filelen + 2);
    608 
    609             /* test for NULL */
    610             if(openFileName == NULL) {
    611                 status = U_MEMORY_ALLOCATION_ERROR;
    612                 goto finish;
    613             }
    614 
    615             openFileName[0] = '\0';
    616             /*
    617              * append the input dir to openFileName if the first char in
    618              * filename is not file seperation char and the last char input directory is  not '.'.
    619              * This is to support :
    620              * genrb -s. /home/icu/data
    621              * genrb -s. icu/data
    622              * The user cannot mix notations like
    623              * genrb -s. /icu/data --- the absolute path specified. -s redundant
    624              * user should use
    625              * genrb -s. icu/data  --- start from CWD and look in icu/data dir
    626              */
    627             if( (filename[0] != U_FILE_SEP_CHAR) && (inputDir[dirlen-1] !='.')){
    628                 uprv_strcpy(openFileName, inputDir);
    629                 openFileName[dirlen]     = U_FILE_SEP_CHAR;
    630             }
    631             openFileName[dirlen + 1] = '\0';
    632         } else {
    633             openFileName = (char *) uprv_malloc(dirlen + filelen + 1);
    634 
    635             /* test for NULL */
    636             if(openFileName == NULL) {
    637                 status = U_MEMORY_ALLOCATION_ERROR;
    638                 goto finish;
    639             }
    640 
    641             uprv_strcpy(openFileName, inputDir);
    642 
    643         }
    644     }
    645 
    646     uprv_strcat(openFileName, filename);
    647 
    648     ucbuf = ucbuf_open(openFileName, &cp,getShowWarning(),TRUE, &status);
    649     if(status == U_FILE_ACCESS_ERROR) {
    650 
    651         fprintf(stderr, "couldn't open file %s\n", openFileName == NULL ? filename : openFileName);
    652         goto finish;
    653     }
    654     if (ucbuf == NULL || U_FAILURE(status)) {
    655         fprintf(stderr, "An error occured processing file %s. Error: %s\n",
    656                 openFileName == NULL ? filename : openFileName, u_errorName(status));
    657         goto finish;
    658     }
    659     /* auto detected popular encodings? */
    660     if (cp!=NULL && isVerbose()) {
    661         printf("autodetected encoding %s\n", cp);
    662     }
    663     /* Parse the data into an SRBRoot */
    664     data.adoptInstead(parse(ucbuf, inputDir, outputDir, filename,
    665             !omitBinaryCollation, options[NO_COLLATION_RULES].doesOccur, &status));
    666 
    667     if (data.isNull() || U_FAILURE(status)) {
    668         fprintf(stderr, "couldn't parse the file %s. Error:%s\n", filename, u_errorName(status));
    669         goto finish;
    670     }
    671     if(options[WRITE_POOL_BUNDLE].doesOccur) {
    672         data->fWritePoolBundle = newPoolBundle;
    673         data->compactKeys(status);
    674         int32_t newKeysLength;
    675         const char *newKeys = data->getKeyBytes(&newKeysLength);
    676         newPoolBundle->addKeyBytes(newKeys, newKeysLength, status);
    677         if(U_FAILURE(status)) {
    678             fprintf(stderr, "bundle_compactKeys(%s) or bundle_getKeyBytes() failed: %s\n",
    679                     filename, u_errorName(status));
    680             goto finish;
    681         }
    682         /* count the number of just-added key strings */
    683         for(const char *newKeysLimit = newKeys + newKeysLength; newKeys < newKeysLimit; ++newKeys) {
    684             if(*newKeys == 0) {
    685                 ++newPoolBundle->fKeysCount;
    686             }
    687         }
    688     }
    689 
    690     if(options[USE_POOL_BUNDLE].doesOccur) {
    691         data->fUsePoolBundle = &poolBundle;
    692     }
    693 
    694     /* Determine the target rb filename */
    695     rbname = make_res_filename(filename, outputDir, packageName, status);
    696     if(U_FAILURE(status)) {
    697         fprintf(stderr, "couldn't make the res fileName for  bundle %s. Error:%s\n",
    698                 filename, u_errorName(status));
    699         goto finish;
    700     }
    701     if(write_java== TRUE){
    702         bundle_write_java(data.getAlias(), outputDir, outputEnc,
    703                           outputFileName, sizeof(outputFileName),
    704                           options[JAVA_PACKAGE].value, options[BUNDLE_NAME].value, &status);
    705     }else if(write_xliff ==TRUE){
    706         bundle_write_xml(data.getAlias(), outputDir, outputEnc,
    707                          filename, outputFileName, sizeof(outputFileName),
    708                          language, xliffOutputFileName, &status);
    709     }else{
    710         /* Write the data to the file */
    711         data->write(outputDir, packageName, outputFileName, sizeof(outputFileName), status);
    712     }
    713     if (U_FAILURE(status)) {
    714         fprintf(stderr, "couldn't write bundle %s. Error:%s\n", outputFileName, u_errorName(status));
    715     }
    716 
    717 finish:
    718 
    719     if (inputDirBuf != NULL) {
    720         uprv_free(inputDirBuf);
    721     }
    722 
    723     if (openFileName != NULL) {
    724         uprv_free(openFileName);
    725     }
    726 
    727     if(ucbuf) {
    728         ucbuf_close(ucbuf);
    729     }
    730 
    731     if (rbname) {
    732         uprv_free(rbname);
    733     }
    734 }
    735 
    736 /* Generate the target .res file name from the input file name */
    737 static char*
    738 make_res_filename(const char *filename,
    739                   const char *outputDir,
    740                   const char *packageName,
    741                   UErrorCode &status) {
    742     char *basename;
    743     char *dirname;
    744     char *resName;
    745 
    746     int32_t pkgLen = 0; /* length of package prefix */
    747 
    748 
    749     if (U_FAILURE(status)) {
    750         return 0;
    751     }
    752 
    753     if(packageName != NULL)
    754     {
    755         pkgLen = (int32_t)(1 + uprv_strlen(packageName));
    756     }
    757 
    758     /* setup */
    759     basename = dirname = resName = 0;
    760 
    761     /* determine basename, and compiled file names */
    762     basename = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1));
    763     if(basename == 0) {
    764         status = U_MEMORY_ALLOCATION_ERROR;
    765         goto finish;
    766     }
    767 
    768     get_basename(basename, filename);
    769 
    770     dirname = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(filename) + 1));
    771     if(dirname == 0) {
    772         status = U_MEMORY_ALLOCATION_ERROR;
    773         goto finish;
    774     }
    775 
    776     get_dirname(dirname, filename);
    777 
    778     if (outputDir == NULL) {
    779         /* output in same dir as .txt */
    780         resName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(dirname)
    781                                       + pkgLen
    782                                       + uprv_strlen(basename)
    783                                       + uprv_strlen(RES_SUFFIX) + 8));
    784         if(resName == 0) {
    785             status = U_MEMORY_ALLOCATION_ERROR;
    786             goto finish;
    787         }
    788 
    789         uprv_strcpy(resName, dirname);
    790 
    791         if(packageName != NULL)
    792         {
    793             uprv_strcat(resName, packageName);
    794             uprv_strcat(resName, "_");
    795         }
    796 
    797         uprv_strcat(resName, basename);
    798 
    799     } else {
    800         int32_t dirlen      = (int32_t)uprv_strlen(outputDir);
    801         int32_t basenamelen = (int32_t)uprv_strlen(basename);
    802 
    803         resName = (char*) uprv_malloc(sizeof(char) * (dirlen + pkgLen + basenamelen + 8));
    804 
    805         if (resName == NULL) {
    806             status = U_MEMORY_ALLOCATION_ERROR;
    807             goto finish;
    808         }
    809 
    810         uprv_strcpy(resName, outputDir);
    811 
    812         if(outputDir[dirlen] != U_FILE_SEP_CHAR) {
    813             resName[dirlen]     = U_FILE_SEP_CHAR;
    814             resName[dirlen + 1] = '\0';
    815         }
    816 
    817         if(packageName != NULL)
    818         {
    819             uprv_strcat(resName, packageName);
    820             uprv_strcat(resName, "_");
    821         }
    822 
    823         uprv_strcat(resName, basename);
    824     }
    825 
    826 finish:
    827     uprv_free(basename);
    828     uprv_free(dirname);
    829 
    830     return resName;
    831 }
    832 
    833 /*
    834  * Local Variables:
    835  * indent-tabs-mode: nil
    836  * End:
    837  */
    838