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