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