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