1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_i18npool.hxx"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <iostream>
34 #include <set>
35 
36 #include <rtl/ustrbuf.hxx>
37 
38 #include "LocaleNode.hxx"
39 #include <com/sun/star/i18n/NumberFormatIndex.hpp>
40 
41 // NOTE: MUST match the Locale versionDTD attribute defined in data/locale.dtd
42 #define LOCALE_VERSION_DTD "2.0.3"
43 
44 typedef ::std::set< ::rtl::OUString > NameSet;
45 typedef ::std::set< sal_Int16 > ValueSet;
46 
47 namespace cssi = ::com::sun::star::i18n;
48 
49 LocaleNode::LocaleNode (const OUString& name, const Reference< XAttributeList > & attr)
50     : aName(name)
51     , xAttribs(new Attr(attr))
52     , parent(0)
53     , children(0)
54     , nChildren(0)
55     , childArrSize(0)
56     , nError(0)
57 {
58 }
59 
60 int LocaleNode::getError() const
61 {
62     int err = nError;
63     for (sal_Int32 i=0;i<nChildren;i++)
64         err += children[i]->getError();
65     return err;
66 }
67 
68 void LocaleNode::print () const {
69 	printf ("<");
70 	::rtl::OUString str (aName);
71 	for(sal_Int32 i = 0; i < str.getLength(); i++)
72 		printf( "%c", str[i]);
73 	printf (">\n");
74 }
75 
76 void LocaleNode::printR () const {
77 	print();
78 	for (sal_Int32 i=0;i<nChildren;i++)
79 		children[i]->printR();
80 	printf ("\t");
81 	print();
82 }
83 
84 void LocaleNode::addChild ( LocaleNode * node) {
85 	if (childArrSize <= nChildren) {
86 		LocaleNode ** arrN = (LocaleNode **)malloc( sizeof (LocaleNode *)*(childArrSize+10) ) ;
87 		for (sal_Int32 i = 0; i<childArrSize ; i++)
88 			arrN[i] = children[i];
89 		if ( childArrSize > 0 )
90 			free(children);
91 		childArrSize += 10;
92 		children = arrN;
93 	}
94 	children[nChildren++] = node;
95 	node->setParent (this);
96 }
97 
98 void LocaleNode::setParent ( LocaleNode * node) {
99 	parent = node;
100 }
101 
102 const LocaleNode* LocaleNode::getRoot() const
103 {
104     const LocaleNode* pRoot = 0;
105     const LocaleNode* pParent = this;
106     while ( (pParent = pParent->getParent()) != 0 )
107         pRoot = pParent;
108     return pRoot;
109 }
110 
111 const LocaleNode * LocaleNode::findNode ( const sal_Char *name) const {
112 	if (aName.equalsAscii(name))
113 		return this;
114 	for (sal_Int32 i = 0; i< nChildren; i++)  {
115 		const LocaleNode *n=children[i]->findNode(name);
116 		if (n)
117 			return n;
118 		}
119 	return 0;
120 }
121 
122  LocaleNode::~LocaleNode() {
123 	for (sal_Int32 i=0; i<nChildren;i++)
124 		delete (children[i]);
125 }
126 
127 LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr)
128 {
129 	if (name.equalsAscii("LC_INFO"))
130 		return new LCInfoNode (name,attr);
131 	if (name.equalsAscii("LC_CTYPE"))
132 		return new LCCTYPENode (name,attr);
133 	if (name.equalsAscii("LC_FORMAT"))
134 		return new LCFormatNode (name,attr);
135 	if (name.equalsAscii("LC_FORMAT_1"))
136 		return new LCFormatNode (name,attr);
137 	if (name.equalsAscii("LC_CALENDAR"))
138 		return new LCCalendarNode (name,attr);
139 	if (name.equalsAscii("LC_CURRENCY"))
140 		return new LCCurrencyNode (name,attr);
141 	if (name.equalsAscii("LC_TRANSLITERATION"))
142 		return new LCTransliterationNode (name,attr);
143 	if (name.equalsAscii("LC_COLLATION"))
144 		return new LCCollationNode (name,attr);
145 	if (name.equalsAscii("LC_INDEX"))
146 		return new LCIndexNode (name,attr);
147 	if (name.equalsAscii("LC_SEARCH"))
148 		return new LCSearchNode (name,attr);
149 	if (name.equalsAscii("LC_MISC"))
150 		return new LCMiscNode (name,attr);
151   	if (name.equalsAscii("LC_NumberingLevel"))
152                 return new LCNumberingLevelNode (name, attr);
153   	if (name.equalsAscii("LC_OutLineNumberingLevel"))
154                 return new LCOutlineNumberingLevelNode (name, attr);
155 
156 	return new LocaleNode(name,attr);
157 }
158 
159 
160 //   printf(" name: '%s'\n", p->getName().pData->buffer );
161 //   printf("value: '%s'\n", p->getValue().pData->buffer );
162 
163 #define OSTR(s) (OUStringToOString( (s), RTL_TEXTENCODING_UTF8).getStr())
164 
165 void print_OUString( const OUString& s )
166 {
167     printf( "%s", OSTR(s));
168 }
169 
170 bool is_empty( const OUString& s )
171 {
172      return (s.getLength()==0) || (s.getLength()==1 && s[0]=='\n');
173 }
174 
175 void print_indent( int depth )
176 {
177      for( int i=0; i<depth; i++ ) printf("    ");
178 }
179 
180 void print_color( int color )
181 {
182      printf("\033[%dm", color);
183 }
184 
185 void print_node( const LocaleNode* p, int depth=0 )
186 {
187      if( !p ) return;
188 
189      print_indent( depth );
190      printf("<");
191      print_color(36);
192      print_OUString( p->getName()  );
193      print_color(0);
194      const Attr* q = p->getAttr();
195      if( q )
196      {
197           for( sal_Int32 j=0; j<q->getLength(); j++ )
198           {
199                printf(" ");
200                print_color(33);
201                print_OUString( q->getTypeByIndex(j) );
202                print_color(0);
203                printf("=");
204                print_color(31);
205                printf("'");
206                print_OUString( q->getValueByIndex(j) );
207                printf("'");
208                print_color(0);
209           }
210      }
211      printf(">");
212      printf("\n");
213      if( !is_empty( p->getValue() ) )
214      {
215           print_indent( depth+1 );
216           printf("value: ");
217           print_color(31);
218           printf("'");
219           print_OUString( p->getValue() );
220           printf("'");
221           print_color(0);
222           printf("\n");
223      }
224      for( sal_Int32 i=0; i<p->getNumberOfChildren(); i++ )
225      {
226           print_node( p->getChildAt(i), depth+1 );
227      }
228      print_indent( depth );
229      printf("</");
230      print_OUString( p->getName()  );
231      printf(">");
232      printf("\n");
233 }
234 
235 void LocaleNode :: generateCode (const OFileWriter &of) const
236 {
237     ::rtl::OUString aDTD = getAttr()->getValueByName("versionDTD");
238     if (!aDTD.equalsAscii( LOCALE_VERSION_DTD))
239     {
240         ++nError;
241         fprintf( stderr, "Error: Locale versionDTD is not %s, see comment in locale.dtd\n", LOCALE_VERSION_DTD);
242     }
243 	for (sal_Int32 i=0; i<nChildren;i++)
244 		children[i]->generateCode (of);
245 //      print_node( this );
246 }
247 
248 
249 ::rtl::OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
250         const char* pParameterName, const LocaleNode* pNode,
251         sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
252 {
253     OUString aVal;
254     if (pNode)
255         aVal = pNode->getValue();
256     else
257     {
258         ++nError;
259         fprintf( stderr, "Error: node NULL pointer for parameter %s.\n",
260                 pParameterName);
261     }
262     // write empty data if error
263     of.writeParameter( pParameterName, aVal);
264     sal_Int32 nLen = aVal.getLength();
265     if (nLen < nMinLen)
266     {
267         ++nError;
268         fprintf( stderr, "Error: less than %ld character%s (%ld) in %s '%s'.\n",
269                 sal::static_int_cast< long >(nMinLen), (nMinLen > 1 ? "s" : ""),
270                 sal::static_int_cast< long >(nLen),
271                 (pNode ? OSTR( pNode->getName()) : ""),
272                 OSTR( aVal));
273     }
274     else if (nLen > nMaxLen && nMaxLen >= 0)
275         fprintf( stderr,
276                 "Warning: more than %ld character%s (%ld) in %s %s not supported by application.\n",
277                 sal::static_int_cast< long >(nMaxLen), (nMaxLen > 1 ? "s" : ""),
278                 sal::static_int_cast< long >(nLen),
279                 (pNode ? OSTR( pNode->getName()) : ""),
280                 OSTR( aVal));
281     return aVal;
282 }
283 
284 
285 ::rtl::OUString LocaleNode::writeParameterCheckLen( const OFileWriter &of,
286         const char* pNodeName, const char* pParameterName,
287         sal_Int32 nMinLen, sal_Int32 nMaxLen ) const
288 {
289     OUString aVal;
290 	const LocaleNode * pNode = findNode( pNodeName);
291     if (pNode)
292         aVal = writeParameterCheckLen( of, pParameterName, pNode, nMinLen, nMaxLen);
293     else
294     {
295         ++nError;
296         fprintf( stderr, "Error: node %s not found.\n", pNodeName);
297         // write empty data if error
298         of.writeParameter( pParameterName, aVal);
299     }
300     return aVal;
301 }
302 
303 void LocaleNode::incError( const char* pStr ) const
304 {
305     ++nError;
306     fprintf( stderr, "Error: %s\n", pStr);
307 }
308 
309 void LocaleNode::incError( const ::rtl::OUString& rStr ) const
310 {
311     incError( OSTR( rStr));
312 }
313 
314 char* LocaleNode::prepareErrorFormat( const char* pFormat, const char* pDefaultConversion ) const
315 {
316     static char buf[2048];
317     strcpy( buf, "Error: ");
318     strncat( buf, pFormat, 2000);
319     char* p = buf;
320     while (((p = strchr( p, '%')) != 0) && p[1] == '%')
321         p += 2;
322     if (!p)
323         strcat( buf, pDefaultConversion);
324     strcat( buf, "\n");
325     return buf;
326 }
327 
328 void LocaleNode::incErrorInt( const char* pStr, int nVal ) const
329 {
330     ++nError;
331     fprintf( stderr, prepareErrorFormat( pStr, ": %d"), nVal);
332 }
333 
334 void LocaleNode::incErrorStr( const char* pStr, const ::rtl::OUString& rVal ) const
335 {
336     ++nError;
337     fprintf( stderr, prepareErrorFormat( pStr, ": %s"), OSTR( rVal));
338 }
339 
340 void LCInfoNode::generateCode (const OFileWriter &of) const
341 {
342 
343 	const LocaleNode * languageNode = findNode("Language");
344 	const LocaleNode * countryNode = findNode("Country");
345 	const LocaleNode * variantNode = findNode("Variant");
346 
347 	if (languageNode)
348     {
349 		writeParameterCheckLen( of, "langID", languageNode->getChildAt(0), 2, -1);
350 		of.writeParameter("langDefaultName", languageNode->getChildAt(1)->getValue());
351 	}
352     else
353         incError( "No Language node.");
354 	if (countryNode)
355     {
356 		of.writeParameter("countryID", countryNode->getChildAt(0)->getValue());
357 		of.writeParameter("countryDefaultName", countryNode->getChildAt(1)->getValue());
358 	}
359     else
360         incError( "No Country node.");
361     if (variantNode)
362     {
363         of.writeParameter("Variant", variantNode->getValue());
364         fprintf( stderr, "Warning: %s\n",
365                 "Variants are not supported by application.");
366     }
367     else
368         of.writeParameter("Variant", ::rtl::OUString());
369 	of.writeAsciiString("\nstatic const sal_Unicode* LCInfoArray[] = {\n");
370 	of.writeAsciiString("\tlangID,\n");
371 	of.writeAsciiString("\tlangDefaultName,\n");
372 	of.writeAsciiString("\tcountryID,\n");
373 	of.writeAsciiString("\tcountryDefaultName,\n");
374 	of.writeAsciiString("\tVariant\n");
375 	of.writeAsciiString("};\n\n");
376 	of.writeFunction("getLCInfo_", "0", "LCInfoArray");
377 }
378 
379 void LCCTYPENode::generateCode (const OFileWriter &of) const
380 {
381 	const LocaleNode * sepNode = 0;
382 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
383 	if (useLocale.getLength() > 0) {
384 	    of.writeRefFunction("getLocaleItem_", useLocale);
385 	    return;
386 	}
387 	::rtl::OUString str =   getAttr() -> getValueByName("unoid");
388 	of.writeAsciiString("\n\n");
389 	of.writeParameter("LC_CTYPE_Unoid", str);;
390 
391     OUString aDateSep =
392         writeParameterCheckLen( of, "DateSeparator", "dateSeparator", 1, 1);
393     OUString aThoSep =
394         writeParameterCheckLen( of, "ThousandSeparator", "thousandSeparator", 1, 1);
395     OUString aDecSep =
396         writeParameterCheckLen( of, "DecimalSeparator", "decimalSeparator", 1, 1);
397     OUString aTimeSep =
398         writeParameterCheckLen( of, "TimeSeparator", "timeSeparator", 1, 1);
399     OUString aTime100Sep =
400         writeParameterCheckLen( of, "Time100SecSeparator", "time100SecSeparator", 1, 1);
401     OUString aListSep =
402         writeParameterCheckLen( of, "ListSeparator", "listSeparator", 1, 1);
403 
404     OUString aLDS;
405 
406 	sepNode = findNode("LongDateDayOfWeekSeparator");
407     aLDS = sepNode->getValue();
408 	of.writeParameter("LongDateDayOfWeekSeparator", aLDS);
409     if (aLDS.getLength() == 1 && aLDS.getStr()[0] == ',')
410         fprintf( stderr, "Warning: %s\n",
411                 "LongDateDayOfWeekSeparator is only a comma not followed by a space. Usually this is not the case and may lead to concatenated display names like \"Wednesday,May 9, 2007\".");
412 
413 	sepNode = findNode("LongDateDaySeparator");
414     aLDS = sepNode->getValue();
415 	of.writeParameter("LongDateDaySeparator", aLDS);
416     if (aLDS.getLength() == 1 && (aLDS.getStr()[0] == ',' || aLDS.getStr()[0] == '.'))
417         fprintf( stderr, "Warning: %s\n",
418                 "LongDateDaySeparator is only a comma or dot not followed by a space. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May 9,2007\".");
419 
420 	sepNode = findNode("LongDateMonthSeparator");
421     aLDS = sepNode->getValue();
422 	of.writeParameter("LongDateMonthSeparator", aLDS);
423     if (aLDS.getLength() == 0)
424         fprintf( stderr, "Warning: %s\n",
425                 "LongDateMonthSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, May9, 2007\".");
426 
427 	sepNode = findNode("LongDateYearSeparator");
428     aLDS = sepNode->getValue();
429 	of.writeParameter("LongDateYearSeparator", aLDS);
430     if (aLDS.getLength() == 0)
431         fprintf( stderr, "Warning: %s\n",
432                 "LongDateYearSeparator is empty. Usually this is not the case and may lead to concatenated display names like \"Wednesday, 2007May 9\".");
433 
434 
435     int nSavErr = nError;
436     int nWarn = 0;
437     if (aDateSep == aTimeSep)
438         incError( "DateSeparator equals TimeSeparator.");
439     if (aDecSep == aThoSep)
440         incError( "DecimalSeparator equals ThousandSeparator.");
441     if (aThoSep.equalsAscii( " "))
442         incError( "ThousandSeparator is an ' ' ordinary space, this should be a non-breaking space U+00A0 instead.");
443     if (aListSep == aDecSep)
444         fprintf( stderr, "Warning: %s\n",
445                 "ListSeparator equals DecimalSeparator.");
446     if (aListSep == aThoSep)
447         fprintf( stderr, "Warning: %s\n",
448                 "ListSeparator equals ThousandSeparator.");
449     if (aListSep.getLength() != 1 || aListSep.getStr()[0] != ';')
450     {
451         incError( "ListSeparator not ';' semicolon. Strongly recommended. Currently required.");
452         ++nSavErr;  // format codes not affected
453     }
454     if (aTimeSep == aTime100Sep)
455         ++nWarn, fprintf( stderr, "Warning: %s\n",
456                 "Time100SecSeparator equals TimeSeparator, this is probably an error.");
457     if (aDecSep != aTime100Sep)
458         ++nWarn, fprintf( stderr, "Warning: %s\n",
459                 "Time100SecSeparator is different from DecimalSeparator, this may be correct or not. Intended?");
460     if (nSavErr != nError || nWarn)
461         fprintf( stderr, "Warning: %s\n",
462                 "Don't forget to adapt corresponding FormatCode elements when changing separators.");
463 
464 	OUString aQuoteStart =
465         writeParameterCheckLen( of, "QuotationStart", "quotationStart", 1, 1);
466 	OUString aQuoteEnd =
467         writeParameterCheckLen( of, "QuotationEnd", "quotationEnd", 1, 1);
468 	OUString aDoubleQuoteStart =
469         writeParameterCheckLen( of, "DoubleQuotationStart", "doubleQuotationStart", 1, 1);
470 	OUString aDoubleQuoteEnd =
471         writeParameterCheckLen( of, "DoubleQuotationEnd", "doubleQuotationEnd", 1, 1);
472 
473     if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() > 127)
474         fprintf( stderr, "Warning: %s\n",
475                 "QuotationStart is an ASCII character but QuotationEnd is not.");
476     if (aQuoteEnd.toChar() <= 127 && aQuoteStart.toChar() > 127)
477         fprintf( stderr, "Warning: %s\n",
478                 "QuotationEnd is an ASCII character but QuotationStart is not.");
479     if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() > 127)
480         fprintf( stderr, "Warning: %s\n",
481                 "DoubleQuotationStart is an ASCII character but DoubleQuotationEnd is not.");
482     if (aDoubleQuoteEnd.toChar() <= 127 && aDoubleQuoteStart.toChar() > 127)
483         fprintf( stderr, "Warning: %s\n",
484                 "DoubleQuotationEnd is an ASCII character but DoubleQuotationStart is not.");
485     if (aQuoteStart.toChar() <= 127 && aQuoteEnd.toChar() <= 127)
486         fprintf( stderr, "Warning: %s\n",
487                 "QuotationStart and QuotationEnd are both ASCII characters. Not necessarily an error, but unusual.");
488     if (aDoubleQuoteStart.toChar() <= 127 && aDoubleQuoteEnd.toChar() <= 127)
489         fprintf( stderr, "Warning: %s\n",
490                 "DoubleQuotationStart and DoubleQuotationEnd are both ASCII characters. Not necessarily an error, but unusual.");
491     if (aQuoteStart == aQuoteEnd)
492         fprintf( stderr, "Warning: %s\n",
493                 "QuotationStart equals QuotationEnd. Not necessarily an error, but unusual.");
494     if (aDoubleQuoteStart == aDoubleQuoteEnd)
495         fprintf( stderr, "Warning: %s\n",
496                 "DoubleQuotationStart equals DoubleQuotationEnd. Not necessarily an error, but unusual.");
497     /* TODO: should equalness of single and double quotes be an error? Would
498      * need to adapt quite some locales' data. */
499     if (aQuoteStart == aDoubleQuoteStart)
500         fprintf( stderr, "Warning: %s\n",
501                 "QuotationStart equals DoubleQuotationStart. Not necessarily an error, but unusual.");
502     if (aQuoteEnd == aDoubleQuoteEnd)
503         fprintf( stderr, "Warning: %s\n",
504                 "QuotationEnd equals DoubleQuotationEnd. Not necessarily an error, but unusual.");
505     // Known good values, exclude ASCII single (U+0027, ') and double (U+0022, ") quotes.
506     int ic;
507     switch (ic = aQuoteStart.toChar())
508     {
509         case 0x2018:    // LEFT SINGLE QUOTATION MARK
510         case 0x201a:    // SINGLE LOW-9 QUOTATION MARK
511         case 0x201b:    // SINGLE HIGH-REVERSED-9 QUOTATION MARK
512         case 0x2039:    // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
513         case 0x203a:    // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
514         case 0x300c:    // LEFT CORNER BRACKET (Chinese)
515             ;
516             break;
517         default:
518             fprintf( stderr, "Warning: %s U+%04X %s\n",
519                     "QuotationStart may be wrong:", ic, OSTR( aQuoteStart));
520     }
521     switch (ic = aQuoteEnd.toChar())
522     {
523         case 0x2019:    // RIGHT SINGLE QUOTATION MARK
524         case 0x201a:    // SINGLE LOW-9 QUOTATION MARK
525         case 0x201b:    // SINGLE HIGH-REVERSED-9 QUOTATION MARK
526         case 0x2039:    // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
527         case 0x203a:    // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
528         case 0x300d:    // RIGHT CORNER BRACKET (Chinese)
529             ;
530             break;
531         default:
532             fprintf( stderr, "Warning: %s U+%04X %s\n",
533                     "QuotationEnd may be wrong:", ic, OSTR( aQuoteEnd));
534     }
535     switch (ic = aDoubleQuoteStart.toChar())
536     {
537         case 0x00ab:    // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
538         case 0x00bb:    // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
539         case 0x201c:    // LEFT DOUBLE QUOTATION MARK
540         case 0x201e:    // DOUBLE LOW-9 QUOTATION MARK
541         case 0x201f:    // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
542         case 0x300e:    // LEFT WHITE CORNER BRACKET (Chinese)
543             ;
544             break;
545         default:
546             fprintf( stderr, "Warning: %s U+%04X %s\n",
547                     "DoubleQuotationStart may be wrong:", ic, OSTR( aDoubleQuoteStart));
548     }
549     switch (ic = aDoubleQuoteEnd.toChar())
550     {
551         case 0x00ab:    // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
552         case 0x00bb:    // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
553         case 0x201d:    // RIGHT DOUBLE QUOTATION MARK
554         case 0x201e:    // DOUBLE LOW-9 QUOTATION MARK
555         case 0x201f:    // DOUBLE HIGH-REVERSED-9 QUOTATION MARK
556         case 0x300f:    // RIGHT WHITE CORNER BRACKET (Chinese)
557             ;
558             break;
559         default:
560             fprintf( stderr, "Warning: %s U+%04X %s\n",
561                     "DoubleQuotationEnd may be wrong:", ic, OSTR( aDoubleQuoteEnd));
562     }
563 
564 	writeParameterCheckLen( of, "TimeAM", "timeAM", 1, -1);
565 	writeParameterCheckLen( of, "TimePM", "timePM", 1, -1);
566 	sepNode = findNode("MeasurementSystem");
567 	of.writeParameter("measurementSystem", sepNode->getValue());
568 
569 	of.writeAsciiString("\nstatic const sal_Unicode* LCType[] = {\n");
570 	of.writeAsciiString("\tLC_CTYPE_Unoid,\n");
571 	of.writeAsciiString("\tdateSeparator,\n");
572 	of.writeAsciiString("\tthousandSeparator,\n");
573 	of.writeAsciiString("\tdecimalSeparator,\n");
574 	of.writeAsciiString("\ttimeSeparator,\n");
575 	of.writeAsciiString("\ttime100SecSeparator,\n");
576 	of.writeAsciiString("\tlistSeparator,\n");
577 	of.writeAsciiString("\tquotationStart,\n");
578 	of.writeAsciiString("\tquotationEnd,\n");
579 	of.writeAsciiString("\tdoubleQuotationStart,\n");
580 	of.writeAsciiString("\tdoubleQuotationEnd,\n");
581 	of.writeAsciiString("\ttimeAM,\n");
582 	of.writeAsciiString("\ttimePM,\n");
583 	of.writeAsciiString("\tmeasurementSystem,\n");
584 	of.writeAsciiString("\tLongDateDayOfWeekSeparator,\n");
585 	of.writeAsciiString("\tLongDateDaySeparator,\n");
586 	of.writeAsciiString("\tLongDateMonthSeparator,\n");
587 	of.writeAsciiString("\tLongDateYearSeparator\n");
588 	of.writeAsciiString("};\n\n");
589 	of.writeFunction("getLocaleItem_", "0", "LCType");
590 }
591 
592 
593 sal_Int16 LCFormatNode::mnSection = 0;
594 sal_Int16 LCFormatNode::mnFormats = 0;
595 
596 void LCFormatNode::generateCode (const OFileWriter &of) const
597 {
598     OUString str;
599     if (mnSection >= 2)
600         incError("more than 2 LC_FORMAT sections");
601     of.writeParameter("replaceFrom", getAttr() -> getValueByName("replaceFrom"), mnSection);
602     str = getAttr() -> getValueByName("replaceTo");
603     // Locale data generator inserts FFFF for LangID, we need to adapt that.
604     if (str.endsWithIgnoreAsciiCaseAsciiL( "-FFFF]", 6))
605         incErrorStr("replaceTo=\"%s\" needs FFFF to be adapted to the real LangID value.", str);
606     of.writeParameter("replaceTo", str, mnSection);
607     ::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
608     if (useLocale.getLength() > 0) {
609         switch (mnSection)
610         {
611             case 0:
612                 of.writeRefFunction("getAllFormats0_", useLocale, "replaceTo0");
613                 break;
614             case 1:
615                 of.writeRefFunction("getAllFormats1_", useLocale, "replaceTo1");
616                 break;
617         }
618         return;
619     }
620     sal_Int16 formatCount = mnFormats;
621     NameSet  aMsgIdSet;
622     ValueSet aFormatIndexSet;
623     NameSet  aDefaultsSet;
624     bool bCtypeIsRef = false;
625 
626     for (sal_Int16 i = 0; i< getNumberOfChildren() ; i++,formatCount++) {
627         LocaleNode * currNode = getChildAt (i);
628         OUString aUsage;
629         OUString aType;
630         OUString aFormatIndex;
631         //		currNode -> print();
632         const Attr *  currNodeAttr = currNode->getAttr();
633         //printf ("getLen() = %d\n", currNode->getAttr()->getLength());
634 
635         str = currNodeAttr -> getValueByName("msgid");
636         if (!aMsgIdSet.insert( str).second)
637             incErrorStr( "Duplicated msgid=\"%s\" in FormatElement.", str);
638         of.writeParameter("FormatKey", str, formatCount);
639 
640         str = currNodeAttr -> getValueByName("default");
641         bool bDefault = str.equalsAscii( "true");
642         of.writeDefaultParameter("FormatElement", str, formatCount);
643 
644         aType = currNodeAttr -> getValueByName("type");
645         of.writeParameter("FormatType", aType, formatCount);
646 
647         aUsage = currNodeAttr -> getValueByName("usage");
648         of.writeParameter("FormatUsage", aUsage, formatCount);
649 
650         aFormatIndex = currNodeAttr -> getValueByName("formatindex");
651         sal_Int16 formatindex = (sal_Int16)aFormatIndex.toInt32();
652         if (!aFormatIndexSet.insert( formatindex).second)
653             incErrorInt( "Duplicated formatindex=\"%d\" in FormatElement.", formatindex);
654         of.writeIntParameter("Formatindex", formatCount, formatindex);
655 
656         // Ensure only one default per usage and type.
657         if (bDefault)
658         {
659             OUString aKey( aUsage + OUString( sal_Unicode(',')) + aType);
660             if (!aDefaultsSet.insert( aKey).second)
661             {
662                 OUString aStr( RTL_CONSTASCII_USTRINGPARAM( "Duplicated default for usage=\""));
663                 aStr += aUsage;
664                 aStr += OUString( RTL_CONSTASCII_USTRINGPARAM( "\" type=\""));
665                 aStr += aType;
666                 aStr += OUString( RTL_CONSTASCII_USTRINGPARAM( "\": formatindex=\""));
667                 aStr += aFormatIndex;
668                 aStr += OUString( RTL_CONSTASCII_USTRINGPARAM( "\"."));
669                 incError( aStr);
670             }
671         }
672 
673         const LocaleNode * n = currNode -> findNode("FormatCode");
674         if (n)
675         {
676             of.writeParameter("FormatCode", n->getValue(), formatCount);
677             // Check separator usage for some FormatCode elements.
678             const LocaleNode* pCtype = 0;
679             switch (formatindex)
680             {
681                 case cssi::NumberFormatIndex::NUMBER_1000DEC2 : // #,##0.00
682                 case cssi::NumberFormatIndex::TIME_MMSS00 :     // MM:SS.00
683                 case cssi::NumberFormatIndex::TIME_HH_MMSS00 :  // [HH]:MM:SS.00
684                     {
685                         const LocaleNode* pRoot = getRoot();
686                         if (!pRoot)
687                             incError( "No root for FormatCode.");
688                         else
689                         {
690                             pCtype = pRoot->findNode( "LC_CTYPE");
691                             if (!pCtype)
692                                 incError( "No LC_CTYPE found for FormatCode.");
693                             else
694                             {
695                                 OUString aRef( pCtype->getAttr()->getValueByName("ref"));
696                                 if (aRef.getLength() > 0)
697                                 {
698                                     if (!bCtypeIsRef)
699                                         fprintf( stderr,
700                                                 "Warning: Can't check separators used in FormatCode due to LC_CTYPE ref=\"%s\".\n"
701                                                 "If these two locales use identical format codes, you should consider to use the ref= mechanism also for the LC_FORMAT element, together with replaceFrom= and replaceTo= for the currency.\n",
702                                                 OSTR( aRef));
703                                     bCtypeIsRef = true;
704                                     pCtype = 0;
705                                 }
706                             }
707                         }
708                     }
709                     break;
710                 // Currency formats should be something like [C]###0;-[C]###0
711                 // and not parenthesized [C]###0;([C]###0) if not en_US.
712                 case cssi::NumberFormatIndex::CURRENCY_1000INT :
713                 case cssi::NumberFormatIndex::CURRENCY_1000INT_RED :
714                 case cssi::NumberFormatIndex::CURRENCY_1000DEC2 :
715                 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_RED :
716                 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_CCC :
717                 case cssi::NumberFormatIndex::CURRENCY_1000DEC2_DASHED :
718                     if (strcmp( of.getLocale(), "en_US") != 0)
719                     {
720                         OUString aCode( n->getValue());
721                         OUString aPar1( RTL_CONSTASCII_USTRINGPARAM( "0)" ));
722                         OUString aPar2( RTL_CONSTASCII_USTRINGPARAM( "-)" ));
723                         OUString aPar3( RTL_CONSTASCII_USTRINGPARAM( " )" ));
724                         OUString aPar4( RTL_CONSTASCII_USTRINGPARAM( "])" ));
725                         if (aCode.indexOf( aPar1 ) > 0 || aCode.indexOf( aPar2 ) > 0 ||
726                                 aCode.indexOf( aPar3 ) > 0 || aCode.indexOf( aPar4 ) > 0)
727                             fprintf( stderr, "Warning: FormatCode formatindex=\"%d\" for currency uses parentheses for negative amounts, which probably is not correct for locales not based on en_US.\n", formatindex);
728                     }
729                     break;
730             }
731             if (pCtype)
732             {
733                 int nSavErr = nError;
734                 OUString aCode( n->getValue());
735                 if (formatindex == cssi::NumberFormatIndex::NUMBER_1000DEC2)
736                 {
737                     sal_Int32 nDec = -1;
738                     sal_Int32 nGrp = -1;
739                     const LocaleNode* pSep = pCtype->findNode( "DecimalSeparator");
740                     if (!pSep)
741                         incError( "No DecimalSeparator found for FormatCode.");
742                     else
743                     {
744                         nDec = aCode.indexOf( pSep->getValue());
745                         if (nDec < 0)
746                             incErrorInt( "DecimalSeparator not present in FormatCode formatindex=\"%d\".",
747                                     formatindex);
748                     }
749                     pSep = pCtype->findNode( "ThousandSeparator");
750                     if (!pSep)
751                         incError( "No ThousandSeparator found for FormatCode.");
752                     else
753                     {
754                         nGrp = aCode.indexOf( pSep->getValue());
755                         if (nGrp < 0)
756                             incErrorInt( "ThousandSeparator not present in FormatCode formatindex=\"%d\".",
757                                     formatindex);
758                     }
759                     if (nDec >= 0 && nGrp >= 0 && nDec <= nGrp)
760                         incErrorInt( "Ordering of ThousandSeparator and DecimalSeparator not correct in formatindex=\"%d\".",
761                                 formatindex);
762                 }
763                 if (formatindex == cssi::NumberFormatIndex::TIME_MMSS00 ||
764                         formatindex == cssi::NumberFormatIndex::TIME_HH_MMSS00)
765                 {
766                     sal_Int32 nTime = -1;
767                     sal_Int32 n100s = -1;
768                     const LocaleNode* pSep = pCtype->findNode( "TimeSeparator");
769                     if (!pSep)
770                         incError( "No TimeSeparator found for FormatCode.");
771                     else
772                     {
773                         nTime = aCode.indexOf( pSep->getValue());
774                         if (nTime < 0)
775                             incErrorInt( "TimeSeparator not present in FormatCode formatindex=\"%d\".",
776                                     formatindex);
777                     }
778                     pSep = pCtype->findNode( "Time100SecSeparator");
779                     if (!pSep)
780                         incError( "No Time100SecSeparator found for FormatCode.");
781                     else
782                     {
783                         n100s = aCode.indexOf( pSep->getValue());
784                         if (n100s < 0)
785                             incErrorInt( "Time100SecSeparator not present in FormatCode formatindex=\"%d\".",
786                                     formatindex);
787                         OUStringBuffer a100s( pSep->getValue());
788                         a100s.appendAscii( "00");
789                         n100s = aCode.indexOf( a100s.makeStringAndClear());
790                         if (n100s < 0)
791                             incErrorInt( "Time100SecSeparator+00 not present in FormatCode formatindex=\"%d\".",
792                                     formatindex);
793                     }
794                     if (n100s >= 0 && nTime >= 0 && n100s <= nTime)
795                         incErrorInt( "Ordering of Time100SecSeparator and TimeSeparator not correct in formatindex=\"%d\".",
796                                 formatindex);
797                 }
798                 if (nSavErr != nError)
799                     fprintf( stderr,
800                             "Warning: formatindex=\"%d\",\"%d\",\"%d\" are the only FormatCode elements checked for separator usage, there may be others that have errors.\n",
801                             int(cssi::NumberFormatIndex::NUMBER_1000DEC2),
802                             int(cssi::NumberFormatIndex::TIME_MMSS00),
803                             int(cssi::NumberFormatIndex::TIME_HH_MMSS00));
804 
805             }
806         }
807         else
808             incError( "No FormatCode in FormatElement.");
809         n = currNode -> findNode("DefaultName");
810         if (n)
811             of.writeParameter("FormatDefaultName", n->getValue(), formatCount);
812         else
813             of.writeParameter("FormatDefaultName", ::rtl::OUString(), formatCount);
814 
815     }
816 
817     // Check presence of all required format codes only in first section
818     // LC_FORMAT, not in optional LC_FORMAT_1
819     if (mnSection == 0)
820     {
821         // 0..47 MUST be present, 48,49 MUST NOT be present
822         ValueSet::const_iterator aIter( aFormatIndexSet.begin());
823         for (sal_Int16 nNext = cssi::NumberFormatIndex::NUMBER_START;
824                 nNext < cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES; ++nNext)
825         {
826             sal_Int16 nHere = ::std::min( ((aIter != aFormatIndexSet.end() ? *aIter :
827                     cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES)),
828                     cssi::NumberFormatIndex::INDEX_TABLE_ENTRIES);
829             if (aIter != aFormatIndexSet.end()) ++aIter;
830             for ( ; nNext < nHere; ++nNext)
831             {
832                 switch (nNext)
833                 {
834                     case cssi::NumberFormatIndex::FRACTION_1 :
835                     case cssi::NumberFormatIndex::FRACTION_2 :
836                     case cssi::NumberFormatIndex::BOOLEAN :
837                     case cssi::NumberFormatIndex::TEXT :
838                         // generated internally
839                         break;
840                     default:
841                         incErrorInt( "FormatElement formatindex=\"%d\" not present.", nNext);
842                 }
843             }
844             switch (nHere)
845             {
846                 case cssi::NumberFormatIndex::BOOLEAN :
847                     incErrorInt( "FormatElement formatindex=\"%d\" reserved for internal ``BOOLEAN''.", nNext);
848                     break;
849                 case cssi::NumberFormatIndex::TEXT :
850                     incErrorInt( "FormatElement formatindex=\"%d\" reserved for internal ``@'' (TEXT).", nNext);
851                     break;
852                 default:
853                     ;   // nothing
854             }
855         }
856     }
857 
858     of.writeAsciiString("\nstatic const sal_Int16 ");
859     of.writeAsciiString("FormatElementsCount");
860     of.writeInt(mnSection);
861     of.writeAsciiString(" = ");
862     of.writeInt( formatCount - mnFormats);
863     of.writeAsciiString(";\n");
864     of.writeAsciiString("static const sal_Unicode* ");
865     of.writeAsciiString("FormatElementsArray");
866     of.writeInt(mnSection);
867     of.writeAsciiString("[] = {\n");
868     for(sal_Int16 i = mnFormats; i < formatCount; i++) {
869 
870         of.writeAsciiString("\t");
871         of.writeAsciiString("FormatCode");
872         of.writeInt(i);
873         of.writeAsciiString(",\n");
874 
875         of.writeAsciiString("\t");
876         of.writeAsciiString("FormatDefaultName");
877         of.writeInt(i);
878         of.writeAsciiString(",\n");
879 
880         of.writeAsciiString("\t");
881         of.writeAsciiString("FormatKey");
882         of.writeInt(i);
883         of.writeAsciiString(",\n");
884 
885         of.writeAsciiString("\t");
886         of.writeAsciiString("FormatType");
887         of.writeInt(i);
888         of.writeAsciiString(",\n");
889 
890         of.writeAsciiString("\t");
891         of.writeAsciiString("FormatUsage");
892         of.writeInt(i);
893         of.writeAsciiString(",\n");
894 
895         of.writeAsciiString("\t");
896         of.writeAsciiString("Formatindex");
897         of.writeInt(i);
898         of.writeAsciiString(",\n");
899 
900 
901         of.writeAsciiString("\tdefaultFormatElement");
902         of.writeInt(i);
903         of.writeAsciiString(",\n");
904     }
905     of.writeAsciiString("};\n\n");
906 
907     switch (mnSection)
908     {
909         case 0:
910             of.writeFunction("getAllFormats0_", "FormatElementsCount0", "FormatElementsArray0", "replaceFrom0", "replaceTo0");
911             break;
912         case 1:
913             of.writeFunction("getAllFormats1_", "FormatElementsCount1", "FormatElementsArray1", "replaceFrom1", "replaceTo1");
914             break;
915     }
916 
917     mnFormats = mnFormats + formatCount;
918     ++mnSection;
919 }
920 
921 void LCCollationNode::generateCode (const OFileWriter &of) const
922 {
923 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
924 	if (useLocale.getLength() > 0) {
925 	    of.writeRefFunction("getCollatorImplementation_", useLocale);
926 	    of.writeRefFunction("getCollationOptions_", useLocale);
927 	    return;
928 	}
929 	sal_Int16 nbOfCollations = 0;
930 	sal_Int16 nbOfCollationOptions = 0;
931 	sal_Int16 j;
932 
933 	for ( j = 0; j < getNumberOfChildren(); j++ ) {
934 		LocaleNode * currNode = getChildAt (j);
935 		if( currNode->getName().compareToAscii("Collator") == 0 )
936 		{
937 			::rtl::OUString str;
938 			str = currNode->getAttr() -> getValueByName("unoid");
939 			of.writeParameter("CollatorID", str, j);
940 			str = currNode->getValue();
941 			of.writeParameter("CollatorRule", str, j);
942 			str = currNode -> getAttr() -> getValueByName("default");
943 			of.writeDefaultParameter("Collator", str, j);
944 			of.writeAsciiString("\n");
945 
946 			nbOfCollations++;
947 		}
948 		if( currNode->getName().compareToAscii("CollationOptions") == 0 )
949 		{
950 			LocaleNode* pCollationOptions = currNode;
951 			nbOfCollationOptions = sal::static_int_cast<sal_Int16>( pCollationOptions->getNumberOfChildren() );
952 			for( sal_Int16 i=0; i<nbOfCollationOptions; i++ )
953 			{
954 				of.writeParameter("collationOption", pCollationOptions->getChildAt( i )->getValue(), i );
955 			}
956 
957 			of.writeAsciiString("static const sal_Int16 nbOfCollationOptions = ");
958 			of.writeInt( nbOfCollationOptions );
959 			of.writeAsciiString(";\n\n");
960 		}
961 	}
962 	of.writeAsciiString("static const sal_Int16 nbOfCollations = ");
963 	of.writeInt(nbOfCollations);
964 	of.writeAsciiString(";\n\n");
965 
966 	of.writeAsciiString("\nstatic const sal_Unicode* LCCollatorArray[] = {\n");
967 	for(j = 0; j < nbOfCollations; j++) {
968 		of.writeAsciiString("\tCollatorID");
969 		of.writeInt(j);
970 		of.writeAsciiString(",\n");
971 
972 		of.writeAsciiString("\tdefaultCollator");
973 		of.writeInt(j);
974 		of.writeAsciiString(",\n");
975 
976         of.writeAsciiString("\tCollatorRule");
977         of.writeInt(j);
978         of.writeAsciiString(",\n");
979 	}
980 	of.writeAsciiString("};\n\n");
981 
982 	of.writeAsciiString("static const sal_Unicode* collationOptions[] = {");
983 	for( j=0; j<nbOfCollationOptions; j++ )
984 	{
985 		of.writeAsciiString( "collationOption" );
986 		of.writeInt( j );
987 		of.writeAsciiString( ", " );
988 	}
989 	of.writeAsciiString("NULL };\n");
990 	of.writeFunction("getCollatorImplementation_", "nbOfCollations", "LCCollatorArray");
991 	of.writeFunction("getCollationOptions_", "nbOfCollationOptions", "collationOptions");
992 }
993 
994 void LCSearchNode::generateCode (const OFileWriter &of) const
995 {
996 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
997 	if (useLocale.getLength() > 0) {
998 	    of.writeRefFunction("getSearchOptions_", useLocale);
999 	    return;
1000 	}
1001 
1002 	if( getNumberOfChildren() != 1 )
1003 	{
1004         ++nError;
1005         fprintf(
1006             stderr, "Error: LC_SEARCH: more than 1 child: %ld\n",
1007             sal::static_int_cast< long >(getNumberOfChildren()));
1008 	}
1009 	sal_Int32 i;
1010 	LocaleNode* pSearchOptions = getChildAt( 0 );
1011 	sal_Int32   nSearchOptions = pSearchOptions->getNumberOfChildren();
1012 	for( i=0; i<nSearchOptions; i++ )
1013 	{
1014 		of.writeParameter("searchOption", pSearchOptions->getChildAt( i )->getValue(), sal::static_int_cast<sal_Int16>(i) );
1015 	}
1016 
1017 	of.writeAsciiString("static const sal_Int16 nbOfSearchOptions = ");
1018 	of.writeInt( sal::static_int_cast<sal_Int16>( nSearchOptions ) );
1019 	of.writeAsciiString(";\n\n");
1020 
1021 	of.writeAsciiString("static const sal_Unicode* searchOptions[] = {");
1022 	for( i=0; i<nSearchOptions; i++ )
1023 	{
1024 		of.writeAsciiString( "searchOption" );
1025 		of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1026 		of.writeAsciiString( ", " );
1027 	}
1028 	of.writeAsciiString("NULL };\n");
1029 	of.writeFunction("getSearchOptions_", "nbOfSearchOptions", "searchOptions");
1030 }
1031 
1032 void LCIndexNode::generateCode (const OFileWriter &of) const
1033 {
1034 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1035 	if (useLocale.getLength() > 0) {
1036 	    of.writeRefFunction("getIndexAlgorithm_", useLocale);
1037 	    of.writeRefFunction("getUnicodeScripts_", useLocale);
1038 	    of.writeRefFunction("getFollowPageWords_", useLocale);
1039 	    return;
1040 	}
1041 	sal_Int16 nbOfIndexs = 0;
1042     sal_Int16 nbOfUnicodeScripts = 0;
1043 	sal_Int16 nbOfPageWords = 0;
1044     sal_Int16 i;
1045 	for (i = 0; i< getNumberOfChildren();i++) {
1046 		LocaleNode * currNode = getChildAt (i);
1047 		if( currNode->getName().compareToAscii("IndexKey") == 0 )
1048 		{
1049 			::rtl::OUString str;
1050 			str = currNode->getAttr() -> getValueByName("unoid");
1051 			of.writeParameter("IndexID", str, nbOfIndexs);
1052 			str = currNode->getAttr() -> getValueByName("module");
1053 			of.writeParameter("IndexModule", str, nbOfIndexs);
1054 			str = currNode->getValue();
1055 			of.writeParameter("IndexKey", str, nbOfIndexs);
1056 			str = currNode -> getAttr() -> getValueByName("default");
1057 			of.writeDefaultParameter("Index", str, nbOfIndexs);
1058 			str = currNode -> getAttr() -> getValueByName("phonetic");
1059 			of.writeDefaultParameter("Phonetic", str, nbOfIndexs);
1060 			of.writeAsciiString("\n");
1061 
1062 			nbOfIndexs++;
1063 		}
1064 		if( currNode->getName().compareToAscii("UnicodeScript") == 0 )
1065 		{
1066             of.writeParameter("unicodeScript", currNode->getValue(), nbOfUnicodeScripts );
1067             nbOfUnicodeScripts++;
1068 
1069 		}
1070 		if( currNode->getName().compareToAscii("FollowPageWord") == 0 )
1071         {
1072 			of.writeParameter("followPageWord", currNode->getValue(), nbOfPageWords);
1073             nbOfPageWords++;
1074         }
1075 	}
1076 	of.writeAsciiString("static const sal_Int16 nbOfIndexs = ");
1077 	of.writeInt(nbOfIndexs);
1078 	of.writeAsciiString(";\n\n");
1079 
1080 	of.writeAsciiString("\nstatic const sal_Unicode* IndexArray[] = {\n");
1081 	for(i = 0; i < nbOfIndexs; i++) {
1082 		of.writeAsciiString("\tIndexID");
1083 		of.writeInt(i);
1084 		of.writeAsciiString(",\n");
1085 
1086 		of.writeAsciiString("\tIndexModule");
1087 		of.writeInt(i);
1088 		of.writeAsciiString(",\n");
1089 
1090 		of.writeAsciiString("\tIndexKey");
1091 		of.writeInt(i);
1092 		of.writeAsciiString(",\n");
1093 
1094 		of.writeAsciiString("\tdefaultIndex");
1095 		of.writeInt(i);
1096 		of.writeAsciiString(",\n");
1097 
1098 		of.writeAsciiString("\tdefaultPhonetic");
1099 		of.writeInt(i);
1100 		of.writeAsciiString(",\n");
1101 	}
1102 	of.writeAsciiString("};\n\n");
1103 
1104     of.writeAsciiString("static const sal_Int16 nbOfUnicodeScripts = ");
1105     of.writeInt( nbOfUnicodeScripts );
1106     of.writeAsciiString(";\n\n");
1107 
1108 	of.writeAsciiString("static const sal_Unicode* UnicodeScriptArray[] = {");
1109 	for( i=0; i<nbOfUnicodeScripts; i++ )
1110 	{
1111 		of.writeAsciiString( "unicodeScript" );
1112 		of.writeInt( i );
1113 		of.writeAsciiString( ", " );
1114 	}
1115 	of.writeAsciiString("NULL };\n\n");
1116 
1117 	of.writeAsciiString("static const sal_Int16 nbOfPageWords = ");
1118 	of.writeInt(nbOfPageWords);
1119 	of.writeAsciiString(";\n\n");
1120 
1121 	of.writeAsciiString("static const sal_Unicode* FollowPageWordArray[] = {\n");
1122 	for(i = 0; i < nbOfPageWords; i++) {
1123 		of.writeAsciiString("\tfollowPageWord");
1124 		of.writeInt(i);
1125 		of.writeAsciiString(",\n");
1126 	}
1127 	of.writeAsciiString("\tNULL\n};\n\n");
1128 
1129 	of.writeFunction("getIndexAlgorithm_", "nbOfIndexs", "IndexArray");
1130 	of.writeFunction("getUnicodeScripts_", "nbOfUnicodeScripts", "UnicodeScriptArray");
1131 	of.writeFunction("getFollowPageWords_", "nbOfPageWords", "FollowPageWordArray");
1132 }
1133 
1134 void LCCalendarNode::generateCode (const OFileWriter &of) const
1135 {
1136     ::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1137     if (useLocale.getLength() > 0) {
1138         of.writeRefFunction("getAllCalendars_", useLocale);
1139         return;
1140     }
1141     sal_Int16 nbOfCalendars = sal::static_int_cast<sal_Int16>( getNumberOfChildren() );
1142     ::rtl::OUString str;
1143     sal_Int16 * nbOfDays = new sal_Int16[nbOfCalendars];
1144     sal_Int16 * nbOfMonths = new sal_Int16[nbOfCalendars];
1145     sal_Int16 * nbOfEras = new sal_Int16[nbOfCalendars];
1146     sal_Int16 j;
1147     sal_Int16 i;
1148     bool bHasGregorian = false;
1149 
1150 
1151     for ( i = 0; i < nbOfCalendars; i++) {
1152         LocaleNode * calNode = getChildAt (i);
1153         OUString calendarID = calNode -> getAttr() -> getValueByName("unoid");
1154         of.writeParameter( "calendarID", calendarID, i);
1155         bool bGregorian = calendarID.equalsAscii( "gregorian");
1156         if (!bHasGregorian)
1157             bHasGregorian = bGregorian;
1158         str = calNode -> getAttr() -> getValueByName("default");
1159         of.writeDefaultParameter("Calendar", str, i);
1160 
1161         // Generate Days of Week
1162         const sal_Char *elementTag;
1163         LocaleNode * daysNode = NULL;
1164         ::rtl::OUString ref_name = calNode->getChildAt(0)->getAttr()->getValueByName("ref");
1165         if (ref_name.getLength() > 0 && i > 0) {
1166             for (j = 0; j < i; j++) {
1167                 str = getChildAt(j)->getAttr()->getValueByName("unoid");
1168                 if (str.equals(ref_name))
1169                     daysNode = getChildAt(j)->getChildAt(0);
1170             }
1171         }
1172         if (ref_name.getLength() > 0 && daysNode == NULL) {
1173             of.writeParameter("dayRef", OUString::createFromAscii("ref"), i);
1174             of.writeParameter("dayRefName", ref_name, i);
1175             nbOfDays[i] = 0;
1176         } else {
1177             if (daysNode == NULL)
1178                 daysNode = calNode -> getChildAt(0);
1179             nbOfDays[i] = sal::static_int_cast<sal_Int16>( daysNode->getNumberOfChildren() );
1180             if (bGregorian && nbOfDays[i] != 7)
1181                 incErrorInt( "A Gregorian calendar must have 7 days per week, this one has %d", nbOfDays[i]);
1182             elementTag = "day";
1183             for (j = 0; j < nbOfDays[i]; j++) {
1184                 LocaleNode *currNode = daysNode -> getChildAt(j);
1185                 OUString dayID( currNode->getChildAt(0)->getValue());
1186                 of.writeParameter("dayID", dayID, i, j);
1187                 if (j == 0 && bGregorian && !dayID.equalsAscii( "sun"))
1188                     incError( "First day of a week of a Gregorian calendar must be <DayID>sun</DayID>");
1189                 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1190                 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1191             }
1192         }
1193 
1194         // Generate Months of Year
1195         LocaleNode * monthsNode = NULL;
1196         ref_name = calNode->getChildAt(1)->getAttr()->getValueByName("ref");
1197         if (ref_name.getLength() > 0 && i > 0) {
1198             for (j = 0; j < i; j++) {
1199                 str = getChildAt(j)->getAttr()->getValueByName("unoid");
1200                 if (str.equals(ref_name))
1201                     monthsNode = getChildAt(j)->getChildAt(1);
1202             }
1203         }
1204         if (ref_name.getLength() > 0 && monthsNode == NULL) {
1205             of.writeParameter("monthRef", OUString::createFromAscii("ref"), i);
1206             of.writeParameter("monthRefName", ref_name, i);
1207             nbOfMonths[i] = 0;
1208         } else {
1209             if (monthsNode == NULL)
1210                 monthsNode = calNode -> getChildAt(1);
1211             nbOfMonths[i] = sal::static_int_cast<sal_Int16>( monthsNode->getNumberOfChildren() );
1212             if (bGregorian && nbOfMonths[i] != 12)
1213                 incErrorInt( "A Gregorian calendar must have 12 months, this one has %d", nbOfMonths[i]);
1214             elementTag = "month";
1215             for (j = 0; j < nbOfMonths[i]; j++) {
1216                 LocaleNode *currNode = monthsNode -> getChildAt(j);
1217                 OUString monthID( currNode->getChildAt(0)->getValue());
1218                 of.writeParameter("monthID", monthID, i, j);
1219                 if (j == 0 && bGregorian && !monthID.equalsAscii( "jan"))
1220                     incError( "First month of a year of a Gregorian calendar must be <MonthID>jan</MonthID>");
1221                 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1222                 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1223             }
1224         }
1225 
1226         // Generate Era name
1227         LocaleNode * erasNode = NULL;
1228         ref_name =   calNode -> getChildAt(2) ->getAttr()->getValueByName("ref");
1229         if (ref_name.getLength() > 0 && i > 0) {
1230             for (j = 0; j < i; j++) {
1231                 str = getChildAt(j)->getAttr()->getValueByName("unoid");
1232                 if (str.equals(ref_name))
1233                     erasNode = getChildAt(j)->getChildAt(2);
1234             }
1235         }
1236         if (ref_name.getLength() > 0 && erasNode == NULL) {
1237             of.writeParameter("eraRef", OUString::createFromAscii("ref"), i);
1238             of.writeParameter("eraRefName", ref_name, i);
1239             nbOfEras[i] = 0;
1240         } else {
1241             if (erasNode == NULL)
1242                 erasNode = calNode -> getChildAt(2);
1243             nbOfEras[i] = sal::static_int_cast<sal_Int16>( erasNode->getNumberOfChildren() );
1244             if (bGregorian && nbOfEras[i] != 2)
1245                 incErrorInt( "A Gregorian calendar must have 2 eras, this one has %d", nbOfEras[i]);
1246             elementTag = "era";
1247             for (j = 0; j < nbOfEras[i]; j++) {
1248                 LocaleNode *currNode = erasNode -> getChildAt(j);
1249                 OUString eraID( currNode->getChildAt(0)->getValue());
1250                 of.writeParameter("eraID", eraID, i, j);
1251                 if (j == 0 && bGregorian && !eraID.equalsAscii( "bc"))
1252                     incError( "First era of a Gregorian calendar must be <EraID>bc</EraID>");
1253                 if (j == 1 && bGregorian && !eraID.equalsAscii( "ad"))
1254                     incError( "Second era of a Gregorian calendar must be <EraID>ad</EraID>");
1255                 of.writeAsciiString("\n");
1256                 of.writeParameter(elementTag, "DefaultAbbrvName",currNode->getChildAt(1)->getValue() ,i, j);
1257                 of.writeParameter(elementTag, "DefaultFullName",currNode->getChildAt(2)->getValue() , i, j);
1258             }
1259         }
1260         str = calNode->getChildAt(3)->getChildAt(0)->getValue();
1261         if (nbOfDays[i])
1262         {
1263             for (j = 0; j < nbOfDays[i]; j++)
1264             {
1265                 LocaleNode *currNode = daysNode->getChildAt(j);
1266                 OUString dayID( currNode->getChildAt(0)->getValue());
1267                 if (str == dayID)
1268                     break;  // for
1269             }
1270             if (j >= nbOfDays[i])
1271                 incErrorStr( "<StartDayOfWeek> <DayID> must be one of the <DaysOfWeek>, but is", str);
1272         }
1273         of.writeParameter("startDayOfWeek", str, i);
1274         str = calNode ->getChildAt(4)-> getValue();
1275         sal_Int16 nDays = sal::static_int_cast<sal_Int16>( str.toInt32() );
1276         if (nDays < 1 || (0 < nbOfDays[i] && nbOfDays[i] < nDays))
1277             incErrorInt( "Bad value of MinimalDaysInFirstWeek: %d, must be 1 <= value <= days_in_week",  nDays);
1278         of.writeIntParameter("minimalDaysInFirstWeek", i, nDays);
1279     }
1280     if (!bHasGregorian)
1281         fprintf( stderr, "Warning: %s\n", "No Gregorian calendar defined, are you sure?");
1282 
1283     of.writeAsciiString("static const sal_Int16 calendarsCount = ");
1284     of.writeInt(nbOfCalendars);
1285     of.writeAsciiString(";\n\n");
1286 
1287     of.writeAsciiString("static const sal_Unicode nbOfDays[] = {");
1288     for(i = 0; i < nbOfCalendars - 1; i++) {
1289         of.writeInt(nbOfDays[i]);
1290         of.writeAsciiString(", ");
1291     };
1292     of.writeInt(nbOfDays[i]);
1293     of.writeAsciiString("};\n");
1294 
1295     of.writeAsciiString("static const sal_Unicode nbOfMonths[] = {");
1296     for(i = 0; i < nbOfCalendars - 1; i++) {
1297         of.writeInt(nbOfMonths[i]);
1298         of.writeAsciiString(", ");
1299     };
1300     of.writeInt(nbOfMonths[i]);
1301     of.writeAsciiString("};\n");
1302 
1303     of.writeAsciiString("static const sal_Unicode nbOfEras[] = {");
1304     for(i = 0; i < nbOfCalendars - 1; i++) {
1305         of.writeInt(nbOfEras[i]);
1306         of.writeAsciiString(", ");
1307     };
1308     of.writeInt(nbOfEras[i]);
1309     of.writeAsciiString("};\n");
1310 
1311 
1312     of.writeAsciiString("static const sal_Unicode* calendars[] = {\n");
1313     of.writeAsciiString("\tnbOfDays,\n");
1314     of.writeAsciiString("\tnbOfMonths,\n");
1315     of.writeAsciiString("\tnbOfEras,\n");
1316     for(i = 0; i < nbOfCalendars; i++) {
1317         of.writeAsciiString("\tcalendarID");
1318         of.writeInt(i);
1319         of.writeAsciiString(",\n");
1320         of.writeAsciiString("\tdefaultCalendar");
1321         of.writeInt(i);
1322         of.writeAsciiString(",\n");
1323         if (nbOfDays[i] == 0) {
1324             of.writeAsciiString("\tdayRef");
1325             of.writeInt(i); of.writeAsciiString(",\n");
1326             of.writeAsciiString("\tdayRefName");
1327             of.writeInt(i); of.writeAsciiString(",\n");
1328         } else {
1329             for(j = 0; j < nbOfDays[i]; j++) {
1330                 of.writeAsciiString("\tdayID");
1331                 of.writeInt(i);	of.writeInt(j);	of.writeAsciiString(",\n");
1332                 of.writeAsciiString("\tdayDefaultAbbrvName");
1333                 of.writeInt(i);	of.writeInt(j);	of.writeAsciiString(",\n");
1334                 of.writeAsciiString("\tdayDefaultFullName");of.writeInt(i);	of.writeInt(j);	of.writeAsciiString(",\n");
1335             }
1336         }
1337         if (nbOfMonths[i] == 0) {
1338             of.writeAsciiString("\tmonthRef");
1339             of.writeInt(i); of.writeAsciiString(",\n");
1340             of.writeAsciiString("\tmonthRefName");
1341             of.writeInt(i); of.writeAsciiString(",\n");
1342         } else {
1343             for(j = 0; j < nbOfMonths[i]; j++) {
1344                 of.writeAsciiString("\tmonthID");of.writeInt(i);of.writeInt(j);of.writeAsciiString(",\n");
1345                 of.writeAsciiString("\tmonthDefaultAbbrvName");of.writeInt(i);of.writeInt(j);of.writeAsciiString(",\n");
1346                 of.writeAsciiString("\tmonthDefaultFullName");of.writeInt(i);of.writeInt(j);of.writeAsciiString(",\n");
1347             }
1348         }
1349         if (nbOfEras[i] == 0) {
1350             of.writeAsciiString("\teraRef");
1351             of.writeInt(i); of.writeAsciiString(",\n");
1352             of.writeAsciiString("\teraRefName");
1353             of.writeInt(i); of.writeAsciiString(",\n");
1354         } else {
1355             for(j = 0; j < nbOfEras[i]; j++) {
1356                 of.writeAsciiString("\teraID");	of.writeInt(i);	of.writeInt(j);	of.writeAsciiString(",\n");
1357                 of.writeAsciiString("\teraDefaultAbbrvName");of.writeInt(i);of.writeInt(j);of.writeAsciiString(",\n");
1358                 of.writeAsciiString("\teraDefaultFullName");of.writeInt(i);of.writeInt(j);of.writeAsciiString(",\n");
1359             }
1360         }
1361         of.writeAsciiString("\tstartDayOfWeek");of.writeInt(i);	of.writeAsciiString(",\n");
1362         of.writeAsciiString("\tminimalDaysInFirstWeek");of.writeInt(i);	of.writeAsciiString(",\n");
1363     }
1364 
1365     of.writeAsciiString("};\n\n");
1366     of.writeFunction("getAllCalendars_", "calendarsCount", "calendars");
1367 
1368     delete []nbOfDays;
1369     delete []nbOfMonths;
1370     delete []nbOfEras;
1371 }
1372 
1373 bool isIso4217( const OUString& rStr )
1374 {
1375     const sal_Unicode* p = rStr.getStr();
1376     return rStr.getLength() == 3
1377         && 'A' <= p[0] && p[0] <= 'Z'
1378         && 'A' <= p[1] && p[1] <= 'Z'
1379         && 'A' <= p[2] && p[2] <= 'Z'
1380         ;
1381 }
1382 
1383 void LCCurrencyNode :: generateCode (const OFileWriter &of) const
1384 {
1385 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1386 	if (useLocale.getLength() > 0) {
1387 	    of.writeRefFunction("getAllCurrencies_", useLocale);
1388 	    return;
1389 	}
1390 	sal_Int16 nbOfCurrencies = 0;
1391 	::rtl::OUString str;
1392 	sal_Int16 i;
1393 
1394     bool bTheDefault= false;
1395     bool bTheCompatible = false;
1396 	for ( i = 0; i < getNumberOfChildren(); i++,nbOfCurrencies++) {
1397 		LocaleNode * calNode = getChildAt (i);
1398         str = calNode->getAttr() -> getValueByName("default");
1399 		bool bDefault = of.writeDefaultParameter("Currency", str, nbOfCurrencies);
1400         str = calNode->getAttr() -> getValueByName("usedInCompatibleFormatCodes");
1401         bool bCompatible = of.writeDefaultParameter("CurrencyUsedInCompatibleFormatCodes", str, nbOfCurrencies);
1402         str = calNode->getAttr() -> getValueByName("legacyOnly");
1403         bool bLegacy = of.writeDefaultParameter("CurrencyLegacyOnly", str, nbOfCurrencies);
1404         if (bLegacy && (bDefault || bCompatible))
1405             incError( "Currency: if legacyOnly==true, both 'default' and 'usedInCompatibleFormatCodes' must be false.");
1406         if (bDefault)
1407         {
1408             if (bTheDefault)
1409                 incError( "Currency: more than one default currency.");
1410             bTheDefault = true;
1411         }
1412         if (bCompatible)
1413         {
1414             if (bTheCompatible)
1415                 incError( "Currency: more than one currency flagged as usedInCompatibleFormatCodes.");
1416             bTheCompatible = true;
1417         }
1418 		str = calNode -> findNode ("CurrencyID") -> getValue();
1419 		of.writeParameter("currencyID", str, nbOfCurrencies);
1420         // CurrencyID MUST be ISO 4217.
1421         if (!bLegacy && !isIso4217(str))
1422             incError( "CurrencyID is not ISO 4217");
1423 		str = calNode -> findNode ("CurrencySymbol") -> getValue();
1424 		of.writeParameter("currencySymbol", str, nbOfCurrencies);
1425 		str = calNode -> findNode ("BankSymbol") -> getValue();
1426 		of.writeParameter("bankSymbol", str, nbOfCurrencies);
1427         // BankSymbol currently must be ISO 4217. May change later if
1428         // application always uses CurrencyID instead of BankSymbol.
1429         if (!bLegacy && !isIso4217(str))
1430             incError( "BankSymbol is not ISO 4217");
1431 		str = calNode -> findNode ("CurrencyName") -> getValue();
1432 		of.writeParameter("currencyName", str, nbOfCurrencies);
1433         str = calNode -> findNode ("DecimalPlaces") -> getValue();
1434         sal_Int16 nDecimalPlaces = (sal_Int16)str.toInt32();
1435         of.writeIntParameter("currencyDecimalPlaces", nbOfCurrencies, nDecimalPlaces);
1436 		of.writeAsciiString("\n");
1437 	};
1438 
1439     if (!bTheDefault)
1440         incError( "Currency: no default currency.");
1441     if (!bTheCompatible)
1442         incError( "Currency: no currency flagged as usedInCompatibleFormatCodes.");
1443 
1444 	of.writeAsciiString("static const sal_Int16 currencyCount = ");
1445 	of.writeInt(nbOfCurrencies);
1446 	of.writeAsciiString(";\n\n");
1447 	of.writeAsciiString("static const sal_Unicode* currencies[] = {\n");
1448 	for(i = 0; i < nbOfCurrencies; i++) {
1449 		of.writeAsciiString("\tcurrencyID");
1450 		of.writeInt(i);
1451 		of.writeAsciiString(",\n");
1452 		of.writeAsciiString("\tcurrencySymbol");
1453 		of.writeInt(i);
1454 		of.writeAsciiString(",\n");
1455 		of.writeAsciiString("\tbankSymbol");
1456 		of.writeInt(i);
1457 		of.writeAsciiString(",\n");
1458 		of.writeAsciiString("\tcurrencyName");
1459 		of.writeInt(i);
1460 		of.writeAsciiString(",\n");
1461 		of.writeAsciiString("\tdefaultCurrency");
1462 		of.writeInt(i);
1463 		of.writeAsciiString(",\n");
1464         of.writeAsciiString("\tdefaultCurrencyUsedInCompatibleFormatCodes");
1465 		of.writeInt(i);
1466 		of.writeAsciiString(",\n");
1467         of.writeAsciiString("\tcurrencyDecimalPlaces");
1468 		of.writeInt(i);
1469 		of.writeAsciiString(",\n");
1470 		of.writeAsciiString("\tdefaultCurrencyLegacyOnly");
1471 		of.writeInt(i);
1472 		of.writeAsciiString(",\n");
1473 	}
1474 	of.writeAsciiString("};\n\n");
1475 	of.writeFunction("getAllCurrencies_", "currencyCount", "currencies");
1476 }
1477 
1478 void LCTransliterationNode::generateCode (const OFileWriter &of) const
1479 {
1480 	::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1481 	if (useLocale.getLength() > 0) {
1482 	    of.writeRefFunction("getTransliterations_", useLocale);
1483 	    return;
1484 	}
1485 	sal_Int16 nbOfModules = 0;
1486 	::rtl::OUString str;
1487 	sal_Int16 i;
1488 
1489 	for ( i = 0; i < getNumberOfChildren(); i++,nbOfModules++) {
1490 		LocaleNode * calNode = getChildAt (i);
1491 		str = calNode->getAttr() -> getValueByIndex(0);
1492 		of.writeParameter("Transliteration", str, nbOfModules);
1493 	}
1494 	of.writeAsciiString("static const sal_Int16 nbOfTransliterations = ");
1495 	of.writeInt(nbOfModules);
1496 	of.writeAsciiString(";\n\n");
1497 
1498 	of.writeAsciiString("\nstatic const sal_Unicode* LCTransliterationsArray[] = {\n");
1499 	for( i = 0; i < nbOfModules; i++) {
1500 		of.writeAsciiString("\tTransliteration");
1501 		of.writeInt(i);
1502 		of.writeAsciiString(",\n");
1503 	}
1504 	of.writeAsciiString("};\n\n");
1505 	of.writeFunction("getTransliterations_", "nbOfTransliterations", "LCTransliterationsArray");
1506 }
1507 
1508 struct NameValuePair {
1509 	const sal_Char *name;
1510 	const sal_Char *value;
1511 };
1512 static NameValuePair ReserveWord[] = {
1513 	{ "trueWord", "true" },
1514 	{ "falseWord", "false" },
1515 	{ "quarter1Word", "1st quarter" },
1516 	{ "quarter2Word", "2nd quarter" },
1517 	{ "quarter3Word", "3rd quarter" },
1518 	{ "quarter4Word", "4th quarter" },
1519 	{ "aboveWord", "above" },
1520 	{ "belowWord", "below" },
1521 	{ "quarter1Abbreviation", "Q1" },
1522 	{ "quarter2Abbreviation", "Q2" },
1523 	{ "quarter3Abbreviation", "Q3" },
1524 	{ "quarter4Abbreviation", "Q4" }
1525 };
1526 
1527 void LCMiscNode::generateCode (const OFileWriter &of) const
1528 {
1529     ::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1530     if (useLocale.getLength() > 0) {
1531 	of.writeRefFunction("getForbiddenCharacters_", useLocale);
1532 	of.writeRefFunction("getBreakIteratorRules_", useLocale);
1533 	of.writeRefFunction("getReservedWords_", useLocale);
1534 	return;
1535     }
1536     const LocaleNode * reserveNode = findNode("ReservedWords");
1537     if (!reserveNode)
1538         incError( "No ReservedWords element."); // should not happen if validated..
1539     const LocaleNode * forbidNode = findNode("ForbiddenCharacters");
1540     const LocaleNode * breakNode = findNode("BreakIteratorRules");
1541 
1542     bool bEnglishLocale = (strncmp( of.getLocale(), "en_", 3) == 0);
1543 
1544     sal_Int16 nbOfWords = 0;
1545 	::rtl::OUString str;
1546 	sal_Int16 i;
1547 
1548 	for ( i = 0; i < sal_Int16(sizeof(ReserveWord)/sizeof(ReserveWord[0])); i++,nbOfWords++) {
1549         const LocaleNode * curNode = (reserveNode ? reserveNode->findNode(
1550                     ReserveWord[i].name) : 0);
1551         if (!curNode)
1552             fprintf( stderr,
1553                     "Warning: No %s in ReservedWords, using en_US default: \"%s\".\n",
1554                     ReserveWord[i].name, ReserveWord[i].value);
1555         str = curNode ? curNode -> getValue() : OUString::createFromAscii(ReserveWord[i].value);
1556         if (!str.getLength())
1557         {
1558             ++nError;
1559             fprintf( stderr, "Error: No content for ReservedWords %s.\n", ReserveWord[i].name);
1560         }
1561         of.writeParameter("ReservedWord", str, nbOfWords);
1562         // "true", ..., "below" trigger untranslated warning.
1563         if (!bEnglishLocale && curNode && (0 <= i && i <= 7) &&
1564                 str.equalsIgnoreAsciiCaseAscii( ReserveWord[i].value))
1565         {
1566             fprintf( stderr,
1567                     "Warning: ReservedWord %s seems to be untranslated \"%s\".\n",
1568                     ReserveWord[i].name, ReserveWord[i].value);
1569         }
1570     }
1571     of.writeAsciiString("static const sal_Int16 nbOfReservedWords = ");
1572 	of.writeInt(nbOfWords);
1573 	of.writeAsciiString(";\n\n");
1574 	of.writeAsciiString("\nstatic const sal_Unicode* LCReservedWordsArray[] = {\n");
1575 	for( i = 0; i < nbOfWords; i++) {
1576 		of.writeAsciiString("\tReservedWord");
1577 		of.writeInt(i);
1578 		of.writeAsciiString(",\n");
1579 	}
1580 	of.writeAsciiString("};\n\n");
1581 	of.writeFunction("getReservedWords_", "nbOfReservedWords", "LCReservedWordsArray");
1582 
1583     if (forbidNode)    {
1584      	of.writeParameter( "forbiddenBegin", forbidNode -> getChildAt(0)->getValue());
1585      	of.writeParameter( "forbiddenEnd", forbidNode -> getChildAt(1)->getValue());
1586      	of.writeParameter( "hangingChars", forbidNode -> getChildAt(2)->getValue());
1587     } else {
1588      	of.writeParameter( "forbiddenBegin", ::rtl::OUString());
1589      	of.writeParameter( "forbiddenEnd", ::rtl::OUString());
1590      	of.writeParameter( "hangingChars", ::rtl::OUString());
1591     }
1592 	of.writeAsciiString("\nstatic const sal_Unicode* LCForbiddenCharactersArray[] = {\n");
1593 	of.writeAsciiString("\tforbiddenBegin,\n");
1594 	of.writeAsciiString("\tforbiddenEnd,\n");
1595 	of.writeAsciiString("\thangingChars\n");
1596 	of.writeAsciiString("};\n\n");
1597 	of.writeFunction("getForbiddenCharacters_", "3", "LCForbiddenCharactersArray");
1598 
1599     if (breakNode) {
1600      	of.writeParameter( "EditMode", breakNode -> getChildAt(0)->getValue());
1601      	of.writeParameter( "DictionaryMode", breakNode -> getChildAt(1)->getValue());
1602      	of.writeParameter( "WordCountMode", breakNode -> getChildAt(2)->getValue());
1603      	of.writeParameter( "CharacterMode", breakNode -> getChildAt(3)->getValue());
1604      	of.writeParameter( "LineMode", breakNode -> getChildAt(4)->getValue());
1605     } else {
1606      	of.writeParameter( "EditMode", ::rtl::OUString());
1607      	of.writeParameter( "DictionaryMode", ::rtl::OUString());
1608      	of.writeParameter( "WordCountMode", ::rtl::OUString());
1609      	of.writeParameter( "CharacterMode", ::rtl::OUString());
1610      	of.writeParameter( "LineMode", ::rtl::OUString());
1611     }
1612 	of.writeAsciiString("\nstatic const sal_Unicode* LCBreakIteratorRulesArray[] = {\n");
1613 	of.writeAsciiString("\tEditMode,\n");
1614 	of.writeAsciiString("\tDictionaryMode,\n");
1615 	of.writeAsciiString("\tWordCountMode,\n");
1616 	of.writeAsciiString("\tCharacterMode,\n");
1617 	of.writeAsciiString("\tLineMode\n");
1618 	of.writeAsciiString("};\n\n");
1619 	of.writeFunction("getBreakIteratorRules_", "5", "LCBreakIteratorRulesArray");
1620 
1621 }
1622 
1623 void LCNumberingLevelNode::generateCode (const OFileWriter &of) const
1624 {
1625      of.writeAsciiString("// ---> ContinuousNumbering\n");
1626     ::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1627     if (useLocale.getLength() > 0) {
1628 	of.writeRefFunction2("getContinuousNumberingLevels_", useLocale);
1629 	return;
1630     }
1631 
1632      // hard code number of attributes per style.
1633      const int   nAttributes = 5;
1634      const char* attr[ nAttributes ] = { "Prefix", "NumType", "Suffix", "Transliteration", "NatNum" };
1635 
1636      // record each attribute of each style in a static C++ variable.
1637      // determine number of styles on the fly.
1638      sal_Int32 nStyles = getNumberOfChildren();
1639      sal_Int32 i;
1640 
1641      for( i = 0; i < nStyles; i++ )
1642      {
1643           const Attr* q = getChildAt( i )->getAttr();
1644           for( sal_Int32 j=0; j<nAttributes; j++ )
1645           {
1646                const char* name = attr[j];
1647                OUString   value = q->getValueByName( name );
1648                of.writeParameter("continuous", name, value, sal::static_int_cast<sal_Int16>(i) );
1649           }
1650      }
1651 
1652      // record number of styles and attributes.
1653      of.writeAsciiString("static const sal_Int16 continuousNbOfStyles = ");
1654      of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
1655      of.writeAsciiString(";\n\n");
1656      of.writeAsciiString("static const sal_Int16 continuousNbOfAttributesPerStyle = ");
1657      of.writeInt( nAttributes );
1658      of.writeAsciiString(";\n\n");
1659 
1660      // generate code. (intermediate arrays)
1661      for( i=0; i<nStyles; i++ )
1662      {
1663           of.writeAsciiString("\nstatic const sal_Unicode* continuousStyle" );
1664           of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1665           of.writeAsciiString("[] = {\n");
1666           for( sal_Int32 j=0; j<nAttributes; j++)
1667           {
1668                of.writeAsciiString("\t");
1669                of.writeAsciiString( "continuous" );
1670                of.writeAsciiString( attr[j] );
1671                of.writeInt(sal::static_int_cast<sal_Int16>(i));
1672                of.writeAsciiString(",\n");
1673           }
1674           of.writeAsciiString("\t0\n};\n\n");
1675      }
1676 
1677      // generate code. (top-level array)
1678      of.writeAsciiString("\n");
1679      of.writeAsciiString("static const sal_Unicode** LCContinuousNumberingLevelsArray[] = {\n" );
1680      for( i=0; i<nStyles; i++ )
1681      {
1682           of.writeAsciiString( "\t" );
1683           of.writeAsciiString( "continuousStyle" );
1684           of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1685           of.writeAsciiString( ",\n");
1686      }
1687      of.writeAsciiString("\t0\n};\n\n");
1688      of.writeFunction2("getContinuousNumberingLevels_", "continuousNbOfStyles",
1689 			"continuousNbOfAttributesPerStyle", "LCContinuousNumberingLevelsArray");
1690 }
1691 
1692 
1693 void LCOutlineNumberingLevelNode::generateCode (const OFileWriter &of) const
1694 {
1695      of.writeAsciiString("// ---> OutlineNumbering\n");
1696     ::rtl::OUString useLocale =   getAttr() -> getValueByName("ref");
1697     if (useLocale.getLength() > 0) {
1698 	of.writeRefFunction3("getOutlineNumberingLevels_", useLocale);
1699 	return;
1700     }
1701 
1702      // hardcode number of attributes per level
1703      const int   nAttributes = 11;
1704      const char* attr[ nAttributes ] =
1705      {
1706           "Prefix",
1707           "NumType",
1708           "Suffix",
1709           "BulletChar",
1710           "BulletFontName",
1711           "ParentNumbering",
1712           "LeftMargin",
1713           "SymbolTextDistance",
1714           "FirstLineOffset",
1715           "Transliteration",
1716           "NatNum",
1717      };
1718 
1719      // record each attribute of each level of each style in a static C++ variable.
1720      // determine number of styles and number of levels per style on the fly.
1721      sal_Int32 nStyles = getNumberOfChildren();
1722      vector<sal_Int32> nLevels; // may be different for each style?
1723      for( sal_Int32 i = 0; i < nStyles; i++ )
1724      {
1725           LocaleNode* p = getChildAt( i );
1726           nLevels.push_back( p->getNumberOfChildren() );
1727           for( sal_Int32 j=0; j<nLevels.back(); j++ )
1728           {
1729                const Attr* q = p->getChildAt( j )->getAttr();
1730                for( sal_Int32 k=0; k<nAttributes; k++ )
1731                {
1732                     const char* name = attr[k];
1733                     OUString   value = q->getValueByName( name );
1734                     of.writeParameter("outline", name, value,
1735                                         sal::static_int_cast<sal_Int16>(i),
1736                                         sal::static_int_cast<sal_Int16>(j) );
1737                }
1738           }
1739      }
1740 
1741      // verify that each style has the same number of levels.
1742      for( size_t i=0; i<nLevels.size(); i++ )
1743      {
1744           if( nLevels[0] != nLevels[i] )
1745           {
1746                incError( "Numbering levels don't match.");
1747           }
1748      }
1749 
1750      // record number of attributes, levels, and styles.
1751      of.writeAsciiString("static const sal_Int16 outlineNbOfStyles = ");
1752      of.writeInt( sal::static_int_cast<sal_Int16>( nStyles ) );
1753      of.writeAsciiString(";\n\n");
1754      of.writeAsciiString("static const sal_Int16 outlineNbOfLevelsPerStyle = ");
1755      of.writeInt( sal::static_int_cast<sal_Int16>( nLevels.back() ) );
1756      of.writeAsciiString(";\n\n");
1757      of.writeAsciiString("static const sal_Int16 outlineNbOfAttributesPerLevel = ");
1758      of.writeInt( nAttributes );
1759      of.writeAsciiString(";\n\n");
1760 
1761      // too complicated for now...
1762 //     of.writeAsciiString("static const sal_Int16 nbOfOutlineNumberingLevels[] = { ");
1763 //     for( sal_Int32 j=0; j<nStyles; j++ )
1764 //     {
1765 //          of.writeInt( nLevels[j] );
1766 //          of.writeAsciiString(", ");
1767 //     }
1768 //     of.writeAsciiString("};\n\n");
1769 
1770 
1771      for( sal_Int32 i=0; i<nStyles; i++ )
1772      {
1773           for( sal_Int32 j=0; j<nLevels.back(); j++ )
1774           {
1775                of.writeAsciiString("static const sal_Unicode* outline");
1776                of.writeAsciiString("Style");
1777                of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1778                of.writeAsciiString("Level");
1779                of.writeInt( sal::static_int_cast<sal_Int16>(j) );
1780                of.writeAsciiString("[] = { ");
1781 
1782                for( sal_Int32 k=0; k<nAttributes; k++ )
1783                {
1784                     of.writeAsciiString( "outline" );
1785                     of.writeAsciiString( attr[k] );
1786                     of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1787                     of.writeInt( sal::static_int_cast<sal_Int16>(j) );
1788                     of.writeAsciiString(", ");
1789                }
1790                of.writeAsciiString("NULL };\n");
1791           }
1792      }
1793 
1794      of.writeAsciiString("\n");
1795 
1796 
1797      for( sal_Int32 i=0; i<nStyles; i++ )
1798      {
1799           of.writeAsciiString("static const sal_Unicode** outline");
1800           of.writeAsciiString( "Style" );
1801           of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1802           of.writeAsciiString("[] = { ");
1803 
1804           for( sal_Int32 j=0; j<nLevels.back(); j++ )
1805           {
1806                of.writeAsciiString("outlineStyle");
1807                of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1808                of.writeAsciiString("Level");
1809                of.writeInt( sal::static_int_cast<sal_Int16>(j) );
1810                of.writeAsciiString(", ");
1811           }
1812           of.writeAsciiString("NULL };\n");
1813      }
1814      of.writeAsciiString("\n");
1815 
1816      of.writeAsciiString("static const sal_Unicode*** LCOutlineNumberingLevelsArray[] = {\n" );
1817      for( sal_Int32 i=0; i<nStyles; i++ )
1818      {
1819           of.writeAsciiString( "\t" );
1820           of.writeAsciiString( "outlineStyle" );
1821           of.writeInt( sal::static_int_cast<sal_Int16>(i) );
1822           of.writeAsciiString(",\n");
1823      }
1824      of.writeAsciiString("\tNULL\n};\n\n");
1825      of.writeFunction3("getOutlineNumberingLevels_", "outlineNbOfStyles", "outlineNbOfLevelsPerStyle",
1826 			"outlineNbOfAttributesPerLevel", "LCOutlineNumberingLevelsArray");
1827 }
1828 
1829 Attr::Attr (const Reference< XAttributeList > & attr) {
1830 	sal_Int16 len = attr->getLength();
1831 	name.realloc (len);
1832 	value.realloc (len);
1833 	for (sal_Int16 i =0; i< len;i++) {
1834 		name[i] = attr->getNameByIndex(i);
1835 		value[i] = attr -> getValueByIndex(i);
1836 	}
1837 }
1838 
1839 const OUString& Attr::getValueByName (const sal_Char *str) const {
1840     static OUString empty;
1841 	sal_Int32 len = name.getLength();
1842 	for (sal_Int32 i = 0;i<len;i++)
1843 		if (name[i].equalsAscii(str))
1844 			return value[i];
1845 	return empty;
1846 }
1847 
1848 sal_Int32 Attr::getLength() const{
1849 	return name.getLength();
1850 }
1851 
1852 const OUString& Attr::getTypeByIndex (sal_Int32 idx) const {
1853 	return name[idx];
1854 }
1855 
1856 const OUString& Attr::getValueByIndex (sal_Int32 idx) const
1857 {
1858 	return value[idx];
1859 }
1860