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