1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <defaultnumberingprovider.hxx>
21 #include <transliterationImpl.hxx>
22 #include <com/sun/star/i18n/NativeNumberMode.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <com/sun/star/style/NumberingType.hpp>
25 #include <com/sun/star/beans/PropertyValue.hpp>
26 #include <com/sun/star/configuration/theDefaultProvider.hpp>
27 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
28 #include <osl/diagnose.h>
29 #include <rtl/ref.hxx>
30 #include <localedata.hxx>
31 #include <nativenumbersupplier.hxx>
32 #include <string.h>
33 #include <comphelper/propertysequence.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <officecfg/Office/Common.hxx>
36
37 // Cyrillic upper case
38 #define C_CYR_A "\xD0\x90"
39 #define C_CYR_B "\xD0\x91"
40 // Cyrillic lower case
41 #define S_CYR_A "\xD0\xB0"
42 #define S_CYR_B "\xD0\xB1"
43
44 //Greek upper case
45 #define C_GR_A "\xCE\x91"
46 #define C_GR_B "\xCE\x92"
47 //Greek lower case
48 #define S_GR_A "\xCE\xB1"
49 #define S_GR_B "\xCE\xB2"
50
51 //Hebrew
52 #define S_HE_ALEPH "\xD7\x90"
53 #define S_HE_YOD "\xD7\x99"
54 #define S_HE_QOF "\xD7\xA7"
55
56 //Arabic-Indic
57 #define S_AR_ONE "\xd9\xa1"
58 #define S_AR_TWO "\xd9\xa2"
59 #define S_AR_THREE "\xd9\xa3"
60
61 // East Arabic-Indic
62 #define S_FA_ONE "\xDB\xB1"
63 #define S_FA_TWO "\xDB\xB2"
64 #define S_FA_THREE "\xDB\xB3"
65
66 // Indic Devanagari
67 #define S_HI_ONE "\xE0\xA5\xA7"
68 #define S_HI_TWO "\xE0\xA5\xA8"
69 #define S_HI_THREE "\xE0\xA5\xA9"
70
71 // Chicago footnote symbols
72 #define S_DAGGER "\xE2\x80\xA0"
73 #define S_DBL_DAGGER "\xE2\x80\xA1"
74 #define S_SECTION "\xC2\xA7"
75
76 #include <sal/macros.h>
77 #include <rtl/ustring.hxx>
78 #include <rtl/ustrbuf.hxx>
79
80 #include <bullet.h>
81
82 using namespace com::sun::star;
83 using namespace com::sun::star::uno;
84 using namespace ::com::sun::star::i18n;
85 using namespace com::sun::star::lang;
86
87 namespace i18npool {
88
89 const sal_Unicode table_Alphabet_ar[] = {
90 0x0623, 0x0628, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E,
91 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635,
92 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x0642,
93 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649
94 };
95
96 const sal_Unicode table_Alphabet_ar_abjad[] = {
97 0x0627, 0x0628, 0x062c, 0x062f, 0x0647, 0x0648, 0x0632, 0x062d,
98 0x0637, 0x064a, 0x0643, 0x0644, 0x0645, 0x0646, 0x0633, 0x0639,
99 0x0641, 0x0635, 0x0642, 0x0631, 0x0634, 0x062a, 0x062b, 0x062e,
100 0x0630, 0x0636, 0x0638, 0x063a
101 };
102
103 const sal_Unicode table_Alphabet_th[] = {
104 0x0E01, 0x0E02, 0x0E04, 0x0E07,
105 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
106 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
107 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
108 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
109 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E
110 };
111
112 const sal_Unicode table_Alphabet_he[] = {
113 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
114 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, 0x05E1, 0x05E2,
115 0x05E4, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA
116 };
117
118 const sal_Unicode table_Alphabet_ne[] = {
119 0x0915, 0x0916, 0x0917, 0x0918, 0x0919, 0x091A, 0x091B, 0x091C,
120 0x091D, 0x091E, 0x091F, 0x0920, 0x0921, 0x0922, 0x0923, 0x0924,
121 0x0925, 0x0926, 0x0927, 0x0928, 0x092A, 0x092B, 0x092C, 0x092D,
122 0x092E, 0x092F, 0x0930, 0x0932, 0x0935, 0x0936, 0x0937, 0x0938,
123 0x0939
124 };
125
126 const sal_Unicode table_Alphabet_km[] = {
127 0x1780, 0x1781, 0x1782, 0x1783, 0x1784, 0x1785, 0x1786, 0x1787,
128 0x1788, 0x1789, 0x178A, 0x178B, 0x178C, 0x178D, 0x178E, 0x178F,
129 0x1790, 0x1791, 0x1792, 0x1793, 0x1794, 0x1795, 0x1796, 0x1797,
130 0x1798, 0x1799, 0x179A, 0x179B, 0x179C, 0x179F,
131 0x17A0, 0x17A1, 0x17A2
132 };
133
134 const sal_Unicode table_Alphabet_lo[] = {
135 0x0E81, 0x0E82, 0x0E84, 0x0E87, 0x0E88, 0x0E8A, 0x0E8D, 0x0E94,
136 0x0E95, 0x0E96, 0x0E97, 0x0E99, 0x0E9A, 0x0E9B, 0x0E9C,
137 0x0E9D, 0x0E9E, 0x0E9F, 0x0EA1, 0x0EA2, 0x0EA3, 0x0EA5, 0x0EA7,
138 0x0EAA, 0x0EAB, 0x0EAD, 0x0EAE, 0x0EAF, 0x0EAE, 0x0EDC, 0x0EDD
139 };
140
141 const sal_Unicode table_Alphabet_dz[] = {
142 0x0F40, 0x0F41, 0x0F42, 0x0F44, 0x0F45, 0x0F46, 0x0F47, 0x0F49,
143 0x0F4F, 0x0F50, 0x0F51, 0x0F53, 0x0F54, 0x0F55, 0x0F56, 0x0F58,
144 0x0F59, 0x0F5A, 0x0F5B, 0x0F5D, 0x0F5E, 0x0F5F, 0x0F60, 0x0F61,
145 0x0F62, 0x0F63, 0x0F64, 0x0F66, 0x0F67, 0x0F68
146 };
147
148 const sal_Unicode table_Alphabet_my[] = {
149 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
150 0x1008,/*0x1009,*/0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
151 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
152 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
153 0x1020, 0x1021
154 };
155
156 // Bulgarian Cyrillic upper case letters
157 const sal_Unicode table_CyrillicUpperLetter_bg[] = {
158 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418,
159 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422,
160 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042E,
161 0x042F
162 };
163
164 // Bulgarian cyrillic lower case letters
165 const sal_Unicode table_CyrillicLowerLetter_bg[] = {
166 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438,
167 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442,
168 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044E,
169 0x044F
170 };
171
172 // Russian Cyrillic upper letters
173 const sal_Unicode table_CyrillicUpperLetter_ru[] = {
174 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
175 0x0418, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420,
176 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428,
177 0x0429, 0x042B, 0x042D, 0x042E, 0x042F
178 };
179
180 // Russian cyrillic lower letters
181 const sal_Unicode table_CyrillicLowerLetter_ru[] = {
182 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
183 0x0438, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440,
184 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448,
185 0x0449, 0x044B, 0x044D, 0x044E, 0x044F
186 };
187
188 // Serbian Cyrillic upper letters
189 const sal_Unicode table_CyrillicUpperLetter_sr[] = {
190 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0402, 0x0415, 0x0416,
191 0x0417, 0x0418, 0x0408, 0x041A, 0x041B, 0x0409, 0x041C, 0x041D,
192 0x040A, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x040B, 0x0423,
193 0x0424, 0x0425, 0x0426, 0x0427, 0x040F, 0x0428
194 };
195
196 // Serbian cyrillic lower letters
197 const sal_Unicode table_CyrillicLowerLetter_sr[] = {
198 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0452, 0x0435, 0x0436,
199 0x0437, 0x0438, 0x0458, 0x043A, 0x043B, 0x0459, 0x043C, 0x043D,
200 0x045A, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x045B, 0x0443,
201 0x0444, 0x0445, 0x0446, 0x0447, 0x045F, 0x0448
202 };
203
204 // Ukrainian Cyrillic upper letters
205 const sal_Unicode table_CyrillicUpperLetter_uk[] = {
206 0x0410, 0x0411, 0x0412, 0x0413, 0x0490, 0x0414, 0x0415, 0x0404,
207 0x0416, 0x0417, 0x0418, 0x0406, 0x0407, 0x0419, 0x041A, 0x041B,
208 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423,
209 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042C, 0x042E,
210 0x042F
211 };
212
213 // Ukrainian cyrillic lower letters
214 const sal_Unicode table_CyrillicLowerLetter_uk[] = {
215 0x0430, 0x0431, 0x0432, 0x0433, 0x0491, 0x0434, 0x0435, 0x0454,
216 0x0436, 0x0437, 0x0438, 0x0456, 0x0457, 0x0439, 0x043A, 0x043B,
217 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443,
218 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044C, 0x044E,
219 0x044F
220 };
221
222 const sal_Unicode table_GreekUpperLetter[] = {
223 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x03DB, 0x0396, 0x0397, 0x0398,
224 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03DF,
225 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03E0
226 };
227
228 const sal_Unicode table_GreekLowerLetter[] = {
229 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03DB, 0x03B6, 0x03B7, 0x03B8,
230 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03DF,
231 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03E1
232 };
233
234 const sal_Unicode table_Alphabet_fa[] = {
235 0x0622, 0x0628, 0x067E, 0x062A, 0x062B, 0x062C, 0x0686, 0x062D,
236 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0698, 0x0633, 0x0634,
237 0x0635, 0x0636, 0x0637, 0x0638, 0x0639, 0x0640, 0x0641, 0x0642,
238 0x06A9, 0x06AF, 0x0644, 0x0645, 0x0646, 0x0648, 0x0647, 0x06CC
239 };
240
241 const sal_Unicode upperLetter[] = {
242 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
243 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
244 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A
245 };
246
247 const sal_Unicode lowerLetter[] = {
248 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
249 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
250 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
251 };
252
253 const sal_Unicode table_Chicago[] = {
254 0x002a, 0x2020, 0x2021, 0x00a7
255 };
256
257 // Tables used for numbering in persian words
258 const sal_Unicode table_PersianWord_decade1[][7]={
259 {0}, // 0
260 {0x06cc, 0x06a9, 0}, // 1
261 {0x062f, 0x0648, 0}, // 2
262 {0x0633, 0x0647, 0}, // 3
263 {0x0686, 0x0647, 0x0627, 0x0631, 0}, // 4
264 {0x067e, 0x0646, 0x062c, 0}, // 5
265 {0x0634, 0x0634, 0}, // 6
266 {0x0647, 0x0641, 0x062a, 0}, // 7
267 {0x0647, 0x0634, 0x062a, 0}, // 8
268 {0x0646, 0x0647, 0}, // 9
269 {0x062f, 0x0647, 0}, // 10
270 {0x06cc, 0x0627, 0x0632, 0x062f, 0x0647, 0}, // 11
271 {0x062f, 0x0648, 0x0627, 0x0632, 0x062f, 0x0647, 0}, // 12
272 {0x0633, 0x06cc, 0x0632, 0x062f, 0x0647, 0}, // 13
273 {0x0686, 0x0647, 0x0627, 0x0631, 0x062f, 0x0647, 0}, // 14
274 {0x067e, 0x0627, 0x0646, 0x0632, 0x062f, 0x0647, 0}, // 15
275 {0x0634, 0x0627, 0x0646, 0x0632, 0x062f, 0x0647, 0}, // 16
276 {0x0647, 0x0641, 0x062f, 0x0647, 0}, // 17
277 {0x0647, 0x062c, 0x062f, 0x0647, 0}, // 18
278 {0x0646, 0x0648, 0x0632, 0x062f, 0x0647, 0} // 19
279 };
280
281 const sal_Unicode table_PersianWord_decade2[][6]={
282 {0x0628, 0x06cc, 0x0633, 0x062a, 0}, // 20
283 {0x0633, 0x06cc, 0}, // 30
284 {0x0686, 0x0647, 0x0644, 0}, // 40
285 {0x067e, 0x0646, 0x062c, 0x0627, 0x0647, 0}, // 50
286 {0x0634, 0x0635, 0x062a, 0}, // 60
287 {0x0647, 0x0641, 0x062a, 0x0627, 0x062f, 0}, // 70
288 {0x0647, 0x0634, 0x062a, 0x0627, 0x062f, 0}, // 80
289 {0x0646, 0x0648, 0x062f, 0} // 90
290 };
291
292 const sal_Unicode table_PersianWord_decade3[][7]={
293 {0x0635, 0x062f, 0}, // 100
294 {0x062f, 0x0648, 0x06cc, 0x0633, 0x062a, 0}, // 200
295 {0x0633, 0x06cc, 0x0635, 0x062f, 0}, // 300
296 {0x0686, 0x0647, 0x0627, 0x0631, 0x0635, 0x062f, 0}, // 400
297 {0x067e, 0x0627, 0x0646, 0x0635, 0x062f, 0}, // 500
298 {0x0634, 0x0635, 0x062f, 0}, // 600
299 {0x0647, 0x0641, 0x062a, 0x0635, 0x062f, 0}, // 700
300 {0x0647, 0x0634, 0x062a, 0x0635, 0x062f, 0}, // 800
301 {0x0646, 0x0647, 0x0635, 0x062f, 0} // 900
302 };
303
304 const sal_Unicode table_PersianWord_decadeX[][8]={
305 {0x0647, 0x0632, 0x0627, 0x0631, 0}, // 1000
306 {0x0645, 0x06cc, 0x0644, 0x06cc, 0x0648, 0x0646, 0}, // 1000000
307 {0x0645, 0x06cc, 0x0644, 0x06cc, 0x0627, 0x0631, 0x062f, 0} // 1000000000
308 };
309
310 const sal_Unicode table_KoreanLegalWord_decade1[][3] = {
311 {0xd558, 0xb098, 0}, // 1
312 {0xb458, 0}, // 2
313 {0xc14b, 0}, // 3
314 {0xb137, 0}, // 4
315 {0xb2e4, 0xc12f, 0}, // 5
316 {0xc5ec, 0xc12f, 0}, // 6
317 {0xc77c, 0xacf1, 0}, // 7
318 {0xc5ec, 0xb35f, 0}, // 8
319 {0xc544, 0xd649, 0} // 9
320 };
321
322 const sal_Unicode table_KoreanLegalWord_decade2[][3] = {
323 {0xc5f4, 0}, // 10
324 {0xc2a4, 0xbb3c, 0}, // 20
325 {0xc11c, 0xb978, 0}, // 30
326 {0xb9c8, 0xd754, 0}, // 40
327 {0xc270, 0}, // 50
328 {0xc608, 0xc21c, 0}, // 60
329 {0xc77c, 0xd754, 0}, // 70
330 {0xc5ec, 0xb4e0, 0}, // 80
331 {0xc544, 0xd754, 0} // 90
332 };
333
DefaultNumberingProvider(const Reference<XComponentContext> & rxContext)334 DefaultNumberingProvider::DefaultNumberingProvider( const Reference < XComponentContext >& rxContext ) : m_xContext(rxContext)
335 {
336
337 }
338
~DefaultNumberingProvider()339 DefaultNumberingProvider::~DefaultNumberingProvider()
340 {
341 }
342
343 Sequence< Reference<container::XIndexAccess> >
getDefaultOutlineNumberings(const Locale & rLocale)344 DefaultNumberingProvider::getDefaultOutlineNumberings(const Locale& rLocale )
345 {
346 return LocaleDataImpl::get()->getOutlineNumberingLevels( rLocale );
347 }
348
349 Sequence< Sequence<beans::PropertyValue> >
getDefaultContinuousNumberingLevels(const Locale & rLocale)350 DefaultNumberingProvider::getDefaultContinuousNumberingLevels( const Locale& rLocale )
351 {
352 return LocaleDataImpl::get()->getContinuousNumberingLevels( rLocale );
353 }
354
toRoman(sal_Int32 n)355 static OUString toRoman( sal_Int32 n )
356 {
357
358 // i, ii, iii, iv, v, vi, vii, vii, viii, ix
359 // (Dummy),1000,500,100,50,10,5,1
360 static const char coRomanArr[] = "MDCLXVI--"; // +2 Dummy entries !!
361 const char* cRomanStr = coRomanArr;
362 sal_uInt16 nMask = 1000;
363 sal_uInt32 nOver1000 = n / nMask;
364 n -= ( nOver1000 * nMask );
365
366 OUStringBuffer sTmp;
367 while(nOver1000--)
368 sTmp.append(*coRomanArr);
369
370 while( nMask )
371 {
372 sal_uInt8 nNumber = sal_uInt8( n / nMask );
373 sal_uInt8 nDiff = 1;
374 n %= nMask;
375
376 if( 5 < nNumber )
377 {
378 if( nNumber < 9 )
379 sTmp.append(*(cRomanStr-1));
380 ++nDiff;
381 nNumber -= 5;
382 }
383 switch( nNumber )
384 {
385 case 3: sTmp.append(*cRomanStr); [[fallthrough]];
386 case 2: sTmp.append(*cRomanStr); [[fallthrough]];
387 case 1: sTmp.append(*cRomanStr); break;
388 case 4: sTmp.append(OUStringChar(*cRomanStr) + OUStringChar(*(cRomanStr-nDiff))); break;
389 case 5: sTmp.append(*(cRomanStr-nDiff)); break;
390 }
391
392 nMask /= 10; // to the next decade
393 cRomanStr += 2;
394 }
395 return sTmp.makeStringAndClear();
396 }
397
398 // not used:
399
400 static
lcl_formatChars(const sal_Unicode table[],int tableSize,int n,OUString & s)401 void lcl_formatChars( const sal_Unicode table[], int tableSize, int n, OUString& s )
402 {
403 // string representation of n is appended to s.
404 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>AA, 27=>AB, ...
405 // if A=='a' then 0=>a, 1=>b, ..., 25=>z, 26=>aa, 27=>ab, ...
406
407 if( n>=tableSize ) lcl_formatChars( table, tableSize, (n-tableSize)/tableSize, s );
408
409 s += OUStringChar( table[ n % tableSize ] );
410 }
411
412 static
lcl_formatChars1(const sal_Unicode table[],int tableSize,int n,OUString & s)413 void lcl_formatChars1( const sal_Unicode table[], int tableSize, int n, OUString& s )
414 {
415 // string representation of n is appended to s.
416 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>AA, 27=>BB, ...
417 // if A=='a' then 0=>a, 1=>b, ..., 25=>z, 26=>aa, 27=>bb, ...
418
419 int repeat_count = n / tableSize + 1;
420
421 for( int i=0; i<repeat_count; i++ )
422 s += OUStringChar( table[ n%tableSize ] );
423 }
424
425 static
lcl_formatChars2(const sal_Unicode table_capital[],const sal_Unicode table_small[],int tableSize,int n,OUString & s)426 void lcl_formatChars2( const sal_Unicode table_capital[], const sal_Unicode table_small[], int tableSize, int n, OUString& s )
427 {
428 // string representation of n is appended to s.
429 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>Aa, 27=>Ab, ...
430
431 if( n>=tableSize )
432 {
433 lcl_formatChars2( table_capital, table_small, tableSize, (n-tableSize)/tableSize, s );
434 s += OUStringChar( table_small[ n % tableSize ] );
435 } else
436 s += OUStringChar( table_capital[ n % tableSize ] );
437 }
438
439 static
lcl_formatChars3(const sal_Unicode table_capital[],const sal_Unicode table_small[],int tableSize,int n,OUString & s)440 void lcl_formatChars3( const sal_Unicode table_capital[], const sal_Unicode table_small[], int tableSize, int n, OUString& s )
441 {
442 // string representation of n is appended to s.
443 // if A=='A' then 0=>A, 1=>B, ..., 25=>Z, 26=>Aa, 27=>Bb, ...
444
445 int repeat_count = n / tableSize + 1;
446 s += OUStringChar( table_capital[ n%tableSize ] );
447
448 for( int i=1; i<repeat_count; i++ )
449 s += OUStringChar( table_small[ n%tableSize ] );
450 }
451
452
453 /** Returns number's representation in persian words up to 999999999999
454 respectively limited by sal_Int32 >=0.
455 The caller assures that nNumber is not negative.
456
457 @throws IllegalArgumentException
458 @throws RuntimeException
459 */
460 static
lcl_formatPersianWord(sal_Int32 nNumber,OUString & rsResult)461 void lcl_formatPersianWord( sal_Int32 nNumber, OUString& rsResult )
462 {
463 OUStringBuffer aTemp(64);
464 static constexpr OUStringLiteral asPersianWord_conjunction_data = u" \u0648 ";
465 OUString asPersianWord_conjunction( asPersianWord_conjunction_data );
466 unsigned char nSection = 0;
467
468 while (int nPart = nNumber % 1000)
469 {
470 if (nSection)
471 {
472 if (nSection > SAL_N_ELEMENTS( table_PersianWord_decadeX))
473 throw IllegalArgumentException(); // does not happen with sal_Int32
474 aTemp.insert( 0, table_PersianWord_decadeX[nSection-1] + asPersianWord_conjunction );
475 }
476
477 unsigned int nDigit;
478 if ((nDigit = nPart % 100) < 20)
479 {
480 if (!aTemp.isEmpty())
481 aTemp.insert( 0, u' ');
482 aTemp.insert( 0, table_PersianWord_decade1[nDigit]);
483 }
484 else
485 {
486 if ((nDigit = nPart % 10) != 0)
487 {
488 if (!aTemp.isEmpty())
489 aTemp.insert( 0, asPersianWord_conjunction);
490 aTemp.insert( 0, table_PersianWord_decade1[nDigit]);
491 }
492 if ((nDigit = (nPart / 10) % 10) != 0)
493 {
494 if (!aTemp.isEmpty())
495 aTemp.insert( 0, asPersianWord_conjunction);
496 aTemp.insert( 0, table_PersianWord_decade2[nDigit-2]);
497 }
498 }
499
500 if ((nDigit = nPart / 100) != 0)
501 {
502 if (!aTemp.isEmpty())
503 aTemp.insert( 0, asPersianWord_conjunction);
504 aTemp.insert( 0, table_PersianWord_decade3[nDigit-1]);
505 }
506
507 nNumber /= 1000;
508 nSection++;
509 }
510 rsResult += aTemp;
511 }
512
lcl_formatKoreanLegalWord(sal_Int32 nNumber,OUString & rsResult)513 static void lcl_formatKoreanLegalWord(sal_Int32 nNumber, OUString& rsResult) {
514 OUStringBuffer aTemp(64);
515 int digit1 = nNumber % 10;
516 int digit2 = nNumber / 10;
517 if (digit1 > 0)
518 aTemp.insert(0, (table_KoreanLegalWord_decade1[digit1 - 1]));
519 if (digit2 > 0)
520 aTemp.insert(0, (table_KoreanLegalWord_decade2[digit2 - 1]));
521 rsResult += aTemp;
522 }
523
524 // Greek Letter Numbering
525
526 // KERAIA separates numerals from other text
527 #define STIGMA u'\x03DB'
528 #define LEFT_KERAIA u'\x0375'
529 #define MYRIAD_SYM u'\x039C'
530 #define DOT_SYM u'.'
531 #define SIGMA_OFFSET 19
532 #define TAU_OFFSET 20
533 #define MYRIAD 10000
534
535 /*
536 * Return the 1-999999 number's representation in the Greek numbering system.
537 * Adding a "left keraia" to represent numbers in the range 10000 ... 999999 is
538 * not orthodox, so it's better to use the myriad notation and call this method
539 * only for numbers up to 9999.
540 */
541 static
gr_smallNum(const sal_Unicode table[],int n)542 OUString gr_smallNum(const sal_Unicode table[], int n)
543 {
544 if (n > 9999)
545 throw IllegalArgumentException();
546
547 int i = 0;
548 OUStringBuffer sb;
549 for (int v = n; v > 0; v /= 10, i++) {
550 int digit = v % 10;
551 if (digit == 0)
552 continue;
553
554 sal_Unicode sign = table[(digit - 1) + 9 * (i % 3)];
555 if (sign == STIGMA) {
556 sb.insert(0, table[TAU_OFFSET]);
557 sb.insert(0, table[SIGMA_OFFSET]);
558 } else {
559 sb.insert(0, sign);
560 }
561
562 if (i > 2)
563 sb.insert(0, LEFT_KERAIA);
564 }
565
566 return sb.makeStringAndClear();
567 }
568
569 static
lcl_formatCharsGR(const sal_Unicode table[],int n,OUString & s)570 void lcl_formatCharsGR(const sal_Unicode table[], int n, OUString& s )
571 {
572 OUStringBuffer sb;
573 int myriadPower = 2;
574
575 for (int divisor = MYRIAD * MYRIAD; divisor > 1; divisor /= MYRIAD, myriadPower--) {
576 if (n > divisor - 1) {
577 /*
578 * Follow the Diophantus representation of:
579 * A myriad sign, M(10000) as many times as the power
580 * followed by the multiplier for the myriad
581 * followed by a dot
582 * followed by the rest
583 * This is enough for 32-bit integers
584 */
585 for (int i = 0; i < myriadPower; i++)
586 sb.append(MYRIAD_SYM);
587
588 sb.append(gr_smallNum(table, n/divisor));
589 n %= divisor;
590
591 if (n > 0)
592 sb.append(DOT_SYM);
593 }
594 }
595 sb.append(gr_smallNum(table,n));
596
597 s += sb;
598 }
599
600 static
should_ignore(std::u16string_view s)601 bool should_ignore( std::u16string_view s )
602 {
603 // return true if blank or null
604 return s == u" " || (!s.empty() && s[0]==0);
605 }
606
607 /**
608 * Turn nNumber into a string and pad the result to nLimit by inserting zero characters at the
609 * start.
610 */
lcl_formatArabicZero(sal_Int32 nNumber,sal_Int32 nLimit)611 static OUString lcl_formatArabicZero(sal_Int32 nNumber, sal_Int32 nLimit)
612 {
613 OUString aRet = OUString::number(nNumber);
614 sal_Int32 nDiff = nLimit - aRet.getLength();
615
616 if (nDiff <= 0)
617 {
618 return aRet;
619 }
620
621 OUStringBuffer aBuffer;
622 aBuffer.setLength(nDiff);
623 for (sal_Int32 i = 0; i < nDiff; ++i)
624 {
625 aBuffer[i] = '0';
626 }
627 aBuffer.append(aRet);
628 return aBuffer.makeStringAndClear();
629 }
630
631 static
getPropertyByName(const Sequence<beans::PropertyValue> & aProperties,const char * name)632 Any getPropertyByName( const Sequence<beans::PropertyValue>& aProperties,
633 const char* name )
634 {
635 auto pProp = std::find_if(aProperties.begin(), aProperties.end(),
636 [&name](const beans::PropertyValue& rProp) { return rProp.Name.equalsAscii(name); });
637 if (pProp != aProperties.end())
638 return pProp->Value;
639 throw IllegalArgumentException();
640 }
641
642 //XNumberingFormatter
643 OUString
makeNumberingString(const Sequence<beans::PropertyValue> & aProperties,const Locale & aLocale)644 DefaultNumberingProvider::makeNumberingString( const Sequence<beans::PropertyValue>& aProperties,
645 const Locale& aLocale )
646 {
647 // the Sequence of PropertyValues is expected to have at least 4 elements:
648 // elt Name Type purpose
649
650
651 // 0. "Prefix" OUString
652 // 1. "NumberingType" sal_Int16 type of formatting from style::NumberingType (roman, arabic, etc)
653 // 2. "Suffix" OUString
654 // ... ... ...
655 // n. "Value" sal_Int32 the number to be formatted
656 // example:
657 // given the Sequence { '(', NumberingType::ROMAN_UPPER, ')', ..., 7 }
658 // makeNumberingString() returns the string "(VII)".
659
660 // Q: why is the type of numType sal_Int16 instead of style::NumberingType?
661 // A: an Any can't hold a style::NumberingType for some reason.
662 // add.: style::NumberingType holds constants of type sal_Int16, it's not an enum type
663
664 sal_Int16 natNum = 0;
665 sal_Int16 tableSize = 0;
666 const sal_Unicode *table = nullptr; // initialize to avoid compiler warning
667 bool bRecycleSymbol = false;
668 OUString sNatNumParams;
669 Locale locale;
670
671 OUString prefix;
672 sal_Int16 numType = -1; // type of formatting from style::NumberingType (roman, arabic, etc)
673 OUString suffix;
674 sal_Int32 number = -1; // the number that needs to be formatted.
675
676 // int nProperties = aProperties.getLength();
677 // int last = nProperties-1;
678
679 for (auto const & prop : aProperties)
680 {
681 if (prop.Name == "Prefix")
682 prop.Value >>= prefix;
683 else if (prop.Name == "Suffix")
684 prop.Value >>= suffix;
685 else if (prop.Name == "NumberingType")
686 prop.Value >>= numType;
687 else if (prop.Name == "Value")
688 prop.Value >>= number;
689 }
690
691 if( number <= 0 )
692 throw IllegalArgumentException();
693
694 // start empty
695 OUString result;
696
697 // append prefix
698 if( !should_ignore(prefix) ) result += prefix;
699
700 // append formatted number
701 using namespace style::NumberingType;
702 switch( numType )
703 {
704 case CHARS_UPPER_LETTER:
705 lcl_formatChars( upperLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>AB, ...
706 break;
707 case CHARS_LOWER_LETTER:
708 lcl_formatChars( lowerLetter, 26, number-1, result );
709 break;
710 case TEXT_NUMBER: // ordinal indicators (1st, 2nd, 3rd, ...)
711 natNum = NativeNumberMode::NATNUM12;
712 sNatNumParams = "capitalize ordinal-number";
713 locale = aLocale;
714 break;
715 case TEXT_CARDINAL: // cardinal number names (One, Two, Three, ...)
716 natNum = NativeNumberMode::NATNUM12;
717 sNatNumParams = "capitalize";
718 locale = aLocale;
719 break;
720 case TEXT_ORDINAL: // ordinal number names (First, Second, Third, ...)
721 natNum = NativeNumberMode::NATNUM12;
722 sNatNumParams = "capitalize ordinal";
723 locale = aLocale;
724 break;
725 case ROMAN_UPPER:
726 result += toRoman( number );
727 break;
728 case ROMAN_LOWER:
729 result += toRoman( number ).toAsciiLowerCase();
730 break;
731 case ARABIC:
732 result += OUString::number( number );
733 break;
734 case NUMBER_NONE:
735 return OUString(); // ignore prefix and suffix
736 case CHAR_SPECIAL:
737 // apparently, we're supposed to return an empty string in this case...
738 return OUString(); // ignore prefix and suffix
739 case PAGE_DESCRIPTOR:
740 case BITMAP:
741 OSL_ASSERT(false);
742 throw IllegalArgumentException();
743 case CHARS_UPPER_LETTER_N:
744 lcl_formatChars1( upperLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>BB, ...
745 break;
746 case CHARS_LOWER_LETTER_N:
747 lcl_formatChars1( lowerLetter, 26, number-1, result ); // 1=>A, 2=>B, ..., 26=>Z, 27=>AA, 28=>BB, ...
748 break;
749 case TRANSLITERATION:
750 try {
751 const OUString &tmp = OUString::number( number );
752 OUString transliteration;
753 getPropertyByName(aProperties, "Transliteration") >>= transliteration;
754 if ( !translit )
755 translit = new TransliterationImpl(m_xContext);
756 translit->loadModuleByImplName(transliteration, aLocale);
757 result += translit->transliterateString2String(tmp, 0, tmp.getLength());
758 } catch (Exception& ) {
759 // When transliteration property is missing, return default number (bug #101141#)
760 result += OUString::number( number );
761 // OSL_ASSERT(0);
762 // throw IllegalArgumentException();
763 }
764 break;
765 case NATIVE_NUMBERING:
766 natNum = NativeNumberMode::NATNUM1;
767 locale = aLocale;
768 break;
769 case FULLWIDTH_ARABIC:
770 natNum = NativeNumberMode::NATNUM3;
771 locale = aLocale;
772 break;
773 case NUMBER_LOWER_ZH:
774 natNum = NativeNumberMode::NATNUM12;
775 locale.Language = "zh";
776 break;
777 case NUMBER_UPPER_ZH:
778 natNum = NativeNumberMode::NATNUM5;
779 locale.Language = "zh";
780 break;
781 case NUMBER_UPPER_ZH_TW:
782 natNum = NativeNumberMode::NATNUM5;
783 locale.Language = "zh";
784 locale.Country = "TW";
785 break;
786 case NUMBER_TRADITIONAL_JA:
787 natNum = NativeNumberMode::NATNUM8;
788 locale.Language = "ja";
789 break;
790 case NUMBER_UPPER_KO:
791 natNum = NativeNumberMode::NATNUM8;
792 locale.Language = "ko";
793 break;
794 case NUMBER_HANGUL_KO:
795 natNum = NativeNumberMode::NATNUM11;
796 locale.Language = "ko";
797 break;
798 case NUMBER_DIGITAL_KO:
799 natNum = NativeNumberMode::NATNUM9;
800 locale.Language = "ko";
801 break;
802 case NUMBER_DIGITAL2_KO:
803 natNum = NativeNumberMode::NATNUM1;
804 locale.Language = "ko";
805 break;
806 case NUMBER_LEGAL_KO:
807 if (number < 1 || number >= 100)
808 {
809 natNum = NativeNumberMode::NATNUM11;
810 locale.Language = "ko";
811 }
812 else
813 {
814 lcl_formatKoreanLegalWord(number, result);
815 }
816 break;
817
818 case CIRCLE_NUMBER:
819 table = table_CircledNumber;
820 tableSize = SAL_N_ELEMENTS(table_CircledNumber);
821 break;
822 case TIAN_GAN_ZH:
823 table = table_TianGan_zh;
824 tableSize = SAL_N_ELEMENTS(table_TianGan_zh);
825 break;
826 case DI_ZI_ZH:
827 table = table_DiZi_zh;
828 tableSize = SAL_N_ELEMENTS(table_DiZi_zh);
829 break;
830 case AIU_FULLWIDTH_JA:
831 table = table_AIUFullWidth_ja_JP;
832 tableSize = SAL_N_ELEMENTS(table_AIUFullWidth_ja_JP);
833 bRecycleSymbol = true;
834 break;
835 case AIU_HALFWIDTH_JA:
836 table = table_AIUHalfWidth_ja_JP;
837 tableSize = SAL_N_ELEMENTS(table_AIUHalfWidth_ja_JP);
838 bRecycleSymbol = true;
839 break;
840 case IROHA_FULLWIDTH_JA:
841 table = table_IROHAFullWidth_ja_JP;
842 tableSize = SAL_N_ELEMENTS(table_IROHAFullWidth_ja_JP);
843 bRecycleSymbol = true;
844 break;
845 case IROHA_HALFWIDTH_JA:
846 table = table_IROHAHalfWidth_ja_JP;
847 tableSize = SAL_N_ELEMENTS(table_IROHAHalfWidth_ja_JP);
848 bRecycleSymbol = true;
849 break;
850 case HANGUL_JAMO_KO:
851 table = table_HangulJamo_ko;
852 tableSize = SAL_N_ELEMENTS(table_HangulJamo_ko);
853 bRecycleSymbol = true;
854 break;
855 case HANGUL_SYLLABLE_KO:
856 table = table_HangulSyllable_ko;
857 tableSize = SAL_N_ELEMENTS(table_HangulSyllable_ko);
858 bRecycleSymbol = true;
859 break;
860 case HANGUL_CIRCLED_JAMO_KO:
861 table = table_HangulCircledJamo_ko;
862 tableSize = SAL_N_ELEMENTS(table_HangulCircledJamo_ko);
863 bRecycleSymbol = true;
864 break;
865 case HANGUL_CIRCLED_SYLLABLE_KO:
866 table = table_HangulCircledSyllable_ko;
867 tableSize = SAL_N_ELEMENTS(table_HangulCircledSyllable_ko);
868 bRecycleSymbol = true;
869 break;
870 case CHARS_ARABIC:
871 lcl_formatChars(table_Alphabet_ar, SAL_N_ELEMENTS(table_Alphabet_ar), number - 1, result);
872 break;
873 case CHARS_ARABIC_ABJAD:
874 lcl_formatChars(table_Alphabet_ar_abjad, SAL_N_ELEMENTS(table_Alphabet_ar_abjad), number - 1, result);
875 break;
876 case NUMBER_ARABIC_INDIC:
877 natNum = NativeNumberMode::NATNUM1;
878 locale.Language = "ar";
879 break;
880 case NUMBER_EAST_ARABIC_INDIC:
881 natNum = NativeNumberMode::NATNUM1;
882 locale.Language = "fa";
883 break;
884 case NUMBER_INDIC_DEVANAGARI:
885 natNum = NativeNumberMode::NATNUM1;
886 locale.Language = "hi";
887 break;
888 case CHARS_THAI:
889 lcl_formatChars(table_Alphabet_th, SAL_N_ELEMENTS(table_Alphabet_th), number - 1, result);
890 break;
891 case CHARS_HEBREW:
892 lcl_formatChars(table_Alphabet_he, SAL_N_ELEMENTS(table_Alphabet_he), number - 1, result);
893 break;
894 case NUMBER_HEBREW:
895 natNum = NativeNumberMode::NATNUM1;
896 locale.Language = "he";
897 break;
898 case CHARS_NEPALI:
899 lcl_formatChars(table_Alphabet_ne, SAL_N_ELEMENTS(table_Alphabet_ne), number - 1, result);
900 break;
901 case CHARS_KHMER:
902 lcl_formatChars(table_Alphabet_km, SAL_N_ELEMENTS(table_Alphabet_km), number - 1, result);
903 break;
904 case CHARS_LAO:
905 lcl_formatChars(table_Alphabet_lo, SAL_N_ELEMENTS(table_Alphabet_lo), number - 1, result);
906 break;
907 case CHARS_MYANMAR:
908 lcl_formatChars(table_Alphabet_my, SAL_N_ELEMENTS(table_Alphabet_my), number - 1, result);
909 break;
910 case CHARS_TIBETAN:
911 lcl_formatChars(table_Alphabet_dz, SAL_N_ELEMENTS(table_Alphabet_dz), number - 1, result);
912 break;
913 case CHARS_CYRILLIC_UPPER_LETTER_BG:
914 lcl_formatChars2( table_CyrillicUpperLetter_bg,
915 table_CyrillicLowerLetter_bg,
916 SAL_N_ELEMENTS(table_CyrillicLowerLetter_bg), number-1,
917 result); // 1=>a, 2=>b, ..., 28=>z, 29=>Aa, 30=>Ab, ...
918 break;
919 case CHARS_CYRILLIC_LOWER_LETTER_BG:
920 lcl_formatChars( table_CyrillicLowerLetter_bg,
921 SAL_N_ELEMENTS(table_CyrillicLowerLetter_bg), number-1,
922 result); // 1=>a, 2=>b, ..., 28=>z, 29=>aa, 30=>ab, ...
923 break;
924 case CHARS_CYRILLIC_UPPER_LETTER_N_BG:
925 lcl_formatChars3( table_CyrillicUpperLetter_bg,
926 table_CyrillicLowerLetter_bg,
927 SAL_N_ELEMENTS(table_CyrillicLowerLetter_bg), number-1,
928 result); // 1=>a, 2=>b, ..., 28=>z, 29=>Aa, 30=>Bb, ...
929 break;
930 case CHARS_CYRILLIC_LOWER_LETTER_N_BG:
931 lcl_formatChars1( table_CyrillicLowerLetter_bg,
932 SAL_N_ELEMENTS(table_CyrillicLowerLetter_bg), number-1,
933 result); // 1=>a, 2=>b, ..., 28=>z, 29=>aa, 30=>bb, ...
934 break;
935 case CHARS_CYRILLIC_UPPER_LETTER_RU:
936 lcl_formatChars2( table_CyrillicUpperLetter_ru,
937 table_CyrillicLowerLetter_ru,
938 SAL_N_ELEMENTS(table_CyrillicLowerLetter_ru), number-1,
939 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Ab, ...
940 break;
941 case CHARS_CYRILLIC_LOWER_LETTER_RU:
942 lcl_formatChars( table_CyrillicLowerLetter_ru,
943 SAL_N_ELEMENTS(table_CyrillicLowerLetter_ru), number-1,
944 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>ab, ...
945 break;
946 case CHARS_CYRILLIC_UPPER_LETTER_N_RU:
947 lcl_formatChars3( table_CyrillicUpperLetter_ru,
948 table_CyrillicLowerLetter_ru,
949 SAL_N_ELEMENTS(table_CyrillicLowerLetter_ru), number-1,
950 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Bb, ...
951 break;
952 case CHARS_CYRILLIC_LOWER_LETTER_N_RU:
953 lcl_formatChars1( table_CyrillicLowerLetter_ru,
954 SAL_N_ELEMENTS(table_CyrillicLowerLetter_ru), number-1,
955 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>bb, ...
956 break;
957 case CHARS_CYRILLIC_UPPER_LETTER_SR:
958 lcl_formatChars2( table_CyrillicUpperLetter_sr,
959 table_CyrillicLowerLetter_sr,
960 SAL_N_ELEMENTS(table_CyrillicLowerLetter_sr), number-1,
961 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Ab, ...
962 break;
963 case CHARS_CYRILLIC_LOWER_LETTER_SR:
964 lcl_formatChars( table_CyrillicLowerLetter_sr,
965 SAL_N_ELEMENTS(table_CyrillicLowerLetter_sr), number-1,
966 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>ab, ...
967 break;
968 case CHARS_CYRILLIC_UPPER_LETTER_N_SR:
969 lcl_formatChars3( table_CyrillicUpperLetter_sr,
970 table_CyrillicLowerLetter_sr,
971 SAL_N_ELEMENTS(table_CyrillicLowerLetter_sr), number-1,
972 result); // 1=>a, 2=>b, ..., 27=>z, 28=>Aa, 29=>Bb, ...
973 break;
974 case CHARS_CYRILLIC_LOWER_LETTER_N_SR:
975 lcl_formatChars1( table_CyrillicLowerLetter_sr,
976 SAL_N_ELEMENTS(table_CyrillicLowerLetter_sr), number-1,
977 result); // 1=>a, 2=>b, ..., 27=>z, 28=>aa, 29=>bb, ...
978 break;
979
980 case CHARS_CYRILLIC_UPPER_LETTER_UK:
981 lcl_formatChars2( table_CyrillicUpperLetter_uk,
982 table_CyrillicLowerLetter_uk,
983 SAL_N_ELEMENTS(table_CyrillicLowerLetter_uk), number-1,
984 result);
985 break;
986 case CHARS_CYRILLIC_LOWER_LETTER_UK:
987 lcl_formatChars( table_CyrillicLowerLetter_uk,
988 SAL_N_ELEMENTS(table_CyrillicLowerLetter_uk), number-1,
989 result);
990 break;
991 case CHARS_CYRILLIC_UPPER_LETTER_N_UK:
992 lcl_formatChars3( table_CyrillicUpperLetter_uk,
993 table_CyrillicLowerLetter_uk,
994 SAL_N_ELEMENTS(table_CyrillicLowerLetter_uk), number-1,
995 result);
996 break;
997 case CHARS_CYRILLIC_LOWER_LETTER_N_UK:
998 lcl_formatChars1( table_CyrillicLowerLetter_uk,
999 SAL_N_ELEMENTS(table_CyrillicLowerLetter_uk), number-1,
1000 result);
1001 break;
1002
1003 case CHARS_GREEK_LOWER_LETTER:
1004 lcl_formatCharsGR( table_GreekLowerLetter, number, result);
1005 break;
1006
1007 case CHARS_GREEK_UPPER_LETTER:
1008 lcl_formatCharsGR( table_GreekUpperLetter, number, result);
1009 break;
1010
1011 case CHARS_PERSIAN:
1012 lcl_formatChars(table_Alphabet_fa, SAL_N_ELEMENTS(table_Alphabet_fa), number - 1, result);
1013 break;
1014
1015 case CHARS_PERSIAN_WORD:
1016 lcl_formatPersianWord(number, result);
1017 break;
1018
1019 case SYMBOL_CHICAGO:
1020 lcl_formatChars1( table_Chicago, 4, number-1, result ); // *, +, |, S, **, ++, ...
1021 break;
1022
1023 case ARABIC_ZERO:
1024 result += lcl_formatArabicZero(number, 2);
1025 break;
1026
1027 case ARABIC_ZERO3:
1028 result += lcl_formatArabicZero(number, 3);
1029 break;
1030
1031 case ARABIC_ZERO4:
1032 result += lcl_formatArabicZero(number, 4);
1033 break;
1034
1035 case ARABIC_ZERO5:
1036 result += lcl_formatArabicZero(number, 5);
1037 break;
1038
1039 case SZEKELY_ROVAS: // Old Hungarian
1040 natNum = NativeNumberMode::NATNUM12;
1041 locale.Language = "hu-Hung";
1042 break;
1043
1044 default:
1045 OSL_ASSERT(false);
1046 throw IllegalArgumentException();
1047 }
1048
1049 if (natNum) {
1050 if (!mxNatNum)
1051 mxNatNum.set(new NativeNumberSupplierService);
1052 result += mxNatNum->getNativeNumberStringParams(OUString::number(number), locale,
1053 natNum, sNatNumParams);
1054 } else if (tableSize) {
1055 if ( number > tableSize && !bRecycleSymbol)
1056 result += OUString::number( number);
1057 else
1058 result += OUStringChar(table[--number % tableSize]);
1059 }
1060
1061 // append suffix
1062 if( !should_ignore(suffix) ) result += suffix;
1063
1064 return result;
1065 }
1066
1067 #define LANG_ALL (1 << 0)
1068 #define LANG_CJK (1 << 1)
1069 #define LANG_CTL (1 << 2)
1070
1071 struct Supported_NumberingType
1072 {
1073 const char* cSymbol;
1074 sal_Int16 nType;
1075 sal_Int16 langOption;
Supported_NumberingTypei18npool::Supported_NumberingType1076 Supported_NumberingType(sal_Int16 nType_, const char* pSymbol, sal_Int16 opt)
1077 : cSymbol(pSymbol), nType(nType_), langOption(opt) {}
1078 };
1079 const Supported_NumberingType aSupportedTypes[] =
1080 {
1081 {style::NumberingType::CHARS_UPPER_LETTER, "A", LANG_ALL},
1082 {style::NumberingType::CHARS_LOWER_LETTER, "a", LANG_ALL},
1083 {style::NumberingType::ROMAN_UPPER, "I", LANG_ALL},
1084 {style::NumberingType::ROMAN_LOWER, "i", LANG_ALL},
1085 {style::NumberingType::ARABIC, "1", LANG_ALL},
1086 {style::NumberingType::NUMBER_NONE, "''", LANG_ALL},
1087 {style::NumberingType::CHAR_SPECIAL, "Bullet", LANG_ALL},
1088 {style::NumberingType::PAGE_DESCRIPTOR, "Page", LANG_ALL},
1089 {style::NumberingType::BITMAP, "Bitmap", LANG_ALL},
1090 {style::NumberingType::SYMBOL_CHICAGO, "*, " S_DAGGER ", " S_DBL_DAGGER ", " S_SECTION ", **, " S_DAGGER S_DAGGER ", ...", LANG_ALL},
1091 {style::NumberingType::TEXT_NUMBER, "1st", LANG_ALL},
1092 {style::NumberingType::TEXT_CARDINAL, "One", LANG_ALL},
1093 {style::NumberingType::TEXT_ORDINAL, "First", LANG_ALL},
1094 {style::NumberingType::CHARS_UPPER_LETTER_N, "AAA", LANG_ALL},
1095 {style::NumberingType::CHARS_LOWER_LETTER_N, "aaa", LANG_ALL},
1096 {style::NumberingType::NATIVE_NUMBERING, "Native Numbering", LANG_CJK|LANG_CTL},
1097 {style::NumberingType::FULLWIDTH_ARABIC, nullptr, LANG_CJK},
1098 {style::NumberingType::CIRCLE_NUMBER, nullptr, LANG_CJK},
1099 // The cSymbol is defined here for compatibility with files created by old releases.
1100 // Otherwise if nullptr, these 3 digits may change as NATNUM12 depends on 3rd-party lib.
1101 {style::NumberingType::NUMBER_LOWER_ZH, "一, 二, 三, ...", LANG_CJK},
1102 {style::NumberingType::NUMBER_UPPER_ZH, nullptr, LANG_CJK},
1103 {style::NumberingType::NUMBER_UPPER_ZH_TW, nullptr, LANG_CJK},
1104 {style::NumberingType::TIAN_GAN_ZH, nullptr, LANG_CJK},
1105 {style::NumberingType::DI_ZI_ZH, nullptr, LANG_CJK},
1106 {style::NumberingType::NUMBER_TRADITIONAL_JA, nullptr, LANG_CJK},
1107 {style::NumberingType::AIU_FULLWIDTH_JA, nullptr, LANG_CJK},
1108 {style::NumberingType::AIU_HALFWIDTH_JA, nullptr, LANG_CJK},
1109 {style::NumberingType::IROHA_FULLWIDTH_JA, nullptr, LANG_CJK},
1110 {style::NumberingType::IROHA_HALFWIDTH_JA, nullptr, LANG_CJK},
1111 {style::NumberingType::NUMBER_UPPER_KO, nullptr, LANG_CJK},
1112 {style::NumberingType::NUMBER_HANGUL_KO, nullptr, LANG_CJK},
1113 {style::NumberingType::HANGUL_JAMO_KO, nullptr, LANG_CJK},
1114 {style::NumberingType::HANGUL_SYLLABLE_KO, nullptr, LANG_CJK},
1115 {style::NumberingType::HANGUL_CIRCLED_JAMO_KO, nullptr, LANG_CJK},
1116 {style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO, nullptr, LANG_CJK},
1117 {style::NumberingType::NUMBER_LEGAL_KO, nullptr, LANG_CJK},
1118 {style::NumberingType::NUMBER_DIGITAL_KO, nullptr, LANG_CJK},
1119 {style::NumberingType::NUMBER_DIGITAL2_KO, nullptr, LANG_CJK},
1120 {style::NumberingType::CHARS_ARABIC, nullptr, LANG_CTL},
1121 {style::NumberingType::CHARS_ARABIC_ABJAD, nullptr, LANG_CTL},
1122 {style::NumberingType::NUMBER_ARABIC_INDIC, S_AR_ONE ", " S_AR_TWO ", " S_AR_THREE ", ...", LANG_CTL},
1123 {style::NumberingType::NUMBER_EAST_ARABIC_INDIC, S_FA_ONE ", " S_FA_TWO ", " S_FA_THREE ", ...", LANG_CTL},
1124 {style::NumberingType::NUMBER_INDIC_DEVANAGARI, S_HI_ONE ", " S_HI_TWO ", " S_HI_THREE ", ...", LANG_CTL},
1125 {style::NumberingType::CHARS_THAI, nullptr, LANG_CTL},
1126 {style::NumberingType::CHARS_HEBREW, nullptr, LANG_CTL},
1127 {style::NumberingType::NUMBER_HEBREW, S_HE_ALEPH ", " S_HE_YOD ", " S_HE_QOF ", ...", LANG_CTL},
1128 {style::NumberingType::CHARS_NEPALI, nullptr, LANG_CTL},
1129 {style::NumberingType::CHARS_KHMER, nullptr, LANG_CTL},
1130 {style::NumberingType::CHARS_LAO, nullptr, LANG_CTL},
1131 {style::NumberingType::CHARS_MYANMAR, nullptr, LANG_CTL},
1132 {style::NumberingType::CHARS_TIBETAN, nullptr, LANG_CTL},
1133 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_BG, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (bg)", LANG_ALL},
1134 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_BG, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (bg)", LANG_ALL},
1135 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_BG, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (bg)", LANG_ALL},
1136 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_BG, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (bg)", LANG_ALL},
1137 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (ru)", LANG_ALL},
1138 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (ru)", LANG_ALL},
1139 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_RU, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (ru)", LANG_ALL},
1140 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_RU, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (ru)", LANG_ALL},
1141 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_SR, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (sr)", LANG_ALL},
1142 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_SR, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (sr)", LANG_ALL},
1143 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_SR, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (sr)", LANG_ALL},
1144 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_SR, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (sr)", LANG_ALL},
1145 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_UK, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_A S_CYR_B ", ... (uk)", LANG_ALL},
1146 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_UK, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_A S_CYR_B ", ... (uk)", LANG_ALL},
1147 {style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_UK, C_CYR_A ", " C_CYR_B ", .., " C_CYR_A S_CYR_A ", " C_CYR_B S_CYR_B ", ... (uk)", LANG_ALL},
1148 {style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_UK, S_CYR_A ", " S_CYR_B ", .., " S_CYR_A S_CYR_A ", " S_CYR_B S_CYR_B ", ... (uk)", LANG_ALL},
1149 {style::NumberingType::CHARS_PERSIAN, nullptr, LANG_CTL},
1150 {style::NumberingType::CHARS_PERSIAN_WORD, nullptr, LANG_CTL},
1151 {style::NumberingType::SZEKELY_ROVAS, nullptr, LANG_CTL},
1152 {style::NumberingType::CHARS_GREEK_UPPER_LETTER, C_GR_A ", " C_GR_B ", ... (gr)", LANG_ALL},
1153 {style::NumberingType::CHARS_GREEK_LOWER_LETTER, S_GR_A ", " S_GR_B ", ... (gr)", LANG_ALL},
1154 {style::NumberingType::ARABIC_ZERO, "01, 02, 03, ...", LANG_ALL},
1155 {style::NumberingType::ARABIC_ZERO3, "001, 002, 003, ...", LANG_ALL},
1156 {style::NumberingType::ARABIC_ZERO4, "0001, 0002, 0003, ...", LANG_ALL},
1157 {style::NumberingType::ARABIC_ZERO5, "00001, 00002, 00003, ...", LANG_ALL},
1158 };
1159 const sal_Int32 nSupported_NumberingTypes = SAL_N_ELEMENTS(aSupportedTypes);
1160
makeNumberingIdentifier(sal_Int16 index)1161 OUString DefaultNumberingProvider::makeNumberingIdentifier(sal_Int16 index)
1162 {
1163 if (index < 0 || index >= nSupported_NumberingTypes)
1164 throw RuntimeException();
1165
1166 if (aSupportedTypes[index].cSymbol)
1167 return OUString(aSupportedTypes[index].cSymbol, strlen(aSupportedTypes[index].cSymbol), RTL_TEXTENCODING_UTF8);
1168 else {
1169 OUStringBuffer result;
1170 Locale aLocale(u"en"_ustr, OUString(), OUString());
1171 Sequence<beans::PropertyValue> aProperties(2);
1172 auto aPropertiesRange = asNonConstRange(aProperties);
1173 aPropertiesRange[0].Name = "NumberingType";
1174 aPropertiesRange[0].Value <<= aSupportedTypes[index].nType;
1175 aPropertiesRange[1].Name = "Value";
1176 for (sal_Int32 j = 1; j <= 3; j++) {
1177 aPropertiesRange[1].Value <<= j;
1178 result.append( makeNumberingString( aProperties, aLocale ) + ", " );
1179 }
1180 result.append("...");
1181 // Make known duplicate generated identifiers unique.
1182 // Note this alone works only for newly added numberings, if duplicates
1183 // are in the wild further handling is needed when loading documents
1184 // and asking for numberings.
1185 switch (aSupportedTypes[index].nType)
1186 {
1187 case css::style::NumberingType::NUMBER_DIGITAL_KO:
1188 // Duplicate of NUMBER_HANGUL_KO.
1189 result.append(" (ko-x-digital)");
1190 break;
1191 case css::style::NumberingType::NUMBER_DIGITAL2_KO:
1192 // Duplicate of NUMBER_LOWER_ZH.
1193 result.append(" (ko)");
1194 break;
1195 default:
1196 ; // nothing
1197 }
1198 return result.makeStringAndClear();
1199 }
1200 }
1201
1202 bool
isScriptFlagEnabled(const OUString & aName)1203 DefaultNumberingProvider::isScriptFlagEnabled(const OUString& aName)
1204 {
1205 if (! xHierarchicalNameAccess.is())
1206 xHierarchicalNameAccess = officecfg::Office::Common::I18N::get();
1207
1208 Any aEnabled = xHierarchicalNameAccess->getByHierarchicalName(aName);
1209
1210 bool enabled = false;
1211
1212 aEnabled >>= enabled;
1213
1214 return enabled;
1215 }
1216
getSupportedNumberingTypes()1217 Sequence< sal_Int16 > DefaultNumberingProvider::getSupportedNumberingTypes( )
1218 {
1219 Sequence< sal_Int16 > aRet(nSupported_NumberingTypes );
1220 sal_Int16* pArray = aRet.getArray();
1221
1222 bool cjkEnabled = isScriptFlagEnabled(u"CJK/CJKFont"_ustr);
1223 bool ctlEnabled = isScriptFlagEnabled(u"CTL/CTLFont"_ustr);
1224
1225 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++) {
1226 if ( (aSupportedTypes[i].langOption & LANG_ALL) ||
1227 ((aSupportedTypes[i].langOption & LANG_CJK) && cjkEnabled) ||
1228 ((aSupportedTypes[i].langOption & LANG_CTL) && ctlEnabled) )
1229 pArray[i] = aSupportedTypes[i].nType;
1230 }
1231 return aRet;
1232 }
1233
getNumberingType(const OUString & rNumberingIdentifier)1234 sal_Int16 DefaultNumberingProvider::getNumberingType( const OUString& rNumberingIdentifier )
1235 {
1236 auto it = maSupportedTypesCache.find(rNumberingIdentifier);
1237 if (it != maSupportedTypesCache.end())
1238 return it->second->nType;
1239 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1240 if(rNumberingIdentifier == makeNumberingIdentifier(i))
1241 {
1242 maSupportedTypesCache.emplace(rNumberingIdentifier, &aSupportedTypes[i]);
1243 return aSupportedTypes[i].nType;
1244 }
1245 throw RuntimeException();
1246 }
1247
hasNumberingType(const OUString & rNumberingIdentifier)1248 sal_Bool DefaultNumberingProvider::hasNumberingType( const OUString& rNumberingIdentifier )
1249 {
1250 auto it = maSupportedTypesCache.find(rNumberingIdentifier);
1251 if (it != maSupportedTypesCache.end())
1252 return true;
1253 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1254 if(rNumberingIdentifier == makeNumberingIdentifier(i))
1255 {
1256 maSupportedTypesCache.emplace(rNumberingIdentifier, &aSupportedTypes[i]);
1257 return true;
1258 }
1259 return false;
1260 }
1261
getNumberingIdentifier(sal_Int16 nNumberingType)1262 OUString DefaultNumberingProvider::getNumberingIdentifier( sal_Int16 nNumberingType )
1263 {
1264 for(sal_Int16 i = 0; i < nSupported_NumberingTypes; i++)
1265 if(nNumberingType == aSupportedTypes[i].nType)
1266 return makeNumberingIdentifier(i);
1267 return OUString();
1268 }
1269
getImplementationName()1270 OUString DefaultNumberingProvider::getImplementationName()
1271 {
1272 return u"com.sun.star.text.DefaultNumberingProvider"_ustr;
1273 }
1274
supportsService(const OUString & rServiceName)1275 sal_Bool DefaultNumberingProvider::supportsService(const OUString& rServiceName)
1276 {
1277 return cppu::supportsService(this, rServiceName);
1278 }
1279
getSupportedServiceNames()1280 Sequence< OUString > DefaultNumberingProvider::getSupportedServiceNames()
1281 {
1282 Sequence< OUString > aRet { u"com.sun.star.text.DefaultNumberingProvider"_ustr };
1283 return aRet;
1284 }
1285
1286 }
1287
1288 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_text_DefaultNumberingProvider_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)1289 com_sun_star_text_DefaultNumberingProvider_get_implementation(
1290 css::uno::XComponentContext *context,
1291 css::uno::Sequence<css::uno::Any> const &)
1292 {
1293 return cppu::acquire(new i18npool::DefaultNumberingProvider(context));
1294 }
1295
1296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1297