bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / ww8par5.cxx
blob8cfdeed55d1860d7a358c2344216452ab54abe6f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <ctype.h> // tolower
22 #include <stdio.h> // sscanf()
24 #include <sal/types.h>
25 #include <tools/solar.h>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/storagehelper.hxx>
28 #include <comphelper/string.hxx>
29 #include <sot/storinfo.hxx>
30 #include <com/sun/star/embed/XStorage.hpp>
31 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <com/sun/star/io/XStream.hpp>
35 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
36 #include <svl/urihelper.hxx>
37 #include <svl/zforlist.hxx>
38 #include <svl/zformat.hxx>
39 #include <sfx2/linkmgr.hxx>
41 #include <ucbhelper/content.hxx>
43 #include <com/sun/star/i18n/ScriptType.hpp>
44 #include <hintids.hxx>
45 #include <editeng/fontitem.hxx>
46 #include <editeng/fhgtitem.hxx>
47 #include <editeng/langitem.hxx>
48 #include <fmtfld.hxx>
49 #include <fmtanchr.hxx>
50 #include <pam.hxx> // fuer SwPam
51 #include <doc.hxx>
52 #include <charatr.hxx> // class SwFmtFld
53 #include <flddat.hxx> // class SwDateTimeField
54 #include <docufld.hxx> // class SwPageNumberField
55 #include <reffld.hxx> // class SwGetRefField
56 #include <IMark.hxx>
57 #include <expfld.hxx> // class SwSetExpField
58 #include <dbfld.hxx> // class SwDBField
59 #include <usrfld.hxx>
60 #include <tox.hxx>
61 #include <section.hxx> // class SwSection
62 #include <ndtxt.hxx>
63 #include <fmtinfmt.hxx>
64 #include <chpfld.hxx>
65 #include <ftnidx.hxx>
66 #include <txtftn.hxx>
67 #include <viewsh.hxx>
68 #include <shellres.hxx>
69 #include <fmtruby.hxx>
70 #include <charfmt.hxx>
71 #include <txtatr.hxx>
72 #include <breakit.hxx>
73 #include <fmtclds.hxx>
74 #include <pagedesc.hxx>
75 #include <SwStyleNameMapper.hxx>
77 #include "ww8scan.hxx" // WW8FieldDesc
78 #include "ww8par.hxx"
79 #include "ww8par2.hxx"
80 #include "writerhelper.hxx"
81 #include "fields.hxx"
82 #include <unotools/fltrcfg.hxx>
83 #include <xmloff/odffields.hxx>
85 #include <algorithm> // #i24377#
87 #define MAX_FIELDLEN 64000
89 #define WW8_TOX_LEVEL_DELIM ':'
91 using namespace ::com::sun::star;
92 using namespace sw::util;
93 using namespace sw::mark;
94 using namespace std; // #i24377#
95 using namespace nsSwDocInfoSubType;
98 class WW8ReadFieldParams
100 private:
101 String aData;
102 xub_StrLen nLen, nFnd, nNext, nSavPtr;
103 public:
104 WW8ReadFieldParams( const String& rData );
105 ~WW8ReadFieldParams();
107 xub_StrLen GoToTokenParam();
108 long SkipToNextToken();
109 xub_StrLen GetTokenSttPtr() const { return nFnd; }
111 xub_StrLen FindNextStringPiece( xub_StrLen _nStart = STRING_NOTFOUND );
112 bool GetTokenSttFromTo(xub_StrLen* _pFrom, xub_StrLen* _pTo,
113 xub_StrLen _nMax);
115 String GetResult() const;
119 WW8ReadFieldParams::WW8ReadFieldParams( const String& _rData )
120 : aData( _rData ), nLen( _rData.Len() ), nNext( 0 )
123 erstmal nach einer oeffnenden Klammer oder einer Leerstelle oder einem
124 Anfuehrungszeichen oder einem Backslash suchen, damit der Feldbefehl
125 (also INCLUDEPICTURE bzw EINFUeGENGRAFIK bzw ...) ueberlesen wird
127 while( (nLen > nNext) && (aData.GetChar( nNext ) == ' ') )
128 ++nNext;
130 sal_Unicode c;
131 while( nLen > nNext
132 && (c = aData.GetChar( nNext )) != ' '
133 && c != '"'
134 && c != '\\'
135 && c != 132
136 && c != 0x201c )
137 ++nNext;
139 nFnd = nNext;
140 nSavPtr = nNext;
144 WW8ReadFieldParams::~WW8ReadFieldParams()
150 String WW8ReadFieldParams::GetResult() const
152 return (STRING_NOTFOUND == nFnd)
153 ? aEmptyStr
154 : aData.Copy( nFnd, (nSavPtr - nFnd) );
158 xub_StrLen WW8ReadFieldParams::GoToTokenParam()
160 xub_StrLen nOld = nNext;
161 if( -2 == SkipToNextToken() )
162 return GetTokenSttPtr();
163 nNext = nOld;
164 return STRING_NOTFOUND;
167 // ret: -2: NOT a '\' parameter but normal Text
168 long WW8ReadFieldParams::SkipToNextToken()
170 long nRet = -1; // Ende
171 if (
172 (STRING_NOTFOUND != nNext) && (nLen > nNext) &&
173 STRING_NOTFOUND != (nFnd = FindNextStringPiece(nNext))
176 nSavPtr = nNext;
178 if ('\\' == aData.GetChar(nFnd) && '\\' != aData.GetChar(nFnd + 1))
180 nRet = aData.GetChar(++nFnd);
181 nNext = ++nFnd; // und dahinter setzen
183 else
185 nRet = -2;
186 if (
187 (STRING_NOTFOUND != nSavPtr ) &&
189 ('"' == aData.GetChar(nSavPtr - 1)) ||
190 (0x201d == aData.GetChar(nSavPtr - 1))
194 --nSavPtr;
198 return nRet;
201 // FindNextPara sucht naechsten Backslash-Parameter oder naechste Zeichenkette
202 // bis zum Blank oder naechsten "\" oder zum schliessenden Anfuehrungszeichen
203 // oder zum String-Ende von pStr.
205 // Ausgabe ppNext (falls ppNext != 0) Suchbeginn fuer naechsten Parameter bzw. 0
207 // Returnwert: 0 falls String-Ende erreicht,
208 // ansonsten Anfang des Paramters bzw. der Zeichenkette
210 xub_StrLen WW8ReadFieldParams::FindNextStringPiece(const xub_StrLen nStart)
212 xub_StrLen n = ( STRING_NOTFOUND == nStart ) ? nFnd : nStart; // Anfang
213 xub_StrLen n2; // Ende
215 nNext = STRING_NOTFOUND; // Default fuer nicht gefunden
217 while( (nLen > n) && (aData.GetChar( n ) == ' ') )
218 ++n;
220 if ( aData.GetChar( n ) == 0x13 )
222 // Skip the nested field code since it's not supported
223 while ( ( nLen > n ) && ( aData.GetChar( n ) != 0x14 ) )
224 n++;
227 if( nLen == n )
228 return STRING_NOTFOUND; // String End reached!
230 if( (aData.GetChar( n ) == '"') // Anfuehrungszeichen vor Para?
231 || (aData.GetChar( n ) == 0x201c)
232 || (aData.GetChar( n ) == 132)
233 || (aData.GetChar( n ) == 0x14) )
235 n++; // Anfuehrungszeichen ueberlesen
236 n2 = n; // ab hier nach Ende suchen
237 while( (nLen > n2)
238 && (aData.GetChar( n2 ) != '"')
239 && (aData.GetChar( n2 ) != 0x201d)
240 && (aData.GetChar( n2 ) != 147)
241 && (aData.GetChar( n2 ) != 0x15) )
242 n2++; // Ende d. Paras suchen
244 else // keine Anfuehrungszeichen
246 n2 = n; // ab hier nach Ende suchen
247 while( (nLen > n2) && (aData.GetChar( n2 ) != ' ') ) // Ende d. Paras suchen
249 if( aData.GetChar( n2 ) == '\\' )
251 if( aData.GetChar( n2+1 ) == '\\' )
252 n2 += 2; // Doppel-Backslash -> OK
253 else
255 if( n2 > n )
256 n2--;
257 break; // einfach-Backslash -> Ende
260 else
261 n2++; // kein Backslash -> OK
264 if( nLen > n2 )
266 if(aData.GetChar( n2 ) != ' ') n2++;
267 nNext = n2;
269 return n;
274 // read parameters "1-3" or 1-3 with both values between 1 and nMax
275 bool WW8ReadFieldParams::GetTokenSttFromTo(sal_uInt16* pFrom, sal_uInt16* pTo, sal_uInt16 nMax)
277 sal_uInt16 nStart = 0;
278 sal_uInt16 nEnd = 0;
279 xub_StrLen n = GoToTokenParam();
280 if( STRING_NOTFOUND != n )
283 String sParams( GetResult() );
285 sal_Int32 nIndex = 0;
286 String sStart( sParams.GetToken(0, '-', nIndex) );
287 if( -1 != nIndex )
289 nStart = static_cast<sal_uInt16>(sStart.ToInt32());
290 nEnd = static_cast<sal_uInt16>(sParams.Copy(nIndex).ToInt32());
293 if( pFrom ) *pFrom = nStart;
294 if( pTo ) *pTo = nEnd;
296 return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd);
299 //----------------------------------------
300 // Bookmarks
301 //----------------------------------------
303 long SwWW8ImplReader::Read_Book(WW8PLCFManResult*)
305 // muesste auch ueber pRes.nCo2OrIdx gehen
306 WW8PLCFx_Book* pB = pPlcxMan->GetBook();
307 if( !pB )
309 OSL_ENSURE( pB, "WW8PLCFx_Book - Pointer nicht da" );
310 return 0;
313 eBookStatus eB = pB->GetStatus();
314 if (eB & BOOK_IGNORE)
315 return 0; // Bookmark zu ignorieren
317 if (pB->GetIsEnd())
319 pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true,
320 pB->GetHandle(), (eB & BOOK_FIELD)!=0);
321 return 0;
324 //"_Toc*" and "_Hlt*" are unnecessary
325 const String* pName = pB->GetName();
326 #if !defined(WW_NATIVE_TOC)
327 if( !pName || pName->EqualsIgnoreCaseAscii( "_Toc", 0, 4 )
328 || pName->EqualsIgnoreCaseAscii( "_Hlt", 0, 4 ) )
329 return 0;
330 #endif
332 //ToUpper darf auf keinen Fall gemacht werden, weil der Bookmark- name ein Hyperlink-Ziel sein kann!
334 String aVal;
335 if( SwFltGetFlag( nFieldFlags, SwFltControlStack::BOOK_TO_VAR_REF ) )
337 // Fuer UEbersetzung Bookmark -> Variable setzen
338 long nLen = pB->GetLen();
339 if( nLen > MAX_FIELDLEN )
340 nLen = MAX_FIELDLEN;
342 long nOldPos = pStrm->Tell();
343 nLen = pSBase->WW8ReadString( *pStrm, aVal, pB->GetStartPos(), nLen,
344 eStructCharSet );
345 pStrm->Seek( nOldPos );
347 // now here the implementation of the old "QuoteString" and
348 // I hope with a better performance as before. It's also only
349 // needed if the filterflags say we will convert bookmarks
350 // to SetExpFields! And this the exception!
352 OUString sHex("\\x");
353 bool bSetAsHex;
354 bool bAllowCr = SwFltGetFlag(nFieldFlags,
355 SwFltControlStack::ALLOW_FLD_CR) ? true : false;
357 sal_Unicode cChar;
359 for( xub_StrLen nI = 0;
360 nI < aVal.Len() && aVal.Len() < (MAX_FIELDLEN - 4); ++nI )
362 switch( cChar = aVal.GetChar( nI ) )
364 case 0x0b:
365 case 0x0c:
366 case 0x0d:
367 if( bAllowCr )
368 aVal.SetChar( nI, '\n' ), bSetAsHex = false;
369 else
370 bSetAsHex = true;
371 break;
373 case 0xFE:
374 case 0xFF:
375 bSetAsHex = true;
376 break;
378 default:
379 bSetAsHex = 0x20 > cChar;
380 break;
383 if( bSetAsHex )
385 //all Hex-Numbers with \x before
386 String sTmp( sHex );
387 if( cChar < 0x10 )
388 sTmp += '0';
389 sTmp += OUString::number( cChar, 16 );
390 aVal.Replace( nI, 1 , sTmp );
391 nI += sTmp.Len() - 1;
395 if( aVal.Len() > (MAX_FIELDLEN - 4))
396 aVal.Erase( MAX_FIELDLEN - 4 );
399 //e.g. inserting bookmark around field result, so we need to put
400 //it around the entire writer field, as we don't have the separation
401 //of field and field result of word, see #i16941#
402 SwPosition aStart(*pPaM->GetPoint());
403 if (!maFieldStack.empty())
405 const WW8FieldEntry &rTest = maFieldStack.back();
406 aStart = rTest.maStartPos;
409 pReffedStck->NewAttr(aStart, SwFltBookmark(BookmarkToWriter(*pName), aVal,
410 pB->GetHandle(), 0));
411 return 0;
414 //----------------------------------------------------------------------
415 // allgemeine Hilfsroutinen zum Auseinanderdroeseln der Parameter
416 //----------------------------------------------------------------------
418 // ConvertFFileName uebersetzt FeldParameter-Namen u. ae. in den
419 // System-Zeichensatz.
420 // Gleichzeitig werden doppelte Backslashes in einzelne uebersetzt.
421 void SwWW8ImplReader::ConvertFFileName( String& rName, const String& rOrg )
423 rName = rOrg;
424 rName.SearchAndReplaceAllAscii( "\\\\", OUString( '\\' ));
425 rName.SearchAndReplaceAllAscii( "%20", OUString( ' ' ));
427 // ggfs. anhaengende Anfuehrungszeichen entfernen
428 if( rName.Len() && '"' == rName.GetChar( rName.Len()-1 ))
429 rName.Erase( rName.Len()-1, 1);
431 // Need the more sophisticated url converter. cmc
432 if (rName.Len())
433 rName = URIHelper::SmartRel2Abs(
434 INetURLObject(sBaseURL), rName, Link(), false);
437 // ConvertUFNneme uebersetzt FeldParameter-Namen u. ae. in den
438 // System-Zeichensatz und Upcased sie ( z.B. fuer Ref-Felder )
439 namespace
441 void ConvertUFName( String& rName )
443 rName = GetAppCharClass().uppercase( rName );
447 static void lcl_ConvertSequenceName(String& rSequenceName)
449 ConvertUFName(rSequenceName);
450 if ('0' <= rSequenceName.GetChar(0) && '9' >= rSequenceName.GetChar(0))
451 rSequenceName.Insert('_', 0);
454 // FindParaStart() finds 1st Parameter that follows '\' and cToken
455 // and returns start of this parameter or STRING_NOT_FOUND.
456 xub_StrLen FindParaStart( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 )
458 bool bStr = false; // innerhalb String ignorieren
460 for( xub_StrLen nBuf=0; nBuf+1 < rStr.Len(); nBuf++ )
462 if( rStr.GetChar( nBuf ) == '"' )
463 bStr = !bStr;
465 if( !bStr
466 && rStr.GetChar( nBuf ) == '\\'
467 && ( rStr.GetChar( nBuf + 1 ) == cToken
468 || rStr.GetChar( nBuf + 1 ) == cToken2 ) )
470 nBuf += 2;
471 // skip spaces between cToken and it's parameters
472 while( nBuf < rStr.Len()
473 && rStr.GetChar( nBuf ) == ' ' )
474 nBuf++;
475 // return start of parameters
476 return nBuf < rStr.Len() ? nBuf : STRING_NOTFOUND;
479 return STRING_NOTFOUND;
482 // FindPara() findet den ersten Parameter mit '\' und cToken. Es wird
483 // ein neuer String allokiert ( der vom Aufrufer deallokiert werden muss )
484 // und alles, was zum Parameter gehoert, wird in ihm zurueckgeliefert.
485 String FindPara( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 )
487 xub_StrLen n2; // Ende
488 xub_StrLen n = FindParaStart( rStr, cToken, cToken2 ); // Anfang
489 if( STRING_NOTFOUND == n )
490 return aEmptyStr;
492 if( rStr.GetChar( n ) == '"'
493 || rStr.GetChar( n ) == 132 )
494 { // Anfuehrungszeichen vor Para
495 n++; // Anfuehrungszeichen ueberlesen
496 n2 = n; // ab hier nach Ende suchen
497 while( n2 < rStr.Len()
498 && rStr.GetChar( n2 ) != 147
499 && rStr.GetChar( n2 ) != '"' )
500 n2++; // Ende d. Paras suchen
502 else
503 { // keine Anfuehrungszeichen
504 n2 = n; // ab hier nach Ende suchen
505 while( n2 < rStr.Len()
506 && rStr.GetChar( n2 ) != ' ' )
507 n2++; // Ende d. Paras suchen
509 return rStr.Copy( n, n2-n );
513 static SvxExtNumType GetNumTypeFromName(const String& rStr,
514 bool bAllowPageDesc = false)
516 SvxExtNumType eTyp = bAllowPageDesc ? SVX_NUM_PAGEDESC : SVX_NUM_ARABIC;
517 if( rStr.EqualsIgnoreCaseAscii( "Arabi", 0, 5 ) ) // Arabisch, Arabic
518 eTyp = SVX_NUM_ARABIC;
519 else if( rStr.EqualsAscii( "misch", 2, 5 ) ) // r"omisch
520 eTyp = SVX_NUM_ROMAN_LOWER;
521 else if( rStr.EqualsAscii( "MISCH", 2, 5 ) ) // R"OMISCH
522 eTyp = SVX_NUM_ROMAN_UPPER;
523 else if( rStr.EqualsIgnoreCaseAscii( "alphabeti", 0, 9 ) )// alphabetisch, alphabetic
524 eTyp = ( rStr.GetChar( 0 ) == 'A' )
525 ? SVX_NUM_CHARS_UPPER_LETTER_N
526 : SVX_NUM_CHARS_LOWER_LETTER_N;
527 else if( rStr.EqualsIgnoreCaseAscii( "roman", 0, 5 ) ) // us
528 eTyp = ( rStr.GetChar( 0 ) == 'R' )
529 ? SVX_NUM_ROMAN_UPPER
530 : SVX_NUM_ROMAN_LOWER;
531 return eTyp;
534 static SvxExtNumType GetNumberPara(String& rStr, bool bAllowPageDesc = false)
536 String s( FindPara( rStr, '*', '*' ) ); // Ziffernart
537 SvxExtNumType aType = GetNumTypeFromName( s, bAllowPageDesc );
538 return aType;
544 bool SwWW8ImplReader::ForceFieldLanguage(SwField &rFld, sal_uInt16 nLang)
546 bool bRet(false);
548 const SvxLanguageItem *pLang =
549 (const SvxLanguageItem*)GetFmtAttr(RES_CHRATR_LANGUAGE);
550 OSL_ENSURE(pLang, "impossible");
551 sal_uInt16 nDefault = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
553 if (nLang != nDefault)
555 rFld.SetAutomaticLanguage(false);
556 rFld.SetLanguage(nLang);
557 bRet = true;
560 return bRet;
563 String GetWordDefaultDateStringAsUS(SvNumberFormatter* pFormatter, sal_uInt16 nLang)
565 //Get the system date in the correct final language layout, convert to
566 //a known language and modify the 2 digit year part to be 4 digit, and
567 //convert back to the correct language layout.
568 sal_uLong nIndex = pFormatter->GetFormatIndex(NF_DATE_SYSTEM_SHORT, nLang);
570 SvNumberformat aFormat = const_cast<SvNumberformat &>
571 (*(pFormatter->GetEntry(nIndex)));
572 aFormat.ConvertLanguage(*pFormatter, nLang, LANGUAGE_ENGLISH_US);
574 String sParams(aFormat.GetFormatstring());
575 // #i36594#
576 // Fix provided by mloiseleur@openoffice.org.
577 // A default date can have already 4 year digits, in some case
578 const xub_StrLen pos = sParams.Search(OUString("YYYY"));
579 if ( pos == STRING_NOTFOUND )
581 sParams.SearchAndReplace(OUString("YY"), OUString("YYYY"));
583 return sParams;
586 short SwWW8ImplReader::GetTimeDatePara(String& rStr, sal_uInt32& rFormat,
587 sal_uInt16 &rLang, int nWhichDefault, bool bHijri)
589 bool bRTL = false;
590 if (pPlcxMan && !bVer67)
592 const sal_uInt8 *pResult = pPlcxMan->HasCharSprm(0x85A);
593 if (pResult && *pResult)
594 bRTL = true;
596 RES_CHRATR eLang = bRTL ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
597 const SvxLanguageItem *pLang = (SvxLanguageItem*)GetFmtAttr( static_cast< sal_uInt16 >(eLang));
598 OSL_ENSURE(pLang, "impossible");
599 rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
601 SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
602 String sParams( FindPara( rStr, '@', '@' ) );// Date/Time
603 if (!sParams.Len())
605 bool bHasTime = false;
606 switch (nWhichDefault)
608 case ww::ePRINTDATE:
609 case ww::eSAVEDATE:
610 sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang);
611 sParams.AppendAscii(" HH:MM:SS AM/PM");
612 bHasTime = true;
613 break;
614 case ww::eCREATEDATE:
615 sParams.AssignAscii("DD/MM/YYYY HH:MM:SS");
616 bHasTime = true;
617 break;
618 default:
619 case ww::eDATE:
620 sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang);
621 break;
624 if (bHijri)
625 sParams.Insert(OUString("[~hijri]"), 0);
627 sal_Int32 nCheckPos = 0;
628 short nType = NUMBERFORMAT_DEFINED;
629 rFormat = 0;
631 OUString sTemp(sParams);
632 pFormatter->PutandConvertEntry(sTemp, nCheckPos, nType, rFormat,
633 LANGUAGE_ENGLISH_US, rLang);
634 sParams = sTemp;
636 return bHasTime ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE;
639 sal_uLong nFmtIdx =
640 sw::ms::MSDateTimeFormatToSwFormat(sParams, pFormatter, rLang, bHijri,
641 GetFib().lid);
642 short nNumFmtType = NUMBERFORMAT_UNDEFINED;
643 if (nFmtIdx)
644 nNumFmtType = pFormatter->GetType(nFmtIdx);
645 rFormat = nFmtIdx;
647 return nNumFmtType;
650 //-----------------------------------------
651 // Felder
652 //-----------------------------------------
653 // Am Ende des Einlesens entsprechende Felder updaten ( z.Zt. die Referenzen )
654 void SwWW8ImplReader::UpdateFields()
656 rDoc.SetUpdateExpFldStat(true); // JP: neu fuer alles wichtige
657 rDoc.SetInitDBFields(true); // Datenbank-Felder auch
660 sal_uInt16 SwWW8ImplReader::End_Field()
662 sal_uInt16 nRet = 0;
663 WW8PLCFx_FLD* pF = pPlcxMan->GetFld();
664 OSL_ENSURE(pF, "WW8PLCFx_FLD - Pointer nicht da");
665 if (!pF || !pF->EndPosIsFieldEnd())
666 return nRet;
668 const SvtFilterOptions &rOpt = SvtFilterOptions::Get();
669 sal_Bool bUseEnhFields = rOpt.IsUseEnhancedFields();
671 OSL_ENSURE(!maFieldStack.empty(), "Empty field stack\n");
672 if (!maFieldStack.empty())
675 only hyperlinks currently need to be handled like this, for the other
676 cases we have inserted a field not an attribute with an unknown end
677 point
679 nRet = maFieldStack.back().mnFieldId;
680 switch (nRet)
682 case 70:
683 if (bUseEnhFields && pPaM!=NULL && pPaM->GetPoint()!=NULL) {
684 SwPosition aEndPos = *pPaM->GetPoint();
685 SwPaM aFldPam( maFieldStack.back().GetPtNode(), maFieldStack.back().GetPtCntnt(), aEndPos.nNode, aEndPos.nContent.GetIndex());
686 IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess( );
687 IFieldmark *pFieldmark = dynamic_cast<IFieldmark*>( pMarksAccess->makeFieldBookmark(
688 aFldPam, maFieldStack.back().GetBookmarkName(), ODF_FORMTEXT ) );
689 OSL_ENSURE(pFieldmark!=NULL, "hmmm; why was the bookmark not created?");
690 if (pFieldmark!=NULL) {
691 const IFieldmark::parameter_map_t& pParametersToAdd = maFieldStack.back().getParameters();
692 pFieldmark->GetParameters()->insert(pParametersToAdd.begin(), pParametersToAdd.end());
695 break;
696 #if defined(WW_NATIVE_TOC)
697 case 8: // TOX_INDEX
698 case 13: // TOX_CONTENT
699 case 88: // HYPERLINK
700 case 37: // REF
701 if (pPaM!=NULL && pPaM->GetPoint()!=NULL) {
703 SwPosition aEndPos = *pPaM->GetPoint();
704 SwPaM aFldPam( maFieldStack.back().GetPtNode(), maFieldStack.back().GetPtCntnt(), aEndPos.nNode, aEndPos.nContent.GetIndex());
705 SwFieldBookmark *pFieldmark=(SwFieldBookmark*)rDoc.makeFieldBookmark(aFldPam, maFieldStack.back().GetBookmarkName(), maFieldStack.back().GetBookmarkType());
706 OSL_ENSURE(pFieldmark!=NULL, "hmmm; why was the bookmark not created?");
707 if (pFieldmark!=NULL) {
708 const IFieldmark::parameter_map_t& pParametersToAdd = maFieldStack.back().getParameters();
709 pFieldmark->GetParameters()->insert(pParameters.begin(), pParameters.end());
712 break;
713 #else
714 case 88:
715 pCtrlStck->SetAttr(*pPaM->GetPoint(),RES_TXTATR_INETFMT);
716 break;
717 #endif
718 case 36:
719 case 68:
720 //Move outside the section associated with this type of field
721 *pPaM->GetPoint() = maFieldStack.back().maStartPos;
722 break;
723 default:
724 OUString aCode = maFieldStack.back().GetBookmarkCode();
725 if ( !aCode.isEmpty() )
727 // Unhandled field with stored code
728 SwPosition aEndPos = *pPaM->GetPoint();
729 SwPaM aFldPam(
730 maFieldStack.back().GetPtNode(), maFieldStack.back().GetPtCntnt(),
731 aEndPos.nNode, aEndPos.nContent.GetIndex());
733 IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess( );
735 IFieldmark* pFieldmark = pMarksAccess->makeFieldBookmark(
736 aFldPam,
737 maFieldStack.back().GetBookmarkName(),
738 ODF_UNHANDLED );
739 if ( pFieldmark )
741 const IFieldmark::parameter_map_t& pParametersToAdd = maFieldStack.back().getParameters();
742 pFieldmark->GetParameters()->insert(pParametersToAdd.begin(), pParametersToAdd.end());
743 OUString sFieldId = OUString::valueOf( sal_Int32( maFieldStack.back().mnFieldId ) );
744 pFieldmark->GetParameters()->insert(
745 std::pair< OUString, uno::Any > (
746 ODF_ID_PARAM,
747 uno::makeAny( sFieldId ) ) );
748 pFieldmark->GetParameters()->insert(
749 std::pair< OUString, uno::Any > (
750 ODF_CODE_PARAM,
751 uno::makeAny( aCode ) ) );
753 if ( maFieldStack.back().mnObjLocFc > 0 )
755 // Store the OLE object as an internal link
756 String sOleId = OUString('_');
757 sOleId += OUString::number( maFieldStack.back().mnObjLocFc );
759 SvStorageRef xSrc0 = pStg->OpenSotStorage(OUString(SL::aObjectPool));
760 SvStorageRef xSrc1 = xSrc0->OpenSotStorage( sOleId, STREAM_READ );
762 // Store it now!
763 uno::Reference< embed::XStorage > xDocStg = GetDoc().GetDocStorage();
764 if (xDocStg.is())
766 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement(
767 "OLELinks", embed::ElementModes::WRITE );
768 SotStorageRef xObjDst = SotStorage::OpenOLEStorage( xOleStg, sOleId );
770 if ( xObjDst.Is() )
772 xSrc1->CopyTo( xObjDst );
774 if ( !xObjDst->GetError() )
775 xObjDst->Commit();
778 uno::Reference< embed::XTransactedObject > xTransact( xOleStg, uno::UNO_QUERY );
779 if ( xTransact.is() )
780 xTransact->commit();
783 // Store the OLE Id as a parameter
784 pFieldmark->GetParameters()->insert(
785 std::pair< OUString, uno::Any >(
786 ODF_OLE_PARAM, uno::makeAny( OUString( sOleId ) ) ) );
792 break;
794 maFieldStack.pop_back();
796 return nRet;
799 bool AcceptableNestedField(sal_uInt16 nFieldCode)
801 switch (nFieldCode)
803 #if defined(WW_NATIVE_TOC)
804 case 8: // allow recursive field in TOC...
805 case 13: // allow recursive field in TOC...
806 #endif
807 case 36:
808 case 68:
809 case 79:
810 case 88:
811 // Accept AutoTextList field as nested field.
812 // Thus, the field result is imported as plain text.
813 case 89:
814 return true;
815 default:
816 return false;
820 WW8FieldEntry::WW8FieldEntry(SwPosition &rPos, sal_uInt16 nFieldId) throw()
821 : maStartPos(rPos), mnFieldId(nFieldId), mnObjLocFc(0)
825 WW8FieldEntry::WW8FieldEntry(const WW8FieldEntry &rOther) throw()
826 : maStartPos(rOther.maStartPos), mnFieldId(rOther.mnFieldId), mnObjLocFc(rOther.mnObjLocFc)
830 void WW8FieldEntry::Swap(WW8FieldEntry &rOther) throw()
832 std::swap(maStartPos, rOther.maStartPos);
833 std::swap(mnFieldId, rOther.mnFieldId);
836 WW8FieldEntry &WW8FieldEntry::operator=(const WW8FieldEntry &rOther) throw()
838 WW8FieldEntry aTemp(rOther);
839 Swap(aTemp);
840 return *this;
843 OUString WW8FieldEntry::GetBookmarkName()
845 return msBookmarkName;
848 OUString WW8FieldEntry::GetBookmarkCode()
850 return msMarkCode;
853 void WW8FieldEntry::SetBookmarkName(OUString bookmarkName)
855 msBookmarkName=bookmarkName;
858 void WW8FieldEntry::SetBookmarkType(OUString bookmarkType)
860 msMarkType=bookmarkType;
863 void WW8FieldEntry::SetBookmarkCode(OUString bookmarkCode)
865 msMarkCode = bookmarkCode;
869 ::sw::mark::IFieldmark::parameter_map_t& WW8FieldEntry::getParameters() {
870 return maParams;
874 // Read_Field liest ein Feld ein oder, wenn es nicht gelesen werden kann,
875 // wird 0 zurueckgegeben, so dass das Feld vom Aufrufer textuell gelesen wird.
876 // Returnwert: Gesamtlaenge des Feldes ( zum UEberlesen )
877 long SwWW8ImplReader::Read_Field(WW8PLCFManResult* pRes)
879 typedef eF_ResT (SwWW8ImplReader:: *FNReadField)( WW8FieldDesc*, String& );
880 enum Limits {eMax = 96};
881 static FNReadField aWW8FieldTab[eMax+1] =
884 &SwWW8ImplReader::Read_F_Input,
886 &SwWW8ImplReader::Read_F_Ref, // 3
889 &SwWW8ImplReader::Read_F_Set, // 6
891 &SwWW8ImplReader::Read_F_Tox, // 8
895 &SwWW8ImplReader::Read_F_Seq, // 12
896 &SwWW8ImplReader::Read_F_Tox, // 13
897 &SwWW8ImplReader::Read_F_DocInfo, // 14
898 &SwWW8ImplReader::Read_F_DocInfo, // 15
899 &SwWW8ImplReader::Read_F_DocInfo, // 16
900 &SwWW8ImplReader::Read_F_Author, // 17
901 &SwWW8ImplReader::Read_F_DocInfo, // 18
902 &SwWW8ImplReader::Read_F_DocInfo, // 19
903 &SwWW8ImplReader::Read_F_DocInfo, // 20
904 &SwWW8ImplReader::Read_F_DocInfo, // 21
905 &SwWW8ImplReader::Read_F_DocInfo, // 22
906 &SwWW8ImplReader::Read_F_DocInfo, // 23
907 &SwWW8ImplReader::Read_F_DocInfo, // 24
908 &SwWW8ImplReader::Read_F_DocInfo, // 25
909 &SwWW8ImplReader::Read_F_Anz, // 26
910 &SwWW8ImplReader::Read_F_Anz, // 27
911 &SwWW8ImplReader::Read_F_Anz, // 28
912 &SwWW8ImplReader::Read_F_FileName, // 29
913 &SwWW8ImplReader::Read_F_TemplName, // 30
914 &SwWW8ImplReader::Read_F_DateTime, // 31
915 &SwWW8ImplReader::Read_F_DateTime, // 32
916 &SwWW8ImplReader::Read_F_CurPage, // 33
919 &SwWW8ImplReader::Read_F_IncludeText, // 36
920 &SwWW8ImplReader::Read_F_PgRef, // 37
921 &SwWW8ImplReader::Read_F_InputVar, // 38
922 &SwWW8ImplReader::Read_F_Input, // 39
924 &SwWW8ImplReader::Read_F_DBNext, // 41
927 &SwWW8ImplReader::Read_F_DBNum, // 44
932 &SwWW8ImplReader::Read_F_Equation, // 49
934 &SwWW8ImplReader::Read_F_Macro, // 51
935 &SwWW8ImplReader::Read_F_ANumber, // 52
936 &SwWW8ImplReader::Read_F_ANumber, // 53
937 &SwWW8ImplReader::Read_F_ANumber, // 54
941 0, // 56
944 &SwWW8ImplReader::Read_F_Symbol, // 57
945 &SwWW8ImplReader::Read_F_Embedd, // 58
946 &SwWW8ImplReader::Read_F_DBField, // 59
951 &SwWW8ImplReader::Read_F_DocInfo, // 64 - DOCVARIABLE
954 &SwWW8ImplReader::Read_F_IncludePicture, // 67
955 &SwWW8ImplReader::Read_F_IncludeText, // 68
957 &SwWW8ImplReader::Read_F_FormTextBox, // 70
958 &SwWW8ImplReader::Read_F_FormCheckBox, // 71
959 &SwWW8ImplReader::Read_F_NoteReference, // 72
960 0, /*&SwWW8ImplReader::Read_F_Tox*/
970 &SwWW8ImplReader::Read_F_FormListBox, // 83
971 0, // 84
972 &SwWW8ImplReader::Read_F_DocInfo, // 85
973 0, // 86
974 &SwWW8ImplReader::Read_F_OCX, // 87
975 &SwWW8ImplReader::Read_F_Hyperlink, // 88
976 0, // 89
977 0, // 90
978 &SwWW8ImplReader::Read_F_HTMLControl, // 91
979 0, // 92
980 0, // 93
981 0, // 94
982 &SwWW8ImplReader::Read_F_Shape, // 95
983 0 // eMax - Dummy leer Methode
985 OSL_ENSURE( ( sizeof( aWW8FieldTab ) / sizeof( *aWW8FieldTab ) == eMax+1 ),
986 "FeldFunc-Tabelle stimmt nicht" );
988 WW8PLCFx_FLD* pF = pPlcxMan->GetFld();
989 OSL_ENSURE(pF, "WW8PLCFx_FLD - Pointer nicht da");
991 if (!pF || !pF->StartPosIsFieldStart())
992 return 0;
994 bool bNested = false;
995 if (!maFieldStack.empty())
997 mycFieldIter aEnd = maFieldStack.end();
998 for(mycFieldIter aIter = maFieldStack.begin(); aIter != aEnd; ++aIter)
1000 bNested = !AcceptableNestedField(aIter->mnFieldId);
1001 if (bNested)
1002 break;
1006 WW8FieldDesc aF;
1007 bool bOk = pF->GetPara(pRes->nCp2OrIdx, aF);
1009 OSL_ENSURE(bOk, "WW8: Bad Field!\n");
1010 if (aF.nId == 33) aF.bCodeNest=false; // do not recurse into nested page fields
1011 bool bCodeNest = aF.bCodeNest;
1012 if ( aF.nId == 6 ) bCodeNest = false; // We can handle them and loose the inner data
1014 maFieldStack.push_back(WW8FieldEntry(*pPaM->GetPoint(), aF.nId));
1016 if (bNested)
1017 return 0;
1019 sal_uInt16 n = (aF.nId <= eMax) ? aF.nId : static_cast<sal_uInt16>(eMax);
1020 sal_uInt16 nI = n / 32; // # des sal_uInt32
1021 sal_uLong nMask = 1 << ( n % 32 ); // Maske fuer Bits
1023 if ((sizeof(nFieldTagAlways)/sizeof(nFieldTagAlways[0])) <= nI)
1024 { // if indexes larger than 95 are needed, then a new configuration
1025 // item has to be added, and nFieldTagAlways/nFieldTagBad expanded!
1026 return aF.nLen;
1029 if( nFieldTagAlways[nI] & nMask ) // Flag: Tag it
1030 return Read_F_Tag( &aF ); // Resultat nicht als Text
1032 if( !bOk || !aF.nId ) // Feld kaputt
1033 return aF.nLen; // -> ignorieren
1035 if( aF.nId > eMax - 1) // WW: Nested Field
1037 if( nFieldTagBad[nI] & nMask ) // Flag: Tag it when bad
1038 return Read_F_Tag( &aF ); // Resultat nicht als Text
1039 else
1040 return aF.nLen;
1043 //Only one type of field (hyperlink) in drawing textboxes exists
1044 if (aF.nId != 88 && pPlcxMan && pPlcxMan->GetDoingDrawTextBox())
1045 return aF.nLen;
1047 // keine Routine vorhanden
1048 if (bNested || !aWW8FieldTab[aF.nId] || bCodeNest)
1050 if( nFieldTagBad[nI] & nMask ) // Flag: Tag it when bad
1051 return Read_F_Tag( &aF ); // Resultat nicht als Text
1052 // Lese nur Resultat
1053 if (aF.bResNest && !AcceptableNestedField(aF.nId))
1054 return aF.nLen; // Result nested -> nicht brauchbar
1056 long nOldPos = pStrm->Tell();
1057 String aStr;
1058 aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+
1059 aF.nSCode, aF.nLCode, eTextCharSet );
1060 pStrm->Seek( nOldPos );
1062 // field codes which contain '/' or '.' are not displayed in WinWord
1063 // skip if it is formula field or found space before. see #i119446, #i119585.
1064 const xub_StrLen nDotPos = aStr.Search('.');
1065 const xub_StrLen nSlashPos = aStr.Search('/');
1066 xub_StrLen nSpacePos = aStr.Search( ' ', 1 );
1067 if ( nSpacePos == STRING_NOTFOUND )
1068 nSpacePos = aStr.Len();
1070 if ( !( aStr.EqualsAscii( "=", 1, 1 ) ) &&
1071 ((( nDotPos != STRING_NOTFOUND ) && ( nDotPos < nSpacePos )) ||
1072 (( nSlashPos != STRING_NOTFOUND ) && ( nSlashPos < nSpacePos ))))
1073 return aF.nLen;
1074 else
1076 // Link fields aren't supported, but they are bound to an OLE object
1077 // that needs to be roundtripped
1078 if ( aF.nId == 56 )
1079 bEmbeddObj = true;
1080 // Field not supported: store the field code for later use
1081 maFieldStack.back().SetBookmarkCode( aStr );
1082 return aF.nLen - aF.nLRes - 1; // so viele ueberlesen, das Resultfeld
1083 // wird wie Haupttext eingelesen
1086 else
1087 { // Lies Feld
1088 long nOldPos = pStrm->Tell();
1089 String aStr;
1090 if ( aF.nId == 6 && aF.bCodeNest )
1092 // TODO Extract the whole code string using the nested codes
1093 aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs() +
1094 aF.nSCode, aF.nSRes - aF.nSCode - 1, eTextCharSet );
1096 else
1098 aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+
1099 aF.nSCode, aF.nLCode, eTextCharSet );
1102 // #i51312# - graphics inside field code not supported by Writer.
1103 // Thus, delete character 0x01, which stands for such a graphic.
1104 if (aF.nId==51) //#i56768# only do it for the MACROBUTTON field, since DropListFields need the 0x01.
1106 aStr = comphelper::string::remove(aStr, 0x01);
1109 eF_ResT eRes = (this->*aWW8FieldTab[aF.nId])( &aF, aStr );
1110 pStrm->Seek( nOldPos );
1112 switch ( eRes )
1114 case FLD_OK:
1115 return aF.nLen; // alles OK
1116 case FLD_TAGTXT:
1117 if ((nFieldTagBad[nI] & nMask)) // Flag: Tag bad
1118 return Read_F_Tag(&aF); // Taggen
1119 //fall through...
1120 case FLD_TEXT:
1121 // so viele ueberlesen, das Resultfeld wird wie Haupttext
1122 // eingelesen
1123 // attributes can start at char 0x14 so skip one
1124 // char more back == "-2"
1125 if (aF.nLRes)
1126 return aF.nLen - aF.nLRes - 2;
1127 else
1128 return aF.nLen;
1129 case FLD_TAGIGN:
1130 if( ( nFieldTagBad[nI] & nMask ) ) // Flag: Tag bad
1131 return Read_F_Tag( &aF ); // Taggen
1132 return aF.nLen; // oder ignorieren
1133 case FLD_READ_FSPA:
1134 return aF.nLen - aF.nLRes - 2; // auf Char 1 positionieren
1135 default:
1136 return aF.nLen; // ignorieren
1141 //-----------------------------------------
1142 // Felder Taggen
1143 //-----------------------------------------
1145 // MakeTagString() gibt als Returnwert die Position des ersten
1146 // CR / Zeilenende / Seitenumbruch in pText und wandelt auch nur bis dort
1147 // Wenn keins dieser Sonderzeichen enthalten ist, wird 0 zurueckgeliefert.
1148 void SwWW8ImplReader::MakeTagString( String& rStr, const String& rOrg )
1150 OUString sHex("\\x");
1151 bool bAllowCr = SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_IN_TEXT )
1152 || SwFltGetFlag( nFieldFlags, SwFltControlStack::ALLOW_FLD_CR );
1153 sal_Unicode cChar;
1154 rStr = rOrg;
1156 for( xub_StrLen nI = 0;
1157 nI < rStr.Len() && rStr.Len() < (MAX_FIELDLEN - 4); ++nI )
1159 bool bSetAsHex = false;
1160 switch( cChar = rStr.GetChar( nI ) )
1162 case 132: // Typographische Anfuehrungszeichen
1163 case 148: // gegen normale tauschen
1164 case 147:
1165 rStr.SetChar( nI, '"' );
1166 break;
1167 case 19:
1168 rStr.SetChar( nI, '{' );
1169 break; // 19..21 zu {|}
1170 case 20:
1171 rStr.SetChar( nI, '|' );
1172 break;
1173 case 21:
1174 rStr.SetChar( nI, '}' );
1175 break;
1176 case '\\': // \{|} per \ Taggen
1177 case '{':
1178 case '|':
1179 case '}':
1180 rStr.Insert( nI, '\\' );
1181 ++nI;
1182 break;
1183 case 0x0b:
1184 case 0x0c:
1185 case 0x0d:
1186 if( bAllowCr )
1187 rStr.SetChar( nI, '\n' );
1188 else
1189 bSetAsHex = true;
1190 break;
1191 case 0xFE:
1192 case 0xFF:
1193 bSetAsHex = true;
1194 break;
1195 default:
1196 bSetAsHex = 0x20 > cChar;
1197 break;
1200 if( bSetAsHex )
1202 //all Hex-Numbers with \x before
1203 String sTmp( sHex );
1204 if( cChar < 0x10 )
1205 sTmp += '0';
1206 sTmp += OUString::number( cChar, 16 );
1207 rStr.Replace( nI, 1 , sTmp );
1208 nI += sTmp.Len() - 1;
1212 if( rStr.Len() > (MAX_FIELDLEN - 4))
1213 rStr.Erase( MAX_FIELDLEN - 4 );
1216 void SwWW8ImplReader::InsertTagField( const sal_uInt16 nId, const String& rTagText )
1218 String aName(OUString("WwFieldTag"));
1219 if( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_DO_ID ) ) // Nummer?
1220 aName += OUString::number( nId ); // ausgeben ?
1222 if( SwFltGetFlag(nFieldFlags, SwFltControlStack::TAGS_IN_TEXT))
1224 aName += rTagText; // als Txt taggen
1225 rDoc.InsertString(*pPaM, aName,
1226 IDocumentContentOperations::INS_NOHINTEXPAND);
1228 else
1229 { // normal tagggen
1231 SwFieldType* pFT = rDoc.InsertFldType(
1232 SwSetExpFieldType( &rDoc, aName, nsSwGetSetExpType::GSE_STRING ) );
1233 SwSetExpField aFld( (SwSetExpFieldType*)pFT, rTagText ); // SUB_INVISIBLE
1234 sal_uInt16 nSubType = ( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_VISIBLE ) ) ? 0 : nsSwExtendedSubType::SUB_INVISIBLE;
1235 aFld.SetSubType(nSubType | nsSwGetSetExpType::GSE_STRING);
1237 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1241 long SwWW8ImplReader::Read_F_Tag( WW8FieldDesc* pF )
1243 long nOldPos = pStrm->Tell();
1245 WW8_CP nStart = pF->nSCode - 1; // mit 0x19 am Anfang
1246 long nL = pF->nLen; // Gesamtlaenge mit Resultat u. Nest
1247 if( nL > MAX_FIELDLEN )
1248 nL = MAX_FIELDLEN; // MaxLaenge, durch Quoten
1249 // max. 4* so gross
1250 String sFTxt;
1251 nL = pSBase->WW8ReadString( *pStrm, sFTxt,
1252 pPlcxMan->GetCpOfs() + nStart, nL, eStructCharSet);
1255 String aTagText;
1256 MakeTagString( aTagText, sFTxt );
1257 InsertTagField( pF->nId, aTagText );
1259 pStrm->Seek( nOldPos );
1260 return pF->nLen;
1264 //-----------------------------------------
1265 // normale Felder
1266 //-----------------------------------------
1268 eF_ResT SwWW8ImplReader::Read_F_Input( WW8FieldDesc* pF, String& rStr )
1270 String aDef;
1271 String aQ;
1272 long nRet;
1273 WW8ReadFieldParams aReadParam( rStr );
1274 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1276 switch( nRet )
1278 case -2:
1279 if( !aQ.Len() )
1280 aQ = aReadParam.GetResult();
1281 break;
1282 case 'd':
1283 case 'D':
1285 xub_StrLen n = aReadParam.GoToTokenParam();
1286 if( STRING_NOTFOUND != n )
1287 aDef = aReadParam.GetResult();
1289 break;
1292 if( !aDef.Len() )
1293 aDef = GetFieldResult( pF );
1295 if ( pF->nId != 0x01 ) // 0x01 fields have no result
1297 SwInputField aFld( (SwInputFieldType*)rDoc.GetSysFldType( RES_INPUTFLD ),
1298 aDef, aQ, INP_TXT, 0 ); // sichtbar ( geht z.Zt. nicht anders )
1299 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1302 return FLD_OK;
1305 // GetFieldResult alloziert einen String und liest das Feld-Resultat ein
1306 String SwWW8ImplReader::GetFieldResult( WW8FieldDesc* pF )
1308 long nOldPos = pStrm->Tell();
1310 WW8_CP nStart = pF->nSRes; // Start Resultat
1311 long nL = pF->nLRes; // Laenge Resultat
1312 if( !nL )
1313 return aEmptyStr; // kein Resultat
1315 if( nL > MAX_FIELDLEN )
1316 nL = MAX_FIELDLEN; // MaxLaenge, durch Quoten
1317 // max. 4* so gross
1319 String sRes;
1320 nL = pSBase->WW8ReadString( *pStrm, sRes, pPlcxMan->GetCpOfs() + nStart,
1321 nL, eStructCharSet );
1323 pStrm->Seek( nOldPos );
1325 //replace CR 0x0D with LF 0x0A
1326 sRes.SearchAndReplaceAll(0x0D, 0x0A);
1327 //replace VT 0x0B with LF 0x0A
1328 sRes.SearchAndReplaceAll(0x0B, 0x0A);
1329 return sRes;
1333 Bookmarks can be set with fields SET and ASK, and they can be referenced with
1334 REF. When set, they behave like variables in writer, otherwise they behave
1335 like normal bookmarks. We can check whether we should use a show variable
1336 instead of a normal bookmark ref by converting to "show variable" at the end
1337 of the document those refs which look for the content of a bookmark but whose
1338 bookmarks were set with SET or ASK. (See SwWW8FltRefStack)
1340 The other piece of the puzzle is that refs that point to the "location" of the
1341 bookmark will in word actually point to the last location where the bookmark
1342 was set with SET or ASK, not the actual bookmark. This is only noticable when
1343 a document sets the bookmark more than once. This is because word places the
1344 true bookmark at the location of the last set, but the refs will display the
1345 position of the first set before the ref.
1347 So what we will do is
1349 1) keep a list of all bookmarks that were set, any bookmark names mentioned
1350 here that are refed by content will be converted to show variables.
1352 2) create pseudo bookmarks for every position that a bookmark is set with SET
1353 or ASK but has no existing bookmark. We can then keep a map from the original
1354 bookmark name to the new one. As we parse the document new pseudo names will
1355 replace the older ones, so the map always contains the bookmark of the
1356 location that msword itself would use.
1358 3) word's bookmarks are case insensitive, writers are not. So we need to
1359 map case different versions together, regardless of whether they are
1360 variables or not.
1362 4) when a reference is (first) SET or ASK, the bookmark associated with it
1363 is placed around the 0x14 0x15 result part of the field. We will fiddle
1364 the placement to be the writer equivalent of directly before and after
1365 the field, which gives the same effect and meaning, to do so we must
1366 get any bookmarks in the field range, and begin them immediately before
1367 the set/ask field, and end them directly afterwards. MapBookmarkVariables
1368 returns an identifier of the bookmark attribute to close after inserting
1369 the appropriate set/ask field.
1371 long SwWW8ImplReader::MapBookmarkVariables(const WW8FieldDesc* pF,
1372 String &rOrigName, const String &rData)
1374 OSL_ENSURE(pPlcxMan,"No pPlcxMan");
1375 long nNo;
1377 If there was no bookmark associated with this set field, then we create a
1378 pseudo one and insert it in the document.
1380 sal_uInt16 nIndex;
1381 pPlcxMan->GetBook()->MapName(rOrigName);
1382 String sName = pPlcxMan->GetBook()->GetBookmark(
1383 pF->nSCode, pF->nSCode + pF->nLen, nIndex);
1384 if (sName.Len())
1386 pPlcxMan->GetBook()->SetStatus(nIndex, BOOK_IGNORE);
1387 nNo = nIndex;
1389 else
1391 sName = OUString("WWSetBkmk");
1392 nNo = pReffingStck->aFieldVarNames.size()+1;
1393 sName += OUString::number(nNo);
1394 nNo += pPlcxMan->GetBook()->GetIMax();
1396 pReffedStck->NewAttr(*pPaM->GetPoint(),
1397 SwFltBookmark(BookmarkToWriter(sName), rData, nNo, 0));
1398 pReffingStck->aFieldVarNames[rOrigName] = sName;
1399 return nNo;
1403 Word can set a bookmark with set or with ask, such a bookmark is equivalent to
1404 our variables, but until the end of a document we cannot be sure if a bookmark
1405 is a variable or not, at the end we will have a list of reference names which
1406 were set or asked, all bookmarks using the content of those bookmarks are
1407 converted to show variables, those that reference the position of the field
1408 can be left as references, because a bookmark is also inserted at the position
1409 of a set or ask field, either by word, or in some special cases by the import
1410 filter itself.
1412 SwFltStackEntry *SwWW8FltRefStack::RefToVar(const SwField* pFld,
1413 SwFltStackEntry &rEntry)
1415 SwFltStackEntry *pRet=0;
1416 if (pFld && RES_GETREFFLD == pFld->Which())
1418 //Get the name of the ref field, and see if actually a variable
1419 const String &rName = pFld->GetPar1();
1420 ::std::map<String,String,SwWW8FltRefStack::ltstr>::const_iterator
1421 aResult = aFieldVarNames.find(rName);
1423 if (aResult != aFieldVarNames.end())
1425 SwGetExpField aFld( (SwGetExpFieldType*)
1426 pDoc->GetSysFldType(RES_GETEXPFLD), rName, nsSwGetSetExpType::GSE_STRING, 0);
1427 delete rEntry.pAttr;
1428 SwFmtFld aTmp(aFld);
1429 rEntry.pAttr = aTmp.Clone();
1430 pRet = &rEntry;
1433 return pRet;
1436 String SwWW8ImplReader::GetMappedBookmark(const String &rOrigName)
1438 String sName(BookmarkToWriter(rOrigName));
1439 OSL_ENSURE(pPlcxMan,"no pPlcxMan");
1440 pPlcxMan->GetBook()->MapName(sName);
1442 //See if there has been a variable set with this name, if so get
1443 //the pseudo bookmark name that was set with it.
1444 ::std::map<String,String,SwWW8FltRefStack::ltstr>::const_iterator aResult =
1445 pReffingStck->aFieldVarNames.find(sName);
1447 const String &rBkmName = (aResult == pReffingStck->aFieldVarNames.end())
1448 ? sName : (*aResult).second;
1450 return rBkmName;
1453 // "ASK"
1454 eF_ResT SwWW8ImplReader::Read_F_InputVar( WW8FieldDesc* pF, String& rStr )
1456 String sOrigName;
1457 String aQ;
1458 String aDef;
1459 long nRet;
1460 WW8ReadFieldParams aReadParam( rStr );
1461 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1463 switch( nRet )
1465 case -2:
1466 if (!sOrigName.Len())
1467 sOrigName = aReadParam.GetResult();
1468 else if( !aQ.Len() )
1469 aQ = aReadParam.GetResult();
1470 break;
1471 case 'd':
1472 case 'D':
1473 if (STRING_NOTFOUND != aReadParam.GoToTokenParam())
1474 aDef = aReadParam.GetResult();
1475 break;
1479 if( !sOrigName.Len() )
1480 return FLD_TAGIGN; // macht ohne Textmarke keinen Sinn
1482 String aResult(GetFieldResult(pF));
1484 //#i24377#, munge Default Text into title as we have only one slot
1485 //available for aResult and aDef otherwise
1486 if (aDef.Len())
1488 if (aQ.Len())
1489 aQ.AppendAscii(" - ");
1490 aQ.Append(aDef);
1493 long nNo = MapBookmarkVariables(pF, sOrigName, aResult);
1495 SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType(
1496 SwSetExpFieldType(&rDoc, sOrigName, nsSwGetSetExpType::GSE_STRING));
1497 SwSetExpField aFld(pFT, aResult);
1498 aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING);
1499 aFld.SetInputFlag(true);
1500 aFld.SetPromptText( aQ );
1502 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1504 pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo);
1505 return FLD_OK;
1508 // "AUTONR"
1509 eF_ResT SwWW8ImplReader::Read_F_ANumber( WW8FieldDesc*, String& rStr )
1511 if( !pNumFldType ){ // 1. Mal
1512 SwSetExpFieldType aT( &rDoc, OUString("AutoNr"), nsSwGetSetExpType::GSE_SEQ );
1513 pNumFldType = rDoc.InsertFldType( aT );
1515 SwSetExpField aFld( (SwSetExpFieldType*)pNumFldType, aEmptyStr,
1516 GetNumberPara( rStr ) );
1517 aFld.SetValue( ++nFldNum );
1518 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1519 return FLD_OK;
1522 // "SEQ"
1523 eF_ResT SwWW8ImplReader::Read_F_Seq( WW8FieldDesc*, String& rStr )
1525 String aSequenceName;
1526 String aBook;
1527 bool bCountOn = true;
1528 String sStart;
1529 SvxExtNumType eNumFormat = SVX_NUM_ARABIC;
1530 long nRet;
1531 WW8ReadFieldParams aReadParam( rStr );
1532 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1534 switch( nRet )
1536 case -2:
1537 if( !aSequenceName.Len() )
1538 aSequenceName = aReadParam.GetResult();
1539 else if( !aBook.Len() )
1540 aBook = aReadParam.GetResult();
1541 break;
1543 case 'h':
1544 break;
1546 case '*':
1547 nRet = aReadParam.SkipToNextToken();
1548 if( -2 == nRet && !( aReadParam.GetResult().EqualsAscii("MERGEFORMAT") || aReadParam.GetResult().EqualsAscii("CHARFORMAT") ))
1549 eNumFormat = GetNumTypeFromName( aReadParam.GetResult() );
1550 break;
1552 case 'r':
1553 bCountOn = false;
1554 nRet = aReadParam.SkipToNextToken();
1555 if( -2 == nRet )
1556 sStart = aReadParam.GetResult();
1557 break;
1559 case 'c':
1560 bCountOn = false;
1561 break;
1563 case 'n':
1564 bCountOn = true; // Nummer um eins erhoehen (default)
1565 break;
1567 case 's': // Outline Level
1568 //#i19682, what am I to do with this value
1569 break;
1572 if (!aSequenceName.Len() && !aBook.Len())
1573 return FLD_TAGIGN;
1575 SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType(
1576 SwSetExpFieldType( &rDoc, aSequenceName, nsSwGetSetExpType::GSE_SEQ ) );
1577 SwSetExpField aFld( pFT, aEmptyStr, eNumFormat );
1579 if (sStart.Len())
1580 aFld.SetFormula( ( aSequenceName += '=' ) += sStart );
1581 else if (!bCountOn)
1582 aFld.SetFormula(aSequenceName);
1584 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1585 return FLD_OK;
1588 eF_ResT SwWW8ImplReader::Read_F_DocInfo( WW8FieldDesc* pF, String& rStr )
1590 sal_uInt16 nSub=0;
1591 // RegInfoFormat, DefaultFormat fuer DocInfoFelder
1592 sal_uInt16 nReg = DI_SUB_AUTHOR;
1593 bool bDateTime = false;
1595 if( 85 == pF->nId )
1597 String aDocProperty;
1598 WW8ReadFieldParams aReadParam( rStr );
1599 long nRet;
1600 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1602 switch( nRet )
1604 case -2:
1605 if( !aDocProperty.Len() )
1606 aDocProperty = aReadParam.GetResult();
1607 break;
1608 case '*':
1609 //Skip over MERGEFORMAT
1610 aReadParam.SkipToNextToken();
1611 break;
1615 aDocProperty = comphelper::string::remove(aDocProperty, '"');
1618 There are up to 26 fields that may be meant by 'DocumentProperty'.
1619 Which of them is to be inserted here ?
1620 This Problem can only be solved by implementing a name matching
1621 method that compares the given Parameter String with the four
1622 possible name sets (english, german, french, spanish)
1625 static const sal_Char* aName10 = "\x0F"; // SW field code
1626 static const sal_Char* aName11 // German
1627 = "TITEL";
1628 static const sal_Char* aName12 // French
1629 = "TITRE";
1630 static const sal_Char* aName13 // English
1631 = "TITLE";
1632 static const sal_Char* aName14 // Spanish
1633 = "TITRO";
1634 static const sal_Char* aName20 = "\x15"; // SW filed code
1635 static const sal_Char* aName21 // German
1636 = "ERSTELLDATUM";
1637 static const sal_Char* aName22 // French
1638 = "CR\xC9\xC9";
1639 static const sal_Char* aName23 // English
1640 = "CREATED";
1641 static const sal_Char* aName24 // Spanish
1642 = "CREADO";
1643 static const sal_Char* aName30 = "\x16"; // SW filed code
1644 static const sal_Char* aName31 // German
1645 = "ZULETZTGESPEICHERTZEIT";
1646 static const sal_Char* aName32 // French
1647 = "DERNIERENREGISTREMENT";
1648 static const sal_Char* aName33 // English
1649 = "SAVED";
1650 static const sal_Char* aName34 // Spanish
1651 = "MODIFICADO";
1652 static const sal_Char* aName40 = "\x17"; // SW filed code
1653 static const sal_Char* aName41 // German
1654 = "ZULETZTGEDRUCKT";
1655 static const sal_Char* aName42 // French
1656 = "DERNI\xC8" "REIMPRESSION";
1657 static const sal_Char* aName43 // English
1658 = "LASTPRINTED";
1659 static const sal_Char* aName44 // Spanish
1660 = "HUPS PUPS";
1661 static const sal_Char* aName50 = "\x18"; // SW filed code
1662 static const sal_Char* aName51 // German
1663 = "\xDC" "BERARBEITUNGSNUMMER";
1664 static const sal_Char* aName52 // French
1665 = "NUM\xC9" "RODEREVISION";
1666 static const sal_Char* aName53 // English
1667 = "REVISIONNUMBER";
1668 static const sal_Char* aName54 // Spanish
1669 = "SNUBBEL BUBBEL";
1670 static const sal_uInt16 nFldCnt = 5;
1672 // additional fields are to be coded soon! :-)
1674 static const sal_uInt16 nLangCnt = 4;
1675 static const sal_Char *aNameSet_26[nFldCnt][nLangCnt+1] =
1677 {aName10, aName11, aName12, aName13, aName14},
1678 {aName20, aName21, aName22, aName23, aName24},
1679 {aName30, aName31, aName32, aName33, aName34},
1680 {aName40, aName41, aName42, aName43, aName44},
1681 {aName50, aName51, aName52, aName53, aName54}
1684 bool bFldFound= false;
1685 sal_uInt16 nFIdx;
1686 for(sal_uInt16 nLIdx=1; !bFldFound && (nLangCnt > nLIdx); ++nLIdx)
1688 for(nFIdx = 0; !bFldFound && (nFldCnt > nFIdx); ++nFIdx)
1690 if( aDocProperty.Equals( String( aNameSet_26[nFIdx][nLIdx],
1691 RTL_TEXTENCODING_MS_1252 ) ) )
1693 bFldFound = true;
1694 pF->nId = aNameSet_26[nFIdx][0][0];
1699 if( !bFldFound )
1701 SwDocInfoField aFld( (SwDocInfoFieldType*)
1702 rDoc.GetSysFldType( RES_DOCINFOFLD ), DI_CUSTOM|nReg, aDocProperty, GetFieldResult( pF ) );
1703 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1705 return FLD_OK;
1709 switch( pF->nId )
1711 case 14:
1712 /* kann alle INFO-Vars!! */
1713 nSub = DI_KEYS;
1714 break;
1715 case 15:
1716 nSub = DI_TITEL;
1717 break;
1718 case 16:
1719 nSub = DI_THEMA;
1720 break;
1721 case 18:
1722 nSub = DI_KEYS;
1723 break;
1724 case 19:
1725 nSub = DI_COMMENT;
1726 break;
1727 case 20:
1728 nSub = DI_CHANGE;
1729 nReg = DI_SUB_AUTHOR;
1730 break;
1731 case 21:
1732 nSub = DI_CREATE;
1733 nReg = DI_SUB_DATE;
1734 bDateTime = true;
1735 break;
1736 case 23:
1737 nSub = DI_PRINT;
1738 nReg = DI_SUB_DATE;
1739 bDateTime = true;
1740 break;
1741 case 24:
1742 nSub = DI_DOCNO;
1743 break;
1744 case 22:
1745 nSub = DI_CHANGE;
1746 nReg = DI_SUB_DATE;
1747 bDateTime = true;
1748 break;
1749 case 25:
1750 nSub = DI_CHANGE;
1751 nReg = DI_SUB_TIME;
1752 bDateTime = true;
1753 break;
1754 case 64: // DOCVARIABLE
1755 nSub = DI_CUSTOM;
1756 break;
1759 sal_uInt32 nFormat = 0;
1761 sal_uInt16 nLang(0);
1762 if (bDateTime)
1764 short nDT = GetTimeDatePara(rStr, nFormat, nLang, pF->nId);
1765 switch (nDT)
1767 case NUMBERFORMAT_DATE:
1768 nReg = DI_SUB_DATE;
1769 break;
1770 case NUMBERFORMAT_TIME:
1771 nReg = DI_SUB_TIME;
1772 break;
1773 case NUMBERFORMAT_DATETIME:
1774 nReg = DI_SUB_DATE;
1775 break;
1776 default:
1777 nReg = DI_SUB_DATE;
1778 break;
1782 String aData;
1783 // Extract DOCVARIABLE varname
1784 if ( 64 == pF->nId )
1786 WW8ReadFieldParams aReadParam( rStr );
1787 long nRet;
1788 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1790 switch( nRet )
1792 case -2:
1793 if( !aData.Len() )
1794 aData = aReadParam.GetResult();
1795 break;
1796 case '*':
1797 //Skip over MERGEFORMAT
1798 aReadParam.SkipToNextToken();
1799 break;
1803 aData = comphelper::string::remove(aData, '"');
1806 SwDocInfoField aFld( (SwDocInfoFieldType*)
1807 rDoc.GetSysFldType( RES_DOCINFOFLD ), nSub|nReg, aData, nFormat );
1808 if (bDateTime)
1809 ForceFieldLanguage(aFld, nLang);
1810 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1812 return FLD_OK;
1815 eF_ResT SwWW8ImplReader::Read_F_Author( WW8FieldDesc*, String& )
1817 // SH: Das SwAuthorField bezeichnet nicht den urspruenglichen
1818 // Autor, sondern den aktuellen Benutzer, also besser ueber DocInfo
1819 SwDocInfoField aFld( (SwDocInfoFieldType*)
1820 rDoc.GetSysFldType( RES_DOCINFOFLD ),
1821 DI_CREATE|DI_SUB_AUTHOR, String() );
1822 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1823 return FLD_OK;
1826 eF_ResT SwWW8ImplReader::Read_F_TemplName( WW8FieldDesc*, String& )
1828 SwTemplNameField aFld( (SwTemplNameFieldType*)
1829 rDoc.GetSysFldType( RES_TEMPLNAMEFLD ), FF_NAME );
1830 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1831 return FLD_OK;
1834 // Sowohl das Datum- wie auch das Uhrzeit-Feld kann fuer Datum, fuer Uhrzeit
1835 // oder fuer beides benutzt werden.
1836 eF_ResT SwWW8ImplReader::Read_F_DateTime( WW8FieldDesc*pF, String& rStr )
1838 bool bHijri = false;
1839 WW8ReadFieldParams aReadParam(rStr);
1840 long nTok;
1841 while (-1 != (nTok = aReadParam.SkipToNextToken()))
1843 switch (nTok)
1845 default:
1846 case 'l':
1847 case -2:
1848 break;
1849 case 'h':
1850 bHijri = true;
1851 break;
1852 case 's':
1853 //Saka Calendar, should we do something with this ?
1854 break;
1858 sal_uInt32 nFormat = 0;
1860 sal_uInt16 nLang(0);
1861 short nDT = GetTimeDatePara(rStr, nFormat, nLang, ww::eDATE, bHijri);
1863 if( NUMBERFORMAT_UNDEFINED == nDT ) // no D/T-Formatstring
1865 if (32 == pF->nId)
1867 nDT = NUMBERFORMAT_TIME;
1868 nFormat = rDoc.GetNumberFormatter()->GetFormatIndex(
1869 NF_TIME_START, LANGUAGE_SYSTEM );
1871 else
1873 nDT = NUMBERFORMAT_DATE;
1874 nFormat = rDoc.GetNumberFormatter()->GetFormatIndex(
1875 NF_DATE_START, LANGUAGE_SYSTEM );
1879 if (nDT & NUMBERFORMAT_DATE)
1881 SwDateTimeField aFld((SwDateTimeFieldType*)
1882 rDoc.GetSysFldType(RES_DATETIMEFLD ), DATEFLD, nFormat);
1883 ForceFieldLanguage(aFld, nLang);
1884 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1886 else if (nDT == NUMBERFORMAT_TIME)
1888 SwDateTimeField aFld((SwDateTimeFieldType*)
1889 rDoc.GetSysFldType(RES_DATETIMEFLD), TIMEFLD, nFormat);
1890 ForceFieldLanguage(aFld, nLang);
1891 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1894 return FLD_OK;
1897 eF_ResT SwWW8ImplReader::Read_F_FileName(WW8FieldDesc*, String &rStr)
1899 SwFileNameFormat eType = FF_NAME;
1900 long nRet;
1901 WW8ReadFieldParams aReadParam(rStr);
1902 while (-1 != (nRet = aReadParam.SkipToNextToken()))
1904 switch (nRet)
1906 case 'p':
1907 eType = FF_PATHNAME;
1908 break;
1909 case '*':
1910 //Skip over MERGEFORMAT
1911 aReadParam.SkipToNextToken();
1912 break;
1913 default:
1914 OSL_ENSURE(!this, "unknown option in FileName field");
1915 break;
1919 SwFileNameField aFld(
1920 (SwFileNameFieldType*)rDoc.GetSysFldType(RES_FILENAMEFLD), eType);
1921 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1922 return FLD_OK;
1925 eF_ResT SwWW8ImplReader::Read_F_Anz( WW8FieldDesc* pF, String& rStr )
1926 { // SeitenZahl - Feld
1927 sal_uInt16 nSub = DS_PAGE;
1928 switch ( pF->nId ){
1929 case 27: nSub = DS_WORD; break; // Wordzahl
1930 case 28: nSub = DS_CHAR; break; // Zeichenzahl
1932 SwDocStatField aFld( (SwDocStatFieldType*)
1933 rDoc.GetSysFldType( RES_DOCSTATFLD ), nSub,
1934 GetNumberPara( rStr ) );
1935 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1936 return FLD_OK;
1939 eF_ResT SwWW8ImplReader::Read_F_CurPage( WW8FieldDesc*, String& rStr )
1941 // Seitennummer
1942 SwPageNumberField aFld( (SwPageNumberFieldType*)
1943 rDoc.GetSysFldType( RES_PAGENUMBERFLD ), PG_RANDOM,
1944 GetNumberPara(rStr, true));
1946 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1947 return FLD_OK;
1950 eF_ResT SwWW8ImplReader::Read_F_Symbol( WW8FieldDesc*, String& rStr )
1952 //e.g. #i20118#
1953 String aQ;
1954 String aName;
1955 sal_Int32 nSize = 0;
1956 long nRet;
1957 WW8ReadFieldParams aReadParam( rStr );
1958 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1960 switch( nRet )
1962 case -2:
1963 if( !aQ.Len() )
1964 aQ = aReadParam.GetResult();
1965 break;
1966 case 'f':
1967 case 'F':
1969 xub_StrLen n = aReadParam.GoToTokenParam();
1970 if( STRING_NOTFOUND != n )
1971 aName = aReadParam.GetResult();
1973 break;
1974 case 's':
1975 case 'S':
1977 String aSiz;
1978 xub_StrLen n = aReadParam.GoToTokenParam();
1979 if (STRING_NOTFOUND != n)
1980 aSiz = aReadParam.GetResult();
1981 if (aSiz.Len())
1982 nSize = aSiz.ToInt32() * 20; // pT -> twip
1984 break;
1987 if( !aQ.Len() )
1988 return FLD_TAGIGN; // -> kein 0-Zeichen in Text
1990 if (sal_Unicode cChar = static_cast<sal_Unicode>(aQ.ToInt32()))
1992 if (aName.Len()) // Font Name set ?
1994 SvxFontItem aFont(FAMILY_DONTKNOW, aName, aEmptyStr,
1995 PITCH_DONTKNOW, RTL_TEXTENCODING_SYMBOL, RES_CHRATR_FONT);
1996 NewAttr(aFont); // new Font
1999 if (nSize > 0) //#i20118#
2001 SvxFontHeightItem aSz(nSize, 100, RES_CHRATR_FONTSIZE);
2002 NewAttr(aSz);
2005 rDoc.InsertString(*pPaM, OUString(cChar));
2007 if (nSize > 0)
2008 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONTSIZE);
2009 if (aName.Len())
2010 pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONT);
2012 else
2014 rDoc.InsertString(*pPaM, OUString("###"));
2017 return FLD_OK;
2020 // "EINBETTEN"
2021 eF_ResT SwWW8ImplReader::Read_F_Embedd( WW8FieldDesc*, String& rStr )
2023 String sHost;
2025 long nRet;
2026 WW8ReadFieldParams aReadParam( rStr );
2027 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2029 switch( nRet )
2031 case -2:
2032 sHost = aReadParam.GetResult();
2033 break;
2035 case 's':
2036 // use ObjectSize
2037 break;
2041 if( bObj && nPicLocFc )
2042 nObjLocFc = nPicLocFc;
2043 bEmbeddObj = true;
2044 return FLD_TEXT;
2048 // "SET"
2049 eF_ResT SwWW8ImplReader::Read_F_Set( WW8FieldDesc* pF, String& rStr )
2051 String sOrigName;
2052 String sVal;
2053 long nRet;
2054 WW8ReadFieldParams aReadParam( rStr );
2055 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2057 switch( nRet )
2059 case -2:
2060 if( !sOrigName.Len() )
2061 sOrigName = aReadParam.GetResult();
2062 else if( !sVal.Len() )
2063 sVal = aReadParam.GetResult();
2064 break;
2068 long nNo = MapBookmarkVariables(pF,sOrigName,sVal);
2070 SwFieldType* pFT = rDoc.InsertFldType( SwSetExpFieldType( &rDoc, sOrigName,
2071 nsSwGetSetExpType::GSE_STRING ) );
2072 SwSetExpField aFld( (SwSetExpFieldType*)pFT, sVal, ULONG_MAX );
2073 aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING);
2075 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2077 pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo);
2079 return FLD_OK;
2082 // "REF"
2083 eF_ResT SwWW8ImplReader::Read_F_Ref( WW8FieldDesc*, String& rStr )
2084 { // Reference - Field
2085 String sOrigBkmName;
2086 REFERENCEMARK eFormat = REF_CONTENT;
2088 long nRet;
2089 WW8ReadFieldParams aReadParam( rStr );
2090 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2092 switch( nRet )
2094 case -2:
2095 if( !sOrigBkmName.Len() ) // get name of bookmark
2096 sOrigBkmName = aReadParam.GetResult();
2097 break;
2099 /* References to numbers in Word could be either to a numbered
2100 paragraph or to a chapter number. However Word does not seem to
2101 have the capability we do, of refering to the chapter number some
2102 other bookmark is in. As a result, cross-references to chapter
2103 numbers in a word document will be cross-references to a numbered
2104 paragraph, being the chapter heading paragraph. As it happens, our
2105 cross-references to numbered paragraphs will do the right thing
2106 when the target is a numbered chapter heading, so there is no need
2107 for us to use the REF_CHAPTER bookmark format on import.
2109 case 'n':
2110 eFormat = REF_NUMBER_NO_CONTEXT;
2111 break;
2112 case 'r':
2113 eFormat = REF_NUMBER;
2114 break;
2115 case 'w':
2116 eFormat = REF_NUMBER_FULL_CONTEXT;
2117 break;
2119 case 'p':
2120 eFormat = REF_UPDOWN;
2121 break;
2122 case 'h':
2123 break;
2124 default:
2125 // unimplemented switch: just do 'nix nought nothing' :-)
2126 break;
2130 String sBkmName(GetMappedBookmark(sOrigBkmName));
2132 SwGetRefField aFld(
2133 (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ),
2134 sBkmName,REF_BOOKMARK,0,eFormat);
2136 if (eFormat == REF_CONTENT)
2139 If we are just inserting the contents of the bookmark, then it
2140 is possible that the bookmark is actually a variable, so we
2141 must store it until the end of the document to see if it was,
2142 in which case we'll turn it into a show variable
2144 pReffingStck->NewAttr( *pPaM->GetPoint(), SwFmtFld(aFld) );
2145 pReffingStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_FIELD);
2147 else
2149 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
2151 return FLD_OK;
2154 // Note Reference - Field
2155 eF_ResT SwWW8ImplReader::Read_F_NoteReference( WW8FieldDesc*, String& rStr )
2157 String aBkmName;
2158 bool bAboveBelow = false;
2160 long nRet;
2161 WW8ReadFieldParams aReadParam( rStr );
2162 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2164 switch( nRet )
2166 case -2:
2167 if( !aBkmName.Len() ) // get name of foot/endnote
2168 aBkmName = aReadParam.GetResult();
2169 break;
2170 case 'r':
2171 // activate flag 'Chapter Number'
2172 break;
2173 case 'p':
2174 bAboveBelow = true;
2175 break;
2176 case 'h':
2177 break;
2178 default:
2179 // unimplemented switch: just do 'nix nought nothing' :-)
2180 break;
2184 // set Sequence No of corresponding Foot-/Endnote to Zero
2185 // (will be corrected in
2186 SwGetRefField aFld( (SwGetRefFieldType*)
2187 rDoc.GetSysFldType( RES_GETREFFLD ), aBkmName, REF_FOOTNOTE, 0,
2188 REF_ONLYNUMBER );
2189 pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld));
2190 pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD);
2191 if (bAboveBelow)
2193 SwGetRefField aFld2( (SwGetRefFieldType*)
2194 rDoc.GetSysFldType( RES_GETREFFLD ),aBkmName, REF_FOOTNOTE, 0,
2195 REF_UPDOWN );
2196 pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld2));
2197 pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD);
2199 return FLD_OK;
2202 // "SEITENREF"
2203 eF_ResT SwWW8ImplReader::Read_F_PgRef( WW8FieldDesc*, String& rStr )
2205 String sOrigName;
2206 long nRet;
2207 WW8ReadFieldParams aReadParam( rStr );
2208 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2210 switch( nRet )
2212 case -2:
2213 if( !sOrigName.Len() )
2214 sOrigName = aReadParam.GetResult();
2215 break;
2219 String sName(GetMappedBookmark(sOrigName));
2221 #if defined(WW_NATIVE_TOC)
2222 if (1) {
2223 OUString aBookmarkName("_REF");
2224 maFieldStack.back().SetBookmarkName(aBookmarkName);
2225 maFieldStack.back().SetBookmarkType(ODF_PAGEREF);
2226 maFieldStack.back().AddParam(OUString(), sName);
2227 return FLD_TEXT;
2229 #endif
2232 SwGetRefField aFld(
2233 (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ), sName,
2234 REF_BOOKMARK, 0, REF_PAGE );
2236 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2237 return FLD_OK;
2239 //helper function
2240 //For MS MacroButton field, the symbol in plain text is always "(" (0x28),
2241 //which should be mapped according to the macro type
2242 bool ConvertMacroSymbol( const String& rName, String& rReference )
2244 bool bConverted = false;
2245 if( rReference.EqualsAscii( "(" ) )
2247 bConverted = true;
2248 sal_Unicode cSymbol = sal_Unicode(); // silence false warning
2249 if( rName.EqualsAscii( "CheckIt" ) )
2250 cSymbol = 0xF06F;
2251 else if( rName.EqualsAscii( "UncheckIt" ) )
2252 cSymbol = 0xF0FE;
2253 else if( rName.EqualsAscii( "ShowExample" ) )
2254 cSymbol = 0xF02A;
2255 //else if... : todo
2256 else
2257 bConverted = false;
2259 if( bConverted )
2260 rReference = cSymbol;
2262 return bConverted;
2264 //end
2266 // "MACROSCHALTFL"ACHE"
2267 eF_ResT SwWW8ImplReader::Read_F_Macro( WW8FieldDesc*, String& rStr)
2269 String aName;
2270 String aVText;
2271 long nRet;
2272 bool bNewVText = true;
2273 bool bBracket = false;
2274 WW8ReadFieldParams aReadParam( rStr );
2276 xub_StrLen nOffset = 0;
2278 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2280 switch( nRet )
2282 case -2:
2283 if( !aName.Len() )
2284 aName = aReadParam.GetResult();
2285 else if( !aVText.Len() || bBracket )
2287 nOffset = aReadParam.GetTokenSttPtr() + 1;
2289 if( bBracket )
2290 aVText += ' ';
2291 aVText += aReadParam.GetResult();
2292 if (bNewVText)
2294 bBracket = aVText.EqualsIgnoreCaseAscii(OUString('['), 1, 0)
2295 ? true : false;
2296 bNewVText = false;
2298 else if( aVText.GetChar( aVText.Len()-1 ) == ']' )
2299 bBracket = false;
2301 break;
2304 if( !aName.Len() )
2305 return FLD_TAGIGN; // makes no sense without Makro-Name
2307 //try converting macro symbol according to macro name
2308 bool bApplyWingdings = ConvertMacroSymbol( aName, aVText );
2309 aName.InsertAscii( "StarOffice.Standard.Modul1.", 0 );
2311 SwMacroField aFld( (SwMacroFieldType*)
2312 rDoc.GetSysFldType( RES_MACROFLD ), aName, aVText );
2314 if( !bApplyWingdings )
2317 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2318 WW8_CP nOldCp = pPlcxMan->Where();
2319 WW8_CP nCp = nOldCp + nOffset;
2321 SwPaM aPaM(*pPaM);
2322 aPaM.SetMark();
2323 aPaM.Move(fnMoveBackward);
2324 aPaM.Exchange();
2326 mpPostProcessAttrsInfo = new WW8PostProcessAttrsInfo(nCp, nCp, aPaM);
2328 else
2330 //set Wingdings font
2331 sal_uInt16 i = 0;
2332 for ( ; i < pFonts->GetMax(); i++ )
2334 FontFamily eFamily;
2335 String aFontName;
2336 FontPitch ePitch;
2337 CharSet eSrcCharSet;
2338 if( GetFontParams( i, eFamily, aFontName, ePitch, eSrcCharSet )
2339 && aFontName.EqualsAscii("Wingdings") )
2341 break;
2345 if ( i < pFonts->GetMax() )
2348 SetNewFontAttr( i, true, RES_CHRATR_FONT );
2349 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2350 pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_CHRATR_FONT );
2351 ResetCharSetVars();
2355 return FLD_OK;
2358 WW8PostProcessAttrsInfo::WW8PostProcessAttrsInfo(WW8_CP nCpStart, WW8_CP nCpEnd,
2359 SwPaM & rPaM)
2360 : mbCopy(false),
2361 mnCpStart(nCpStart),
2362 mnCpEnd(nCpEnd),
2363 mPaM(*rPaM.GetPoint(), *rPaM.GetMark()),
2364 mItemSet(rPaM.GetDoc()->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END - 1)
2368 bool CanUseRemoteLink(const String &rGrfName)
2370 bool bUseRemote = false;
2373 ::ucbhelper::Content aCnt(rGrfName,
2374 uno::Reference< ucb::XCommandEnvironment >(),
2375 comphelper::getProcessComponentContext() );
2376 OUString aTitle;
2378 aCnt.getPropertyValue("Title") >>= aTitle;
2379 bUseRemote = !aTitle.isEmpty();
2381 catch ( ... )
2383 // this file did not exist, so we will not set this as graphiclink
2384 bUseRemote = false;
2386 return bUseRemote;
2389 // "EINF"UGENGRAFIK"
2390 eF_ResT SwWW8ImplReader::Read_F_IncludePicture( WW8FieldDesc*, String& rStr )
2392 String aGrfName;
2393 bool bEmbedded = true;
2395 long nRet;
2396 WW8ReadFieldParams aReadParam( rStr );
2397 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2399 switch( nRet )
2401 case -2:
2402 if (!aGrfName.Len())
2403 ConvertFFileName(aGrfName, aReadParam.GetResult());
2404 break;
2406 case 'd':
2407 bEmbedded = false; // Embedded-Flag deaktivieren
2408 break;
2410 case 'c':// den Converter-Namen ueberlesen
2411 aReadParam.FindNextStringPiece();
2412 break;
2416 if (!bEmbedded)
2417 bEmbedded = !CanUseRemoteLink(aGrfName);
2419 if (!bEmbedded)
2422 Besonderheit:
2424 Wir setzen jetzt den Link ins Doc und merken uns den SwFlyFrmFmt.
2425 Da wir ja unten auf jjeden Fall mit Return-Wert FLD_READ_FSPA enden,
2426 wird der Skip-Wert so bemessen, dass das folgende Char-1 eingelesen
2427 wird.
2428 Wenn wir dann in SwWW8ImplReader::ImportGraf() reinlaufen, wird
2429 erkannt, dass wir soeben einen Grafik-Link inserted haben und
2430 das passende SwAttrSet wird ins Frame-Format eingesetzt.
2432 SfxItemSet aFlySet( rDoc.GetAttrPool(), RES_FRMATR_BEGIN,
2433 RES_FRMATR_END-1 );
2434 aFlySet.Put( SwFmtAnchor( FLY_AS_CHAR ) );
2435 aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
2436 pFlyFmtOfJustInsertedGraphic = rDoc.Insert( *pPaM,
2437 aGrfName,
2438 aEmptyStr,
2439 0, // Graphic*
2440 &aFlySet,
2441 0, 0); // SwFrmFmt*
2442 maGrfNameGenerator.SetUniqueGraphName(pFlyFmtOfJustInsertedGraphic,
2443 INetURLObject(aGrfName).GetBase());
2445 return FLD_READ_FSPA;
2449 String wwSectionNamer::UniqueName()
2451 String aName(msFileLinkSeed);
2452 aName += OUString::number(++mnFileSectionNo);
2453 return mrDoc.GetUniqueSectionName(&aName);
2456 // "EINFUEGENTEXT"
2457 eF_ResT SwWW8ImplReader::Read_F_IncludeText( WW8FieldDesc* /*pF*/, String& rStr )
2459 String aPara;
2460 String aBook;
2461 long nRet;
2462 WW8ReadFieldParams aReadParam( rStr );
2463 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2465 switch( nRet )
2467 case -2:
2468 if( !aPara.Len() )
2469 aPara = aReadParam.GetResult();
2470 else if( !aBook.Len() )
2471 aBook = aReadParam.GetResult();
2472 break;
2473 case '*':
2474 //Skip over MERGEFORMAT
2475 aReadParam.SkipToNextToken();
2476 break;
2479 ConvertFFileName(aPara, aPara);
2481 if (aBook.Len() && aBook.GetChar( 0 ) != '\\')
2483 // Bereich aus Quelle ( kein Switch ) ?
2484 ConvertUFName(aBook);
2485 aPara += sfx2::cTokenSeparator;
2486 aPara += sfx2::cTokenSeparator;
2487 aPara += aBook;
2491 ##509##
2492 What we will do is insert a section to be linked to a file, but just in
2493 case the file is not available we will fill in the section with the stored
2494 content of this winword field as a fallback.
2496 SwPosition aTmpPos(*pPaM->GetPoint());
2498 SwSectionData aSection(FILE_LINK_SECTION,
2499 maSectionNameGenerator.UniqueName());
2500 aSection.SetLinkFileName( aPara );
2501 aSection.SetProtectFlag(true);
2503 SwSection *const pSection =
2504 rDoc.InsertSwSection(*pPaM, aSection, 0, 0, false);
2505 OSL_ENSURE(pSection, "no section inserted");
2506 if (!pSection)
2507 return FLD_TEXT;
2508 const SwSectionNode* pSectionNode = pSection->GetFmt()->GetSectionNode();
2509 OSL_ENSURE(pSectionNode, "no section node!");
2510 if (!pSectionNode)
2511 return FLD_TEXT;
2513 pPaM->GetPoint()->nNode = pSectionNode->GetIndex()+1;
2514 pPaM->GetPoint()->nContent.Assign(pPaM->GetCntntNode(), 0 );
2516 //we have inserted a section before this point, so adjust pos
2517 //for future page/section segment insertion
2518 maSectionManager.PrependedInlineNode(aTmpPos, *pPaM->GetNode());
2520 return FLD_TEXT;
2523 // "SERIENDRUCKFELD"
2524 eF_ResT SwWW8ImplReader::Read_F_DBField( WW8FieldDesc* pF, String& rStr )
2526 String aName;
2527 long nRet;
2528 WW8ReadFieldParams aReadParam( rStr );
2529 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2531 switch( nRet )
2533 case -2:
2534 if( !aName.Len() )
2535 aName = aReadParam.GetResult();
2536 break;
2539 SwDBFieldType aD( &rDoc, aName, SwDBData() ); // Datenbank: Nichts
2541 SwFieldType* pFT = rDoc.InsertFldType( aD );
2542 SwDBField aFld( (SwDBFieldType*)pFT );
2543 aFld.SetFieldCode( rStr );
2545 String aResult;
2546 pSBase->WW8ReadString( *pStrm, aResult, pPlcxMan->GetCpOfs()+
2547 pF->nSRes, pF->nLRes, eTextCharSet );
2549 aFld.InitContent(aResult);
2551 rDoc.InsertPoolItem(*pPaM, SwFmtFld( aFld ), 0);
2553 return FLD_OK;
2556 // "N"ACHSTER"
2557 eF_ResT SwWW8ImplReader::Read_F_DBNext( WW8FieldDesc*, String& )
2559 SwDBNextSetFieldType aN;
2560 SwFieldType* pFT = rDoc.InsertFldType( aN );
2561 SwDBNextSetField aFld( (SwDBNextSetFieldType*)pFT, aEmptyStr, aEmptyStr,
2562 SwDBData() ); // Datenbank: Nichts
2563 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2564 return FLD_OK;
2567 // "DATENSATZ"
2568 eF_ResT SwWW8ImplReader::Read_F_DBNum( WW8FieldDesc*, String& )
2570 SwDBSetNumberFieldType aN;
2571 SwFieldType* pFT = rDoc.InsertFldType( aN );
2572 SwDBSetNumberField aFld( (SwDBSetNumberFieldType*)pFT,
2573 SwDBData() ); // Datenbank: Nichts
2574 rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2575 return FLD_OK;
2579 EQ , only the usage for
2580 a. Combined Characters supported, must be exactly in the form that word
2581 only accepts as combined charactersm, i.e.
2582 eq \o(\s\up Y(XXX),\s\do Y(XXX))
2583 b. Ruby Text supported, must be in the form that word recognizes as being
2584 ruby text
2587 eF_ResT SwWW8ImplReader::Read_F_Equation( WW8FieldDesc*, String& rStr )
2589 WW8ReadFieldParams aReadParam( rStr );
2590 long cChar = aReadParam.SkipToNextToken();
2591 if ('o' == cChar)
2592 Read_SubF_Combined(aReadParam);
2593 else if ('*' == cChar)
2594 Read_SubF_Ruby(aReadParam);
2595 return FLD_OK;
2598 void SwWW8ImplReader::Read_SubF_Combined( WW8ReadFieldParams& rReadParam)
2600 String sCombinedCharacters;
2601 if ((-2 == rReadParam.SkipToNextToken()) &&
2602 rReadParam.GetResult().EqualsIgnoreCaseAscii(OUString('('), 1, 0))
2604 for (int i=0;i<2;i++)
2606 if ('s' == rReadParam.SkipToNextToken())
2608 long cChar = rReadParam.SkipToNextToken();
2609 if (-2 != rReadParam.SkipToNextToken())
2610 break;
2611 String sF = rReadParam.GetResult();
2612 if ((('u' == cChar) && sF.EqualsIgnoreCaseAscii(OUString('p'), 1, 0))
2613 || (('d' == cChar) && sF.EqualsIgnoreCaseAscii(OUString('o'), 1, 0)))
2615 if (-2 == rReadParam.SkipToNextToken())
2617 String sPart = rReadParam.GetResult();
2618 xub_StrLen nBegin = sPart.Search('(');
2620 //Word disallows brackets in this field, which
2621 //aids figuring out the case of an end of )) vs )
2622 xub_StrLen nEnd = sPart.Search(')');
2624 if ((nBegin != STRING_NOTFOUND) &&
2625 (nEnd != STRING_NOTFOUND))
2627 sCombinedCharacters +=
2628 sPart.Copy(nBegin+1,nEnd-nBegin-1);
2635 if (sCombinedCharacters.Len())
2637 SwCombinedCharField aFld((SwCombinedCharFieldType*)
2638 rDoc.GetSysFldType(RES_COMBINED_CHARS),sCombinedCharacters);
2639 rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
2643 void SwWW8ImplReader::Read_SubF_Ruby( WW8ReadFieldParams& rReadParam)
2645 sal_uInt16 nJustificationCode=0;
2646 String sFontName;
2647 sal_uInt32 nFontSize=0;
2648 String sRuby;
2649 String sText;
2650 long nRet;
2651 while( -1 != ( nRet = rReadParam.SkipToNextToken() ))
2653 switch( nRet )
2655 case -2:
2657 String sTemp = rReadParam.GetResult();
2658 if( sTemp.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
2660 sTemp.Erase(0,2);
2661 nJustificationCode = static_cast<sal_uInt16>(sTemp.ToInt32());
2663 else if( sTemp.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
2665 sTemp.Erase(0,3);
2666 nFontSize= static_cast<sal_uInt32>(sTemp.ToInt32());
2668 else if( sTemp.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
2670 sTemp.Erase(0,5);
2671 sFontName = sTemp;
2674 break;
2675 case '*':
2676 break;
2677 case 'o':
2678 while( -1 != ( nRet = rReadParam.SkipToNextToken() ))
2680 if ('u' == nRet)
2682 if (-2 == rReadParam.SkipToNextToken() &&
2683 (rReadParam.GetResult().EqualsIgnoreCaseAscii(OUString('p'), 1, 0)))
2685 if (-2 == rReadParam.SkipToNextToken())
2687 String sPart = rReadParam.GetResult();
2688 xub_StrLen nBegin = sPart.Search('(');
2690 //Word disallows brackets in this field,
2691 xub_StrLen nEnd = sPart.Search(')');
2693 if ((nBegin != STRING_NOTFOUND) &&
2694 (nEnd != STRING_NOTFOUND))
2696 sRuby = sPart.Copy(nBegin+1,nEnd-nBegin-1);
2698 if (STRING_NOTFOUND ==
2699 (nBegin = sPart.Search(',',nEnd)))
2701 nBegin = sPart.Search(';',nEnd);
2703 nEnd = sPart.SearchBackward(')');
2704 if ((nBegin != STRING_NOTFOUND) &&
2705 (nEnd != STRING_NOTFOUND))
2707 sText = sPart.Copy(nBegin+1,nEnd-nBegin-1);
2714 break;
2718 //Translate and apply
2719 if (sRuby.Len() && sText.Len() && sFontName.Len() && nFontSize)
2721 switch (nJustificationCode)
2723 case 0:
2724 nJustificationCode=1;
2725 break;
2726 case 1:
2727 nJustificationCode=3;
2728 break;
2729 case 2:
2730 nJustificationCode=4;
2731 break;
2732 default:
2733 case 3:
2734 nJustificationCode=0;
2735 break;
2736 case 4:
2737 nJustificationCode=2;
2738 break;
2741 SwFmtRuby aRuby(sRuby);
2742 const SwCharFmt *pCharFmt=0;
2743 //Make a guess at which of asian of western we should be setting
2744 sal_uInt16 nScript;
2745 if (g_pBreakIt->GetBreakIter().is())
2746 nScript = g_pBreakIt->GetBreakIter()->getScriptType(sRuby, 0);
2747 else
2748 nScript = i18n::ScriptType::ASIAN;
2750 //Check to see if we already have a ruby charstyle that this fits
2751 std::vector<const SwCharFmt*>::const_iterator aEnd =
2752 aRubyCharFmts.end();
2753 for(std::vector<const SwCharFmt*>::const_iterator aIter
2754 = aRubyCharFmts.begin(); aIter != aEnd; ++aIter)
2756 const SvxFontHeightItem &rFH =
2757 ItemGet<SvxFontHeightItem>(*(*aIter),
2758 GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript));
2759 if (rFH.GetHeight() == nFontSize*10)
2761 const SvxFontItem &rF = ItemGet<SvxFontItem>(*(*aIter),
2762 GetWhichOfScript(RES_CHRATR_FONT,nScript));
2763 if (rF.GetFamilyName().Equals(sFontName))
2765 pCharFmt=*aIter;
2766 break;
2771 //Create a new char style if necessary
2772 if (!pCharFmt)
2774 SwCharFmt *pFmt=0;
2775 String aNm;
2776 //Take this as the base name
2777 SwStyleNameMapper::FillUIName(RES_POOLCHR_RUBYTEXT,aNm);
2778 aNm+=OUString::number(aRubyCharFmts.size()+1);
2779 pFmt = rDoc.MakeCharFmt(aNm,(SwCharFmt*)rDoc.GetDfltCharFmt());
2780 SvxFontHeightItem aHeightItem(nFontSize*10, 100, RES_CHRATR_FONTSIZE);
2781 SvxFontItem aFontItem(FAMILY_DONTKNOW,sFontName,
2782 aEmptyStr,PITCH_DONTKNOW,RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT);
2783 aHeightItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript));
2784 aFontItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONT,nScript));
2785 pFmt->SetFmtAttr(aHeightItem);
2786 pFmt->SetFmtAttr(aFontItem);
2787 aRubyCharFmts.push_back(pFmt);
2788 pCharFmt = pFmt;
2791 //Set the charstyle and justification
2792 aRuby.SetCharFmtName(pCharFmt->GetName());
2793 aRuby.SetCharFmtId(pCharFmt->GetPoolFmtId());
2794 aRuby.SetAdjustment(nJustificationCode);
2796 NewAttr(aRuby);
2797 rDoc.InsertString( *pPaM, sText );
2798 pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_CJK_RUBY );
2802 //-----------------------------------------
2803 // Verzeichnis-Felder
2804 //-----------------------------------------
2806 static void lcl_toxMatchACSwitch( SwWW8ImplReader& /*rReader*/,
2807 SwDoc& rDoc,
2808 SwTOXBase& rBase,
2809 WW8ReadFieldParams& rParam,
2810 SwCaptionDisplay eCaptionType)
2812 xub_StrLen n = rParam.GoToTokenParam();
2813 if( STRING_NOTFOUND != n )
2815 SwTOXType* pType = (SwTOXType*)rDoc.GetTOXType( TOX_ILLUSTRATIONS, 0);
2816 rBase.RegisterToTOXType( *pType );
2817 rBase.SetCaptionDisplay( eCaptionType );
2818 // Read Sequence Name and store in TOXBase
2819 String sSeqName( rParam.GetResult() );
2820 lcl_ConvertSequenceName( sSeqName );
2821 rBase.SetSequenceName( sSeqName );
2825 //For all outline styles that are not in the outline numbering add them here as
2826 //custom extra styles
2827 bool SwWW8ImplReader::AddExtraOutlinesAsExtraStyles(SwTOXBase& rBase)
2829 bool bExtras = false;
2830 //This is the case if the winword outline numbering is set while the
2831 //writer one is not
2832 for (sal_uInt16 nI = 0; nI < vColl.size(); ++nI)
2834 SwWW8StyInf& rSI = vColl[nI];
2835 if (rSI.IsOutline())
2837 const SwTxtFmtColl *pFmt = (const SwTxtFmtColl*)(rSI.pFmt);
2838 sal_uInt16 nStyleLevel = rSI.nOutlineLevel;
2839 sal_uInt16 nMaxLevel = rBase.GetLevel();
2840 if (
2841 nStyleLevel != (pFmt->GetAttrOutlineLevel()-1) && //<-end,zhaojianwei
2842 nStyleLevel < nMaxLevel
2845 String sStyles(rBase.GetStyleNames(rSI.nOutlineLevel));
2846 if( sStyles.Len())
2847 sStyles += TOX_STYLE_DELIMITER;
2848 sStyles += pFmt->GetName();
2849 rBase.SetStyleNames(sStyles, rSI.nOutlineLevel);
2850 bExtras = true;
2854 return bExtras;
2857 static void EnsureMaxLevelForTemplates(SwTOXBase& rBase)
2859 //If the TOC contains Template entries at levels > the evaluation level
2860 //that was initially taken from the max normal outline level of the word TOC
2861 //then we cannot use that for the evaluation level because writer cuts off
2862 //all styles above that level, while word just cuts off the "standard"
2863 //outline styles, we have no option but to expand to the highest level
2864 //Word included.
2865 if ((rBase.GetLevel() != MAXLEVEL) && (nsSwTOXElement::TOX_TEMPLATE & rBase.GetCreateType()))
2867 for (sal_uInt16 nI = MAXLEVEL; nI > 0; --nI)
2869 if (rBase.GetStyleNames(nI-1).Len())
2871 rBase.SetLevel(nI);
2872 break;
2878 static void lcl_toxMatchTSwitch(SwWW8ImplReader& rReader, SwTOXBase& rBase,
2879 WW8ReadFieldParams& rParam)
2881 xub_StrLen n = rParam.GoToTokenParam();
2882 if( STRING_NOTFOUND != n )
2884 String sParams( rParam.GetResult() );
2885 if( sParams.Len() )
2887 sal_Int32 nIndex = 0;
2889 // Delimiters between styles and style levels appears to allow both ; and ,
2891 String sTemplate( sParams.GetToken(0, ';', nIndex) );
2892 if( -1 == nIndex )
2894 nIndex=0;
2895 sTemplate = sParams.GetToken(0, ',', nIndex);
2897 if( -1 == nIndex )
2899 const SwFmt* pStyle = rReader.GetStyleWithOrgWWName(sTemplate);
2900 if( pStyle )
2901 sTemplate = pStyle->GetName();
2902 // Store Style for Level 0 into TOXBase
2903 rBase.SetStyleNames( sTemplate, 0 );
2905 else while( -1 != nIndex )
2907 sal_Int32 nOldIndex=nIndex;
2908 sal_uInt16 nLevel = static_cast<sal_uInt16>(
2909 sParams.GetToken(0, ';', nIndex).ToInt32());
2910 if( -1 == nIndex )
2912 nIndex = nOldIndex;
2913 nLevel = static_cast<sal_uInt16>(
2914 sParams.GetToken(0, ',', nIndex).ToInt32());
2917 if( (0 < nLevel) && (MAXLEVEL >= nLevel) )
2919 nLevel--;
2920 // Store Style and Level into TOXBase
2921 const SwFmt* pStyle
2922 = rReader.GetStyleWithOrgWWName( sTemplate );
2924 if( pStyle )
2925 sTemplate = pStyle->GetName();
2927 String sStyles( rBase.GetStyleNames( nLevel ) );
2928 if( sStyles.Len() )
2929 sStyles += TOX_STYLE_DELIMITER;
2930 sStyles += sTemplate;
2931 rBase.SetStyleNames( sStyles, nLevel );
2933 // read next style name...
2934 nOldIndex = nIndex;
2935 sTemplate = sParams.GetToken(0, ';', nIndex);
2936 if( -1 == nIndex )
2938 nIndex=nOldIndex;
2939 sTemplate = sParams.GetToken(0, ',', nIndex);
2946 sal_uInt16 wwSectionManager::CurrentSectionColCount() const
2948 sal_uInt16 nIndexCols = 1;
2949 if (!maSegments.empty())
2950 nIndexCols = maSegments.back().maSep.ccolM1 + 1;
2951 return nIndexCols;
2954 //Will there be a new pagebreak at this position (don't know what type
2955 //until later)
2956 bool wwSectionManager::WillHavePageDescHere(SwNodeIndex aIdx) const
2958 bool bRet = false;
2959 if (!maSegments.empty())
2961 if (!maSegments.back().IsContinous() &&
2962 maSegments.back().maStart == aIdx)
2964 bRet = true;
2967 return bRet;
2970 static sal_uInt16 lcl_GetMaxValidWordTOCLevel(const SwForm &rForm)
2972 // GetFormMax() returns level + 1, hence the -1
2973 sal_uInt16 nRet = rForm.GetFormMax()-1;
2975 // If the max of this type of TOC is greater than the max of a word
2976 // possible toc, then clip to the word max
2977 if (nRet > WW8ListManager::nMaxLevel)
2978 nRet = WW8ListManager::nMaxLevel;
2980 return nRet;
2983 eF_ResT SwWW8ImplReader::Read_F_Tox( WW8FieldDesc* pF, String& rStr )
2985 #if defined(WW_NATIVE_TOC)
2986 if (1) {
2987 OUString aBookmarkName("_TOC");
2988 maFieldStack.back().SetBookmarkName(aBookmarkName);
2989 maFieldStack.back().SetBookmarkType(ODF_TOC);
2990 return FLD_TEXT;
2992 #endif
2994 if (pF->nLRes < 3)
2995 return FLD_TEXT; // ignore (#i25440#)
2997 TOXTypes eTox; // Baue ToxBase zusammen
2998 switch( pF->nId )
3000 case 8:
3001 eTox = TOX_INDEX;
3002 break;
3003 case 13:
3004 eTox = TOX_CONTENT;
3005 break;
3006 default:
3007 eTox = TOX_USER;
3008 break;
3011 sal_uInt16 nCreateOf = (eTox == TOX_CONTENT) ? nsSwTOXElement::TOX_OUTLINELEVEL : nsSwTOXElement::TOX_MARK;
3013 sal_uInt16 nIndexCols = 1;
3015 const SwTOXType* pType = rDoc.GetTOXType( eTox, 0 );
3016 SwForm aOrigForm(eTox);
3017 SwTOXBase* pBase = new SwTOXBase( pType, aOrigForm, nCreateOf, aEmptyStr );
3018 pBase->SetProtected(maSectionManager.CurrentSectionIsProtected());
3019 switch( eTox ){
3020 case TOX_INDEX:
3022 sal_uInt16 eOptions = nsSwTOIOptions::TOI_SAME_ENTRY | nsSwTOIOptions::TOI_CASE_SENSITIVE;
3024 // TOX_OUTLINELEVEL setzen wir genau dann, wenn
3025 // die Parameter \o in 1 bis 9 liegen
3026 // oder der Parameter \f existiert
3027 // oder GARKEINE Switches Parameter angegeben sind.
3028 long nRet;
3029 WW8ReadFieldParams aReadParam( rStr );
3030 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3032 switch( nRet )
3034 case 'c':
3036 xub_StrLen n = aReadParam.GoToTokenParam();
3037 if( STRING_NOTFOUND != n )
3039 String sParams( aReadParam.GetResult() );
3040 // if NO String just ignore the \c
3041 if( sParams.Len() )
3043 nIndexCols =
3044 static_cast<sal_uInt16>(sParams.ToInt32());
3048 break;
3049 case 'e':
3051 xub_StrLen n = aReadParam.GoToTokenParam();
3052 if( STRING_NOTFOUND != n ) // if NO String just ignore the \e
3054 String sDelimiter( aReadParam.GetResult() );
3055 SwForm aForm( pBase->GetTOXForm() );
3057 // Attention: if TOX_CONTENT brave
3058 // GetFormMax() returns MAXLEVEL + 1 !!
3059 sal_uInt16 nEnd = aForm.GetFormMax()-1;
3061 for(sal_uInt16 nLevel = 1;
3062 nLevel <= nEnd;
3063 ++nLevel)
3065 // Levels count from 1
3066 // Level 0 is reserved for CAPTION
3068 // Delimiter statt Tabstop vor der Seitenzahl einsetzen,
3069 // falls es eine Seitenzahl gibt:
3070 FormTokenType ePrevType = TOKEN_END;
3071 FormTokenType eType;
3072 // -> #i21237#
3073 SwFormTokens aPattern =
3074 aForm.GetPattern(nLevel);
3075 SwFormTokens::iterator aIt = aPattern.begin();
3078 eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3080 if (eType == TOKEN_PAGE_NUMS)
3082 if (TOKEN_TAB_STOP == ePrevType)
3084 --aIt;
3086 if(0x09 == sDelimiter.GetChar(0))
3087 aIt->eTabAlign = SVX_TAB_ADJUST_END;
3088 else
3090 SwFormToken aToken(TOKEN_TEXT);
3091 aToken.sText = sDelimiter;
3092 *aIt = aToken;
3094 aForm.SetPattern(nLevel, aPattern);
3097 eType = TOKEN_END;
3100 ePrevType = eType;
3102 while (TOKEN_END != eType);
3103 // <- #i21237#
3105 pBase->SetTOXForm( aForm );
3108 break;
3109 case 'h':
3111 eOptions |= nsSwTOIOptions::TOI_ALPHA_DELIMITTER;
3113 break;
3116 pBase->SetOptions( eOptions );
3118 break;
3120 case TOX_CONTENT:
3122 bool bIsHyperlink = false;
3123 // TOX_OUTLINELEVEL setzen wir genau dann, wenn
3124 // die Parameter \o in 1 bis 9 liegen
3125 // oder der Parameter \f existiert
3126 // oder GARKEINE Switches Parameter angegeben sind.
3127 sal_uInt16 eCreateFrom = 0;
3128 sal_uInt16 nMaxLevel = 0;
3129 long nRet;
3130 WW8ReadFieldParams aReadParam( rStr );
3131 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3133 switch( nRet )
3135 case 'h':
3136 bIsHyperlink = true;
3137 break;
3138 case 'a':
3139 case 'c':
3140 lcl_toxMatchACSwitch(*this, rDoc, *pBase, aReadParam,
3141 ('c' == nRet)
3142 ? CAPTION_COMPLETE
3143 : CAPTION_TEXT );
3144 break;
3145 case 'o':
3147 sal_uInt16 nVal;
3148 if( !aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) )
3149 nVal = lcl_GetMaxValidWordTOCLevel(aOrigForm);
3150 if( nMaxLevel < nVal )
3151 nMaxLevel = nVal;
3152 eCreateFrom |= nsSwTOXElement::TOX_OUTLINELEVEL;
3154 break;
3155 case 'f':
3156 eCreateFrom |= nsSwTOXElement::TOX_MARK;
3157 break;
3158 case 'l':
3160 sal_uInt16 nVal;
3161 if( aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) )
3163 if( nMaxLevel < nVal )
3164 nMaxLevel = nVal;
3165 eCreateFrom |= nsSwTOXElement::TOX_MARK;
3168 break;
3169 case 't': // paragraphs using special styles shall
3170 // provide the TOX's content
3171 lcl_toxMatchTSwitch(*this, *pBase, aReadParam);
3172 eCreateFrom |= nsSwTOXElement::TOX_TEMPLATE;
3173 break;
3174 case 'p':
3176 xub_StrLen n = aReadParam.GoToTokenParam();
3177 if( STRING_NOTFOUND != n ) // if NO String just ignore the \p
3179 String sDelimiter( aReadParam.GetResult() );
3180 SwForm aForm( pBase->GetTOXForm() );
3182 // Attention: if TOX_CONTENT brave
3183 // GetFormMax() returns MAXLEVEL + 1 !!
3184 sal_uInt16 nEnd = aForm.GetFormMax()-1;
3186 for(sal_uInt16 nLevel = 1;
3187 nLevel <= nEnd;
3188 ++nLevel)
3190 // Levels count from 1
3191 // Level 0 is reserved for CAPTION
3193 // Delimiter statt Tabstop vor der Seitenzahl einsetzen,
3194 // falls es eine Seitenzahl gibt:
3195 FormTokenType ePrevType = TOKEN_END;
3196 FormTokenType eType;
3198 // -> #i21237#
3199 SwFormTokens aPattern = aForm.GetPattern(nLevel);
3200 SwFormTokens::iterator aIt = aPattern.begin();
3203 eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3205 if (eType == TOKEN_PAGE_NUMS)
3207 if (TOKEN_TAB_STOP == ePrevType)
3209 --aIt;
3211 SwFormToken aToken(TOKEN_TEXT);
3212 aToken.sText = sDelimiter;
3214 *aIt = aToken;
3215 aForm.SetPattern(nLevel,
3216 aPattern);
3218 eType = TOKEN_END;
3220 ePrevType = eType;
3222 while( TOKEN_END != eType );
3223 // <- #i21237#
3225 pBase->SetTOXForm( aForm );
3228 break;
3229 case 'n': // don't print page numbers
3231 // read START and END param
3232 sal_uInt16 nStart, nEnd;
3233 if( !aReadParam.GetTokenSttFromTo( &nStart, &nEnd,
3234 WW8ListManager::nMaxLevel ) )
3236 nStart = 1;
3237 nEnd = aOrigForm.GetFormMax()-1;
3239 // remove page numbers from this levels
3240 SwForm aForm( pBase->GetTOXForm() );
3241 if (aForm.GetFormMax() <= nEnd)
3242 nEnd = aForm.GetFormMax()-1;
3243 for (
3244 sal_uInt16 nLevel = nStart; nLevel <= nEnd;
3245 ++nLevel
3248 // Levels count from 1
3249 // Level 0 is reserved for CAPTION
3251 // Seitenzahl und ggfs. davorstehenden Tabstop
3252 // entfernen:
3253 FormTokenType eType;
3254 // -> #i21237#
3255 SwFormTokens aPattern = aForm.GetPattern(nLevel);
3256 SwFormTokens::iterator aIt = aPattern.begin();
3259 eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3261 if (eType == TOKEN_PAGE_NUMS)
3263 aIt = aPattern.erase(aIt);
3264 --aIt;
3265 if (
3266 TOKEN_TAB_STOP ==
3267 aIt->eTokenType
3270 aPattern.erase(aIt);
3271 aForm.SetPattern(nLevel, aPattern);
3273 eType = TOKEN_END;
3276 while (TOKEN_END != eType);
3277 // <- #i21237#
3279 pBase->SetTOXForm( aForm );
3281 break;
3284 // the following switches are not (yet) supported
3285 // by good old StarWriter:
3286 case 'b':
3287 case 's':
3288 case 'd':
3289 break;
3294 if (bIsHyperlink)
3296 SwForm aForm(pBase->GetTOXForm());
3297 sal_uInt16 nEnd = aForm.GetFormMax()-1;
3298 SwFormToken aLinkStart(TOKEN_LINK_START);
3299 SwFormToken aLinkEnd(TOKEN_LINK_END);
3301 // -> #i21237#
3302 for(sal_uInt16 nLevel = 1; nLevel <= nEnd; ++nLevel)
3304 SwFormTokens aPattern = aForm.GetPattern(nLevel);
3306 aPattern.insert(aPattern.begin(), aLinkStart);
3307 aPattern.push_back(aLinkEnd);
3309 aForm.SetPattern(nLevel, aPattern);
3312 // <- #i21237#
3313 pBase->SetTOXForm(aForm);
3316 if (!nMaxLevel)
3317 nMaxLevel = WW8ListManager::nMaxLevel;
3318 pBase->SetLevel(nMaxLevel);
3320 const TOXTypes eType = pBase->GetTOXType()->GetType();
3321 switch( eType )
3323 case TOX_CONTENT:
3325 //If we would be created from outlines, either explictly or by default
3326 //then see if we need extra styles added to the outlines
3327 sal_uInt16 eEffectivelyFrom = eCreateFrom ? eCreateFrom : nsSwTOXElement::TOX_OUTLINELEVEL;
3328 if (eEffectivelyFrom & nsSwTOXElement::TOX_OUTLINELEVEL)
3330 if (AddExtraOutlinesAsExtraStyles(*pBase))
3331 eCreateFrom |= (nsSwTOXElement::TOX_TEMPLATE | nsSwTOXElement::TOX_OUTLINELEVEL);
3333 // #i19683# Insert a text token " " between the number and entry token.
3334 // In an ideal world we could handle the tab stop between the number and
3335 // the entry correctly, but I currently have no clue how to obtain
3336 // the tab stop position. It is _not_ set at the paragraph style.
3337 SwForm* pForm = 0;
3338 for (sal_uInt16 nI = 0; nI < vColl.size(); ++nI)
3340 const SwWW8StyInf& rSI = vColl[nI];
3341 if (rSI.IsOutlineNumbered())
3343 sal_uInt16 nStyleLevel = rSI.nOutlineLevel;
3344 const SwNumFmt& rFmt = rSI.GetOutlineNumrule()->Get( nStyleLevel );
3345 if ( SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType() )
3347 ++nStyleLevel;
3349 if ( !pForm )
3350 pForm = new SwForm( pBase->GetTOXForm() );
3352 SwFormTokens aPattern = pForm->GetPattern(nStyleLevel);
3353 SwFormTokens::iterator aIt =
3354 find_if(aPattern.begin(), aPattern.end(),
3355 SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO));
3357 if ( aIt != aPattern.end() )
3359 SwFormToken aNumberEntrySeparator( TOKEN_TEXT );
3360 aNumberEntrySeparator.sText = OUString(" ");
3361 aPattern.insert( ++aIt, aNumberEntrySeparator );
3362 pForm->SetPattern( nStyleLevel, aPattern );
3367 if ( pForm )
3368 pBase->SetTOXForm( *pForm );
3371 if (eCreateFrom)
3372 pBase->SetCreate(eCreateFrom);
3373 EnsureMaxLevelForTemplates(*pBase);
3375 break;
3376 case TOX_ILLUSTRATIONS:
3378 if( !eCreateFrom )
3379 eCreateFrom = nsSwTOXElement::TOX_SEQUENCE;
3380 pBase->SetCreate( eCreateFrom );
3383 We don't know until here if we are an illustration
3384 or not, and so have being used a TOX_CONTENT so far
3385 which has 10 levels, while TOX has only two, this
3386 level is set only in the constructor of SwForm, so
3387 create a new one and copy over anything that could
3388 be set in the old one, and remove entries from the
3389 pattern which do not apply to illustration indices
3391 SwForm aOldForm( pBase->GetTOXForm() );
3392 SwForm aForm( eType );
3393 sal_uInt16 nEnd = aForm.GetFormMax()-1;
3395 // #i21237#
3396 for(sal_uInt16 nLevel = 1; nLevel <= nEnd; ++nLevel)
3398 SwFormTokens aPattern = aOldForm.GetPattern(nLevel);
3400 SwFormTokens::iterator new_end=remove_if(aPattern.begin(), aPattern.end(),
3401 SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO));
3403 // table index imported with wrong page number format
3404 aPattern.erase (new_end, aPattern.end() );
3406 aForm.SetPattern(nLevel, aPattern);
3408 aForm.SetTemplate( nLevel,
3409 aOldForm.GetTemplate(nLevel));
3412 pBase->SetTOXForm( aForm );
3414 break;
3415 default:
3416 OSL_ENSURE(!this, "Unhandled toc options!");
3417 break;
3420 break;
3421 case TOX_USER:
3422 break;
3423 default:
3424 OSL_ENSURE(!this, "Unhandled toc options!");
3425 break;
3426 } // ToxBase fertig
3428 // Update fuer TOX anstossen
3429 rDoc.SetUpdateTOX(true);
3431 // #i21237# - propagate tab stops from paragraph styles
3432 // used in TOX to patterns of the TOX
3434 pBase->AdjustTabStops(rDoc, sal_True);
3436 // #i10028# - inserting a toc implicltly acts like a parabreak in word and writer
3437 if (pPaM->GetPoint()->nContent.GetIndex())
3438 AppendTxtNode(*pPaM->GetPoint());
3440 const SwPosition* pPos = pPaM->GetPoint();
3442 SwFltTOX aFltTOX( pBase, nIndexCols );
3444 // test if there is already a break item on this node
3445 if(SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode())
3447 const SfxItemSet* pSet = pNd->GetpSwAttrSet();
3448 if( pSet )
3450 if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false))
3451 aFltTOX.SetHadBreakItem(true);
3452 if (SFX_ITEM_SET == pSet->GetItemState(RES_PAGEDESC, false))
3453 aFltTOX.SetHadPageDescItem(true);
3457 //Will there be a new pagebreak at this position (don't know what type
3458 //until later)
3459 if (maSectionManager.WillHavePageDescHere(pPos->nNode))
3460 aFltTOX.SetHadPageDescItem(true);
3462 // Setze Anfang in Stack
3463 pReffedStck->NewAttr( *pPos, aFltTOX );
3465 rDoc.InsertTableOf(*pPaM->GetPoint(), *aFltTOX.GetBase());
3467 //inserting a toc inserts a section before this point, so adjust pos
3468 //for future page/section segment insertion
3469 SwPaM aRegion(*pPaM);
3470 aRegion.Move(fnMoveBackward);
3471 OSL_ENSURE(rDoc.GetCurTOX(*aRegion.GetPoint()), "Misunderstood how toc works");
3472 if (SwTOXBase* pBase2 = (SwTOXBase*)rDoc.GetCurTOX(*aRegion.GetPoint()))
3474 if(nIndexCols>1)
3476 // Set the column number for index
3477 SfxItemSet aSet( rDoc.GetAttrPool(), RES_COL, RES_COL );
3478 SwFmtCol aCol;
3479 aCol.Init( nIndexCols, 708, USHRT_MAX );
3480 aSet.Put( aCol );
3481 pBase2->SetAttrSet( aSet );
3484 maSectionManager.PrependedInlineNode(*pPaM->GetPoint(),
3485 *aRegion.GetNode());
3488 // Setze Ende in Stack
3489 pReffedStck->SetAttr( *pPos, RES_FLTR_TOX );
3491 if (!maApos.back()) //a para end in apo doesn't count
3492 bWasParaEnd = true;
3493 return FLD_OK;
3496 eF_ResT SwWW8ImplReader::Read_F_Shape(WW8FieldDesc* /*pF*/, String& /*rStr*/)
3499 #i3958# 0x8 followed by 0x1 where the shape is the 0x8 and its anchoring
3500 to be ignored followed by a 0x1 with an empty drawing. Detect in inserting
3501 the drawing that we are in the Shape field and respond accordingly
3503 return FLD_TEXT;
3506 eF_ResT SwWW8ImplReader::Read_F_Hyperlink( WW8FieldDesc* /*pF*/, String& rStr )
3508 #if defined(WW_NATIVE_TOC)
3509 if (1) {
3510 OUString aBookmarkName("_HYPERLINK");
3511 maFieldStack.back().SetBookmarkName(aBookmarkName);
3512 maFieldStack.back().SetBookmarkType(ODF_HYPERLINK);
3513 return FLD_TEXT;
3515 #endif
3517 String sURL, sTarget, sMark;
3518 bool bDataImport = false;
3519 //HYPERLINK "filename" [switches]
3521 rStr = comphelper::string::stripEnd(rStr, 1);
3523 if (!bDataImport)
3525 bool bOptions = false;
3526 long nRet;
3527 WW8ReadFieldParams aReadParam( rStr );
3528 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3530 switch( nRet )
3532 case -2:
3533 if (!sURL.Len() && !bOptions)
3534 ConvertFFileName(sURL, aReadParam.GetResult());
3535 break;
3537 case 'n':
3538 sTarget.AssignAscii( "_blank" );
3539 bOptions = true;
3540 break;
3542 case 'l':
3543 nRet = aReadParam.SkipToNextToken();
3544 bOptions = true;
3545 if( -2 == nRet )
3547 sMark = aReadParam.GetResult();
3548 if( sMark.Len() && '"' == sMark.GetChar( sMark.Len()-1 ))
3549 sMark.Erase( sMark.Len() - 1 );
3552 break;
3553 case 't':
3554 nRet = aReadParam.SkipToNextToken();
3555 bOptions = true;
3556 if (-2 == nRet)
3557 sTarget = aReadParam.GetResult();
3558 break;
3559 case 'h':
3560 case 'm':
3561 OSL_ENSURE( !this, "Auswertung fehlt noch - Daten unbekannt" );
3562 case 's': //worthless fake anchor option
3563 bOptions = true;
3564 break;
3569 // das Resultat uebernehmen
3570 OSL_ENSURE((sURL.Len() || sMark.Len()), "WW8: Empty URL");
3572 if( sMark.Len() )
3573 ( sURL += INET_MARK_TOKEN ) += sMark;
3575 SwFmtINetFmt aURL( sURL, sTarget );
3577 //As an attribute this needs to be closed, and that'll happen from
3578 //EndExtSprm in conjunction with the maFieldStack If there are are flyfrms
3579 //between the start and begin, their hyperlinks will be set at that time
3580 //as well.
3581 pCtrlStck->NewAttr( *pPaM->GetPoint(), aURL );
3582 return FLD_TEXT;
3585 static void lcl_ImportTox(SwDoc &rDoc, SwPaM &rPaM, const String &rStr, bool bIdx)
3587 TOXTypes eTox = ( !bIdx ) ? TOX_CONTENT : TOX_INDEX; // Default
3589 sal_uInt16 nLevel = 1;
3591 xub_StrLen n;
3592 String sFldTxt;
3593 long nRet;
3594 WW8ReadFieldParams aReadParam(rStr);
3595 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3596 switch( nRet )
3598 case -2:
3599 if( !sFldTxt.Len() )
3601 // PrimaryKey ohne ":", 2nd dahinter
3602 sFldTxt = aReadParam.GetResult();
3604 break;
3606 case 'f':
3607 n = aReadParam.GoToTokenParam();
3608 if( STRING_NOTFOUND != n )
3610 String sParams( aReadParam.GetResult() );
3611 if( 'C' != sParams.GetChar(0) && 'c' != sParams.GetChar(0) )
3612 eTox = TOX_USER;
3614 break;
3616 case 'l':
3617 n = aReadParam.GoToTokenParam();
3618 if( STRING_NOTFOUND != n )
3620 String sParams( aReadParam.GetResult() );
3621 if( sParams.Len() // if NO String just ignore the \l
3622 && sParams.GetChar( 0 ) > '0'
3623 && sParams.GetChar( 0 ) <= '9' )
3625 nLevel = (sal_uInt16)sParams.ToInt32();
3628 break;
3631 OSL_ENSURE( rDoc.GetTOXTypeCount( eTox ), "Doc.GetTOXTypeCount() == 0 :-(" );
3633 const SwTOXType* pT = rDoc.GetTOXType( eTox, 0 );
3634 SwTOXMark aM( pT );
3636 if( eTox != TOX_INDEX )
3637 aM.SetLevel( nLevel );
3638 else
3640 xub_StrLen nFnd = sFldTxt.Search( WW8_TOX_LEVEL_DELIM );
3641 if( STRING_NOTFOUND != nFnd ) // it exist levels
3643 aM.SetPrimaryKey( sFldTxt.Copy( 0, nFnd ) );
3644 xub_StrLen nScndFnd =
3645 sFldTxt.Search( WW8_TOX_LEVEL_DELIM, nFnd+1 );
3646 if( STRING_NOTFOUND != nScndFnd )
3648 aM.SetSecondaryKey( sFldTxt.Copy( nFnd+1, nScndFnd - nFnd - 1 ));
3649 nFnd = nScndFnd;
3651 sFldTxt.Erase( 0, nFnd+1 );
3655 if (sFldTxt.Len())
3657 aM.SetAlternativeText( sFldTxt );
3658 rDoc.InsertPoolItem( rPaM, aM, 0 );
3662 void sw::ms::ImportXE(SwDoc &rDoc, SwPaM &rPaM, const String &rStr)
3664 lcl_ImportTox(rDoc, rPaM, rStr, true);
3667 void SwWW8ImplReader::ImportTox( int nFldId, String aStr )
3669 bool bIdx = (nFldId != 9);
3670 lcl_ImportTox(rDoc, *pPaM, aStr, bIdx);
3673 void SwWW8ImplReader::Read_FldVanish( sal_uInt16, const sal_uInt8*, short nLen )
3675 //Meaningless in a style
3676 if (pAktColl || !pPlcxMan)
3677 return;
3679 const int nChunk = 64; //number of characters to read at one time
3681 // Vorsicht: Bei Feldnamen mit Umlauten geht das MEMICMP nicht!
3682 const static sal_Char *aFldNames[] = { "\x06""INHALT", "\x02""XE", // dt.
3683 "\x02""TC" }; // us
3684 const static sal_uInt8 aFldId[] = { 9, 4, 9 };
3686 if( nLen < 0 )
3688 bIgnoreText = false;
3689 return;
3692 // our methode was called from
3693 // ''Skip attributes of field contents'' loop within ReadTextAttr()
3694 if( bIgnoreText )
3695 return;
3697 bIgnoreText = true;
3698 long nOldPos = pStrm->Tell();
3700 WW8_CP nStartCp = pPlcxMan->Where() + pPlcxMan->GetCpOfs();
3702 String sFieldName;
3703 sal_uInt16 nFieldLen = pSBase->WW8ReadString( *pStrm, sFieldName, nStartCp,
3704 nChunk, eStructCharSet );
3705 nStartCp+=nFieldLen;
3707 xub_StrLen nC = 0;
3708 //If the first chunk did not start with a field start then
3709 //reset the stream position and give up
3710 if( !nFieldLen || (0x13 != sFieldName.GetChar( nC ))) // Field Start Mark
3712 // If Field End Mark found
3713 if( nFieldLen && (0x15 == sFieldName.GetChar( nC )))
3714 bIgnoreText = false;
3715 pStrm->Seek( nOldPos );
3716 return; // kein Feld zu finden
3719 xub_StrLen nFnd;
3720 //If this chunk does not contain a field end, keep reading chunks
3721 //until we find one, or we run out of text,
3722 while (STRING_NOTFOUND == (nFnd = sFieldName.Search(0x15)))
3724 String sTemp;
3725 nFieldLen = pSBase->WW8ReadString( *pStrm, sTemp,
3726 nStartCp, nChunk, eStructCharSet );
3727 sFieldName+=sTemp;
3728 nStartCp+=nFieldLen;
3729 if (!nFieldLen)
3730 break;
3733 pStrm->Seek( nOldPos );
3735 //if we have no 0x15 give up, otherwise erase everything from the 0x15
3736 //onwards
3737 if (STRING_NOTFOUND == nFnd)
3738 return;
3739 else
3740 sFieldName.Erase(nFnd);
3742 nC++;
3743 while( ' ' == sFieldName.GetChar( nC ))
3744 nC++;
3746 for( int i = 0; i < 3; i++ )
3748 const sal_Char* pName = aFldNames[i];
3749 sal_uInt16 nNameLen = *pName++;
3750 if( sFieldName.EqualsIgnoreCaseAscii( pName, nC, nNameLen ) )
3752 ImportTox( aFldId[i], sFieldName.Copy( nC + nNameLen ) );
3753 break; // keine Mehrfachnennungen moeglich
3756 bIgnoreText = true;
3757 pStrm->Seek( nOldPos );
3760 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */