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