Line data Source code
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 : #include <ConversionHelper.hxx>
20 : #include <com/sun/star/table/BorderLine2.hpp>
21 : #include <com/sun/star/table/BorderLineStyle.hpp>
22 : #include <com/sun/star/lang/Locale.hpp>
23 : #include <com/sun/star/text/HoriOrientation.hpp>
24 : #include <com/sun/star/style/NumberingType.hpp>
25 : #include <editeng/borderline.hxx>
26 : #include <ooxml/resourceids.hxx>
27 : #include <rtl/ustrbuf.hxx>
28 : #include <tools/color.hxx>
29 : #include <algorithm>
30 : #include <functional>
31 :
32 : using namespace com::sun::star;
33 : using namespace com::sun::star::table::BorderLineStyle;
34 :
35 : namespace writerfilter {
36 : namespace dmapper{
37 : namespace ConversionHelper{
38 :
39 0 : sal_Int32 MakeBorderLine( sal_Int32 nSprmValue, table::BorderLine2& rToFill )
40 : {
41 : //TODO: Lines are always solid
42 : //Border
43 : //borders are defined as:
44 : // 0x XX XX XX XX
45 : // || || || ||
46 : // || || || ---- Line width in 1/8 pt
47 : // || || ||
48 : // || || ------- Line type: 0 - none 1 - single ... 25 - engrave 3D and 64 - 230 page borders
49 : // || ||
50 : // || ---------- Line color
51 : // ||
52 : // ------------- seven bits line space
53 : // -------------- first bit: with shading
54 0 : sal_Int16 nLineThicknessTwip = (sal_Int16)((nSprmValue & 0xff) * 20)/8L ;
55 0 : sal_Int32 nLineType = ((nSprmValue & 0xff00) >> 8);
56 0 : sal_Int32 nLineColor = (nSprmValue & 0xff0000)>>16;
57 0 : sal_Int32 nLineDistance = (((nSprmValue & 0x3f000000)>>24) * 2540 + 36)/72L;
58 0 : MakeBorderLine( nLineThicknessTwip, nLineType, nLineColor, rToFill, false);
59 0 : return nLineDistance;
60 : }
61 15420 : void MakeBorderLine( sal_Int32 nLineThickness, sal_Int32 nLineType,
62 : sal_Int32 nLineColor,
63 : table::BorderLine2& rToFill, bool bIsOOXML )
64 : {
65 : static const sal_Int32 aBorderDefColor[] =
66 : {
67 : // The first item means automatic color (COL_AUTO), but we
68 : // do not use it anyway (see the next statement) .-)
69 : 0, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
70 : COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
71 : COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
72 : COL_LIGHTGRAY
73 : };
74 : //no auto color for borders
75 15420 : if(!nLineColor)
76 4880 : ++nLineColor;
77 15420 : if(!bIsOOXML && sal::static_int_cast<sal_uInt32>(nLineColor) < SAL_N_ELEMENTS(aBorderDefColor))
78 0 : nLineColor = aBorderDefColor[nLineColor];
79 :
80 : // Map to our border types, we should use of one equal line
81 : // thickness, or one of smaller thickness. If too small we
82 : // can make the defecit up in additional white space or
83 : // object size
84 : ::editeng::SvxBorderStyle const nLineStyle(
85 15420 : ::editeng::ConvertBorderStyleFromWord(nLineType));
86 15420 : rToFill.LineStyle = nLineStyle;
87 : double const fConverted( (NONE == nLineStyle) ? 0.0 :
88 : ::editeng::ConvertBorderWidthFromWord(nLineStyle, nLineThickness,
89 15420 : nLineType));
90 15420 : rToFill.LineWidth = convertTwipToMM100(fConverted);
91 15420 : rToFill.Color = nLineColor;
92 15420 : }
93 :
94 : namespace {
95 14 : void lcl_SwapQuotesInField(OUString &rFmt)
96 : {
97 : //Swap unescaped " and ' with ' and "
98 14 : sal_Int32 nLen = rFmt.getLength();
99 14 : OUStringBuffer aBuffer( rFmt.getStr() );
100 14 : const sal_Unicode* pFmt = rFmt.getStr();
101 81 : for (sal_Int32 nI = 0; nI < nLen; ++nI)
102 : {
103 67 : if ((pFmt[nI] == '\"') && (!nI || pFmt[nI-1] != '\\'))
104 0 : aBuffer[nI] = '\'';
105 67 : else if ((pFmt[nI] == '\'') && (!nI || pFmt[nI-1] != '\\'))
106 0 : aBuffer[nI] = '\"';
107 : }
108 14 : rFmt = aBuffer.makeStringAndClear();
109 14 : }
110 0 : bool lcl_IsNotAM(OUString& rFmt, sal_Int32 nPos)
111 : {
112 : return (
113 0 : (nPos == rFmt.getLength() - 1) ||
114 : (
115 0 : (rFmt[nPos+1] != 'M') &&
116 0 : (rFmt[nPos+1] != 'm')
117 : )
118 0 : );
119 : }
120 : }
121 :
122 14 : OUString ConvertMSFormatStringToSO(
123 : const OUString& rFormat, lang::Locale& rLocale, bool bHijri)
124 : {
125 14 : OUString sFormat(rFormat);
126 14 : lcl_SwapQuotesInField(sFormat);
127 :
128 : //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
129 14 : bool bForceJapanese(false);
130 14 : bool bForceNatNum(false);
131 14 : sal_Int32 nLen = sFormat.getLength();
132 14 : sal_Int32 nI = 0;
133 : // const sal_Unicode* pFormat = sFormat.getStr();
134 28 : OUStringBuffer aNewFormat( sFormat );
135 95 : while (nI < nLen)
136 : {
137 67 : if (aNewFormat[nI] == '\\')
138 0 : nI++;
139 67 : else if (aNewFormat[nI] == '\"')
140 : {
141 0 : ++nI;
142 : //While not at the end and not at an unescaped end quote
143 0 : while ((nI < nLen) && (!(aNewFormat[nI] == '\"') && (aNewFormat[nI-1] != '\\')))
144 0 : ++nI;
145 : }
146 : else //normal unquoted section
147 : {
148 67 : sal_Unicode nChar = aNewFormat[nI];
149 67 : if (nChar == 'O')
150 : {
151 0 : aNewFormat[nI] = 'M';
152 0 : bForceNatNum = true;
153 : }
154 67 : else if (nChar == 'o')
155 : {
156 0 : aNewFormat[nI] = 'm';
157 0 : bForceNatNum = true;
158 : }
159 67 : else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI))
160 : {
161 0 : aNewFormat[nI] = 'D';
162 0 : bForceNatNum = true;
163 : }
164 67 : else if ((nChar == 'g') || (nChar == 'G'))
165 0 : bForceJapanese = true;
166 67 : else if ((nChar == 'a') && lcl_IsNotAM(sFormat, nI))
167 0 : bForceJapanese = true;
168 67 : else if (nChar == 'E')
169 : {
170 0 : if ((nI != nLen-1) && (aNewFormat[nI+1] == 'E'))
171 : {
172 : //todo: this cannot be the right way to replace a part of the string!
173 0 : aNewFormat[nI] = 'Y';
174 0 : aNewFormat[nI + 1] = 'Y';
175 0 : aNewFormat.insert(nI + 2, "YY");
176 0 : nLen+=2;
177 0 : nI+=3;
178 : }
179 0 : bForceJapanese = true;
180 : }
181 67 : else if (nChar == 'e')
182 : {
183 0 : if ((nI != nLen-1) && (aNewFormat[nI+1] == 'e'))
184 : {
185 : //todo: this cannot be the right way to replace a part of the string!
186 0 : aNewFormat[nI] = 'y';
187 0 : aNewFormat[nI + 1] = 'y';
188 0 : aNewFormat.insert(nI + 2, "yy");
189 0 : nLen+=2;
190 0 : nI+=3;
191 : }
192 0 : bForceJapanese = true;
193 : }
194 67 : else if (nChar == '/')
195 : {
196 : // MM We have to escape '/' in case it's used as a char
197 : //todo: this cannot be the right way to replace a part of the string!
198 0 : aNewFormat[nI] = '\\';
199 0 : aNewFormat.insert(nI + 1, "/");
200 0 : nI++;
201 0 : nLen++;
202 : }
203 : }
204 67 : ++nI;
205 : }
206 :
207 14 : if (bForceNatNum)
208 0 : bForceJapanese = true;
209 :
210 14 : if (bForceJapanese)
211 : {
212 0 : rLocale.Language = "ja";
213 0 : rLocale.Country = "JP";
214 : }
215 :
216 14 : if (bForceNatNum)
217 : {
218 0 : aNewFormat.insert( 0, "[NatNum1][$-411]");
219 : }
220 :
221 14 : if (bHijri)
222 : {
223 0 : aNewFormat.insert( 0, "[~hijri]");
224 : }
225 28 : return aNewFormat.makeStringAndClear();
226 :
227 : }
228 :
229 : #define TWIP_TO_MM100(TWIP) ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L))
230 :
231 130037 : sal_Int32 convertTwipToMM100(sal_Int32 _t)
232 : {
233 130037 : return TWIP_TO_MM100( _t );
234 : }
235 :
236 9450 : sal_uInt32 convertTwipToMM100Unsigned(sal_Int32 _t)
237 : {
238 9450 : if( _t < 0 )
239 8 : return 0;
240 : // It appears that MSO handles large twip values specially, probably legacy 16bit handling,
241 : // anything that's bigger than 32767 appears to be simply ignored.
242 9442 : if( _t >= 0x8000 )
243 3 : return 0;
244 9439 : return TWIP_TO_MM100( _t );
245 : }
246 :
247 4101 : sal_Int32 convertEMUToMM100(sal_Int32 _t)
248 : {
249 4101 : return _t / 360;
250 : }
251 :
252 617 : sal_Int16 convertTableJustification( sal_Int32 nIntValue )
253 : {
254 617 : sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
255 617 : switch( nIntValue )
256 : {
257 148 : case 1 : nOrient = text::HoriOrientation::CENTER; break;
258 1 : case 2 : nOrient = text::HoriOrientation::RIGHT; break;
259 : case 0 :
260 : //no break
261 : default:;
262 :
263 : }
264 617 : return nOrient;
265 : }
266 :
267 14088 : sal_Int16 ConvertNumberingType(sal_Int32 nFmt)
268 : {
269 : sal_Int16 nRet;
270 14088 : switch(nFmt)
271 : {
272 : case NS_ooxml::LN_Value_ST_NumberFormat_decimal:
273 : case 0:
274 3277 : nRet = style::NumberingType::ARABIC;
275 3277 : break;
276 : case NS_ooxml::LN_Value_ST_NumberFormat_upperRoman:
277 : case 1:
278 17 : nRet = style::NumberingType::ROMAN_UPPER;
279 17 : break;
280 : case NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman:
281 : case 2:
282 1415 : nRet = style::NumberingType::ROMAN_LOWER;
283 1415 : break;
284 : case 3:
285 0 : nRet = style::NumberingType::CHARS_UPPER_LETTER_N;
286 0 : break;
287 : case 4:
288 0 : nRet = style::NumberingType::CHARS_LOWER_LETTER_N;
289 0 : break;
290 : case 5:
291 0 : nRet = style::NumberingType::ARABIC;
292 0 : break;//ORDINAL
293 : case NS_ooxml::LN_Value_ST_NumberFormat_bullet:
294 : case 23:
295 : case 25:
296 7302 : nRet = style::NumberingType::CHAR_SPECIAL;
297 7302 : break;
298 : case NS_ooxml::LN_Value_ST_NumberFormat_none:
299 : case 255:
300 446 : nRet = style::NumberingType::NUMBER_NONE;
301 446 : break;
302 : case NS_ooxml::LN_Value_ST_NumberFormat_upperLetter:
303 37 : nRet = style::NumberingType::CHARS_UPPER_LETTER;
304 37 : break;
305 : case NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter:
306 1306 : nRet = style::NumberingType::CHARS_LOWER_LETTER;
307 1306 : break;
308 : case NS_ooxml::LN_Value_ST_NumberFormat_iroha:
309 0 : nRet = style::NumberingType::IROHA_HALFWIDTH_JA;
310 0 : break;
311 : case NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth:
312 0 : nRet = style::NumberingType::IROHA_FULLWIDTH_JA;
313 0 : break;
314 : case NS_ooxml::LN_Value_ST_NumberFormat_aiueo:
315 0 : nRet = style::NumberingType::AIU_HALFWIDTH_JA;
316 0 : break;
317 : case NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth:
318 0 : nRet = style::NumberingType::AIU_FULLWIDTH_JA;
319 0 : break;
320 : case NS_ooxml::LN_Value_ST_NumberFormat_hebrew2:
321 0 : nRet = style::NumberingType::CHARS_HEBREW;
322 0 : break;
323 : case NS_ooxml::LN_Value_ST_NumberFormat_thaiLetters:
324 0 : nRet = style::NumberingType::CHARS_THAI;
325 0 : break;
326 : case NS_ooxml::LN_Value_ST_NumberFormat_russianLower:
327 0 : nRet = style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU;
328 0 : break;
329 : case NS_ooxml::LN_Value_ST_NumberFormat_russianUpper:
330 0 : nRet = style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU;
331 0 : break;
332 : case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese:
333 : case NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle:
334 0 : nRet = style::NumberingType::CIRCLE_NUMBER;
335 0 : break;
336 : case NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional:
337 0 : nRet = style::NumberingType::TIAN_GAN_ZH;
338 0 : break;
339 : case NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac:
340 0 : nRet = style::NumberingType::DI_ZI_ZH;
341 0 : break;
342 : case NS_ooxml::LN_Value_ST_NumberFormat_ganada:
343 0 : nRet = style::NumberingType::HANGUL_SYLLABLE_KO;
344 0 : break;
345 : case NS_ooxml::LN_Value_ST_NumberFormat_chosung:
346 0 : nRet = style::NumberingType::HANGUL_JAMO_KO;
347 0 : break;
348 : case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital:
349 : case NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting:
350 : case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2:
351 0 : nRet = style::NumberingType::NUMBER_HANGUL_KO;
352 0 : break;
353 : case NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional:
354 0 : nRet = style::NumberingType::NUMBER_UPPER_ZH_TW;
355 0 : break;
356 : case NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha:
357 0 : nRet = style::NumberingType::CHARS_ARABIC;
358 0 : break;
359 : case NS_ooxml::LN_Value_ST_NumberFormat_hindiVowels:
360 0 : nRet = style::NumberingType::CHARS_NEPALI;
361 0 : break;
362 : case NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal:
363 0 : nRet = style::NumberingType::NUMBER_TRADITIONAL_JA;
364 0 : break;
365 : case NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting:
366 : case NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting:
367 : case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting:
368 : case NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital:
369 : case NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand:
370 0 : nRet = style::NumberingType::NUMBER_LOWER_ZH;
371 0 : break;
372 : case NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified:
373 0 : nRet = style::NumberingType::NUMBER_UPPER_ZH;
374 0 : break;
375 : case NS_ooxml::LN_Value_ST_NumberFormat_hebrew1:
376 : //91726
377 3 : nRet = style::NumberingType::CHARS_HEBREW;
378 3 : break;
379 285 : default: nRet = style::NumberingType::ARABIC;
380 : }
381 : /* TODO: Lots of additional values are available - some are supported in the I18 framework
382 : NS_ooxml::LN_Value_ST_NumberFormat_ordinal = 91682;
383 : NS_ooxml::LN_Value_ST_NumberFormat_cardinalText = 91683;
384 : NS_ooxml::LN_Value_ST_NumberFormat_ordinalText = 91684;
385 : NS_ooxml::LN_Value_ST_NumberFormat_hex = 91685;
386 : NS_ooxml::LN_Value_ST_NumberFormat_chicago = 91686;
387 : NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth = 91691;
388 : NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth = 91692;
389 : NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand = 91694;
390 : NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircle = 91695;
391 : NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2 = 91696;
392 : NS_ooxml::LN_Value_ST_NumberFormat_decimalZero = 91699;
393 : NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop = 91703;
394 : NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen = 91704;
395 : NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional = 91709;
396 : NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand = 91712;
397 : NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital = 91713;
398 : NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified = 91715;
399 : NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand = 91716;
400 : NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal = 91719;
401 : NS_ooxml::LN_Value_ST_NumberFormat_vietnameseCounting = 91721;
402 : NS_ooxml::LN_Value_ST_NumberFormat_numberInDash = 91725;
403 : NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad:
404 : NS_ooxml::LN_Value_ST_NumberFormat_hindiConsonants = 91731;
405 : NS_ooxml::LN_Value_ST_NumberFormat_hindiNumbers = 91732;
406 : NS_ooxml::LN_Value_ST_NumberFormat_hindiCounting = 91733;
407 : NS_ooxml::LN_Value_ST_NumberFormat_thaiNumbers = 91735;
408 : NS_ooxml::LN_Value_ST_NumberFormat_thaiCounting = 91736;*/
409 14088 : return nRet;
410 : }
411 :
412 819 : com::sun::star::util::DateTime ConvertDateStringToDateTime( const OUString& rDateTime )
413 : {
414 819 : com::sun::star::util::DateTime aDateTime;
415 : //xsd::DateTime in the format [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] example: 2008-01-21T10:42:00Z
416 : //OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const SAL_THROW(())
417 819 : sal_Int32 nIndex = 0;
418 819 : OUString sDate = rDateTime.getToken( 0, 'T', nIndex );
419 : // HACK: this is broken according to the spec, but MSOffice always treats the time as local,
420 : // and writes it as Z (=UTC+0)
421 1638 : OUString sTime = rDateTime.getToken( 0, 'Z', nIndex );
422 819 : nIndex = 0;
423 819 : aDateTime.Year = sal_uInt16( sDate.getToken( 0, '-', nIndex ).toInt32() );
424 819 : aDateTime.Month = sal_uInt16( sDate.getToken( 0, '-', nIndex ).toInt32() );
425 819 : if (nIndex != -1)
426 340 : aDateTime.Day = sal_uInt16( sDate.copy( nIndex ).toInt32() );
427 :
428 819 : nIndex = 0;
429 819 : aDateTime.Hours = sal_uInt16( sTime.getToken( 0, ':', nIndex ).toInt32() );
430 819 : aDateTime.Minutes = sal_uInt16( sTime.getToken( 0, ':', nIndex ).toInt32() );
431 819 : if (nIndex != -1)
432 340 : aDateTime.Seconds = sal_uInt16( sTime.copy( nIndex ).toInt32() );
433 :
434 1638 : return aDateTime;
435 : }
436 :
437 :
438 : } // namespace ConversionHelper
439 : } //namespace dmapper
440 : } //namespace writerfilter
441 :
442 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|