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 #include "oox/xls/numberformatsbuffer.hxx"
29 
30 #include <com/sun/star/container/XNameAccess.hpp>
31 #include <com/sun/star/i18n/NumberFormatIndex.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/util/XNumberFormatTypes.hpp>
34 #include <com/sun/star/util/XNumberFormats.hpp>
35 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
36 #include <rtl/strbuf.hxx>
37 #include <rtl/string.hxx>
38 #include <osl/thread.h>
39 #include <rtl/ustrbuf.hxx>
40 #include "oox/core/filterbase.hxx"
41 #include "oox/helper/attributelist.hxx"
42 #include "oox/helper/propertymap.hxx"
43 #include "oox/xls/biffinputstream.hxx"
44 
45 namespace oox {
46 namespace xls {
47 
48 // ============================================================================
49 
50 using namespace ::com::sun::star::container;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::util;
54 
55 using ::rtl::OString;
56 using ::rtl::OStringBuffer;
57 using ::rtl::OStringToOUString;
58 using ::rtl::OUString;
59 using ::rtl::OUStringBuffer;
60 
61 // ============================================================================
62 
63 namespace {
64 
65 /** Stores the number format used in Calc for an Excel built-in number format. */
66 struct BuiltinFormat
67 {
68     sal_Int32           mnNumFmtId;         /// Built-in number format index.
69     const sal_Char*     mpcFmtCode;         /// Format string, UTF-8, may be 0 (mnPredefId is used then).
70     sal_Int16           mnPredefId;         /// Predefined format index, if mpcFmtCode is 0.
71     sal_Int32           mnReuseId;          /// Use this format, if mpcFmtCode is 0 and mnPredefId is -1.
72 };
73 
74 /** Defines a literal built-in number format. */
75 #define NUMFMT_STRING( INDEX, FORMATCODE ) \
76     { INDEX, FORMATCODE, -1, -1 }
77 
78 /** Defines a built-in number format that maps to an own predefined format. */
79 #define NUMFMT_PREDEF( INDEX, PREDEFINED ) \
80     { INDEX, 0, ::com::sun::star::i18n::NumberFormatIndex::PREDEFINED, -1 }
81 
82 /** Defines a built-in number format that is the same as the specified in nReuseId. */
83 #define NUMFMT_REUSE( INDEX, REUSED_INDEX ) \
84     { INDEX, 0, -1, REUSED_INDEX }
85 
86 /** Terminates a built-in number format table. */
87 #define NUMFMT_ENDTABLE() \
88     { -1, 0, -1, -1 }
89 
90 /** Defines builtin date and time formats 14...22.
91     @param SYSTEMDATE  Complete short system date (for formats 14 and 22).
92     @param DAY  Day format (for formats 15 and 16).
93     @param DAYSEP  Separator between day and month (for formats 15 and 16).
94     @param MONTH  Month format (for formats 15...17).
95     @param MONTHSEP  Separator between month and year (for formats 15 and 17).
96     @param YEAR  Year format (for formats 15 and 17).
97     @param HOUR12  Hour format for 12-hour AM/PM formats (formats 18 and 19).
98     @param HOUR24  Hour format for 24-hour formats (formats 20...22). */
99 #define NUMFMT_ALLDATETIMES( SYSTEMDATE, DAY, DAYSEP, MONTH, MONTHSEP, YEAR, HOUR12, HOUR24 ) \
100     NUMFMT_STRING(  14, SYSTEMDATE ), \
101     NUMFMT_STRING(  15, DAY DAYSEP MONTH MONTHSEP YEAR ), \
102     NUMFMT_STRING(  16, DAY DAYSEP MONTH ), \
103     NUMFMT_STRING(  17, MONTH MONTHSEP YEAR ), \
104     NUMFMT_STRING(  18, HOUR12 ":mm AM/PM" ), \
105     NUMFMT_STRING(  19, HOUR12 ":mm:ss AM/PM" ), \
106     NUMFMT_STRING(  20, HOUR24 ":mm" ), \
107     NUMFMT_STRING(  21, HOUR24 ":mm:ss" ), \
108     NUMFMT_STRING(  22, SYSTEMDATE " " HOUR24 ":mm" )
109 
110 /** Defines builtin time formats INDEX and INDEX+1 for CJK locales.
111     @param INDEX  First number format index.
112     @param HOURFORMAT  Hour format.
113     @param HOUR  Hour symbol.
114     @param MINUTE  Minute symbol.
115     @param SECOND  Second symbol. */
116 #define NUMFMT_TIME_CJK( INDEX, HOURFORMAT, HOUR, MINUTE, SECOND ) \
117     NUMFMT_STRING( INDEX + 0, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"" ), \
118     NUMFMT_STRING( INDEX + 1, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"ss\"" SECOND "\"" )
119 
120 /** Defines builtin time formats 32...35 for CJK locales.
121     @param HOUR12  Hour format for 12-hour AM/PM formats (formats 34 and 35).
122     @param HOUR24  Hour format for 24-hour formats (formats 32 and 33).
123     @param HOUR  Hour symbol.
124     @param MINUTE  Minute symbol.
125     @param SECOND  Second symbol. */
126 #define NUMFMT_ALLTIMES_CJK( HOUR12, HOUR24, HOUR, MINUTE, SECOND ) \
127     NUMFMT_TIME_CJK( 32, HOUR24, HOUR, MINUTE, SECOND ), \
128     NUMFMT_TIME_CJK( 34, "AM/PM" HOUR12, HOUR, MINUTE, SECOND )
129 
130 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
131     "symbol, [minus], number".
132     @param INDEX  First number format index.
133     @param SYMBOL  Currency symbol.
134     @param SPACE  Space character(s) between currency symbol and number.
135     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
136 #define NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
137     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;"            MODIF SYMBOL SPACE "-#,##0" ), \
138     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;"    "[RED]" MODIF SYMBOL SPACE "-#,##0" ), \
139     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;"         MODIF SYMBOL SPACE "-#,##0.00" ), \
140     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF SYMBOL SPACE "-#,##0.00" )
141 
142 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
143     "symbol, [minus], number".
144     @param INDEX  First number format index.
145     @param SYMBOL  Currency symbol.
146     @param SPACE  Space character(s) between currency symbol and number. */
147 #define NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE ) \
148     NUMFMT_STRING( INDEX + 0, "_ "              "* #,##0_ ;"    "_ "              "* -#,##0_ ;"    "_ "              "* \"-\"_ ;"    "_ @_ " ), \
149     NUMFMT_STRING( INDEX + 1, "_ " SYMBOL SPACE "* #,##0_ ;"    "_ " SYMBOL SPACE "* -#,##0_ ;"    "_ " SYMBOL SPACE "* \"-\"_ ;"    "_ @_ " ), \
150     NUMFMT_STRING( INDEX + 2, "_ "              "* #,##0.00_ ;" "_ "              "* -#,##0.00_ ;" "_ "              "* \"-\"?\?_ ;" "_ @_ " ), \
151     NUMFMT_STRING( INDEX + 3, "_ " SYMBOL SPACE "* #,##0.00_ ;" "_ " SYMBOL SPACE "* -#,##0.00_ ;" "_ " SYMBOL SPACE "* \"-\"?\?_ ;" "_ @_ " )
152 
153 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
154     (blind currency symbol), and 41...44 (accounting), in the following format:
155     "symbol, [minus], number".
156     @param SYMBOL  Currency symbol.
157     @param SPACE  Space character(s) between currency symbol and number. */
158 #define NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( SYMBOL, SPACE ) \
159     NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 5, SYMBOL, SPACE, "" ), \
160     NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 37, "", "", "" ), \
161     NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( 41, SYMBOL, SPACE )
162 
163 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
164     "symbol, number, [minus]".
165     @param INDEX  First number format index.
166     @param SYMBOL  Currency symbol.
167     @param SPACE  Space character(s) between currency symbol and number.
168     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
169 #define NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
170     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_-;"            MODIF SYMBOL SPACE "#,##0-" ), \
171     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_-;"    "[RED]" MODIF SYMBOL SPACE "#,##0-" ), \
172     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_-;"         MODIF SYMBOL SPACE "#,##0.00-" ), \
173     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_-;" "[RED]" MODIF SYMBOL SPACE "#,##0.00-" )
174 
175 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
176     "symbol, number, [minus]".
177     @param INDEX  First number format index.
178     @param SYMBOL  Currency symbol.
179     @param SPACE  Space character(s) between currency symbol and number. */
180 #define NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE ) \
181     NUMFMT_STRING( INDEX + 0, "_-"              "* #,##0_-;"    "_-"              "* #,##0-;"    "_-"              "* \"-\"_-;"    "_-@_-" ), \
182     NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;"    "_-" SYMBOL SPACE "* #,##0-;"    "_-" SYMBOL SPACE "* \"-\"_-;"    "_-@_-" ), \
183     NUMFMT_STRING( INDEX + 2, "_-"              "* #,##0.00_-;" "_-"              "* #,##0.00-;" "_-"              "* \"-\"?\?_-;" "_-@_-" ), \
184     NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* #,##0.00-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
185 
186 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
187     (blind currency symbol), and 41...44 (accounting), in the following format:
188     "symbol, number, [minus]".
189     @param SYMBOL  Currency symbol.
190     @param SPACE  Space character(s) between currency symbol and number. */
191 #define NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( SYMBOL, SPACE ) \
192     NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 5, SYMBOL, SPACE, "" ), \
193     NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 37, "", "", "" ), \
194     NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( 41, SYMBOL, SPACE )
195 
196 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
197     "number, symbol, [minus]".
198     @param INDEX  First number format index.
199     @param SYMBOL  Currency symbol.
200     @param SPACE  Space character(s) between number and currency symbol.
201     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
202 #define NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
203     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL "_-;"         MODIF "#,##0"    SPACE SYMBOL "-" ), \
204     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0"    SPACE SYMBOL "-" ), \
205     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_-;"         MODIF "#,##0.00" SPACE SYMBOL "-" ), \
206     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0.00" SPACE SYMBOL "-" )
207 
208 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
209     "number, symbol, [minus]".
210     @param INDEX  First number format index.
211     @param SYMBOL  Currency symbol.
212     @param BLINDS  Blind currency symbol.
213     @param SPACE  Space character(s) between number and currency symbol. */
214 #define NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, BLINDS, SPACE ) \
215     NUMFMT_STRING( INDEX + 0, "_-* #,##0"    SPACE BLINDS "_-;_-* #,##0"    SPACE BLINDS "-;_-* \"-\""    SPACE BLINDS "_-;_-@_-" ), \
216     NUMFMT_STRING( INDEX + 1, "_-* #,##0"    SPACE SYMBOL "_-;_-* #,##0"    SPACE SYMBOL "-;_-* \"-\""    SPACE SYMBOL "_-;_-@_-" ), \
217     NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;_-* #,##0.00" SPACE BLINDS "-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
218     NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;_-* #,##0.00" SPACE SYMBOL "-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
219 
220 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
221     (blind currency symbol), and 41...44 (accounting), in the following format:
222     "number, symbol, [minus]".
223     @param SYMBOL  Currency symbol.
224     @param BLINDS  Blind currency symbol.
225     @param SPACE  Space character(s) between number and currency symbol. */
226 #define NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( SYMBOL, BLINDS, SPACE ) \
227     NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 5, SYMBOL, SPACE, "" ), \
228     NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 37, BLINDS, SPACE, "" ), \
229     NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( 41, SYMBOL, BLINDS, SPACE )
230 
231 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
232     "[minus], symbol, number".
233     @param INDEX  First number format index.
234     @param SYMBOL  Currency symbol.
235     @param SPACE  Space character(s) between currency symbol and number.
236     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
237 #define NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
238     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;"            MODIF "-" SYMBOL SPACE "#,##0" ), \
239     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;"    "[RED]" MODIF "-" SYMBOL SPACE "#,##0" ), \
240     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;"         MODIF "-" SYMBOL SPACE "#,##0.00" ), \
241     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF "-" SYMBOL SPACE "#,##0.00" )
242 
243 /** Defines builtin accounting formats INDEX...INDEX+3 in the following order:
244     "[minus], symbol, number".
245     @param INDEX  First number format index.
246     @param SYMBOL  Currency symbol.
247     @param SPACE  Space character(s) between currency symbol and number. */
248 #define NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE ) \
249     NUMFMT_STRING( INDEX + 0, "_-"              "* #,##0_-;"    "-"              "* #,##0_-;"    "_-"              "* \"-\"_-;"    "_-@_-" ), \
250     NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;"    "-" SYMBOL SPACE "* #,##0_-;"    "_-" SYMBOL SPACE "* \"-\"_-;"    "_-@_-" ), \
251     NUMFMT_STRING( INDEX + 2, "_-"              "* #,##0.00_-;" "-"              "* #,##0.00_-;" "_-"              "* \"-\"?\?_-;" "_-@_-" ), \
252     NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
253 
254 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
255     (blind currency symbol), and 41...44 (accounting), in the following order:
256     "[minus], symbol, number".
257     @param SYMBOL  Currency symbol.
258     @param SPACE  Space character(s) between currency symbol and number. */
259 #define NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( SYMBOL, SPACE ) \
260     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 5, SYMBOL, SPACE, "" ), \
261     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ), \
262     NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, SYMBOL, SPACE )
263 
264 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
265     "[minus], number, symbol".
266     @param INDEX  First number format index.
267     @param SYMBOL  Currency symbol.
268     @param SPACE  Space character(s) between number and currency symbol.
269     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
270 #define NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, SPACE, MODIF ) \
271     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL ";"         MODIF "-#,##0"    SPACE SYMBOL ), \
272     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL ";" "[RED]" MODIF "-#,##0"    SPACE SYMBOL ), \
273     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL ";"         MODIF "-#,##0.00" SPACE SYMBOL ), \
274     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL ";" "[RED]" MODIF "-#,##0.00" SPACE SYMBOL )
275 
276 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
277     "[minus], number, symbol".
278     @param INDEX  First number format index.
279     @param SYMBOL  Currency symbol.
280     @param BLINDS  Blind currency symbol.
281     @param SPACE  Space character(s) between number and currency symbol. */
282 #define NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, BLINDS, SPACE ) \
283     NUMFMT_STRING( INDEX + 0, "_-* #,##0"    SPACE BLINDS "_-;-* #,##0"    SPACE BLINDS "_-;_-* \"-\""    SPACE BLINDS "_-;_-@_-" ), \
284     NUMFMT_STRING( INDEX + 1, "_-* #,##0"    SPACE SYMBOL "_-;-* #,##0"    SPACE SYMBOL "_-;_-* \"-\""    SPACE SYMBOL "_-;_-@_-" ), \
285     NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;-* #,##0.00" SPACE BLINDS "_-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
286     NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;-* #,##0.00" SPACE SYMBOL "_-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
287 
288 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
289     (blind currency symbol), and 41...44 (accounting), in the following format:
290     "[minus], number, symbol".
291     @param SYMBOL  Currency symbol.
292     @param BLINDS  Blind currency symbol.
293     @param SPACE  Space character(s) between number and currency symbol. */
294 #define NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( SYMBOL, BLINDS, SPACE ) \
295     NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 5, SYMBOL, SPACE, "" ), \
296     NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 37, BLINDS, SPACE, "" ), \
297     NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( 41, SYMBOL, BLINDS, SPACE )
298 
299 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
300     "[opening parenthesis], symbol, number, [closing parenthesis].".
301     @param INDEX  First number format index.
302     @param SYMBOL  Currency symbol.
303     @param SPACE  Space character(s) between currency symbol and number.
304     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
305 #define NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
306     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_);"            MODIF "(" SYMBOL SPACE "#,##0)" ), \
307     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_);"    "[RED]" MODIF "(" SYMBOL SPACE "#,##0)" ), \
308     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_);"         MODIF "(" SYMBOL SPACE "#,##0.00)" ), \
309     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_);" "[RED]" MODIF "(" SYMBOL SPACE "#,##0.00)" )
310 
311 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
312     "[opening parenthesis], symbol, number, [closing parenthesis].".
313     @param INDEX  First number format index.
314     @param SYMBOL  Currency symbol.
315     @param SPACE  Space character(s) between currency symbol and number. */
316 #define NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE ) \
317     NUMFMT_STRING( INDEX + 0, "_("              "* #,##0_);"    "_("              "* (#,##0);"    "_("              "* \"-\"_);"    "_(@_)" ), \
318     NUMFMT_STRING( INDEX + 1, "_(" SYMBOL SPACE "* #,##0_);"    "_(" SYMBOL SPACE "* (#,##0);"    "_(" SYMBOL SPACE "* \"-\"_);"    "_(@_)" ), \
319     NUMFMT_STRING( INDEX + 2, "_("              "* #,##0.00_);" "_("              "* (#,##0.00);" "_("              "* \"-\"?\?_);" "_(@_)" ), \
320     NUMFMT_STRING( INDEX + 3, "_(" SYMBOL SPACE "* #,##0.00_);" "_(" SYMBOL SPACE "* (#,##0.00);" "_(" SYMBOL SPACE "* \"-\"?\?_);" "_(@_)" )
321 
322 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
323     (blind currency symbol), and 41...44 (accounting), in the following format:
324     "[opening parenthesis], symbol, number, [closing parenthesis].".
325     @param SYMBOL  Currency symbol.
326     @param SPACE  Space character(s) between currency symbol and number. */
327 #define NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( SYMBOL, SPACE ) \
328     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 5, SYMBOL, SPACE, "" ), \
329     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 37, "", "", "" ), \
330     NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( 41, SYMBOL, SPACE )
331 
332 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
333     "[opening parenthesis], number, symbol, [closing parenthesis].".
334     @param INDEX  First number format index.
335     @param SYMBOL  Currency symbol.
336     @param SPACE  Space character(s) between number and currency symbol.
337     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
338 #define NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
339     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL "_);"         MODIF "(#,##0"    SPACE SYMBOL ")" ), \
340     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0"    SPACE SYMBOL ")" ), \
341     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_);"         MODIF "(#,##0.00" SPACE SYMBOL ")" ), \
342     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0.00" SPACE SYMBOL ")" )
343 
344 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
345     "[opening parenthesis], number, symbol, [closing parenthesis].".
346     @param INDEX  First number format index.
347     @param SYMBOL  Currency symbol.
348     @param BLINDS  Blind currency symbol.
349     @param SPACE  Space character(s) between number and currency symbol. */
350 #define NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, BLINDS, SPACE ) \
351     NUMFMT_STRING( INDEX + 0, "_ * #,##0_)"    SPACE BLINDS "_ ;_ * (#,##0)"    SPACE BLINDS "_ ;_ * \"-\"_)"    SPACE BLINDS "_ ;_ @_ " ), \
352     NUMFMT_STRING( INDEX + 1, "_ * #,##0_)"    SPACE SYMBOL "_ ;_ * (#,##0)"    SPACE SYMBOL "_ ;_ * \"-\"_)"    SPACE SYMBOL "_ ;_ @_ " ), \
353     NUMFMT_STRING( INDEX + 2, "_ * #,##0.00_)" SPACE BLINDS "_ ;_ * (#,##0.00)" SPACE BLINDS "_ ;_ * \"-\"?\?_)" SPACE BLINDS "_ ;_ @_ " ), \
354     NUMFMT_STRING( INDEX + 3, "_ * #,##0.00_)" SPACE SYMBOL "_ ;_ * (#,##0.00)" SPACE SYMBOL "_ ;_ * \"-\"?\?_)" SPACE SYMBOL "_ ;_ @_ " )
355 
356 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
357     (blind currency symbol), and 41...44 (accounting), in the following format:
358     "[opening parenthesis], number, symbol, [closing parenthesis].".
359     @param SYMBOL  Currency symbol.
360     @param BLINDS  Blind currency symbol.
361     @param SPACE  Space character(s) between number and currency symbol. */
362 #define NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( SYMBOL, BLINDS, SPACE ) \
363     NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 5, SYMBOL, SPACE, "" ), \
364     NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 37, BLINDS, SPACE, "" ), \
365     NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( 41, SYMBOL, BLINDS, SPACE )
366 
367 // currency unit characters
368 #define UTF8_BAHT           "\340\270\277"
369 #define UTF8_COLON          "\342\202\241"
370 #define UTF8_CURR_AR_AE     "\330\257.\330\245."
371 #define UTF8_CURR_AR_BH     "\330\257.\330\250."
372 #define UTF8_CURR_AR_DZ     "\330\257.\330\254."
373 #define UTF8_CURR_AR_EG     "\330\254.\331\205."
374 #define UTF8_CURR_AR_IQ     "\330\257.\330\271."
375 #define UTF8_CURR_AR_JO     "\330\257.\330\247."
376 #define UTF8_CURR_AR_KW     "\330\257.\331\203."
377 #define UTF8_CURR_AR_LB     "\331\204.\331\204."
378 #define UTF8_CURR_AR_LY     "\330\257.\331\204."
379 #define UTF8_CURR_AR_MA     "\330\257.\331\205."
380 #define UTF8_CURR_AR_OM     "\330\261.\330\271."
381 #define UTF8_CURR_AR_QA     "\330\261.\331\202."
382 #define UTF8_CURR_AR_SA     "\330\261.\330\263."
383 #define UTF8_CURR_AR_SY     "\331\204.\330\263."
384 #define UTF8_CURR_AR_TN     "\330\257.\330\252."
385 #define UTF8_CURR_AR_YE     "\330\261.\331\212."
386 #define UTF8_CURR_BN_IN     "\340\246\237\340\246\276"
387 #define UTF8_CURR_FA_IR     "\330\261\331\212\330\247\331\204"
388 #define UTF8_CURR_GU_IN     "\340\252\260\340\253\202"
389 #define UTF8_CURR_HI_IN     "\340\244\260\340\245\201"
390 #define UTF8_CURR_KN_IN     "\340\262\260\340\263\202"
391 #define UTF8_CURR_ML_IN     "\340\264\225"
392 #define UTF8_CURR_PA_IN     "\340\250\260\340\251\201"
393 #define UTF8_CURR_TA_IN     "\340\256\260\340\257\202"
394 #define UTF8_CURR_TE_IN     "\340\260\260\340\261\202"
395 #define UTF8_DONG           "\342\202\253"
396 #define UTF8_EURO           "\342\202\254"
397 #define UTF8_POUND_GB       "\302\243"
398 #define UTF8_RUFIYAA        "\336\203"
399 #define UTF8_SHEQEL         "\342\202\252"
400 #define UTF8_TUGRUG         "\342\202\256"
401 #define UTF8_WON            "\342\202\251"
402 #define UTF8_YEN_CN         "\357\277\245"
403 #define UTF8_YEN_JP         "\302\245"
404 
405 // Unicode characters for currency units
406 #define UTF8_CCARON_LC      "\304\215"
407 #define UTF8_LSTROKE_LC     "\305\202"
408 // Armenian
409 #define UTF8_HY_DA_LC       "\325\244"
410 #define UTF8_HY_REH_LC      "\326\200"
411 // Cyrillic
412 #define UTF8_CYR_G_LC       "\320\263"
413 #define UTF8_CYR_L_LC       "\320\273"
414 #define UTF8_CYR_M_LC       "\320\274"
415 #define UTF8_CYR_N_LC       "\320\275"
416 #define UTF8_CYR_O_LC       "\320\276"
417 #define UTF8_CYR_R_LC       "\321\200"
418 #define UTF8_CYR_S_LC       "\321\201"
419 #define UTF8_CYR_W_LC       "\320\262"
420 
421 // Japanese/Chinese date/time characters
422 #define UTF8_CJ_YEAR        "\345\271\264"
423 #define UTF8_CJ_MON         "\346\234\210"
424 #define UTF8_CJ_DAY         "\346\227\245"
425 #define UTF8_CJ_HOUR        "\346\231\202"
426 #define UTF8_CJ_MIN         "\345\210\206"
427 #define UTF8_CJ_SEC         "\347\247\222"
428 
429 // Chinese Simplified date/time characters
430 #define UTF8_CS_YEAR        "\345\271\264"
431 #define UTF8_CS_MON         "\346\234\210"
432 #define UTF8_CS_DAY         "\346\227\245"
433 #define UTF8_CS_HOUR        "\346\227\266"
434 #define UTF8_CS_MIN         "\345\210\206"
435 #define UTF8_CS_SEC         "\347\247\222"
436 
437 // Korean date/time characters
438 #define UTF8_KO_YEAR        "\353\205\204"
439 #define UTF8_KO_MON         "\354\233\224"
440 #define UTF8_KO_DAY         "\354\235\274"
441 #define UTF8_KO_HOUR        "\354\213\234"
442 #define UTF8_KO_MIN         "\353\266\204"
443 #define UTF8_KO_SEC         "\354\264\210"
444 
445 // ----------------------------------------------------------------------------
446 
447 /** Default number format table. Last parent of all other tables, used for unknown locales. */
448 static const BuiltinFormat spBuiltinFormats_BASE[] =
449 {
450     // 0..13 numeric and currency formats
451     NUMFMT_PREDEF(   0, NUMBER_STANDARD ),          // General
452     NUMFMT_PREDEF(   1, NUMBER_INT ),               // 0
453     NUMFMT_PREDEF(   2, NUMBER_DEC2 ),              // 0.00
454     NUMFMT_PREDEF(   3, NUMBER_1000INT ),           // #,##0
455     NUMFMT_PREDEF(   4, NUMBER_1000DEC2 ),          // #,##0.00
456     NUMFMT_PREDEF(   5, CURRENCY_1000INT ),         // #,##0[symbol]
457     NUMFMT_PREDEF(   6, CURRENCY_1000INT_RED ),     // #,##0[symbol];[RED]-#,##0[symbol]
458     NUMFMT_PREDEF(   7, CURRENCY_1000DEC2 ),        // #,##0.00[symbol]
459     NUMFMT_PREDEF(   8, CURRENCY_1000DEC2_RED ),    // #,##0.00[symbol];[RED]-#,##0.00[symbol]
460     NUMFMT_PREDEF(   9, PERCENT_INT ),              // 0%
461     NUMFMT_PREDEF(  10, PERCENT_DEC2 ),             // 0.00%
462     NUMFMT_PREDEF(  11, SCIENTIFIC_000E00 ),        // 0.00E+00
463     NUMFMT_PREDEF(  12, FRACTION_1 ),               // # ?/?
464     NUMFMT_PREDEF(  13, FRACTION_2 ),               // # ??/??
465 
466     // 14...22 date and time formats
467     NUMFMT_PREDEF(  14, DATE_SYS_DDMMYYYY ),
468     NUMFMT_PREDEF(  15, DATE_SYS_DMMMYY ),
469     NUMFMT_PREDEF(  16, DATE_SYS_DDMMM ),
470     NUMFMT_PREDEF(  17, DATE_SYS_MMYY ),
471     NUMFMT_PREDEF(  18, TIME_HHMMAMPM ),
472     NUMFMT_PREDEF(  19, TIME_HHMMSSAMPM ),
473     NUMFMT_PREDEF(  20, TIME_HHMM ),
474     NUMFMT_PREDEF(  21, TIME_HHMMSS ),
475     NUMFMT_PREDEF(  22, DATETIME_SYSTEM_SHORT_HHMM ),
476 
477     // 23...36 international formats
478     NUMFMT_REUSE(   23, 0 ),
479     NUMFMT_REUSE(   24, 0 ),
480     NUMFMT_REUSE(   25, 0 ),
481     NUMFMT_REUSE(   26, 0 ),
482     NUMFMT_REUSE(   27, 14 ),
483     NUMFMT_REUSE(   28, 14 ),
484     NUMFMT_REUSE(   29, 14 ),
485     NUMFMT_REUSE(   30, 14 ),
486     NUMFMT_REUSE(   31, 14 ),
487     NUMFMT_REUSE(   32, 21 ),
488     NUMFMT_REUSE(   33, 21 ),
489     NUMFMT_REUSE(   34, 21 ),
490     NUMFMT_REUSE(   35, 21 ),
491     NUMFMT_REUSE(   36, 14 ),
492 
493     // 37...44 accounting formats, defaults without currency symbol here
494     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ),
495     NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, "", "" ),
496 
497     // 45...49 more special formats
498     NUMFMT_STRING(  45, "mm:ss" ),
499     NUMFMT_STRING(  46, "[h]:mm:ss" ),
500     NUMFMT_STRING(  47, "mm:ss.0" ),
501     NUMFMT_STRING(  48, "##0.0E+0" ),
502     NUMFMT_PREDEF(  49, TEXT ),
503 
504     // 50...81 international formats
505     NUMFMT_REUSE(   50, 14 ),
506     NUMFMT_REUSE(   51, 14 ),
507     NUMFMT_REUSE(   52, 14 ),
508     NUMFMT_REUSE(   53, 14 ),
509     NUMFMT_REUSE(   54, 14 ),
510     NUMFMT_REUSE(   55, 14 ),
511     NUMFMT_REUSE(   56, 14 ),
512     NUMFMT_REUSE(   57, 14 ),
513     NUMFMT_REUSE(   58, 14 ),
514     NUMFMT_REUSE(   59, 1 ),
515     NUMFMT_REUSE(   60, 2 ),
516     NUMFMT_REUSE(   61, 3 ),
517     NUMFMT_REUSE(   62, 4 ),
518     NUMFMT_REUSE(   63, 5 ),
519     NUMFMT_REUSE(   64, 6 ),
520     NUMFMT_REUSE(   65, 7 ),
521     NUMFMT_REUSE(   66, 8 ),
522     NUMFMT_REUSE(   67, 9 ),
523     NUMFMT_REUSE(   68, 10 ),
524     NUMFMT_REUSE(   69, 12 ),
525     NUMFMT_REUSE(   70, 13 ),
526     NUMFMT_REUSE(   71, 14 ),
527     NUMFMT_REUSE(   72, 14 ),
528     NUMFMT_REUSE(   73, 15 ),
529     NUMFMT_REUSE(   74, 16 ),
530     NUMFMT_REUSE(   75, 17 ),
531     NUMFMT_REUSE(   76, 20 ),
532     NUMFMT_REUSE(   77, 21 ),
533     NUMFMT_REUSE(   78, 22 ),
534     NUMFMT_REUSE(   79, 45 ),
535     NUMFMT_REUSE(   80, 46 ),
536     NUMFMT_REUSE(   81, 47 ),
537 
538     // 82...163 not used, must not occur in a file (Excel may crash)
539 
540     NUMFMT_ENDTABLE()
541 };
542 
543 // ----------------------------------------------------------------------------
544 
545 /** Arabic, U.A.E. */
546 static const BuiltinFormat spBuiltinFormats_ar_AE[] =
547 {
548     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
549     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_AE "\"", " " ),
550     NUMFMT_ENDTABLE()
551 };
552 
553 /** Arabic, Bahrain. */
554 static const BuiltinFormat spBuiltinFormats_ar_BH[] =
555 {
556     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
557     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_BH "\"", " " ),
558     NUMFMT_ENDTABLE()
559 };
560 
561 /** Arabic, Algeria. */
562 static const BuiltinFormat spBuiltinFormats_ar_DZ[] =
563 {
564     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
565     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_DZ "\"", " " ),
566     NUMFMT_ENDTABLE()
567 };
568 
569 /** Arabic, Egypt. */
570 static const BuiltinFormat spBuiltinFormats_ar_EG[] =
571 {
572     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
573     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_EG "\"", " " ),
574     NUMFMT_ENDTABLE()
575 };
576 
577 /** Arabic, Iraq. */
578 static const BuiltinFormat spBuiltinFormats_ar_IQ[] =
579 {
580     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
581     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_IQ "\"", " " ),
582     NUMFMT_ENDTABLE()
583 };
584 
585 /** Arabic, Jordan. */
586 static const BuiltinFormat spBuiltinFormats_ar_JO[] =
587 {
588     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
589     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_JO "\"", " " ),
590     NUMFMT_ENDTABLE()
591 };
592 
593 /** Arabic, Kuwait. */
594 static const BuiltinFormat spBuiltinFormats_ar_KW[] =
595 {
596     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
597     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_KW "\"", " " ),
598     NUMFMT_ENDTABLE()
599 };
600 
601 /** Arabic, Lebanon. */
602 static const BuiltinFormat spBuiltinFormats_ar_LB[] =
603 {
604     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
605     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LB "\"", " " ),
606     NUMFMT_ENDTABLE()
607 };
608 
609 /** Arabic, Libya. */
610 static const BuiltinFormat spBuiltinFormats_ar_LY[] =
611 {
612     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
613     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LY "\"", " " ),
614     NUMFMT_ENDTABLE()
615 };
616 
617 /** Arabic, Morocco. */
618 static const BuiltinFormat spBuiltinFormats_ar_MA[] =
619 {
620     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
621     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_MA "\"", " " ),
622     NUMFMT_ENDTABLE()
623 };
624 
625 /** Arabic, Oman. */
626 static const BuiltinFormat spBuiltinFormats_ar_OM[] =
627 {
628     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
629     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_OM "\"", " " ),
630     NUMFMT_ENDTABLE()
631 };
632 
633 /** Arabic, Qatar. */
634 static const BuiltinFormat spBuiltinFormats_ar_QA[] =
635 {
636     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
637     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_QA "\"", " " ),
638     NUMFMT_ENDTABLE()
639 };
640 
641 /** Arabic, Saudi Arabia. */
642 static const BuiltinFormat spBuiltinFormats_ar_SA[] =
643 {
644     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
645     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SA "\"", " " ),
646     NUMFMT_ENDTABLE()
647 };
648 
649 /** Arabic, Syria. */
650 static const BuiltinFormat spBuiltinFormats_ar_SY[] =
651 {
652     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
653     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SY "\"", " " ),
654     NUMFMT_ENDTABLE()
655 };
656 
657 /** Arabic, Tunisia. */
658 static const BuiltinFormat spBuiltinFormats_ar_TN[] =
659 {
660     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
661     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_TN "\"", " " ),
662     NUMFMT_ENDTABLE()
663 };
664 
665 /** Arabic, Yemen. */
666 static const BuiltinFormat spBuiltinFormats_ar_YE[] =
667 {
668     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
669     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_YE "\"", " " ),
670     NUMFMT_ENDTABLE()
671 };
672 
673 /** Belarusian, Belarus. */
674 static const BuiltinFormat spBuiltinFormats_be_BY[] =
675 {
676     // space character is group separator, literal spaces must be quoted
677     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
678     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
679     NUMFMT_ENDTABLE()
680 };
681 
682 /** Bulgarian, Bulgaria. */
683 static const BuiltinFormat spBuiltinFormats_bg_BG[] =
684 {
685     // space character is group separator, literal spaces must be quoted
686     NUMFMT_ALLDATETIMES( "DD.M.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
687     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_L_LC UTF8_CYR_W_LC "\"", "_" UTF8_CYR_L_LC "_" UTF8_CYR_W_LC, "\\ " ),
688     NUMFMT_ENDTABLE()
689 };
690 
691 /** Bengali, India. */
692 static const BuiltinFormat spBuiltinFormats_bn_IN[] =
693 {
694     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
695     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_BN_IN "\"", " " ),
696     NUMFMT_ENDTABLE()
697 };
698 
699 /** Czech, Czech Republic. */
700 static const BuiltinFormat spBuiltinFormats_cs_CZ[] =
701 {
702     // space character is group separator, literal spaces must be quoted
703     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
704     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"K" UTF8_CCARON_LC "\"", "_K_" UTF8_CCARON_LC, "\\ " ),
705     NUMFMT_ENDTABLE()
706 };
707 
708 /** Danish, Denmark. */
709 static const BuiltinFormat spBuiltinFormats_da_DK[] =
710 {
711     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
712     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
713     NUMFMT_ENDTABLE()
714 };
715 
716 /** German, Austria. */
717 static const BuiltinFormat spBuiltinFormats_de_AT[] =
718 {
719     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
720     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
721     NUMFMT_ENDTABLE()
722 };
723 
724 /** German, Switzerland. */
725 static const BuiltinFormat spBuiltinFormats_de_CH[] =
726 {
727     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
728     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
729     NUMFMT_ENDTABLE()
730 };
731 
732 /** German, Germany. */
733 static const BuiltinFormat spBuiltinFormats_de_DE[] =
734 {
735     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
736     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
737     NUMFMT_ENDTABLE()
738 };
739 
740 /** German, Liechtenstein. */
741 static const BuiltinFormat spBuiltinFormats_de_LI[] =
742 {
743     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
744     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"CHF\"", " " ),
745     NUMFMT_ENDTABLE()
746 };
747 
748 /** German, Luxembourg. */
749 static const BuiltinFormat spBuiltinFormats_de_LU[] =
750 {
751     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
752     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
753     NUMFMT_ENDTABLE()
754 };
755 
756 /** Divehi, Maldives. */
757 static const BuiltinFormat spBuiltinFormats_div_MV[] =
758 {
759     NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
760     NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( "\"" UTF8_RUFIYAA ".\"", "_" UTF8_RUFIYAA "_.", " " ),
761     NUMFMT_ENDTABLE()
762 };
763 
764 /** Greek, Greece. */
765 static const BuiltinFormat spBuiltinFormats_el_GR[] =
766 {
767     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
768     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
769     NUMFMT_ENDTABLE()
770 };
771 
772 /** English, Australia. */
773 static const BuiltinFormat spBuiltinFormats_en_AU[] =
774 {
775     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
776     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
777     NUMFMT_ENDTABLE()
778 };
779 
780 /** English, Belize. */
781 static const BuiltinFormat spBuiltinFormats_en_BZ[] =
782 {
783     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
784     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"BZ$\"", "" ),
785     NUMFMT_ENDTABLE()
786 };
787 
788 /** English, Canada. */
789 static const BuiltinFormat spBuiltinFormats_en_CA[] =
790 {
791     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
792     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
793     NUMFMT_ENDTABLE()
794 };
795 
796 /** English, Caribbean. */
797 static const BuiltinFormat spBuiltinFormats_en_CB[] =
798 {
799     NUMFMT_ALLDATETIMES( "MM/DD/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
800     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
801     NUMFMT_ENDTABLE()
802 };
803 
804 /** English, United Kingdom. */
805 static const BuiltinFormat spBuiltinFormats_en_GB[] =
806 {
807     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
808     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_POUND_GB, "" ),
809     NUMFMT_ENDTABLE()
810 };
811 
812 /** English, Ireland. */
813 static const BuiltinFormat spBuiltinFormats_en_IE[] =
814 {
815     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
816     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, "" ),
817     NUMFMT_ENDTABLE()
818 };
819 
820 /** English, Jamaica. */
821 static const BuiltinFormat spBuiltinFormats_en_JM[] =
822 {
823     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
824     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"J$\"", "" ),
825     NUMFMT_ENDTABLE()
826 };
827 
828 /** English, New Zealand. */
829 static const BuiltinFormat spBuiltinFormats_en_NZ[] =
830 {
831     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
832     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
833     NUMFMT_ENDTABLE()
834 };
835 
836 /** English, Philippines. */
837 static const BuiltinFormat spBuiltinFormats_en_PH[] =
838 {
839     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
840     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Php\"", "" ),
841     NUMFMT_ENDTABLE()
842 };
843 
844 /** English, Trinidad and Tobago. */
845 static const BuiltinFormat spBuiltinFormats_en_TT[] =
846 {
847     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
848     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"TT$\"", "" ),
849     NUMFMT_ENDTABLE()
850 };
851 
852 /** English, USA. */
853 static const BuiltinFormat spBuiltinFormats_en_US[] =
854 {
855     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
856     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
857     NUMFMT_ENDTABLE()
858 };
859 
860 /** English, South Africa. */
861 static const BuiltinFormat spBuiltinFormats_en_ZA[] =
862 {
863     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
864     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\\R", " " ),
865     NUMFMT_ENDTABLE()
866 };
867 
868 /** English, Zimbabwe. */
869 static const BuiltinFormat spBuiltinFormats_en_ZW[] =
870 {
871     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
872     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Z$\"", "" ),
873     NUMFMT_ENDTABLE()
874 };
875 
876 /** Spanish, Argentina. */
877 static const BuiltinFormat spBuiltinFormats_es_AR[] =
878 {
879     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
880     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "$", " " ),
881     NUMFMT_ENDTABLE()
882 };
883 
884 /** Spanish, Bolivia. */
885 static const BuiltinFormat spBuiltinFormats_es_BO[] =
886 {
887     // slashes must be quoted to prevent conversion to minus
888     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
889     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$b\"", " " ),
890     NUMFMT_ENDTABLE()
891 };
892 
893 /** Spanish, Chile. */
894 static const BuiltinFormat spBuiltinFormats_es_CL[] =
895 {
896     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
897     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", " " ),
898     NUMFMT_ENDTABLE()
899 };
900 
901 /** Spanish, Colombia. */
902 static const BuiltinFormat spBuiltinFormats_es_CO[] =
903 {
904     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
905     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
906     NUMFMT_ENDTABLE()
907 };
908 
909 /** Spanish, Costa Rica. */
910 static const BuiltinFormat spBuiltinFormats_es_CR[] =
911 {
912     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
913     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( UTF8_COLON, "" ),
914     NUMFMT_ENDTABLE()
915 };
916 
917 /** Spanish, Dominican Republic. */
918 static const BuiltinFormat spBuiltinFormats_es_DO[] =
919 {
920     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
921     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"RD$\"", "" ),
922     NUMFMT_ENDTABLE()
923 };
924 
925 /** Spanish, Ecuador. */
926 static const BuiltinFormat spBuiltinFormats_es_EC[] =
927 {
928     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
929     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
930     NUMFMT_ENDTABLE()
931 };
932 
933 /** Spanish, Spain. */
934 static const BuiltinFormat spBuiltinFormats_es_ES[] =
935 {
936     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
937     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
938     NUMFMT_ENDTABLE()
939 };
940 
941 /** Spanish, Guatemala. */
942 static const BuiltinFormat spBuiltinFormats_es_GT[] =
943 {
944     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
945     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\Q", "" ),
946     NUMFMT_ENDTABLE()
947 };
948 
949 /** Spanish, Honduras. */
950 static const BuiltinFormat spBuiltinFormats_es_HN[] =
951 {
952     // slashes must be quoted to prevent conversion to minus
953     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
954     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"L.\"", " " ),
955     NUMFMT_ENDTABLE()
956 };
957 
958 /** Spanish, Mexico. */
959 static const BuiltinFormat spBuiltinFormats_es_MX[] =
960 {
961     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
962     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
963     NUMFMT_ENDTABLE()
964 };
965 
966 /** Spanish, Nicaragua. */
967 static const BuiltinFormat spBuiltinFormats_es_NI[] =
968 {
969     // slashes must be quoted to prevent conversion to minus
970     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
971     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"C$\"", " " ),
972     NUMFMT_ENDTABLE()
973 };
974 
975 /** Spanish, Panama. */
976 static const BuiltinFormat spBuiltinFormats_es_PA[] =
977 {
978     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
979     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"B/.\"", " " ),
980     NUMFMT_ENDTABLE()
981 };
982 
983 /** Spanish, Peru. */
984 static const BuiltinFormat spBuiltinFormats_es_PE[] =
985 {
986     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
987     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"S/.\"", " " ),
988     NUMFMT_ENDTABLE()
989 };
990 
991 /** Spanish, Puerto Rico. */
992 static const BuiltinFormat spBuiltinFormats_es_PR[] =
993 {
994     // slashes must be quoted to prevent conversion to minus
995     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
996     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
997     NUMFMT_ENDTABLE()
998 };
999 
1000 /** Spanish, Paraguay. */
1001 static const BuiltinFormat spBuiltinFormats_es_PY[] =
1002 {
1003     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1004     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Gs\"", " " ),
1005     NUMFMT_ENDTABLE()
1006 };
1007 
1008 /** Spanish, El Salvador. */
1009 static const BuiltinFormat spBuiltinFormats_es_SV[] =
1010 {
1011     // slashes must be quoted to prevent conversion to minus
1012     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1013     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
1014     NUMFMT_ENDTABLE()
1015 };
1016 
1017 /** Spanish, Uruguay. */
1018 static const BuiltinFormat spBuiltinFormats_es_UY[] =
1019 {
1020     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1021     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$U\"", " " ),
1022     NUMFMT_ENDTABLE()
1023 };
1024 
1025 /** Spanish, Venezuela. */
1026 static const BuiltinFormat spBuiltinFormats_es_VE[] =
1027 {
1028     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1029     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "Bs", " " ),
1030     NUMFMT_ENDTABLE()
1031 };
1032 
1033 /** Estonian, Estonia. */
1034 static const BuiltinFormat spBuiltinFormats_et_EE[] =
1035 {
1036     // space character is group separator, literal spaces must be quoted
1037     NUMFMT_ALLDATETIMES( "D.MM.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1038     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
1039     NUMFMT_ENDTABLE()
1040 };
1041 
1042 /** Farsi, Iran. */
1043 static const BuiltinFormat spBuiltinFormats_fa_IR[] =
1044 {
1045     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1046     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_FA_IR "\"", " " ),
1047     NUMFMT_ENDTABLE()
1048 };
1049 
1050 /** Finnish, Finland. */
1051 static const BuiltinFormat spBuiltinFormats_fi_FI[] =
1052 {
1053     // space character is group separator, literal spaces must be quoted
1054     NUMFMT_STRING(  9, "0\\ %" ),
1055     NUMFMT_STRING( 10, "0.00\\ %" ),
1056     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1057     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1058     NUMFMT_ENDTABLE()
1059 };
1060 
1061 /** Faroese, Faroe Islands. */
1062 static const BuiltinFormat spBuiltinFormats_fo_FO[] =
1063 {
1064     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1065     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
1066     NUMFMT_ENDTABLE()
1067 };
1068 
1069 /** French, Belgium. */
1070 static const BuiltinFormat spBuiltinFormats_fr_BE[] =
1071 {
1072     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1073     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1074     NUMFMT_ENDTABLE()
1075 };
1076 
1077 /** French, Canada. */
1078 static const BuiltinFormat spBuiltinFormats_fr_CA[] =
1079 {
1080     // space character is group separator, literal spaces must be quoted
1081     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1082     NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( "$", "_$", "\\ " ),
1083     NUMFMT_ENDTABLE()
1084 };
1085 
1086 /** French, Switzerland. */
1087 static const BuiltinFormat spBuiltinFormats_fr_CH[] =
1088 {
1089     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1090     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
1091     NUMFMT_ENDTABLE()
1092 };
1093 
1094 /** French, France. */
1095 static const BuiltinFormat spBuiltinFormats_fr_FR[] =
1096 {
1097     // space character is group separator, literal spaces must be quoted
1098     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1099     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1100     NUMFMT_ENDTABLE()
1101 };
1102 
1103 /** French, Luxembourg. */
1104 static const BuiltinFormat spBuiltinFormats_fr_LU[] =
1105 {
1106     // space character is group separator, literal spaces must be quoted
1107     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1108     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1109     NUMFMT_ENDTABLE()
1110 };
1111 
1112 /** French, Monaco. */
1113 static const BuiltinFormat spBuiltinFormats_fr_MC[] =
1114 {
1115     // space character is group separator, literal spaces must be quoted
1116     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1117     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1118     NUMFMT_ENDTABLE()
1119 };
1120 
1121 /** Galizian, Spain. */
1122 static const BuiltinFormat spBuiltinFormats_gl_ES[] =
1123 {
1124     NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1125     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
1126     NUMFMT_ENDTABLE()
1127 };
1128 
1129 /** Gujarati, India. */
1130 static const BuiltinFormat spBuiltinFormats_gu_IN[] =
1131 {
1132     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1133     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_GU_IN "\"", " " ),
1134     NUMFMT_ENDTABLE()
1135 };
1136 
1137 /** Hebrew, Israel. */
1138 static const BuiltinFormat spBuiltinFormats_he_IL[] =
1139 {
1140     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1141     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_SHEQEL, " " ),
1142     NUMFMT_ENDTABLE()
1143 };
1144 
1145 /** Hindi, India. */
1146 static const BuiltinFormat spBuiltinFormats_hi_IN[] =
1147 {
1148     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1149     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_HI_IN "\"", " " ),
1150     NUMFMT_ENDTABLE()
1151 };
1152 
1153 /** Croatian, Bosnia and Herzegowina. */
1154 static const BuiltinFormat spBuiltinFormats_hr_BA[] =
1155 {
1156     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1157     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"KM\"", "_K_M", " " ),
1158     NUMFMT_ENDTABLE()
1159 };
1160 
1161 /** Croatian, Croatia. */
1162 static const BuiltinFormat spBuiltinFormats_hr_HR[] =
1163 {
1164     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1165     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kn\"", "_k_n", " " ),
1166     NUMFMT_ENDTABLE()
1167 };
1168 
1169 /** Hungarian, Hungary. */
1170 static const BuiltinFormat spBuiltinFormats_hu_HU[] =
1171 {
1172     // space character is group separator, literal spaces must be quoted
1173     // MMM is rendered differently in Calc and Excel (see #i41488#)
1174     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1175     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Ft\"", "_F_t", "\\ " ),
1176     NUMFMT_ENDTABLE()
1177 };
1178 
1179 /** Armenian, Armenia. */
1180 static const BuiltinFormat spBuiltinFormats_hy_AM[] =
1181 {
1182     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1183     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_HY_DA_LC UTF8_HY_REH_LC ".\"", "_" UTF8_HY_DA_LC "_" UTF8_HY_REH_LC "_.", " " ),
1184     NUMFMT_ENDTABLE()
1185 };
1186 
1187 /** Indonesian, Indonesia. */
1188 static const BuiltinFormat spBuiltinFormats_id_ID[] =
1189 {
1190     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1191     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Rp\"", "" ),
1192     NUMFMT_ENDTABLE()
1193 };
1194 
1195 /** Icelandic, Iceland. */
1196 static const BuiltinFormat spBuiltinFormats_is_IS[] =
1197 {
1198     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
1199     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr.\"", "_k_r_.", " " ),
1200     NUMFMT_ENDTABLE()
1201 };
1202 
1203 /** Italian, Switzerland. */
1204 static const BuiltinFormat spBuiltinFormats_it_CH[] =
1205 {
1206     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1207     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
1208     NUMFMT_ENDTABLE()
1209 };
1210 
1211 /** Italian, Italy. */
1212 static const BuiltinFormat spBuiltinFormats_it_IT[] =
1213 {
1214     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1215     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
1216     NUMFMT_ENDTABLE()
1217 };
1218 
1219 /** Georgian, Georgia. */
1220 static const BuiltinFormat spBuiltinFormats_ka_GE[] =
1221 {
1222     // space character is group separator, literal spaces must be quoted
1223     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1224     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lari\"", "_L_a_r_i", "\\ " ),
1225     NUMFMT_ENDTABLE()
1226 };
1227 
1228 /** Kazakh, Kazakhstan. */
1229 static const BuiltinFormat spBuiltinFormats_kk_KZ[] =
1230 {
1231     // space character is group separator, literal spaces must be quoted
1232     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1233     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\\T", "" ),
1234     NUMFMT_ENDTABLE()
1235 };
1236 
1237 /** Kannada, India. */
1238 static const BuiltinFormat spBuiltinFormats_kn_IN[] =
1239 {
1240     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1241     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_KN_IN "\"", " " ),
1242     NUMFMT_ENDTABLE()
1243 };
1244 
1245 /** Kyrgyz, Kyrgyzstan. */
1246 static const BuiltinFormat spBuiltinFormats_ky_KG[] =
1247 {
1248     // space character is group separator, literal spaces must be quoted
1249     NUMFMT_ALLDATETIMES( "DD.MM.YY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1250     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_S_LC UTF8_CYR_O_LC UTF8_CYR_M_LC "\"", "_" UTF8_CYR_S_LC "_" UTF8_CYR_O_LC "_" UTF8_CYR_M_LC, "\\ " ),
1251     NUMFMT_ENDTABLE()
1252 };
1253 
1254 /** Lithuanian, Lithuania. */
1255 static const BuiltinFormat spBuiltinFormats_lt_LT[] =
1256 {
1257     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1258     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lt\"", "_L_t", " " ),
1259     NUMFMT_ENDTABLE()
1260 };
1261 
1262 /** Latvian, Latvia. */
1263 static const BuiltinFormat spBuiltinFormats_lv_LV[] =
1264 {
1265     // space character is group separator, literal spaces must be quoted
1266     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1267     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Ls\"", "\\ " ),
1268     NUMFMT_ENDTABLE()
1269 };
1270 
1271 /** Malayalam, India. */
1272 static const BuiltinFormat spBuiltinFormats_ml_IN[] =
1273 {
1274     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1275     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_ML_IN "\"", " " ),
1276     NUMFMT_ENDTABLE()
1277 };
1278 
1279 /** Mongolian, Mongolia. */
1280 static const BuiltinFormat spBuiltinFormats_mn_MN[] =
1281 {
1282     NUMFMT_ALLDATETIMES( "YY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1283     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_TUGRUG, "_" UTF8_TUGRUG, "" ),
1284     NUMFMT_ENDTABLE()
1285 };
1286 
1287 /** Malay, Brunei Darussalam. */
1288 static const BuiltinFormat spBuiltinFormats_ms_BN[] =
1289 {
1290     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1291     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
1292     NUMFMT_ENDTABLE()
1293 };
1294 
1295 /** Malay, Malaysia. */
1296 static const BuiltinFormat spBuiltinFormats_ms_MY[] =
1297 {
1298     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1299     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\R", "" ),
1300     NUMFMT_ENDTABLE()
1301 };
1302 
1303 /** Maltese, Malta. */
1304 static const BuiltinFormat spBuiltinFormats_mt_MT[] =
1305 {
1306     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1307     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Lm\"", "" ),
1308     NUMFMT_ENDTABLE()
1309 };
1310 
1311 /** Dutch, Belgium. */
1312 static const BuiltinFormat spBuiltinFormats_nl_BE[] =
1313 {
1314     // slashes must be quoted to prevent conversion to minus
1315     NUMFMT_ALLDATETIMES( "D\\/MM\\/YYYY", "D", "\\/", "MMM", "\\/", "YY", "h", "h" ),
1316     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1317     NUMFMT_ENDTABLE()
1318 };
1319 
1320 /** Dutch, Netherlands. */
1321 static const BuiltinFormat spBuiltinFormats_nl_NL[] =
1322 {
1323     NUMFMT_ALLDATETIMES( "D-M-YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1324     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( UTF8_EURO, " " ),
1325     NUMFMT_ENDTABLE()
1326 };
1327 
1328 /** Norwegian (Bokmal and Nynorsk), Norway. */
1329 static const BuiltinFormat spBuiltinFormats_no_NO[] =
1330 {
1331     // space character is group separator, literal spaces must be quoted
1332     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1333     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", "\\ " ),
1334     NUMFMT_ENDTABLE()
1335 };
1336 
1337 /** Punjabi, India. */
1338 static const BuiltinFormat spBuiltinFormats_pa_IN[] =
1339 {
1340     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1341     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_PA_IN "\"", " " ),
1342     NUMFMT_ENDTABLE()
1343 };
1344 
1345 /** Polish, Poland. */
1346 static const BuiltinFormat spBuiltinFormats_pl_PL[] =
1347 {
1348     // space character is group separator, literal spaces must be quoted
1349     // MMM is rendered differently in Calc and Excel (see #i72300#)
1350     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1351     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"z" UTF8_LSTROKE_LC "\"", "_z_" UTF8_LSTROKE_LC, "\\ " ),
1352     NUMFMT_ENDTABLE()
1353 };
1354 
1355 /** Portugese, Brazil. */
1356 static const BuiltinFormat spBuiltinFormats_pt_BR[] =
1357 {
1358     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "/", "MMM", "/", "YY", "h", "hh" ),
1359     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"R$\"", " " ),
1360     NUMFMT_ENDTABLE()
1361 };
1362 
1363 /** Portugese, Portugal. */
1364 static const BuiltinFormat spBuiltinFormats_pt_PT[] =
1365 {
1366     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1367     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1368     NUMFMT_ENDTABLE()
1369 };
1370 
1371 /** Romanian, Romania. */
1372 static const BuiltinFormat spBuiltinFormats_ro_RO[] =
1373 {
1374     // space character is group separator, literal spaces must be quoted (but see #i75367#)
1375     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1376     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"lei\"", "_l_e_i", "\\ " ),
1377     NUMFMT_ENDTABLE()
1378 };
1379 
1380 /** Russian, Russian Federation. */
1381 static const BuiltinFormat spBuiltinFormats_ru_RU[] =
1382 {
1383     // space character is group separator, literal spaces must be quoted
1384     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1385     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "" ),
1386     NUMFMT_ENDTABLE()
1387 };
1388 
1389 /** Slovak, Slovakia. */
1390 static const BuiltinFormat spBuiltinFormats_sk_SK[] =
1391 {
1392     // space character is group separator, literal spaces must be quoted
1393     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1394     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Sk\"", "_S_k", "\\ " ),
1395     NUMFMT_ENDTABLE()
1396 };
1397 
1398 /** Slovenian, Slovenia. */
1399 static const BuiltinFormat spBuiltinFormats_sl_SI[] =
1400 {
1401     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1402     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"SIT\"", "_S_I_T", " " ),
1403     NUMFMT_ENDTABLE()
1404 };
1405 
1406 /** Swedish, Finland. */
1407 static const BuiltinFormat spBuiltinFormats_sv_FI[] =
1408 {
1409     // space character is group separator, literal spaces must be quoted
1410     NUMFMT_STRING(  9, "0\\ %" ),
1411     NUMFMT_STRING( 10, "0.00\\ %" ),
1412     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
1413     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1414     NUMFMT_ENDTABLE()
1415 };
1416 
1417 /** Swedish, Sweden. */
1418 static const BuiltinFormat spBuiltinFormats_sv_SE[] =
1419 {
1420     // space character is group separator, literal spaces must be quoted
1421     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1422     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
1423     NUMFMT_ENDTABLE()
1424 };
1425 
1426 /** Swahili, Tanzania. */
1427 static const BuiltinFormat spBuiltinFormats_sw_TZ[] =
1428 {
1429     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1430     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\S", "" ),
1431     NUMFMT_ENDTABLE()
1432 };
1433 
1434 /** Tamil, India. */
1435 static const BuiltinFormat spBuiltinFormats_ta_IN[] =
1436 {
1437     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1438     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TA_IN "\"", " " ),
1439     NUMFMT_ENDTABLE()
1440 };
1441 
1442 /** Telugu, India. */
1443 static const BuiltinFormat spBuiltinFormats_te_IN[] =
1444 {
1445     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1446     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TE_IN "\"", " " ),
1447     NUMFMT_ENDTABLE()
1448 };
1449 
1450 /** Thai, Thailand. */
1451 static const BuiltinFormat spBuiltinFormats_th_TH[] =
1452 {
1453     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1454     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_BAHT, "" ),
1455     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 63, UTF8_BAHT, "", "t" ),
1456     NUMFMT_STRING( 59, "t0" ),
1457     NUMFMT_STRING( 60, "t0.00" ),
1458     NUMFMT_STRING( 61, "t#,##0" ),
1459     NUMFMT_STRING( 62, "t#,##0.00" ),
1460     NUMFMT_STRING( 67, "t0%" ),
1461     NUMFMT_STRING( 68, "t0.00%" ),
1462     NUMFMT_STRING( 69, "t# ?/?" ),
1463     NUMFMT_STRING( 70, "t# ?\?/?\?" ),
1464     NUMFMT_STRING( 71, "tD/M/EE" ),
1465     NUMFMT_STRING( 72, "tD-MMM-E" ),
1466     NUMFMT_STRING( 73, "tD-MMM" ),
1467     NUMFMT_STRING( 74, "tMMM-E" ),
1468     NUMFMT_STRING( 75, "th:mm" ),
1469     NUMFMT_STRING( 76, "th:mm:ss" ),
1470     NUMFMT_STRING( 77, "tD/M/EE h:mm" ),
1471     NUMFMT_STRING( 78, "tmm:ss" ),
1472     NUMFMT_STRING( 79, "t[h]:mm:ss" ),
1473     NUMFMT_STRING( 80, "tmm:ss.0" ),
1474     NUMFMT_STRING( 81, "D/M/E" ),
1475     NUMFMT_ENDTABLE()
1476 };
1477 
1478 /** Turkish, Turkey. */
1479 static const BuiltinFormat spBuiltinFormats_tr_TR[] =
1480 {
1481     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1482     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"TL\"", "_T_L", " " ),
1483     NUMFMT_ENDTABLE()
1484 };
1485 
1486 /** Tatar, Russian Federation. */
1487 static const BuiltinFormat spBuiltinFormats_tt_RU[] =
1488 {
1489     // space character is group separator, literal spaces must be quoted
1490     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1491     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
1492     NUMFMT_ENDTABLE()
1493 };
1494 
1495 /** Ukrainian, Ukraine. */
1496 static const BuiltinFormat spBuiltinFormats_uk_UA[] =
1497 {
1498     // space character is group separator, literal spaces must be quoted
1499     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1500     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_G_LC UTF8_CYR_R_LC UTF8_CYR_N_LC ".\"", "_" UTF8_CYR_G_LC "_" UTF8_CYR_R_LC "_" UTF8_CYR_N_LC "_.", "\\ " ),
1501     NUMFMT_ENDTABLE()
1502 };
1503 
1504 /** Urdu, Pakistan. */
1505 static const BuiltinFormat spBuiltinFormats_ur_PK[] =
1506 {
1507     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1508     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"Rs\"", "" ),
1509     NUMFMT_ENDTABLE()
1510 };
1511 
1512 /** Vietnamese, Viet Nam. */
1513 static const BuiltinFormat spBuiltinFormats_vi_VN[] =
1514 {
1515     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1516     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_DONG, "_" UTF8_DONG, " " ),
1517     NUMFMT_ENDTABLE()
1518 };
1519 
1520 // CJK ------------------------------------------------------------------------
1521 
1522 /** Base table for CJK locales. */
1523 static const BuiltinFormat spBuiltinFormats_CJK[] =
1524 {
1525     NUMFMT_REUSE( 29, 28 ),
1526     NUMFMT_REUSE( 36, 27 ),
1527     NUMFMT_REUSE( 50, 27 ),
1528     NUMFMT_REUSE( 51, 28 ),
1529     NUMFMT_REUSE( 52, 34 ),
1530     NUMFMT_REUSE( 53, 35 ),
1531     NUMFMT_REUSE( 54, 28 ),
1532     NUMFMT_REUSE( 55, 34 ),
1533     NUMFMT_REUSE( 56, 35 ),
1534     NUMFMT_REUSE( 57, 27 ),
1535     NUMFMT_REUSE( 58, 28 ),
1536     NUMFMT_ENDTABLE()
1537 };
1538 
1539 /** Japanese, Japan. */
1540 static const BuiltinFormat spBuiltinFormats_ja_JP[] =
1541 {
1542     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1543     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_YEN_JP, "" ),
1544     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1545     NUMFMT_STRING( 27, "[$-411]GE.MM.DD" ),
1546     NUMFMT_STRING( 28, "[$-411]GGGE\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1547     NUMFMT_STRING( 30, "MM/DD/YY" ),
1548     NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1549     NUMFMT_TIME_CJK( 32, "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1550     NUMFMT_STRING( 34, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"" ),
1551     NUMFMT_STRING( 35, "MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1552     NUMFMT_ENDTABLE()
1553 };
1554 
1555 /** Korean, South Korea. */
1556 static const BuiltinFormat spBuiltinFormats_ko_KR[] =
1557 {
1558     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1559     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_WON, "" ),
1560     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1561     NUMFMT_STRING( 27, "YYYY" UTF8_CJ_YEAR " MM" UTF8_CJ_MON " DD" UTF8_CJ_DAY ),
1562     NUMFMT_STRING( 28, "MM-DD" ),
1563     NUMFMT_STRING( 30, "MM-DD-YY" ),
1564     NUMFMT_STRING( 31, "YYYY" UTF8_KO_YEAR " MM" UTF8_KO_MON " DD" UTF8_KO_DAY ),
1565     NUMFMT_TIME_CJK( 32, "h", UTF8_KO_HOUR, UTF8_KO_MIN, UTF8_KO_SEC ),
1566     // slashes must be quoted to prevent conversion to minus
1567     NUMFMT_STRING( 34, "YYYY\\/MM\\/DD" ),
1568     NUMFMT_REUSE( 35, 14 ),
1569     NUMFMT_ENDTABLE()
1570 };
1571 
1572 /** Chinese, China. */
1573 static const BuiltinFormat spBuiltinFormats_zh_CN[] =
1574 {
1575     NUMFMT_ALLDATETIMES( "YYYY-M-D", "D", "-", "MMM", "-", "YY", "h", "h" ),
1576     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_YEN_CN, "" ),
1577     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
1578     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1579     NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
1580     NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1581     NUMFMT_STRING( 30, "M-D-YY" ),
1582     NUMFMT_STRING( 31, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1583     NUMFMT_REUSE( 52, 27 ),
1584     NUMFMT_REUSE( 53, 28 ),
1585     NUMFMT_ENDTABLE()
1586 };
1587 
1588 /** Chinese, Hong Kong. */
1589 static const BuiltinFormat spBuiltinFormats_zh_HK[] =
1590 {
1591     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1592     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"HK$\"", "" ),
1593     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1594     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1595     NUMFMT_STRING( 27, "[$-404]D/M/E" ),
1596     NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
1597     NUMFMT_STRING( 30, "M/D/YY" ),
1598     NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
1599     NUMFMT_ENDTABLE()
1600 };
1601 
1602 /** Chinese, Macau. */
1603 static const BuiltinFormat spBuiltinFormats_zh_MO[] =
1604 {
1605     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1606     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\P", "" ),
1607     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1608     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1609     NUMFMT_STRING( 27, "[$-404]D/M/E" ),
1610     NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
1611     NUMFMT_STRING( 30, "M/D/YY" ),
1612     NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
1613     NUMFMT_ENDTABLE()
1614 };
1615 
1616 /** Chinese, Singapore. */
1617 static const BuiltinFormat spBuiltinFormats_zh_SG[] =
1618 {
1619     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1620     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
1621     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
1622     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1623     NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
1624     NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1625     NUMFMT_STRING( 30, "M/D/YY" ),
1626     NUMFMT_STRING( 31, "D\"" UTF8_CS_DAY "\"M\"" UTF8_CS_MON "\"YYYY\"" UTF8_CS_YEAR "\"" ),
1627     NUMFMT_ENDTABLE()
1628 };
1629 
1630 /** Chinese, Taiwan. */
1631 static const BuiltinFormat spBuiltinFormats_zh_TW[] =
1632 {
1633     NUMFMT_ALLDATETIMES( "YYYY/M/D", "D", "-", "MMM", "-", "YY", "hh", "hh" ),
1634     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
1635     NUMFMT_ALLTIMES_CJK( "hh", "hh", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1636     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1637     NUMFMT_STRING( 27, "[$-404]E/M/D" ),
1638     NUMFMT_STRING( 28, "[$-404]E\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
1639     NUMFMT_STRING( 30, "M/D/YY" ),
1640     NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
1641     NUMFMT_ENDTABLE()
1642 };
1643 
1644 // ----------------------------------------------------------------------------
1645 
1646 /** Specifies a built-in number format table for a specific locale. */
1647 struct BuiltinFormatTable
1648 {
1649     const sal_Char*     mpcLocale;          /// The locale for this table.
1650     const sal_Char*     mpcParent;          /// The locale of the parent table.
1651     const BuiltinFormat* mpFormats;         /// The number format table (may be 0, if equal to parent).
1652 };
1653 
1654 static const BuiltinFormatTable spBuiltinFormatTables[] =
1655 { //  locale    parent      format table
1656     { "*",      "",         spBuiltinFormats_BASE   },  // Base table
1657     { "af-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Afrikaans, South Africa
1658     { "ar-AE",  "*",        spBuiltinFormats_ar_AE  },  // Arabic, U.A.E.
1659     { "ar-BH",  "*",        spBuiltinFormats_ar_BH  },  // Arabic, Bahrain
1660     { "ar-DZ",  "*",        spBuiltinFormats_ar_DZ  },  // Arabic, Algeria
1661     { "ar-EG",  "*",        spBuiltinFormats_ar_EG  },  // Arabic, Egypt
1662     { "ar-IQ",  "*",        spBuiltinFormats_ar_IQ  },  // Arabic, Iraq
1663     { "ar-JO",  "*",        spBuiltinFormats_ar_JO  },  // Arabic, Jordan
1664     { "ar-KW",  "*",        spBuiltinFormats_ar_KW  },  // Arabic, Kuwait
1665     { "ar-LB",  "*",        spBuiltinFormats_ar_LB  },  // Arabic, Lebanon
1666     { "ar-LY",  "*",        spBuiltinFormats_ar_LY  },  // Arabic, Libya
1667     { "ar-MA",  "*",        spBuiltinFormats_ar_MA  },  // Arabic, Morocco
1668     { "ar-OM",  "*",        spBuiltinFormats_ar_OM  },  // Arabic, Oman
1669     { "ar-QA",  "*",        spBuiltinFormats_ar_QA  },  // Arabic, Qatar
1670     { "ar-SA",  "*",        spBuiltinFormats_ar_SA  },  // Arabic, Saudi Arabia
1671     { "ar-SY",  "*",        spBuiltinFormats_ar_SY  },  // Arabic, Syria
1672     { "ar-TN",  "*",        spBuiltinFormats_ar_TN  },  // Arabic, Tunisia
1673     { "ar-YE",  "*",        spBuiltinFormats_ar_YE  },  // Arabic, Yemen
1674     { "be-BY",  "*",        spBuiltinFormats_be_BY  },  // Belarusian, Belarus
1675     { "bg-BG",  "*",        spBuiltinFormats_bg_BG  },  // Bulgarian, Bulgaria
1676     { "bn-IN",  "*",        spBuiltinFormats_bn_IN  },  // Bengali, India
1677     { "ca-ES",  "*",        spBuiltinFormats_es_ES  },  // Catalan, Spain
1678     { "cs-CZ",  "*",        spBuiltinFormats_cs_CZ  },  // Czech, Czech Republic
1679     { "cy-GB",  "*",        spBuiltinFormats_en_GB  },  // Welsh, United Kingdom
1680     { "da-DK",  "*",        spBuiltinFormats_da_DK  },  // Danish, Denmark
1681     { "de-AT",  "*",        spBuiltinFormats_de_AT  },  // German, Austria
1682     { "de-CH",  "*",        spBuiltinFormats_de_CH  },  // German, Switzerland
1683     { "de-DE",  "*",        spBuiltinFormats_de_DE  },  // German, Germany
1684     { "de-LI",  "*",        spBuiltinFormats_de_LI  },  // German, Liechtenstein
1685     { "de-LU",  "*",        spBuiltinFormats_de_LU  },  // German, Luxembourg
1686     { "div-MV", "*",        spBuiltinFormats_div_MV },  // Divehi, Maldives
1687     { "el-GR",  "*",        spBuiltinFormats_el_GR  },  // Greek, Greece
1688     { "en-AU",  "*",        spBuiltinFormats_en_AU  },  // English, Australia
1689     { "en-BZ",  "*",        spBuiltinFormats_en_BZ  },  // English, Belize
1690     { "en-CA",  "*",        spBuiltinFormats_en_CA  },  // English, Canada
1691     { "en-CB",  "*",        spBuiltinFormats_en_CB  },  // English, Caribbean
1692     { "en-GB",  "*",        spBuiltinFormats_en_GB  },  // English, United Kingdom
1693     { "en-IE",  "*",        spBuiltinFormats_en_IE  },  // English, Ireland
1694     { "en-JM",  "*",        spBuiltinFormats_en_JM  },  // English, Jamaica
1695     { "en-NZ",  "*",        spBuiltinFormats_en_NZ  },  // English, New Zealand
1696     { "en-PH",  "*",        spBuiltinFormats_en_PH  },  // English, Philippines
1697     { "en-TT",  "*",        spBuiltinFormats_en_TT  },  // English, Trinidad and Tobago
1698     { "en-US",  "*",        spBuiltinFormats_en_US  },  // English, USA
1699     { "en-ZA",  "*",        spBuiltinFormats_en_ZA  },  // English, South Africa
1700     { "en-ZW",  "*",        spBuiltinFormats_en_ZW  },  // English, Zimbabwe
1701     { "es-AR",  "*",        spBuiltinFormats_es_AR  },  // Spanish, Argentina
1702     { "es-BO",  "*",        spBuiltinFormats_es_BO  },  // Spanish, Bolivia
1703     { "es-CL",  "*",        spBuiltinFormats_es_CL  },  // Spanish, Chile
1704     { "es-CO",  "*",        spBuiltinFormats_es_CO  },  // Spanish, Colombia
1705     { "es-CR",  "*",        spBuiltinFormats_es_CR  },  // Spanish, Costa Rica
1706     { "es-DO",  "*",        spBuiltinFormats_es_DO  },  // Spanish, Dominican Republic
1707     { "es-EC",  "*",        spBuiltinFormats_es_EC  },  // Spanish, Ecuador
1708     { "es-ES",  "*",        spBuiltinFormats_es_ES  },  // Spanish, Spain
1709     { "es-GT",  "*",        spBuiltinFormats_es_GT  },  // Spanish, Guatemala
1710     { "es-HN",  "*",        spBuiltinFormats_es_HN  },  // Spanish, Honduras
1711     { "es-MX",  "*",        spBuiltinFormats_es_MX  },  // Spanish, Mexico
1712     { "es-NI",  "*",        spBuiltinFormats_es_NI  },  // Spanish, Nicaragua
1713     { "es-PA",  "*",        spBuiltinFormats_es_PA  },  // Spanish, Panama
1714     { "es-PE",  "*",        spBuiltinFormats_es_PE  },  // Spanish, Peru
1715     { "es-PR",  "*",        spBuiltinFormats_es_PR  },  // Spanish, Puerto Rico
1716     { "es-PY",  "*",        spBuiltinFormats_es_PY  },  // Spanish, Paraguay
1717     { "es-SV",  "*",        spBuiltinFormats_es_SV  },  // Spanish, El Salvador
1718     { "es-UY",  "*",        spBuiltinFormats_es_UY  },  // Spanish, Uruguay
1719     { "es-VE",  "*",        spBuiltinFormats_es_VE  },  // Spanish, Venezuela
1720     { "et-EE",  "*",        spBuiltinFormats_et_EE  },  // Estonian, Estonia
1721     { "fa-IR",  "*",        spBuiltinFormats_fa_IR  },  // Farsi, Iran
1722     { "fi-FI",  "*",        spBuiltinFormats_fi_FI  },  // Finnish, Finland
1723     { "fo-FO",  "*",        spBuiltinFormats_fo_FO  },  // Faroese, Faroe Islands
1724     { "fr-BE",  "*",        spBuiltinFormats_fr_BE  },  // French, Belgium
1725     { "fr-CA",  "*",        spBuiltinFormats_fr_CA  },  // French, Canada
1726     { "fr-CH",  "*",        spBuiltinFormats_fr_CH  },  // French, Switzerland
1727     { "fr-FR",  "*",        spBuiltinFormats_fr_FR  },  // French, France
1728     { "fr-LU",  "*",        spBuiltinFormats_fr_LU  },  // French, Luxembourg
1729     { "fr-MC",  "*",        spBuiltinFormats_fr_MC  },  // French, Monaco
1730     { "gl-ES",  "*",        spBuiltinFormats_gl_ES  },  // Galizian, Spain
1731     { "gu-IN",  "*",        spBuiltinFormats_gu_IN  },  // Gujarati, India
1732     { "he-IL",  "*",        spBuiltinFormats_he_IL  },  // Hebrew, Israel
1733     { "hi-IN",  "*",        spBuiltinFormats_hi_IN  },  // Hindi, India
1734     { "hr-BA",  "*",        spBuiltinFormats_hr_BA  },  // Croatian, Bosnia and Herzegowina
1735     { "hr-HR",  "*",        spBuiltinFormats_hr_HR  },  // Croatian, Croatia
1736     { "hu-HU",  "*",        spBuiltinFormats_hu_HU  },  // Hungarian, Hungary
1737     { "hy-AM",  "*",        spBuiltinFormats_hy_AM  },  // Armenian, Armenia
1738     { "id-ID",  "*",        spBuiltinFormats_id_ID  },  // Indonesian, Indonesia
1739     { "is-IS",  "*",        spBuiltinFormats_is_IS  },  // Icelandic, Iceland
1740     { "it-CH",  "*",        spBuiltinFormats_it_CH  },  // Italian, Switzerland
1741     { "it-IT",  "*",        spBuiltinFormats_it_IT  },  // Italian, Italy
1742     { "ka-GE",  "*",        spBuiltinFormats_ka_GE  },  // Georgian, Georgia
1743     { "kk-KZ",  "*",        spBuiltinFormats_kk_KZ  },  // Kazakh, Kazakhstan
1744     { "kn-IN",  "*",        spBuiltinFormats_kn_IN  },  // Kannada, India
1745     { "kok-IN", "*",        spBuiltinFormats_hi_IN  },  // Konkani, India
1746     { "ky-KG",  "*",        spBuiltinFormats_ky_KG  },  // Kyrgyz, Kyrgyzstan
1747     { "lt-LT",  "*",        spBuiltinFormats_lt_LT  },  // Lithuanian, Lithuania
1748     { "lv-LV",  "*",        spBuiltinFormats_lv_LV  },  // Latvian, Latvia
1749     { "mi-NZ",  "*",        spBuiltinFormats_en_NZ  },  // Maori, New Zealand
1750     { "ml-IN",  "*",        spBuiltinFormats_ml_IN  },  // Malayalam, India
1751     { "mn-MN",  "*",        spBuiltinFormats_mn_MN  },  // Mongolian, Mongolia
1752     { "mr-IN",  "*",        spBuiltinFormats_hi_IN  },  // Marathi, India
1753     { "ms-BN",  "*",        spBuiltinFormats_ms_BN  },  // Malay, Brunei Darussalam
1754     { "ms-MY",  "*",        spBuiltinFormats_ms_MY  },  // Malay, Malaysia
1755     { "mt-MT",  "*",        spBuiltinFormats_mt_MT  },  // Maltese, Malta
1756     { "nb-NO",  "*",        spBuiltinFormats_no_NO  },  // Norwegian Bokmal, Norway
1757     { "nl-BE",  "*",        spBuiltinFormats_nl_BE  },  // Dutch, Belgium
1758     { "nl-NL",  "*",        spBuiltinFormats_nl_NL  },  // Dutch, Netherlands
1759     { "nn-NO",  "*",        spBuiltinFormats_no_NO  },  // Norwegian Nynorsk, Norway
1760     { "nso-ZA", "*",        spBuiltinFormats_en_ZA  },  // Northern Sotho, South Africa
1761     { "pa-IN",  "*",        spBuiltinFormats_pa_IN  },  // Punjabi, India
1762     { "pl-PL",  "*",        spBuiltinFormats_pl_PL  },  // Polish, Poland
1763     { "pt-BR",  "*",        spBuiltinFormats_pt_BR  },  // Portugese, Brazil
1764     { "pt-PT",  "*",        spBuiltinFormats_pt_PT  },  // Portugese, Portugal
1765     { "qu-BO",  "*",        spBuiltinFormats_es_BO  },  // Quechua, Bolivia
1766     { "qu-EC",  "*",        spBuiltinFormats_es_EC  },  // Quechua, Ecuador
1767     { "qu-PE",  "*",        spBuiltinFormats_es_PE  },  // Quechua, Peru
1768     { "ro-RO",  "*",        spBuiltinFormats_ro_RO  },  // Romanian, Romania
1769     { "ru-RU",  "*",        spBuiltinFormats_ru_RU  },  // Russian, Russian Federation
1770     { "sa-IN",  "*",        spBuiltinFormats_hi_IN  },  // Sanskrit, India
1771     { "se-FI",  "*",        spBuiltinFormats_fi_FI  },  // Sami, Finland
1772     { "se-NO",  "*",        spBuiltinFormats_no_NO  },  // Sami, Norway
1773     { "se-SE",  "*",        spBuiltinFormats_sv_SE  },  // Sami, Sweden
1774     { "sk-SK",  "*",        spBuiltinFormats_sk_SK  },  // Slovak, Slovakia
1775     { "sl-SI",  "*",        spBuiltinFormats_sl_SI  },  // Slovenian, Slovenia
1776     { "sv-FI",  "*",        spBuiltinFormats_sv_FI  },  // Swedish, Finland
1777     { "sv-SE",  "*",        spBuiltinFormats_sv_SE  },  // Swedish, Sweden
1778     { "sw-TZ",  "*",        spBuiltinFormats_sw_TZ  },  // Swahili, Tanzania
1779     { "syr-SY", "*",        spBuiltinFormats_ar_SY  },  // Syriac, Syria
1780     { "syr-TR", "*",        spBuiltinFormats_tr_TR  },  // Syriac, Turkey
1781     { "ta-IN",  "*",        spBuiltinFormats_ta_IN  },  // Tamil, India
1782     { "te-IN",  "*",        spBuiltinFormats_te_IN  },  // Telugu, India
1783     { "th-TH",  "*",        spBuiltinFormats_th_TH  },  // Thai, Thailand
1784     { "tn-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Tswana, South Africa
1785     { "tr-TR",  "*",        spBuiltinFormats_tr_TR  },  // Turkish, Turkey
1786     { "tt-RU",  "*",        spBuiltinFormats_tt_RU  },  // Tatar, Russian Federation
1787     { "uk-UA",  "*",        spBuiltinFormats_uk_UA  },  // Ukrainian, Ukraine
1788     { "ur-PK",  "*",        spBuiltinFormats_ur_PK  },  // Urdu, Pakistan
1789     { "vi-VN",  "*",        spBuiltinFormats_vi_VN  },  // Vietnamese, Viet Nam
1790     { "xh-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Xhosa, South Africa
1791     { "zu-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Zulu, South Africa
1792 
1793     { "*CJK",   "*",        spBuiltinFormats_CJK    },  // CJK base table
1794     { "ja-JP",  "*CJK",     spBuiltinFormats_ja_JP  },  // Japanese, Japan
1795     { "ko-KR",  "*CJK",     spBuiltinFormats_ko_KR  },  // Korean, South Korea
1796     { "zh-CN",  "*CJK",     spBuiltinFormats_zh_CN  },  // Chinese, China
1797     { "zh-HK",  "*CJK",     spBuiltinFormats_zh_HK  },  // Chinese, Hong Kong
1798     { "zh-MO",  "*CJK",     spBuiltinFormats_zh_MO  },  // Chinese, Macau
1799     { "zh-SG",  "*CJK",     spBuiltinFormats_zh_SG  },  // Chinese, Singapore
1800     { "zh-TW",  "*CJK",     spBuiltinFormats_zh_TW  }   // Chinese, Taiwan
1801 };
1802 
1803 } // namespace
1804 
1805 // ============================================================================
1806 
1807 NumFmtModel::NumFmtModel() :
1808     mnPredefId( -1 )
1809 {
1810 }
1811 
1812 // ----------------------------------------------------------------------------
1813 
1814 ApiNumFmtData::ApiNumFmtData() :
1815     mnIndex( 0 )
1816 {
1817 }
1818 
1819 // ----------------------------------------------------------------------------
1820 
1821 namespace {
1822 
1823 sal_Int32 lclCreatePredefinedFormat( const Reference< XNumberFormats >& rxNumFmts,
1824         sal_Int16 nPredefId, const Locale& rToLocale )
1825 {
1826     sal_Int32 nIndex = 0;
1827     try
1828     {
1829         Reference< XNumberFormatTypes > xNumFmtTypes( rxNumFmts, UNO_QUERY_THROW );
1830         nIndex = (nPredefId >= 0) ?
1831             xNumFmtTypes->getFormatIndex( nPredefId, rToLocale ) :
1832             xNumFmtTypes->getStandardIndex( rToLocale );
1833     }
1834     catch( Exception& )
1835     {
1836         OSL_ENSURE( false,
1837             OStringBuffer( "lclCreatePredefinedFormat - cannot create predefined number format " ).
1838             append( OString::valueOf( static_cast< sal_Int32 >( nPredefId ) ) ).getStr() );
1839     }
1840     return nIndex;
1841 }
1842 
1843 sal_Int32 lclCreateFormat( const Reference< XNumberFormats >& rxNumFmts,
1844         const OUString& rFmtCode, const Locale& rToLocale, const Locale& rFromLocale )
1845 {
1846     sal_Int32 nIndex = 0;
1847     try
1848     {
1849         nIndex = rxNumFmts->addNewConverted( rFmtCode, rFromLocale, rToLocale );
1850     }
1851     catch( Exception& )
1852     {
1853         // BIFF2-BIFF4 stores standard format explicitly in stream
1854         if( rFmtCode.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "general" ) ) )
1855         {
1856             nIndex = lclCreatePredefinedFormat( rxNumFmts, 0, rToLocale );
1857         }
1858         else
1859         {
1860             // do not assert fractional number formats with fixed denominator
1861             OSL_ENSURE( rFmtCode.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "#\\ ?/" ) ) ||
1862                         rFmtCode.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "#\\ ?\?/" ) ) ||
1863                         rFmtCode.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "#\\ ?\?\?/" ) ),
1864                 OStringBuffer( "lclCreateFormat - cannot create number format '" ).
1865                 append( OUStringToOString( rFmtCode, osl_getThreadTextEncoding() ) ).
1866                 append( '\'' ).getStr() );
1867         }
1868     }
1869     return nIndex;
1870 }
1871 
1872 // ----------------------------------------------------------------------------
1873 
1874 /** Functor for converting an XML number format to an API number format index. */
1875 class NumberFormatFinalizer
1876 {
1877 public:
1878     explicit            NumberFormatFinalizer( const WorkbookHelper& rHelper );
1879 
1880     inline bool         is() const { return mxNumFmts.is(); }
1881 
1882     inline void         operator()( NumberFormat& rNumFmt ) const
1883                             { rNumFmt.finalizeImport( mxNumFmts, maEnUsLocale ); }
1884 
1885 private:
1886     Reference< XNumberFormats > mxNumFmts;
1887     Locale              maEnUsLocale;
1888 };
1889 
1890 NumberFormatFinalizer::NumberFormatFinalizer( const WorkbookHelper& rHelper ) :
1891     maEnUsLocale( CREATE_OUSTRING( "en" ), CREATE_OUSTRING( "US" ), OUString() )
1892 {
1893     try
1894     {
1895         Reference< XNumberFormatsSupplier > xNumFmtsSupp( rHelper.getDocument(), UNO_QUERY_THROW );
1896         mxNumFmts = xNumFmtsSupp->getNumberFormats();
1897     }
1898     catch( Exception& )
1899     {
1900     }
1901     OSL_ENSURE( mxNumFmts.is(), "NumberFormatFinalizer::NumberFormatFinalizer - cannot get number formats" );
1902 }
1903 
1904 } // namespace
1905 
1906 // ----------------------------------------------------------------------------
1907 
1908 NumberFormat::NumberFormat( const WorkbookHelper& rHelper ) :
1909     WorkbookHelper( rHelper )
1910 {
1911 }
1912 
1913 void NumberFormat::setFormatCode( const OUString& rFmtCode )
1914 {
1915     maModel.maFmtCode = rFmtCode;
1916 }
1917 
1918 void NumberFormat::setFormatCode( const Locale& rLocale, const sal_Char* pcFmtCode )
1919 {
1920     maModel.maLocale = rLocale;
1921     maModel.maFmtCode = OStringToOUString( OString( pcFmtCode ), RTL_TEXTENCODING_UTF8 );
1922     maModel.mnPredefId = -1;
1923 }
1924 
1925 void NumberFormat::setPredefinedId( const Locale& rLocale, sal_Int16 nPredefId )
1926 {
1927     maModel.maLocale = rLocale;
1928     maModel.maFmtCode = OUString();
1929     maModel.mnPredefId = nPredefId;
1930 }
1931 
1932 sal_Int32 NumberFormat::finalizeImport( const Reference< XNumberFormats >& rxNumFmts, const Locale& rFromLocale )
1933 {
1934     if( rxNumFmts.is() && (maModel.maFmtCode.getLength() > 0) )
1935         maApiData.mnIndex = lclCreateFormat( rxNumFmts, maModel.maFmtCode, maModel.maLocale, rFromLocale );
1936     else
1937         maApiData.mnIndex = lclCreatePredefinedFormat( rxNumFmts, maModel.mnPredefId, maModel.maLocale );
1938     return maApiData.mnIndex;
1939 }
1940 
1941 void NumberFormat::writeToPropertyMap( PropertyMap& rPropMap ) const
1942 {
1943     rPropMap[ PROP_NumberFormat ] <<= maApiData.mnIndex;
1944 }
1945 
1946 // ============================================================================
1947 
1948 NumberFormatsBuffer::NumberFormatsBuffer( const WorkbookHelper& rHelper ) :
1949     WorkbookHelper( rHelper ),
1950     mnNextBiffIndex( 0 )
1951 {
1952     // get the current locale
1953     try
1954     {
1955         Reference< XMultiServiceFactory > xConfigProv( getBaseFilter().getServiceFactory()->createInstance(
1956             CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationProvider" ) ), UNO_QUERY_THROW );
1957 
1958         // try user-defined locale setting
1959         Sequence< Any > aArgs( 1 );
1960         aArgs[ 0 ] <<= CREATE_OUSTRING( "org.openoffice.Setup/L10N/" );
1961         Reference< XNameAccess > xConfigNA( xConfigProv->createInstanceWithArguments(
1962             CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationAccess" ), aArgs ), UNO_QUERY_THROW );
1963         xConfigNA->getByName( CREATE_OUSTRING( "ooSetupSystemLocale" ) ) >>= maLocaleStr;
1964 
1965         // if set to "use system", get locale from system
1966         if( maLocaleStr.getLength() == 0 )
1967         {
1968             aArgs[ 0 ] <<= CREATE_OUSTRING( "org.openoffice.System/L10N/" );
1969             xConfigNA.set( xConfigProv->createInstanceWithArguments(
1970                 CREATE_OUSTRING( "com.sun.star.configuration.ConfigurationAccess" ), aArgs ), UNO_QUERY_THROW );
1971             xConfigNA->getByName( CREATE_OUSTRING( "Locale" ) ) >>= maLocaleStr;
1972         }
1973     }
1974     catch( Exception& )
1975     {
1976         OSL_ENSURE( false, "NumberFormatsBuffer::NumberFormatsBuffer - cannot get system locale" );
1977     }
1978 
1979     // create built-in formats for current locale
1980     insertBuiltinFormats();
1981 }
1982 
1983 NumberFormatRef NumberFormatsBuffer::createNumFmt( sal_Int32 nNumFmtId, const OUString& rFmtCode )
1984 {
1985     NumberFormatRef xNumFmt;
1986     if( nNumFmtId >= 0 )
1987     {
1988         xNumFmt.reset( new NumberFormat( *this ) );
1989         maNumFmts[ nNumFmtId ] = xNumFmt;
1990         xNumFmt->setFormatCode( rFmtCode );
1991     }
1992     return xNumFmt;
1993 }
1994 
1995 NumberFormatRef NumberFormatsBuffer::importNumFmt( const AttributeList& rAttribs )
1996 {
1997     sal_Int32 nNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 );
1998     OUString aFmtCode = rAttribs.getXString( XML_formatCode, OUString() );
1999     return createNumFmt( nNumFmtId, aFmtCode );
2000 }
2001 
2002 void NumberFormatsBuffer::importNumFmt( SequenceInputStream& rStrm )
2003 {
2004     sal_Int32 nNumFmtId = rStrm.readuInt16();
2005     OUString aFmtCode = BiffHelper::readString( rStrm );
2006     createNumFmt( nNumFmtId, aFmtCode );
2007 }
2008 
2009 void NumberFormatsBuffer::importFormat( BiffInputStream& rStrm )
2010 {
2011     OUString aFmtCode;
2012     switch( getBiff() )
2013     {
2014         case BIFF2:
2015         case BIFF3:
2016             aFmtCode = rStrm.readByteStringUC( false, getTextEncoding() );
2017         break;
2018         case BIFF4:
2019             rStrm.skip( 2 );    // in BIFF4 the index field exists, but is undefined
2020             aFmtCode = rStrm.readByteStringUC( false, getTextEncoding() );
2021         break;
2022         case BIFF5:
2023             mnNextBiffIndex = rStrm.readuInt16();
2024             aFmtCode = rStrm.readByteStringUC( false, getTextEncoding() );
2025         break;
2026         case BIFF8:
2027             mnNextBiffIndex = rStrm.readuInt16();
2028             aFmtCode = rStrm.readUniString();
2029         break;
2030         case BIFF_UNKNOWN: break;
2031     }
2032 
2033     createNumFmt( mnNextBiffIndex, aFmtCode );
2034     ++mnNextBiffIndex;
2035 }
2036 
2037 void NumberFormatsBuffer::finalizeImport()
2038 {
2039     maNumFmts.forEach( NumberFormatFinalizer( *this ) );
2040 }
2041 
2042 void NumberFormatsBuffer::writeToPropertyMap( PropertyMap& rPropMap, sal_Int32 nNumFmtId ) const
2043 {
2044     if( const NumberFormat* pNumFmt = maNumFmts.get( nNumFmtId ).get() )
2045         pNumFmt->writeToPropertyMap( rPropMap );
2046 }
2047 
2048 void NumberFormatsBuffer::insertBuiltinFormats()
2049 {
2050     // build a map containing pointers to all tables
2051     typedef ::std::map< OUString, const BuiltinFormatTable* > BuiltinMap;
2052     BuiltinMap aBuiltinMap;
2053     for( const BuiltinFormatTable* pTable = spBuiltinFormatTables;
2054             pTable != STATIC_ARRAY_END( spBuiltinFormatTables ); ++pTable )
2055         aBuiltinMap[ OUString::createFromAscii( pTable->mpcLocale ) ] = pTable;
2056 
2057     // convert locale string to locale struct
2058     Locale aSysLocale;
2059     sal_Int32 nDashPos = maLocaleStr.indexOf( '-' );
2060     if( nDashPos < 0 ) nDashPos = maLocaleStr.getLength();
2061     aSysLocale.Language = maLocaleStr.copy( 0, nDashPos );
2062     if( nDashPos + 1 < maLocaleStr.getLength() )
2063         aSysLocale.Country = maLocaleStr.copy( nDashPos + 1 );
2064 
2065     // build a list of table pointers for the current locale, with all parent tables
2066     typedef ::std::vector< const BuiltinFormatTable* > BuiltinVec;
2067     BuiltinVec aBuiltinVec;
2068     BuiltinMap::const_iterator aMIt = aBuiltinMap.find( maLocaleStr ), aMEnd = aBuiltinMap.end();
2069     OSL_ENSURE( aMIt != aMEnd,
2070         OStringBuffer( "NumberFormatsBuffer::insertBuiltinFormats - locale '" ).
2071         append( OUStringToOString( maLocaleStr, RTL_TEXTENCODING_ASCII_US ) ).
2072         append( "' not supported (#i29949#)" ).getStr() );
2073     // start with default table, if no table has been found
2074     if( aMIt == aMEnd )
2075         aMIt = aBuiltinMap.find( CREATE_OUSTRING( "*" ) );
2076     OSL_ENSURE( aMIt != aMEnd, "NumberFormatsBuffer::insertBuiltinFormats - default map not found" );
2077     // insert all tables into the vector
2078     for( ; aMIt != aMEnd; aMIt = aBuiltinMap.find( OUString::createFromAscii( aMIt->second->mpcParent ) ) )
2079         aBuiltinVec.push_back( aMIt->second );
2080 
2081     // insert the default formats in the format map (in reverse order from default table to system locale)
2082     typedef ::std::map< sal_Int32, sal_Int32 > ReuseMap;
2083     ReuseMap aReuseMap;
2084     for( BuiltinVec::reverse_iterator aVIt = aBuiltinVec.rbegin(), aVEnd = aBuiltinVec.rend(); aVIt != aVEnd; ++aVIt )
2085     {
2086         // do not put the current system locale for default table
2087         Locale aLocale;
2088         if( (*aVIt)->mpcLocale[ 0 ] != '\0' )
2089             aLocale = aSysLocale;
2090         for( const BuiltinFormat* pBuiltin = (*aVIt)->mpFormats; pBuiltin && (pBuiltin->mnNumFmtId >= 0); ++pBuiltin )
2091         {
2092             NumberFormatRef& rxNumFmt = maNumFmts[ pBuiltin->mnNumFmtId ];
2093             rxNumFmt.reset( new NumberFormat( *this ) );
2094 
2095             bool bReuse = false;
2096             if( pBuiltin->mpcFmtCode )
2097                 rxNumFmt->setFormatCode( aLocale, pBuiltin->mpcFmtCode );
2098             else if( pBuiltin->mnPredefId >= 0 )
2099                 rxNumFmt->setPredefinedId( aLocale, pBuiltin->mnPredefId );
2100             else
2101                 bReuse = pBuiltin->mnReuseId >= 0;
2102 
2103             if( bReuse )
2104                 aReuseMap[ pBuiltin->mnNumFmtId ] = pBuiltin->mnReuseId;
2105             else
2106                 aReuseMap.erase( pBuiltin->mnNumFmtId );
2107         }
2108     }
2109 
2110     // copy reused number formats
2111     for( ReuseMap::const_iterator aRIt = aReuseMap.begin(), aREnd = aReuseMap.end(); aRIt != aREnd; ++aRIt )
2112         maNumFmts[ aRIt->first ] = maNumFmts[ aRIt->second ];
2113 }
2114 
2115 // ============================================================================
2116 
2117 } // namespace xls
2118 } // namespace oox
2119