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 :
20 : #include <msfilter.hxx>
21 : #include "writerwordglue.hxx"
22 : #include <doc.hxx>
23 : #include "writerhelper.hxx"
24 : #include <IDocumentStylePoolAccess.hxx>
25 :
26 : #include <algorithm>
27 : #include <functional>
28 :
29 : #include <rtl/tencinfo.h>
30 :
31 : #include <unicode/ubidi.h>
32 : #include <tools/tenccvt.hxx>
33 : #include <com/sun/star/i18n/ScriptType.hpp>
34 :
35 : #include <unotools/fontcvt.hxx>
36 : #include <editeng/paperinf.hxx>
37 : #include <editeng/lrspitem.hxx>
38 : #include <editeng/ulspitem.hxx>
39 : #include <editeng/boxitem.hxx>
40 : #include <editeng/fontitem.hxx>
41 : #include <frmfmt.hxx>
42 : #include <fmtclds.hxx>
43 : #include <hfspacingitem.hxx>
44 : #include <fmtfsize.hxx>
45 : #include <swrect.hxx>
46 : #include <fmthdft.hxx>
47 : #include <frmatr.hxx>
48 : #include <ndtxt.hxx>
49 : #include <breakit.hxx>
50 : #include <i18nlangtag/mslangid.hxx>
51 :
52 : using namespace css;
53 :
54 : namespace myImplHelpers
55 : {
56 832 : SwTwips CalcHdFtDist(const SwFrmFmt& rFmt, sal_uInt16 nSpacing)
57 : {
58 : /*
59 : The normal case for reexporting word docs is to have dynamic spacing,
60 : as this is word's only setting, and the reason for the existence of the
61 : dynamic spacing features. If we have dynamic spacing active then we can
62 : add its spacing to the value height of the h/f and get the wanted total
63 : size for word.
64 :
65 : Otherwise we have to get the real layout rendered
66 : height, which is totally nonoptimum, but the best we can do.
67 : */
68 832 : long nDist=0;
69 832 : const SwFmtFrmSize& rSz = rFmt.GetFrmSize();
70 :
71 : const SwHeaderAndFooterEatSpacingItem &rSpacingCtrl =
72 : sw::util::ItemGet<SwHeaderAndFooterEatSpacingItem>
73 832 : (rFmt, RES_HEADER_FOOTER_EAT_SPACING);
74 832 : if (rSpacingCtrl.GetValue())
75 770 : nDist += rSz.GetHeight();
76 : else
77 : {
78 62 : SwRect aRect(rFmt.FindLayoutRect(false));
79 62 : if (aRect.Height())
80 10 : nDist += aRect.Height();
81 : else
82 : {
83 52 : const SwFmtFrmSize& rSize = rFmt.GetFrmSize();
84 52 : if (ATT_VAR_SIZE != rSize.GetHeightSizeType())
85 52 : nDist += rSize.GetHeight();
86 : else
87 : {
88 0 : nDist += 274; // default for 12pt text
89 0 : nDist += nSpacing;
90 : }
91 : }
92 : }
93 832 : return nDist;
94 : }
95 :
96 412 : SwTwips CalcHdDist(const SwFrmFmt& rFmt)
97 : {
98 412 : return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetUpper());
99 : }
100 :
101 420 : SwTwips CalcFtDist(const SwFrmFmt& rFmt)
102 : {
103 420 : return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetLower());
104 : }
105 :
106 : /*
107 : SwTxtFmtColl and SwCharFmt are quite distinct types and how they are
108 : gotten is also distinct, but the algorithm to match word's eqivalents into
109 : them is the same, so we put the different stuff into two separate helper
110 : implementations and a core template that uses the helpers that uses the
111 : same algorithm to do the work. We'll make the helpers specializations of a
112 : non existing template so I can let the compiler figure out the right one
113 : to use from a simple argument to the algorithm class
114 : */
115 : template <class C> class MapperImpl;
116 : template<> class MapperImpl<SwTxtFmtColl>
117 : {
118 : private:
119 : SwDoc &mrDoc;
120 : public:
121 190 : MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {}
122 : SwTxtFmtColl* GetBuiltInStyle(ww::sti eSti);
123 : SwTxtFmtColl* GetStyle(const OUString &rName);
124 : SwTxtFmtColl* MakeStyle(const OUString &rName);
125 : };
126 :
127 1702 : SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetBuiltInStyle(ww::sti eSti)
128 : {
129 1702 : const RES_POOL_COLLFMT_TYPE RES_NONE = RES_POOLCOLL_DOC_END;
130 : static const RES_POOL_COLLFMT_TYPE aArr[]=
131 : {
132 : RES_POOLCOLL_STANDARD, RES_POOLCOLL_HEADLINE1,
133 : RES_POOLCOLL_HEADLINE2, RES_POOLCOLL_HEADLINE3,
134 : RES_POOLCOLL_HEADLINE4, RES_POOLCOLL_HEADLINE5,
135 : RES_POOLCOLL_HEADLINE6, RES_POOLCOLL_HEADLINE7,
136 : RES_POOLCOLL_HEADLINE8, RES_POOLCOLL_HEADLINE9,
137 : RES_POOLCOLL_TOX_IDX1, RES_POOLCOLL_TOX_IDX2,
138 : RES_POOLCOLL_TOX_IDX3, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
139 : RES_NONE, RES_NONE, RES_POOLCOLL_TOX_CNTNT1,
140 : RES_POOLCOLL_TOX_CNTNT2, RES_POOLCOLL_TOX_CNTNT3,
141 : RES_POOLCOLL_TOX_CNTNT4, RES_POOLCOLL_TOX_CNTNT5,
142 : RES_POOLCOLL_TOX_CNTNT6, RES_POOLCOLL_TOX_CNTNT7,
143 : RES_POOLCOLL_TOX_CNTNT8, RES_POOLCOLL_TOX_CNTNT9, RES_NONE,
144 : RES_POOLCOLL_FOOTNOTE, RES_NONE, RES_POOLCOLL_HEADER,
145 : RES_POOLCOLL_FOOTER, RES_POOLCOLL_TOX_IDXH, RES_NONE, RES_NONE,
146 : RES_POOLCOLL_JAKETADRESS, RES_POOLCOLL_SENDADRESS, RES_NONE,
147 : RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_ENDNOTE,
148 : RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_LISTS_BEGIN,
149 : RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
150 : RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
151 : RES_NONE, RES_NONE, RES_POOLCOLL_HEADLINE_BASE, RES_NONE,
152 : RES_POOLCOLL_SIGNATURE, RES_NONE, RES_POOLCOLL_TEXT,
153 : RES_POOLCOLL_TEXT_MOVE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
154 : RES_NONE, RES_NONE, RES_POOLCOLL_DOC_SUBTITEL
155 : };
156 :
157 : OSL_ENSURE(SAL_N_ELEMENTS(aArr) == 75, "Style Array has false size");
158 :
159 1702 : SwTxtFmtColl* pRet = 0;
160 : //If this is a built-in word style that has a built-in writer
161 : //equivalent, then map it to one of our built in styles regardless
162 : //of its name
163 1702 : if (sal::static_int_cast< size_t >(eSti) < SAL_N_ELEMENTS(aArr) && aArr[eSti] != RES_NONE)
164 828 : pRet = mrDoc.getIDocumentStylePoolAccess().GetTxtCollFromPool( static_cast< sal_uInt16 >(aArr[eSti]), false);
165 1702 : return pRet;
166 : }
167 :
168 1492 : SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetStyle(const OUString &rName)
169 : {
170 1492 : return sw::util::GetParaStyle(mrDoc, rName);
171 : }
172 :
173 612 : SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::MakeStyle(const OUString &rName)
174 : {
175 : return mrDoc.MakeTxtFmtColl(rName,
176 612 : const_cast<SwTxtFmtColl *>(mrDoc.GetDfltTxtFmtColl()));
177 : }
178 :
179 : template<> class MapperImpl<SwCharFmt>
180 : {
181 : private:
182 : SwDoc &mrDoc;
183 : public:
184 190 : MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {}
185 : SwCharFmt* GetBuiltInStyle(ww::sti eSti);
186 : SwCharFmt* GetStyle(const OUString &rName);
187 : SwCharFmt* MakeStyle(const OUString &rName);
188 : };
189 :
190 1006 : SwCharFmt* MapperImpl<SwCharFmt>::GetBuiltInStyle(ww::sti eSti)
191 : {
192 1006 : RES_POOL_CHRFMT_TYPE eLookup = RES_POOLCHR_NORMAL_END;
193 1006 : switch (eSti)
194 : {
195 : case ww::stiFtnRef:
196 12 : eLookup = RES_POOLCHR_FOOTNOTE;
197 12 : break;
198 : case ww::stiLnn:
199 2 : eLookup = RES_POOLCHR_LINENUM;
200 2 : break;
201 : case ww::stiPgn:
202 28 : eLookup = RES_POOLCHR_PAGENO;
203 28 : break;
204 : case ww::stiEdnRef:
205 8 : eLookup = RES_POOLCHR_ENDNOTE;
206 8 : break;
207 : case ww::stiHyperlink:
208 42 : eLookup = RES_POOLCHR_INET_NORMAL;
209 42 : break;
210 : case ww::stiHyperlinkFollowed:
211 10 : eLookup = RES_POOLCHR_INET_VISIT;
212 10 : break;
213 : case ww::stiStrong:
214 6 : eLookup = RES_POOLCHR_HTML_STRONG;
215 6 : break;
216 : case ww::stiEmphasis:
217 6 : eLookup = RES_POOLCHR_HTML_EMPHASIS;
218 6 : break;
219 : default:
220 892 : eLookup = RES_POOLCHR_NORMAL_END;
221 892 : break;
222 : }
223 1006 : SwCharFmt *pRet = 0;
224 1006 : if (eLookup != RES_POOLCHR_NORMAL_END)
225 114 : pRet = mrDoc.getIDocumentStylePoolAccess().GetCharFmtFromPool( static_cast< sal_uInt16 >(eLookup) );
226 1006 : return pRet;
227 : }
228 :
229 1580 : SwCharFmt* MapperImpl<SwCharFmt>::GetStyle(const OUString &rName)
230 : {
231 1580 : return sw::util::GetCharStyle(mrDoc, rName);
232 : }
233 :
234 684 : SwCharFmt* MapperImpl<SwCharFmt>::MakeStyle(const OUString &rName)
235 : {
236 684 : return mrDoc.MakeCharFmt(rName, mrDoc.GetDfltCharFmt());
237 : }
238 :
239 380 : template<class C> class StyleMapperImpl
240 : {
241 : private:
242 : MapperImpl<C> maHelper;
243 : std::set<const C*> maUsedStyles;
244 : C* MakeNonCollidingStyle(const OUString& rName);
245 : public:
246 : typedef std::pair<C*, bool> StyleResult;
247 380 : StyleMapperImpl(SwDoc &rDoc) : maHelper(rDoc) {}
248 : StyleResult GetStyle(const OUString& rName, ww::sti eSti);
249 : };
250 :
251 : template<class C>
252 : typename StyleMapperImpl<C>::StyleResult
253 2708 : StyleMapperImpl<C>::GetStyle(const OUString& rName, ww::sti eSti)
254 : {
255 2708 : C *pRet = maHelper.GetBuiltInStyle(eSti);
256 :
257 : //If we've used it once, don't reuse it
258 2708 : if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet)))
259 4 : pRet = 0;
260 :
261 2708 : if (!pRet)
262 : {
263 1770 : pRet = maHelper.GetStyle(rName);
264 : //If we've used it once, don't reuse it
265 1770 : if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet)))
266 2 : pRet = 0;
267 : }
268 :
269 2708 : bool bStyExist = pRet ? true : false;
270 :
271 2708 : if (!pRet)
272 : {
273 1296 : OUString aName(rName);
274 1296 : sal_Int32 nIdx = rName.indexOf(',');
275 : // No commas allow in SW style names
276 1296 : if (-1 != nIdx)
277 18 : aName = rName.copy( 0, nIdx );
278 1296 : pRet = MakeNonCollidingStyle( aName );
279 : }
280 :
281 2708 : if (pRet)
282 2708 : maUsedStyles.insert(pRet);
283 :
284 2708 : return StyleResult(pRet, bStyExist);
285 : }
286 :
287 : template<class C>
288 1296 : C* StyleMapperImpl<C>::MakeNonCollidingStyle(const OUString& rName)
289 : {
290 1296 : OUString aName(rName);
291 1296 : C* pColl = 0;
292 :
293 1296 : if (0 != (pColl = maHelper.GetStyle(aName)))
294 : {
295 : //If the style collides first stick WW- in front of it, unless
296 : //it already has it and then successively add a larger and
297 : //larger number after it, its got to work at some stage!
298 6 : if (!aName.startsWith("WW-"))
299 6 : aName = "WW-" + aName;
300 :
301 6 : sal_Int32 nI = 1;
302 6 : OUString aBaseName = aName;
303 12 : while (
304 6 : 0 != (pColl = maHelper.GetStyle(aName)) &&
305 : (nI < SAL_MAX_INT32)
306 : )
307 : {
308 0 : aName = aBaseName;
309 0 : aName += OUString::number(nI++);
310 6 : }
311 : }
312 :
313 1296 : return pColl ? 0 : maHelper.MakeStyle(aName);
314 : }
315 :
316 25752 : OUString FindBestMSSubstituteFont(const OUString &rFont)
317 : {
318 25752 : if (IsStarSymbol(rFont))
319 156 : return OUString("Arial Unicode MS");
320 25596 : return GetSubsFontName(rFont, SUBSFONT_ONLYONE | SUBSFONT_MS);
321 : }
322 :
323 : //Utility to remove entries before a given starting position
324 : class IfBeforeStart
325 : : public std::unary_function<const sw::util::CharRunEntry&, bool>
326 : {
327 : private:
328 : sal_Int32 mnStart;
329 : public:
330 17344 : IfBeforeStart(sal_Int32 nStart) : mnStart(nStart) {}
331 17596 : bool operator()(const sw::util::CharRunEntry &rEntry) const
332 : {
333 17596 : return rEntry.mnEndPos < mnStart;
334 : }
335 : };
336 : }
337 :
338 : /// Count what Word calls left/right margin from a format's LRSpace + Box.
339 308 : static SvxLRSpaceItem lcl_getWordLRSpace(const SwFrmFmt& rFmt)
340 : {
341 308 : SvxLRSpaceItem aLR(rFmt.GetLRSpace());
342 308 : const SvxBoxItem& rBox = rFmt.GetBox();
343 :
344 308 : aLR.SetLeft(aLR.GetLeft() + rBox.GetDistance(BOX_LINE_LEFT));
345 308 : if (const editeng::SvxBorderLine* pLeft = rBox.GetLeft())
346 14 : aLR.SetLeft(aLR.GetLeft() + pLeft->GetWidth());
347 :
348 308 : aLR.SetRight(aLR.GetRight() + rBox.GetDistance(BOX_LINE_RIGHT));
349 308 : if (const editeng::SvxBorderLine* pRight = rBox.GetRight())
350 14 : aLR.SetRight(aLR.GetRight() + pRight->GetWidth());
351 :
352 308 : return aLR;
353 : }
354 :
355 : namespace sw
356 : {
357 : namespace util
358 : {
359 :
360 154 : bool IsPlausableSingleWordSection(const SwFrmFmt &rTitleFmt, const SwFrmFmt &rFollowFmt)
361 : {
362 154 : bool bPlausableSingleWordSection = true;
363 :
364 154 : const SwFmtCol& rFirstCols = rTitleFmt.GetCol();
365 154 : const SwFmtCol& rFollowCols = rFollowFmt.GetCol();
366 154 : const SwColumns& rFirstColumns = rFirstCols.GetColumns();
367 154 : const SwColumns& rFollowColumns = rFollowCols.GetColumns();
368 154 : SvxLRSpaceItem aOneLR = lcl_getWordLRSpace(rTitleFmt);
369 308 : SvxLRSpaceItem aTwoLR = lcl_getWordLRSpace(rFollowFmt);
370 154 : const SwFmtFrmSize& rFirstFrmSize = rTitleFmt.GetFrmSize();
371 154 : const SwFmtFrmSize& rFollowFrmSize = rFollowFmt.GetFrmSize();
372 :
373 154 : if (rFirstColumns.size() != rFollowColumns.size())
374 : {
375 : //e.g. #i4320#
376 2 : bPlausableSingleWordSection = false;
377 : }
378 152 : else if (aOneLR != aTwoLR)
379 10 : bPlausableSingleWordSection = false;
380 142 : else if (rFirstFrmSize != rFollowFrmSize)
381 2 : bPlausableSingleWordSection = false;
382 : else
383 : {
384 140 : HdFtDistanceGlue aOne(rTitleFmt.GetAttrSet());
385 140 : HdFtDistanceGlue aTwo(rFollowFmt.GetAttrSet());
386 : //e.g. #i14509#
387 140 : if (!aOne.StrictEqualTopBottom(aTwo))
388 2 : bPlausableSingleWordSection = false;
389 : }
390 308 : return bPlausableSingleWordSection;
391 : }
392 :
393 1580 : HdFtDistanceGlue::HdFtDistanceGlue(const SfxItemSet &rPage)
394 : {
395 1580 : if (const SvxBoxItem *pBox = HasItem<SvxBoxItem>(rPage, RES_BOX))
396 : {
397 1580 : dyaHdrTop = pBox->CalcLineSpace(BOX_LINE_TOP);
398 1580 : dyaHdrBottom = pBox->CalcLineSpace(BOX_LINE_BOTTOM);
399 : }
400 : else
401 : {
402 0 : dyaHdrTop = dyaHdrBottom = 0;
403 0 : dyaHdrBottom = 0;
404 : }
405 : const SvxULSpaceItem &rUL =
406 1580 : ItemGet<SvxULSpaceItem>(rPage, RES_UL_SPACE);
407 1580 : dyaHdrTop = dyaHdrTop + rUL.GetUpper();
408 1580 : dyaHdrBottom = dyaHdrBottom + rUL.GetLower();
409 :
410 1580 : dyaTop = dyaHdrTop;
411 1580 : dyaBottom = dyaHdrBottom;
412 :
413 : using sw::types::msword_cast;
414 :
415 1580 : const SwFmtHeader *pHd = HasItem<SwFmtHeader>(rPage, RES_HEADER);
416 1580 : if (pHd && pHd->IsActive() && pHd->GetHeaderFmt())
417 : {
418 412 : mbHasHeader = true;
419 412 : dyaTop = dyaTop + static_cast< sal_uInt16 >( (myImplHelpers::CalcHdDist(*(pHd->GetHeaderFmt()))) );
420 : }
421 : else
422 1168 : mbHasHeader = false;
423 :
424 1580 : const SwFmtFooter *pFt = HasItem<SwFmtFooter>(rPage, RES_FOOTER);
425 1580 : if (pFt && pFt->IsActive() && pFt->GetFooterFmt())
426 : {
427 420 : mbHasFooter = true;
428 420 : dyaBottom = dyaBottom + static_cast< sal_uInt16 >( (myImplHelpers::CalcFtDist(*(pFt->GetFooterFmt()))) );
429 : }
430 : else
431 1160 : mbHasFooter = false;
432 1580 : }
433 :
434 140 : bool HdFtDistanceGlue::StrictEqualTopBottom(const HdFtDistanceGlue &rOther)
435 : const
436 : {
437 : // Check top only if both object have a header or if
438 : // both object don't have a header
439 320 : if ( ( HasHeader() && rOther.HasHeader() ) ||
440 140 : ( !HasHeader() && !rOther.HasHeader() ) )
441 : {
442 106 : if (dyaTop != rOther.dyaTop)
443 2 : return false;
444 : }
445 :
446 : // Check bottom only if both object have a footer or if
447 : // both object don't have a footer
448 322 : if ( ( HasFooter() && rOther.HasFooter() ) ||
449 168 : ( !HasFooter() && !rOther.HasFooter() ) )
450 : {
451 100 : if (dyaBottom != rOther.dyaBottom)
452 0 : return false;
453 : }
454 :
455 138 : return true;
456 : }
457 :
458 190 : ParaStyleMapper::ParaStyleMapper(SwDoc &rDoc)
459 190 : : mpImpl(new myImplHelpers::StyleMapperImpl<SwTxtFmtColl>(rDoc))
460 : {
461 190 : }
462 :
463 190 : ParaStyleMapper::~ParaStyleMapper()
464 : {
465 190 : delete mpImpl;
466 190 : }
467 :
468 1702 : ParaStyleMapper::StyleResult ParaStyleMapper::GetStyle(
469 : const OUString& rName, ww::sti eSti)
470 : {
471 1702 : return mpImpl->GetStyle(rName, eSti);
472 : }
473 :
474 190 : CharStyleMapper::CharStyleMapper(SwDoc &rDoc)
475 190 : : mpImpl(new myImplHelpers::StyleMapperImpl<SwCharFmt>(rDoc))
476 : {
477 190 : }
478 :
479 190 : CharStyleMapper::~CharStyleMapper()
480 : {
481 190 : delete mpImpl;
482 190 : }
483 :
484 1006 : CharStyleMapper::StyleResult CharStyleMapper::GetStyle(
485 : const OUString& rName, ww::sti eSti)
486 : {
487 1006 : return mpImpl->GetStyle(rName, eSti);
488 : }
489 :
490 25752 : FontMapExport::FontMapExport(const OUString &rFamilyName)
491 : {
492 25752 : sal_Int32 nIndex = 0;
493 25752 : msPrimary = GetNextFontToken(rFamilyName, nIndex);
494 25752 : msSecondary = myImplHelpers::FindBestMSSubstituteFont(msPrimary);
495 25752 : if (msSecondary.isEmpty() && nIndex != -1)
496 26 : msSecondary = GetNextFontToken(rFamilyName, nIndex);
497 25752 : }
498 :
499 1414384 : bool ItemSort::operator()(sal_uInt16 nA, sal_uInt16 nB) const
500 : {
501 : /*
502 : #i24291#
503 : All we want to do is ensure for now is that if a charfmt exist
504 : in the character properties that it rises to the top and is
505 : exported first. In the future we might find more ordering
506 : depandancies for export, in which case this is the place to do
507 : it
508 : */
509 1414384 : if (nA == nB)
510 4196 : return false;
511 1410188 : if (nA == RES_TXTATR_CHARFMT)
512 9186 : return true;
513 1401002 : if (nB == RES_TXTATR_CHARFMT)
514 13414 : return false;
515 1387588 : if (nA == RES_TXTATR_INETFMT)
516 1660 : return true;
517 1385928 : if (nB == RES_TXTATR_INETFMT)
518 724 : return false;
519 1385204 : return nA < nB;
520 : }
521 :
522 28688 : CharRuns GetPseudoCharRuns(const SwTxtNode& rTxtNd,
523 : sal_Int32 nTxtStart, bool bSplitOnCharSet)
524 : {
525 28688 : const OUString &rTxt = rTxtNd.GetTxt();
526 :
527 28688 : bool bParaIsRTL = false;
528 : OSL_ENSURE(rTxtNd.GetDoc(), "No document for node?, suspicious");
529 28688 : if (rTxtNd.GetDoc())
530 : {
531 57376 : if (FRMDIR_HORI_RIGHT_TOP ==
532 57376 : rTxtNd.GetDoc()->GetTextDirection(SwPosition(rTxtNd)))
533 : {
534 48 : bParaIsRTL = true;
535 : }
536 : }
537 :
538 : using namespace ::com::sun::star::i18n;
539 :
540 28688 : sal_uInt16 nScript = i18n::ScriptType::LATIN;
541 28688 : if (!rTxt.isEmpty() && g_pBreakIt && g_pBreakIt->GetBreakIter().is())
542 17344 : nScript = g_pBreakIt->GetBreakIter()->getScriptType(rTxt, 0);
543 :
544 : rtl_TextEncoding eChrSet = ItemGet<SvxFontItem>(rTxtNd,
545 28688 : GetWhichOfScript(RES_CHRATR_FONT, nScript)).GetCharSet();
546 28688 : eChrSet = GetExtendedTextEncoding(eChrSet);
547 :
548 28688 : CharRuns aRunChanges;
549 :
550 28688 : if (rTxt.isEmpty())
551 : {
552 : aRunChanges.push_back(CharRunEntry(0, nScript, eChrSet,
553 11344 : bParaIsRTL));
554 11344 : return aRunChanges;
555 : }
556 :
557 : typedef std::pair<int32_t, bool> DirEntry;
558 : typedef std::vector<DirEntry> DirChanges;
559 : typedef DirChanges::const_iterator cDirIter;
560 :
561 : typedef std::pair<sal_Int32, sal_Int16> CharSetEntry;
562 : typedef std::vector<CharSetEntry> CharSetChanges;
563 : typedef CharSetChanges::const_iterator cCharSetIter;
564 :
565 : typedef std::pair<sal_Int32, sal_uInt16> ScriptEntry;
566 : typedef std::vector<ScriptEntry> ScriptChanges;
567 : typedef ScriptChanges::const_iterator cScriptIter;
568 :
569 34688 : DirChanges aDirChanges;
570 34688 : CharSetChanges aCharSets;
571 34688 : ScriptChanges aScripts;
572 :
573 17344 : UBiDiDirection eDefaultDir = bParaIsRTL ? UBIDI_RTL : UBIDI_LTR;
574 17344 : UErrorCode nError = U_ZERO_ERROR;
575 17344 : UBiDi* pBidi = ubidi_openSized(rTxt.getLength(), 0, &nError);
576 17344 : ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(rTxt.getStr()), rTxt.getLength(),
577 34688 : static_cast< UBiDiLevel >(eDefaultDir), 0, &nError);
578 :
579 17344 : sal_Int32 nCount = ubidi_countRuns(pBidi, &nError);
580 17344 : aDirChanges.reserve(nCount);
581 :
582 17344 : int32_t nStart = 0;
583 : int32_t nEnd;
584 : UBiDiLevel nCurrDir;
585 :
586 34688 : for (sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx)
587 : {
588 17344 : ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir);
589 : /*
590 : UBiDiLevel is the type of the level values in this BiDi
591 : implementation.
592 :
593 : It holds an embedding level and indicates the visual direction
594 : by its bit 0 (even/odd value).
595 :
596 : The value for UBIDI_DEFAULT_LTR is even and the one for
597 : UBIDI_DEFAULT_RTL is odd
598 : */
599 17344 : aDirChanges.push_back(DirEntry(nEnd, nCurrDir & 0x1));
600 17344 : nStart = nEnd;
601 : }
602 17344 : ubidi_close(pBidi);
603 :
604 17344 : if (bSplitOnCharSet)
605 : {
606 : //Split unicode text into plausible 8bit ranges for export to
607 : //older non unicode aware format
608 0 : sal_Int32 nLen = rTxt.getLength();
609 0 : sal_Int32 nPos = 0;
610 0 : while (nPos != nLen)
611 : {
612 : rtl_TextEncoding ScriptType =
613 0 : getBestMSEncodingByChar(rTxt[nPos++]);
614 0 : while (
615 0 : (nPos != nLen) &&
616 0 : (ScriptType == getBestMSEncodingByChar(rTxt[nPos]))
617 : )
618 : {
619 0 : ++nPos;
620 : }
621 :
622 0 : aCharSets.push_back(CharSetEntry(nPos, ScriptType));
623 : }
624 : }
625 :
626 : using sw::types::writer_cast;
627 :
628 17344 : if (g_pBreakIt && g_pBreakIt->GetBreakIter().is())
629 : {
630 17344 : sal_Int32 nLen = rTxt.getLength();
631 17344 : sal_Int32 nPos = 0;
632 52284 : while (nPos < nLen)
633 : {
634 35192 : sal_Int32 nEnd2 = g_pBreakIt->GetBreakIter()->endOfScript(rTxt, nPos,
635 17596 : nScript);
636 17596 : if (nEnd2 < 0)
637 0 : break;
638 17596 : nPos = nEnd2;
639 17596 : aScripts.push_back(ScriptEntry(nPos, nScript));
640 17596 : nScript = g_pBreakIt->GetBreakIter()->getScriptType(rTxt, nPos);
641 : }
642 : }
643 :
644 17344 : cDirIter aBiDiEnd = aDirChanges.end();
645 17344 : cCharSetIter aCharSetEnd = aCharSets.end();
646 17344 : cScriptIter aScriptEnd = aScripts.end();
647 :
648 17344 : cDirIter aBiDiIter = aDirChanges.begin();
649 17344 : cCharSetIter aCharSetIter = aCharSets.begin();
650 17344 : cScriptIter aScriptIter = aScripts.begin();
651 :
652 17344 : bool bCharIsRTL = bParaIsRTL;
653 :
654 52284 : while (
655 52284 : aBiDiIter != aBiDiEnd ||
656 52284 : aCharSetIter != aCharSetEnd ||
657 17344 : aScriptIter != aScriptEnd
658 : )
659 : {
660 17596 : sal_Int32 nMinPos = rTxt.getLength();
661 :
662 17596 : if (aBiDiIter != aBiDiEnd)
663 : {
664 17596 : if (aBiDiIter->first < nMinPos)
665 0 : nMinPos = aBiDiIter->first;
666 17596 : bCharIsRTL = aBiDiIter->second;
667 : }
668 :
669 17596 : if (aCharSetIter != aCharSetEnd)
670 : {
671 0 : if (aCharSetIter->first < nMinPos)
672 0 : nMinPos = aCharSetIter->first;
673 0 : eChrSet = aCharSetIter->second;
674 : }
675 :
676 17596 : if (aScriptIter != aScriptEnd)
677 : {
678 17596 : if (aScriptIter->first < nMinPos)
679 252 : nMinPos = aScriptIter->first;
680 17596 : nScript = aScriptIter->second;
681 : }
682 :
683 : aRunChanges.push_back(
684 17596 : CharRunEntry(nMinPos, nScript, eChrSet, bCharIsRTL));
685 :
686 17596 : if (aBiDiIter != aBiDiEnd)
687 : {
688 17596 : if (aBiDiIter->first == nMinPos)
689 17344 : ++aBiDiIter;
690 : }
691 :
692 17596 : if (aCharSetIter != aCharSetEnd)
693 : {
694 0 : if (aCharSetIter->first == nMinPos)
695 0 : ++aCharSetIter;
696 : }
697 :
698 17596 : if (aScriptIter != aScriptEnd)
699 : {
700 17596 : if (aScriptIter->first == nMinPos)
701 17596 : ++aScriptIter;
702 : }
703 : }
704 :
705 : aRunChanges.erase(std::remove_if(aRunChanges.begin(),
706 17344 : aRunChanges.end(), myImplHelpers::IfBeforeStart(nTxtStart)), aRunChanges.end());
707 :
708 17344 : return aRunChanges;
709 : }
710 : }
711 :
712 : namespace ms
713 : {
714 31238 : sal_uInt8 rtl_TextEncodingToWinCharset(rtl_TextEncoding eTextEncoding)
715 : {
716 : sal_uInt8 nRet =
717 31238 : rtl_getBestWindowsCharsetFromTextEncoding(eTextEncoding);
718 31238 : switch (eTextEncoding)
719 : {
720 : case RTL_TEXTENCODING_DONTKNOW:
721 : case RTL_TEXTENCODING_UCS2:
722 : case RTL_TEXTENCODING_UTF7:
723 : case RTL_TEXTENCODING_UTF8:
724 : case RTL_TEXTENCODING_JAVA_UTF8:
725 23702 : nRet = 0x01;
726 23702 : break;
727 : default:
728 7536 : break;
729 : }
730 31238 : return nRet;
731 : }
732 :
733 : static bool
734 4338 : CanEncode(OUString const& rString, rtl_TextEncoding const eEncoding)
735 : {
736 4338 : rtl::OString tmp;
737 : return rString.convertToString(&tmp, eEncoding,
738 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
739 4338 : RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR);
740 : }
741 :
742 2162 : sal_uInt8 rtl_TextEncodingToWinCharsetRTF(
743 : OUString const& rFontName, OUString const& rAltName,
744 : rtl_TextEncoding eTextEncoding)
745 : {
746 : sal_uInt8 nRet =
747 2162 : rtl_getBestWindowsCharsetFromTextEncoding(eTextEncoding);
748 2162 : rtl_TextEncoding enc2 = rtl_getTextEncodingFromWindowsCharset(nRet);
749 4332 : if (!rtl_isOctetTextEncoding(enc2) /* check to avoid asserts */ ||
750 4316 : !(CanEncode(rFontName, enc2) && CanEncode(rAltName, enc2)))
751 : {
752 : static struct { rtl_TextEncoding enc; sal_uInt8 charset; }
753 : const s_fallbacks [] = {
754 : { RTL_TEXTENCODING_MS_932, 0x80 }, // Shift-JIS
755 : { RTL_TEXTENCODING_MS_936, 0x86 }, // GB-2312
756 : { RTL_TEXTENCODING_MS_950, 0x88 }, // Big5
757 : { RTL_TEXTENCODING_MS_949, 0x81 }, // EUC-KR
758 : };
759 14 : for (size_t i = 0; i < SAL_N_ELEMENTS(s_fallbacks); ++i)
760 : {
761 : // fall back to a charset that can at least encode the
762 : // font's name
763 28 : if (CanEncode(rFontName, s_fallbacks[i].enc)
764 14 : && CanEncode(rAltName, s_fallbacks[i].enc))
765 : {
766 8 : return s_fallbacks[i].charset;
767 : }
768 : }
769 : SAL_INFO("sw.rtf", "no fallback charset found for font: "
770 : << rFontName << " " << rAltName);
771 0 : nRet = 0x01; // all hope lost: "default", whatever that is
772 : }
773 2154 : return nRet;
774 : }
775 :
776 130 : long DateTime2DTTM( const DateTime& rDT )
777 : {
778 : /*
779 : mint short :6 0000003F minutes (0-59)
780 : hr short :5 000007C0 hours (0-23)
781 : dom short :5 0000F800 days of month (1-31)
782 : mon short :4 000F0000 months (1-12)
783 : yr short :9 1FF00000 years (1900-2411)-1900
784 : wdy short :3 E0000000 weekday(Sunday=0
785 : Monday=1
786 : ( wdy can be ignored ) Tuesday=2
787 : Wednesday=3
788 : Thursday=4
789 : Friday=5
790 : Saturday=6)
791 : */
792 :
793 130 : if ( rDT.GetDate() == 0L )
794 48 : return 0L;
795 82 : long nDT = ( rDT.GetDayOfWeek() + 1 ) % 7;
796 82 : nDT <<= 9;
797 82 : nDT += ( rDT.GetYear() - 1900 ) & 0x1ff;
798 82 : nDT <<= 4;
799 82 : nDT += rDT.GetMonth() & 0xf;
800 82 : nDT <<= 5;
801 82 : nDT += rDT.GetDay() & 0x1f;
802 82 : nDT <<= 5;
803 82 : nDT += rDT.GetHour() & 0x1f;
804 82 : nDT <<= 6;
805 82 : nDT += rDT.GetMin() & 0x3f;
806 82 : return nDT;
807 : }
808 :
809 :
810 : /** Find cFind in rParams if not embedded in " double quotes.
811 : Will NOT find '\\' or '"'.
812 : */
813 8 : sal_Int32 findUnquoted( const OUString& rParams, sal_Unicode cFind, sal_Int32 nFromPos )
814 : {
815 8 : const sal_Int32 nLen = rParams.getLength();
816 8 : if (nFromPos < 0 || nLen <= nFromPos)
817 0 : return -1;
818 134 : for (sal_Int32 nI = nFromPos; nI < nLen; ++nI)
819 : {
820 128 : const sal_Unicode c = rParams[nI];
821 128 : if (c == '\\')
822 0 : ++nI;
823 128 : else if (c == '\"')
824 : {
825 0 : ++nI;
826 : // While not at the end and not at an unescaped end quote
827 0 : while (nI < nLen)
828 : {
829 0 : if (rParams[nI] == '\"' && rParams[nI-1] != '\\')
830 0 : break;
831 0 : ++nI;
832 : }
833 : }
834 : else //normal unquoted section
835 : {
836 128 : if (c == cFind)
837 2 : return nI;
838 : }
839 : }
840 6 : return -1;
841 : }
842 :
843 : /** Find all rFind in rParams if not embedded in " double quotes and
844 : replace with rReplace. Will NOT find '\\' or '"'.
845 : */
846 8 : bool replaceUnquoted( OUString& rParams, const OUString& rFind, const OUString& rReplace )
847 : {
848 8 : bool bReplaced = false;
849 8 : if (rFind.isEmpty())
850 0 : return bReplaced;
851 8 : const sal_Unicode cFirst = rFind[0];
852 :
853 8 : sal_Int32 nLen = rParams.getLength();
854 184 : for (sal_Int32 nI = 0; nI < nLen; ++nI)
855 : {
856 176 : const sal_Unicode c = rParams[nI];
857 176 : if (rParams[nI] == '\\')
858 0 : ++nI;
859 176 : else if (rParams[nI] == '\"')
860 : {
861 0 : ++nI;
862 : // While not at the end and not at an unescaped end quote
863 0 : while (nI < nLen)
864 : {
865 0 : if (rParams[nI] == '\"' && rParams[nI-1] != '\\')
866 0 : break;
867 0 : ++nI;
868 : }
869 : }
870 : else //normal unquoted section
871 : {
872 176 : if (c == cFirst && rParams.match( rFind, nI))
873 : {
874 0 : const sal_Int32 nFindLen = rFind.getLength();
875 0 : const sal_Int32 nDiff = rReplace.getLength() - nFindLen;
876 0 : rParams = rParams.replaceAt( nI, nFindLen, rReplace);
877 0 : nI += nFindLen + nDiff - 1;
878 0 : nLen += nDiff;
879 0 : bReplaced = true;
880 : }
881 : }
882 : }
883 8 : return bReplaced;
884 : }
885 :
886 2 : sal_uLong MSDateTimeFormatToSwFormat(OUString& rParams,
887 : SvNumberFormatter *pFormatter, sal_uInt16 &rLang, bool bHijri,
888 : sal_uInt16 nDocLang)
889 : {
890 : // tell the Formatter about the new entry
891 2 : sal_Int32 nCheckPos = 0;
892 2 : short nType = NUMBERFORMAT_DEFINED;
893 2 : sal_uInt32 nKey = 0;
894 :
895 2 : SwapQuotesInField(rParams);
896 :
897 : // Force to Japanese when finding one of 'geE'.
898 : // XXX This actually may not be correct, all era keywords could be
899 : // used in other locales as well. I just don't know about Word. But
900 : // this is how it was for 10 years..
901 2 : bool bForceJapanese = (-1 != findUnquoted( rParams, 'g', 0));
902 : // XXX Why replace? The number formatter does handle them and this
903 : // effectively changes from Gengou to Gregorian calendar. Legacy
904 : // because it wasn't supported a decade ago and now moot? Or is
905 : // that a Word specialty?
906 2 : bForceJapanese |= replaceUnquoted( rParams, "ee", "yyyy");
907 2 : bForceJapanese |= replaceUnquoted( rParams, "EE", "YYYY");
908 2 : if (LANGUAGE_FRENCH != nDocLang)
909 : {
910 : // Handle the 'a' case here
911 2 : sal_Int32 nLastPos = 0;
912 4 : do
913 : {
914 4 : sal_Int32 nPos = findUnquoted( rParams, 'a', nLastPos + 1 );
915 4 : bForceJapanese |= ( nPos != -1 && IsNotAM( rParams, nPos ) );
916 4 : nLastPos = nPos;
917 : } while ( -1 != nLastPos );
918 : }
919 :
920 : // Force to NatNum when finding one of 'oOA'
921 2 : bool bForceNatNum = replaceUnquoted( rParams, "o", "m");
922 2 : bForceNatNum |= replaceUnquoted( rParams, "O", "M");
923 2 : if (LANGUAGE_FRENCH != nDocLang)
924 : {
925 : // Handle the 'A' case here
926 2 : sal_Int32 nLastPos = 0;
927 2 : do
928 : {
929 2 : sal_Int32 nPos = findUnquoted( rParams, 'A', nLastPos + 1 );
930 2 : bool bIsCharA = ( nPos != -1 && IsNotAM( rParams, nPos ) );
931 2 : bForceNatNum |= bIsCharA;
932 2 : if ( bIsCharA )
933 0 : rParams = rParams.replaceAt( nPos, 1, "D" );
934 2 : nLastPos = nPos;
935 : } while ( -1 != nLastPos );
936 : }
937 :
938 2 : sal_Int32 nLen = rParams.getLength();
939 44 : for (sal_Int32 nI = 0; nI < nLen; ++nI)
940 : {
941 42 : if (rParams[nI] == '\\')
942 0 : ++nI;
943 42 : else if (rParams[nI] == '\"')
944 : {
945 0 : ++nI;
946 : // While not at the end and not at an unescaped end quote
947 0 : while (nI < nLen)
948 : {
949 0 : if (rParams[nI] == '\"' && rParams[nI-1] != '\\')
950 0 : break;
951 0 : ++nI;
952 : }
953 : }
954 : else //normal unquoted section
955 : {
956 42 : sal_Unicode nChar = rParams[nI];
957 :
958 : // Change the localized word string to english
959 42 : switch ( nDocLang )
960 : {
961 : case LANGUAGE_FRENCH:
962 0 : if ( ( nChar == 'a' || nChar == 'A' ) && IsNotAM(rParams, nI) )
963 0 : rParams = rParams.replaceAt(nI, 1, "Y");
964 0 : break;
965 : default:
966 : ;
967 : }
968 42 : if (nChar == '/')
969 : {
970 : // MM: We have to escape '/' in case it's used as a char.
971 : // But not if it's a '/' inside AM/PM
972 6 : if (!(IsPreviousAM(rParams, nI) && IsNextPM(rParams, nI)))
973 : {
974 4 : rParams = rParams.replaceAt(nI, 1, "\\/");
975 4 : nLen++;
976 : }
977 6 : nI++;
978 : }
979 :
980 : // Deal with language differences in date format expression.
981 : // Should be made with i18n framework.
982 : // The list of the mappings and of those "special" locales is to be found at:
983 : // http://l10n.openoffice.org/i18n_framework/LocaleData.html
984 42 : if ( !bForceJapanese && !bForceNatNum )
985 : {
986 : // Convert to the localized equivalent for OOo
987 42 : switch ( rLang )
988 : {
989 : case LANGUAGE_FINNISH:
990 : {
991 0 : if (nChar == 'y' || nChar == 'Y')
992 0 : rParams = rParams.replaceAt(nI, 1, "V");
993 0 : else if (nChar == 'm' || nChar == 'M')
994 0 : rParams = rParams.replaceAt(nI, 1, "K");
995 0 : else if (nChar == 'd' || nChar == 'D')
996 0 : rParams = rParams.replaceAt(nI, 1, "P");
997 0 : else if (nChar == 'h' || nChar == 'H')
998 0 : rParams = rParams.replaceAt(nI, 1, "T");
999 : }
1000 0 : break;
1001 : case LANGUAGE_DANISH:
1002 : case LANGUAGE_NORWEGIAN:
1003 : case LANGUAGE_NORWEGIAN_BOKMAL:
1004 : case LANGUAGE_NORWEGIAN_NYNORSK:
1005 : case LANGUAGE_SWEDISH:
1006 : case LANGUAGE_SWEDISH_FINLAND:
1007 : {
1008 0 : if (nChar == 'h' || nChar == 'H')
1009 0 : rParams = rParams.replaceAt(nI, 1, "T");
1010 : }
1011 0 : break;
1012 : case LANGUAGE_PORTUGUESE:
1013 : case LANGUAGE_PORTUGUESE_BRAZILIAN:
1014 : case LANGUAGE_SPANISH_MODERN:
1015 : case LANGUAGE_SPANISH_DATED:
1016 : case LANGUAGE_SPANISH_MEXICAN:
1017 : case LANGUAGE_SPANISH_GUATEMALA:
1018 : case LANGUAGE_SPANISH_COSTARICA:
1019 : case LANGUAGE_SPANISH_PANAMA:
1020 : case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
1021 : case LANGUAGE_SPANISH_VENEZUELA:
1022 : case LANGUAGE_SPANISH_COLOMBIA:
1023 : case LANGUAGE_SPANISH_PERU:
1024 : case LANGUAGE_SPANISH_ARGENTINA:
1025 : case LANGUAGE_SPANISH_ECUADOR:
1026 : case LANGUAGE_SPANISH_CHILE:
1027 : case LANGUAGE_SPANISH_URUGUAY:
1028 : case LANGUAGE_SPANISH_PARAGUAY:
1029 : case LANGUAGE_SPANISH_BOLIVIA:
1030 : case LANGUAGE_SPANISH_EL_SALVADOR:
1031 : case LANGUAGE_SPANISH_HONDURAS:
1032 : case LANGUAGE_SPANISH_NICARAGUA:
1033 : case LANGUAGE_SPANISH_PUERTO_RICO:
1034 : {
1035 0 : if (nChar == 'a' || nChar == 'A')
1036 0 : rParams = rParams.replaceAt(nI, 1, "O");
1037 0 : else if (nChar == 'y' || nChar == 'Y')
1038 0 : rParams = rParams.replaceAt(nI, 1, "A");
1039 : }
1040 0 : break;
1041 : case LANGUAGE_DUTCH:
1042 : case LANGUAGE_DUTCH_BELGIAN:
1043 : {
1044 0 : if (nChar == 'y' || nChar == 'Y')
1045 0 : rParams = rParams.replaceAt(nI, 1, "J");
1046 0 : else if (nChar == 'u' || nChar == 'U')
1047 0 : rParams = rParams.replaceAt(nI, 1, "H");
1048 : }
1049 0 : break;
1050 : case LANGUAGE_ITALIAN:
1051 : case LANGUAGE_ITALIAN_SWISS:
1052 : {
1053 0 : if (nChar == 'a' || nChar == 'A')
1054 0 : rParams = rParams.replaceAt(nI, 1, "O");
1055 0 : else if (nChar == 'g' || nChar == 'G')
1056 0 : rParams = rParams.replaceAt(nI, 1, "X");
1057 0 : else if (nChar == 'y' || nChar == 'Y')
1058 0 : rParams = rParams.replaceAt(nI, 1, "A");
1059 0 : else if (nChar == 'd' || nChar == 'D')
1060 0 : rParams = rParams.replaceAt(nI, 1, "G");
1061 : }
1062 0 : break;
1063 : case LANGUAGE_GERMAN:
1064 : case LANGUAGE_GERMAN_SWISS:
1065 : case LANGUAGE_GERMAN_AUSTRIAN:
1066 : case LANGUAGE_GERMAN_LUXEMBOURG:
1067 : case LANGUAGE_GERMAN_LIECHTENSTEIN:
1068 : {
1069 0 : if (nChar == 'y' || nChar == 'Y')
1070 0 : rParams = rParams.replaceAt(nI, 1, "J");
1071 0 : else if (nChar == 'd' || nChar == 'D')
1072 0 : rParams = rParams.replaceAt(nI, 1, "T");
1073 : }
1074 0 : break;
1075 : case LANGUAGE_FRENCH:
1076 : case LANGUAGE_FRENCH_BELGIAN:
1077 : case LANGUAGE_FRENCH_CANADIAN:
1078 : case LANGUAGE_FRENCH_SWISS:
1079 : case LANGUAGE_FRENCH_LUXEMBOURG:
1080 : case LANGUAGE_FRENCH_MONACO:
1081 : {
1082 0 : if (nChar == 'y' || nChar == 'Y' || nChar == 'a')
1083 0 : rParams = rParams.replaceAt(nI, 1, "A");
1084 0 : else if (nChar == 'd' || nChar == 'D' || nChar == 'j')
1085 0 : rParams = rParams.replaceAt(nI, 1, "J");
1086 : }
1087 0 : break;
1088 : default:
1089 : {
1090 : ; // Nothing
1091 : }
1092 : }
1093 : }
1094 : }
1095 : }
1096 :
1097 2 : if (bForceNatNum)
1098 0 : bForceJapanese = true;
1099 :
1100 2 : if (bForceJapanese)
1101 0 : rLang = LANGUAGE_JAPANESE;
1102 :
1103 2 : if (bForceNatNum)
1104 0 : rParams = "[NatNum1][$-411]" + rParams;
1105 :
1106 2 : if (bHijri)
1107 0 : rParams = "[~hijri]" + rParams;
1108 :
1109 2 : pFormatter->PutEntry(rParams, nCheckPos, nType, nKey, rLang);
1110 :
1111 2 : return nKey;
1112 : }
1113 :
1114 6 : bool IsPreviousAM(OUString& rParams, sal_Int32 nPos)
1115 : {
1116 6 : return nPos>=2 && rParams.matchIgnoreAsciiCase("am", nPos-2);
1117 : }
1118 2 : bool IsNextPM(OUString& rParams, sal_Int32 nPos)
1119 : {
1120 2 : return nPos+2<rParams.getLength() && rParams.matchIgnoreAsciiCase("pm", nPos+1);
1121 : }
1122 2 : bool IsNotAM(OUString& rParams, sal_Int32 nPos)
1123 : {
1124 2 : ++nPos;
1125 2 : return nPos>=rParams.getLength() || (rParams[nPos]!='M' && rParams[nPos]!='m');
1126 : }
1127 :
1128 4 : void SwapQuotesInField(OUString &rFmt)
1129 : {
1130 : //Swap unescaped " and ' with ' and "
1131 4 : const sal_Int32 nLen = rFmt.getLength();
1132 60 : for (sal_Int32 nI = 0; nI < nLen; ++nI)
1133 : {
1134 56 : if (!nI || rFmt[nI-1]!='\\')
1135 : {
1136 56 : if (rFmt[nI]=='\"')
1137 0 : rFmt = rFmt.replaceAt(nI, 1, "\'");
1138 56 : else if (rFmt[nI]=='\'')
1139 0 : rFmt = rFmt.replaceAt(nI, 1, "\"");
1140 : }
1141 : }
1142 4 : }
1143 :
1144 : }
1145 102 : }
1146 :
1147 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|