1/*
2*******************************************************************************
3*
4*   Copyright (C) 2000-2009, International Business Machines
5*   Corporation and others.  All Rights Reserved.
6*
7*******************************************************************************
8*
9* File wrtjava.c
10*
11* Modification History:
12*
13*   Date        Name        Description
14*   01/11/02    Ram         Creation.
15*   02/12/08    Spieth      Fix errant 'new Object[][]{' insertion
16*   02/19/08    Spieth      Removed ICUListResourceBundle dependancy
17*******************************************************************************
18*/
19
20#include <assert.h>
21#include "reslist.h"
22#include "unewdata.h"
23#include "unicode/ures.h"
24#include "errmsg.h"
25#include "filestrm.h"
26#include "cstring.h"
27#include "unicode/ucnv.h"
28#include "genrb.h"
29#include "rle.h"
30#include "ucol_tok.h"
31#include "uhash.h"
32#include "uresimp.h"
33#include "unicode/ustring.h"
34
35void res_write_java(struct SResource *res,UErrorCode *status);
36
37
38static const char copyRight[] =
39    "/* \n"
40    " *******************************************************************************\n"
41    " *\n"
42    " *   Copyright (C) International Business Machines\n"
43    " *   Corporation and others.  All Rights Reserved.\n"
44    " *\n"
45    " *******************************************************************************\n"
46    " * $" "Source:  $ \n"
47    " * $" "Date:  $ \n"
48    " * $" "Revision:  $ \n"
49    " *******************************************************************************\n"
50    " */\n\n";
51static const char warningMsg[] =
52    "/*********************************************************************\n"
53    "######################################################################\n"
54    "\n"
55    "   WARNING: This file is generated by genrb Version " GENRB_VERSION ".\n"
56    "            If you edit this file, please make sure that, the source\n"
57    "            of this file (XXXX.txt in LocaleElements_XXXX.java)\n"
58    "            is also edited.\n"
59    "######################################################################\n"
60    " *********************************************************************\n"
61    " */\n\n";
62static const char* openBrace="{\n";
63static const char* closeClass="    };\n"
64                              "}\n";
65
66static const char* javaClass =  "import java.util.ListResourceBundle;\n\n"
67                                "public class ";
68
69static const char* javaClass1=  " extends ListResourceBundle {\n\n"
70                                "    /**\n"
71                                "     * Overrides ListResourceBundle \n"
72                                "     */\n"
73                                "    public final Object[][] getContents() { \n"
74                                "          return  contents;\n"
75                                "    }\n\n"
76                                "    private static Object[][] contents = {\n";
77/*static const char* javaClassICU= " extends ListResourceBundle {\n\n"
78                                 "    public %s  () {\n"
79                                 "          super.contents = data;\n"
80                                 "    }\n"
81                                 "    static final Object[][] data = new Object[][] { \n";*/
82static int tabCount = 3;
83
84static FileStream* out=NULL;
85static struct SRBRoot* srBundle ;
86static const char* outDir = NULL;
87
88static const char* bName=NULL;
89static const char* pName=NULL;
90
91static void write_tabs(FileStream* os){
92    int i=0;
93    for(;i<=tabCount;i++){
94        T_FileStream_write(os,"    ",4);
95    }
96}
97
98#define ZERO 0x30
99
100static const char* enc ="";
101static UConverter* conv = NULL;
102
103static int32_t
104uCharsToChars( char* target,int32_t targetLen, UChar* source, int32_t sourceLen,UErrorCode* status){
105    int i=0, j=0;
106    char str[30]={'\0'};
107    while(i<sourceLen){
108        if (source[i] == '\n') {
109            if (j + 2 < targetLen) {
110                uprv_strcat(target, "\\n");
111            }
112            j += 2;
113        }else if(source[i]==0x0D){
114            if(j+2<targetLen){
115                uprv_strcat(target,"\\f");
116            }
117            j+=2;
118        }else if(source[i] == '"'){
119            if(source[i-1]=='\''){
120                if(j+2<targetLen){
121                    uprv_strcat(target,"\\");
122                    target[j+1]= (char)source[i];
123                }
124                j+=2;
125            }else if(source[i-1]!='\\'){
126
127                if(j+2<targetLen){
128                    uprv_strcat(target,"\\");
129                    target[j+1]= (char)source[i];
130                }
131                j+=2;
132            }else if(source[i-1]=='\\'){
133                target[j++]= (char)source[i];
134            }
135        }else if(source[i]=='\\'){
136            if(i+1<sourceLen){
137                switch(source[i+1]){
138                case ',':
139                case '!':
140                case '?':
141                case '#':
142                case '.':
143                case '%':
144                case '&':
145                case ':':
146                case ';':
147                    if(j+2<targetLen){
148                       uprv_strcat(target,"\\\\");
149                    }
150                    j+=2;
151                    break;
152                case '"':
153                case '\'':
154                    if(j+3<targetLen){
155                       uprv_strcat(target,"\\\\\\");
156                    }
157                    j+=3;
158                    break;
159                default :
160                    if(j<targetLen){
161                        target[j]=(char)source[i];
162                    }
163                    j++;
164                    break;
165                }
166            }else{
167                if(j<targetLen){
168                    uprv_strcat(target,"\\\\");
169                }
170                j+=2;
171            }
172        }else if(source[i]>=0x20 && source[i]<0x7F/*ASCII*/){
173            if(j<targetLen){
174                target[j] = (char) source[i];
175            }
176            j++;
177        }else{
178            if(*enc =='\0' || source[i]==0x0000){
179                uprv_strcpy(str,"\\u");
180                itostr(str+2,source[i],16,4);
181                if(j+6<targetLen){
182                    uprv_strcat(target,str);
183                }
184                j+=6;
185            }else{
186                char dest[30] = {0};
187                int retVal=ucnv_fromUChars(conv,dest,30,source+i,1,status);
188                if(U_FAILURE(*status)){
189                    return 0;
190                }
191                if(j+retVal<targetLen){
192                    uprv_strcat(target,dest);
193                }
194                j+=retVal;
195            }
196        }
197        i++;
198    }
199    return j;
200}
201
202
203static uint32_t
204strrch(const char* source,uint32_t sourceLen,char find){
205    const char* tSourceEnd =source + (sourceLen-1);
206    while(tSourceEnd>= source){
207        if(*tSourceEnd==find){
208            return (uint32_t)(tSourceEnd-source);
209        }
210        tSourceEnd--;
211    }
212    return (uint32_t)(tSourceEnd-source);
213}
214
215static int32_t getColumnCount(int32_t len){
216    int32_t columnCount = 80;
217    int32_t maxLines = 3000;
218    int32_t adjustedLen = len*5; /* assume that every codepoint is represented in \uXXXX format*/
219    /*
220     * calculate the number of lines that
221     * may be required if column count is 80
222     */
223    if (maxLines  < (adjustedLen / columnCount) ){
224        columnCount = adjustedLen / maxLines;
225    }
226    return columnCount;
227}
228static void
229str_write_java( uint16_t* src, int32_t srcLen, UBool printEndLine, UErrorCode *status){
230
231    uint32_t length = srcLen*8;
232    uint32_t bufLen = 0;
233    uint32_t columnCount;
234    char* buf = (char*) malloc(sizeof(char)*length);
235
236    if(buf == NULL) {
237        *status = U_MEMORY_ALLOCATION_ERROR;
238        return;
239    }
240
241    columnCount = getColumnCount(srcLen);
242    memset(buf,0,length);
243
244    bufLen = uCharsToChars(buf,length,src,srcLen,status);
245
246    if(printEndLine)
247        write_tabs(out);
248
249    if(U_FAILURE(*status)){
250        uprv_free(buf);
251        return;
252    }
253
254    if(bufLen+(tabCount*4) > columnCount  ){
255        uint32_t len = 0;
256        char* current = buf;
257        uint32_t add;
258        while(len < bufLen){
259            add = columnCount-(tabCount*4)-5/* for ", +\n */;
260            current = buf +len;
261            if (add < (bufLen-len)) {
262                uint32_t idx = strrch(current,add,'\\');
263                if (idx > add) {
264                    idx = add;
265                } else {
266                    int32_t num =idx-1;
267                    uint32_t seqLen;
268                    while(num>0){
269                        if(current[num]=='\\'){
270                            num--;
271                        }else{
272                            break;
273                        }
274                    }
275                    if ((idx-num)%2==0) {
276                        idx--;
277                    }
278                    seqLen = (current[idx+1]=='u') ? 6 : 2;
279                    if ((add-idx) < seqLen) {
280                        add = idx + seqLen;
281                    }
282                }
283            }
284            T_FileStream_write(out,"\"",1);
285            if(len+add<bufLen){
286                T_FileStream_write(out,current,add);
287                T_FileStream_write(out,"\" +\n",4);
288                write_tabs(out);
289            }else{
290                T_FileStream_write(out,current,bufLen-len);
291            }
292            len+=add;
293        }
294    }else{
295        T_FileStream_write(out,"\"",1);
296        T_FileStream_write(out, buf,bufLen);
297    }
298    if(printEndLine){
299        T_FileStream_write(out,"\",\n",3);
300    }else{
301        T_FileStream_write(out,"\"",1);
302    }
303    uprv_free(buf);
304}
305
306/* Writing Functions */
307static void
308string_write_java(struct SResource *res,UErrorCode *status) {
309    char resKeyBuffer[8];
310    const char *resname = res_getKeyString(srBundle, res, resKeyBuffer);
311
312    str_write_java(res->u.fString.fChars,res->u.fString.fLength,TRUE,status);
313
314	if(resname != NULL && uprv_strcmp(resname,"Rule")==0)
315	{
316        UChar* buf = (UChar*) uprv_malloc(sizeof(UChar)*res->u.fString.fLength);
317        uprv_memcpy(buf,res->u.fString.fChars,res->u.fString.fLength);
318        uprv_free(buf);
319    }
320
321}
322
323static void
324array_write_java( struct SResource *res, UErrorCode *status) {
325
326    uint32_t  i         = 0;
327    const char* arr ="new String[] { \n";
328    struct SResource *current = NULL;
329    struct SResource *first =NULL;
330    UBool decrementTabs = FALSE;
331    UBool allStrings    = TRUE;
332
333    if (U_FAILURE(*status)) {
334        return;
335    }
336
337    if (res->u.fArray.fCount > 0) {
338
339        current = res->u.fArray.fFirst;
340        i = 0;
341        while(current != NULL){
342            if(current->fType!=URES_STRING){
343                allStrings = FALSE;
344                break;
345            }
346            current= current->fNext;
347        }
348
349        current = res->u.fArray.fFirst;
350        if(allStrings==FALSE){
351            const char* object = "new Object[]{\n";
352            write_tabs(out);
353            T_FileStream_write(out, object, (int32_t)uprv_strlen(object));
354            tabCount++;
355            decrementTabs = TRUE;
356        }else{
357            write_tabs(out);
358            T_FileStream_write(out, arr, (int32_t)uprv_strlen(arr));
359            tabCount++;
360        }
361        first=current;
362        while (current != NULL) {
363            /*if(current->fType==URES_STRING){
364                write_tabs(out);
365            }*/
366            res_write_java(current, status);
367            if(U_FAILURE(*status)){
368                return;
369            }
370            i++;
371            current = current->fNext;
372        }
373        T_FileStream_write(out,"\n",1);
374
375        tabCount--;
376        write_tabs(out);
377        T_FileStream_write(out,"},\n",3);
378
379    } else {
380        write_tabs(out);
381        T_FileStream_write(out,arr,(int32_t)uprv_strlen(arr));
382        write_tabs(out);
383        T_FileStream_write(out,"},\n",3);
384    }
385}
386
387static void
388intvector_write_java( struct SResource *res, UErrorCode *status) {
389    uint32_t i = 0;
390    const char* intArr = "new int[] {\n";
391    /* const char* intC   = "new Integer(";   */
392    const char* stringArr = "new String[]{\n";
393    char resKeyBuffer[8];
394    const char *resname = res_getKeyString(srBundle, res, resKeyBuffer);
395    char buf[100];
396    int len =0;
397    buf[0]=0;
398    write_tabs(out);
399
400    if(resname != NULL && uprv_strcmp(resname,"DateTimeElements")==0){
401        T_FileStream_write(out, stringArr, (int32_t)uprv_strlen(stringArr));
402        tabCount++;
403        for(i = 0; i<res->u.fIntVector.fCount; i++) {
404            write_tabs(out);
405            len=itostr(buf,res->u.fIntVector.fArray[i],10,0);
406            T_FileStream_write(out,"\"",1);
407            T_FileStream_write(out,buf,len);
408            T_FileStream_write(out,"\",",2);
409            T_FileStream_write(out,"\n",1);
410        }
411    }else{
412        T_FileStream_write(out, intArr, (int32_t)uprv_strlen(intArr));
413        tabCount++;
414        for(i = 0; i<res->u.fIntVector.fCount; i++) {
415            write_tabs(out);
416            /* T_FileStream_write(out, intC, (int32_t)uprv_strlen(intC)); */
417            len=itostr(buf,res->u.fIntVector.fArray[i],10,0);
418            T_FileStream_write(out,buf,len);
419            /* T_FileStream_write(out,"),",2);  */
420            /* T_FileStream_write(out,"\n",1);  */
421            T_FileStream_write(out,",\n",2);
422        }
423    }
424    tabCount--;
425    write_tabs(out);
426    T_FileStream_write(out,"},\n",3);
427}
428
429static void
430int_write_java(struct SResource *res,UErrorCode *status) {
431    const char* intC   =  "new Integer(";
432    char buf[100];
433    int len =0;
434    buf[0]=0;
435
436    /* write the binary data */
437    write_tabs(out);
438    T_FileStream_write(out, intC, (int32_t)uprv_strlen(intC));
439    len=itostr(buf, res->u.fIntValue.fValue, 10, 0);
440    T_FileStream_write(out,buf,len);
441    T_FileStream_write(out,"),\n",3 );
442
443}
444
445static void
446bytes_write_java( struct SResource *res, UErrorCode *status) {
447	const char* type  = "new byte[] {";
448	const char* byteDecl = "%i, ";
449    char byteBuffer[100] = { 0 };
450	uint8_t*  byteArray = NULL;
451    int byteIterator = 0;
452
453    int32_t srcLen=res->u.fBinaryValue.fLength;
454
455    if(srcLen>0 )
456	{
457        byteArray = res->u.fBinaryValue.fData;
458
459        write_tabs(out);
460        T_FileStream_write(out, type, (int32_t)uprv_strlen(type));
461        T_FileStream_write(out, "\n", 1);
462        tabCount++;
463
464		for (;byteIterator<srcLen;byteIterator++)
465		{
466            if (byteIterator%16 == 0)
467			{
468			    write_tabs(out);
469			}
470
471			if (byteArray[byteIterator] < 128)
472			{
473                sprintf(byteBuffer, byteDecl, byteArray[byteIterator]);
474			}
475			else
476			{
477                sprintf(byteBuffer, byteDecl, (byteArray[byteIterator]-256));
478			}
479
480            T_FileStream_write(out, byteBuffer, (int32_t)uprv_strlen(byteBuffer));
481
482			if (byteIterator%16 == 15)
483			{
484                T_FileStream_write(out, "\n", 1);
485			}
486
487		}
488
489        if (((byteIterator-1)%16) != 15)
490		{
491            T_FileStream_write(out, "\n", 1);
492	    }
493
494		tabCount--;
495        write_tabs(out);
496		T_FileStream_write(out, "},\n", 3);
497
498	}
499	else
500    {
501		/* Empty array */
502        write_tabs(out);
503        T_FileStream_write(out,type,(int32_t)uprv_strlen(type));
504		T_FileStream_write(out,"},\n",3);
505    }
506
507}
508
509static UBool start = TRUE;
510
511static void
512table_write_java(struct SResource *res, UErrorCode *status) {
513    uint32_t  i         = 0;
514    UBool allStrings =TRUE;
515    struct SResource *current = NULL;
516    struct SResource *save = NULL;
517    const char* obj = "new Object[][]{\n";
518
519    if (U_FAILURE(*status)) {
520        return ;
521    }
522
523    if (res->u.fTable.fCount > 0) {
524        if(start==FALSE){
525            write_tabs(out);
526            T_FileStream_write(out, obj, (int32_t)uprv_strlen(obj));
527            tabCount++;
528        }
529        start = FALSE;
530        save = current = res->u.fTable.fFirst;
531        i       = 0;
532
533
534        while (current != NULL) {
535            char currentKeyBuffer[8];
536            const char *currentKeyString = res_getKeyString(srBundle, current, currentKeyBuffer);
537
538            assert(i < res->u.fTable.fCount);
539            write_tabs(out);
540
541            T_FileStream_write(out, openBrace, 2);
542
543
544            tabCount++;
545            allStrings=FALSE;
546
547            write_tabs(out);
548            if(currentKeyString != NULL) {
549                T_FileStream_write(out, "\"", 1);
550                T_FileStream_write(out, currentKeyString,
551                                   (int32_t)uprv_strlen(currentKeyString));
552                T_FileStream_write(out, "\",\n", 2);
553
554                T_FileStream_write(out, "\n", 1);
555            }
556            res_write_java(current, status);
557            if(U_FAILURE(*status)){
558                return;
559            }
560            i++;
561            current = current->fNext;
562            tabCount--;
563            write_tabs(out);
564            T_FileStream_write(out, "},\n", 3);
565        }
566        if(tabCount>4){
567            tabCount--;
568            write_tabs(out);
569            T_FileStream_write(out, "},\n", 3);
570        }
571
572    } else {
573        write_tabs(out);
574        T_FileStream_write(out,obj,(int32_t)uprv_strlen(obj));
575
576        write_tabs(out);
577        T_FileStream_write(out,"},\n",3);
578
579    }
580
581}
582
583void
584res_write_java(struct SResource *res,UErrorCode *status) {
585
586    if (U_FAILURE(*status)) {
587        return ;
588    }
589
590    if (res != NULL) {
591        switch (res->fType) {
592        case URES_STRING:
593             string_write_java    (res, status);
594             return;
595        case URES_ALIAS:
596             printf("Encountered unsupported resource type %d of alias\n", res->fType);
597             *status = U_UNSUPPORTED_ERROR;
598			 return;
599        case URES_INT_VECTOR:
600             intvector_write_java (res, status);
601             return;
602        case URES_BINARY:
603             bytes_write_java     (res, status);
604             return;
605        case URES_INT:
606             int_write_java       (res, status);
607             return;
608        case URES_ARRAY:
609             array_write_java     (res, status);
610             return;
611        case URES_TABLE:
612             table_write_java     (res, status);
613             return;
614        default:
615            break;
616        }
617    }
618
619    *status = U_INTERNAL_PROGRAM_ERROR;
620}
621
622void
623bundle_write_java(struct SRBRoot *bundle, const char *outputDir,const char* outputEnc,
624                  char *writtenFilename, int writtenFilenameLen,
625                  const char* packageName, const char* bundleName,
626                  UErrorCode *status) {
627
628    char fileName[256] = {'\0'};
629    char className[256]={'\0'};
630    /*char constructor[1000] = { 0 };*/
631    /*UBool j1 =FALSE;*/
632    outDir = outputDir;
633
634    start = TRUE;                        /* Reset the start indictor*/
635
636    bName = (bundleName==NULL) ? "LocaleElements" : bundleName;
637    pName = (packageName==NULL)? "com.ibm.icu.impl.data" : packageName;
638
639    uprv_strcpy(className, bName);
640    srBundle = bundle;
641    if(uprv_strcmp(srBundle->fLocale,"root")!=0){
642        uprv_strcat(className,"_");
643        uprv_strcat(className,srBundle->fLocale);
644    }
645    if(outputDir){
646        uprv_strcpy(fileName, outputDir);
647        if(outputDir[uprv_strlen(outputDir)-1] !=U_FILE_SEP_CHAR){
648            uprv_strcat(fileName,U_FILE_SEP_STRING);
649        }
650        uprv_strcat(fileName,className);
651        uprv_strcat(fileName,".java");
652    }else{
653        uprv_strcat(fileName,className);
654        uprv_strcat(fileName,".java");
655    }
656
657    if (writtenFilename) {
658        uprv_strncpy(writtenFilename, fileName, writtenFilenameLen);
659    }
660
661    if (U_FAILURE(*status)) {
662        return;
663    }
664
665    out= T_FileStream_open(fileName,"w");
666
667    if(out==NULL){
668        *status = U_FILE_ACCESS_ERROR;
669        return;
670    }
671    if(getIncludeCopyright()){
672        T_FileStream_write(out, copyRight, (int32_t)uprv_strlen(copyRight));
673        T_FileStream_write(out, warningMsg, (int32_t)uprv_strlen(warningMsg));
674    }
675    T_FileStream_write(out,"package ",(int32_t)uprv_strlen("package "));
676    T_FileStream_write(out,pName,(int32_t)uprv_strlen(pName));
677    T_FileStream_write(out,";\n\n",3);
678    T_FileStream_write(out, javaClass, (int32_t)uprv_strlen(javaClass));
679    T_FileStream_write(out, className, (int32_t)uprv_strlen(className));
680	T_FileStream_write(out, javaClass1, (int32_t)uprv_strlen(javaClass1));
681
682    /* if(j1){
683          T_FileStream_write(out, javaClass1, (int32_t)uprv_strlen(javaClass1));
684       }else{
685           sprintf(constructor,javaClassICU,className);
686           T_FileStream_write(out, constructor, (int32_t)uprv_strlen(constructor));
687       }
688    */
689
690    if(outputEnc && *outputEnc!='\0'){
691        /* store the output encoding */
692        enc = outputEnc;
693        conv=ucnv_open(enc,status);
694        if(U_FAILURE(*status)){
695            return;
696        }
697    }
698    res_write_java(bundle->fRoot, status);
699
700    T_FileStream_write(out, closeClass, (int32_t)uprv_strlen(closeClass));
701
702    T_FileStream_close(out);
703
704    ucnv_close(conv);
705}
706