xref: /trunk/main/sw/source/filter/ww8/ww8par5.cxx (revision 870262e3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 
28 
29 #include <ctype.h>              // tolower
30 #include <stdio.h>              // sscanf()
31 
32 #include <sal/types.h>
33 #include <tools/solar.h>
34 
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>
40 
41 #include <ucbhelper/content.hxx>
42 #include <ucbhelper/contentbroker.hxx>
43 #include <ucbhelper/commandenvironment.hxx>
44 
45 #include <com/sun/star/i18n/ScriptType.hdl>
46 #include <hintids.hxx>
47 #include <editeng/fontitem.hxx>
48 #include <editeng/fhgtitem.hxx>
49 #include <editeng/langitem.hxx>
50 #include <fmtfld.hxx>
51 #include <fmtanchr.hxx>
52 #include <pam.hxx>              // fuer SwPam
53 #include <doc.hxx>
54 #include <charatr.hxx>          // class SwFmtFld
55 #include <flddat.hxx>           // class SwDateTimeField
56 #include <docufld.hxx>          // class SwPageNumberField
57 #include <reffld.hxx>           // class SwGetRefField
58 #include <IMark.hxx>
59 #include <expfld.hxx>           // class SwSetExpField
60 #include <dbfld.hxx>            // class SwDBField
61 #include <usrfld.hxx>
62 #include <tox.hxx>
63 #include <section.hxx>          // class SwSection
64 #include <ndtxt.hxx>
65 #include <fmtinfmt.hxx>
66 #include <chpfld.hxx>
67 #include <ftnidx.hxx>
68 #include <txtftn.hxx>
69 #include <viewsh.hxx>
70 #include <shellres.hxx>
71 #include <fmtruby.hxx>
72 #include <charfmt.hxx>
73 #include <txtatr.hxx>
74 #include <breakit.hxx>
75 #include <fmtclds.hxx>
76 #include <pagedesc.hxx>
77 #include <SwStyleNameMapper.hxx>
78 #include <IMark.hxx>
79 
80 #include "ww8scan.hxx"          // WW8FieldDesc
81 #include "ww8par.hxx"
82 #include "ww8par2.hxx"
83 #include "writerhelper.hxx"
84 #include "fields.hxx"
85 #include <unotools/fltrcfg.hxx>
86 
87 #include <algorithm> // #i24377#
88 
89 #define MAX_FIELDLEN 64000
90 
91 #define WW8_TOX_LEVEL_DELIM     ':'
92 
93 using namespace ::com::sun::star;
94 using namespace sw::util;
95 using namespace sw::mark;
96 using namespace std; // #i24377#
97 using namespace nsSwDocInfoSubType;
98 
99 
100 class _ReadFieldParams
101 {
102 private:
103     String aData;
104     xub_StrLen nLen, nFnd, nNext, nSavPtr;
105 public:
106     _ReadFieldParams( const String& rData );
107     ~_ReadFieldParams();
108 
109     xub_StrLen GoToTokenParam();
110     long SkipToNextToken();
GetTokenSttPtr() const111     xub_StrLen GetTokenSttPtr() const   { return nFnd;  }
112 
113     xub_StrLen FindNextStringPiece( xub_StrLen _nStart = STRING_NOTFOUND );
114     bool GetTokenSttFromTo(xub_StrLen* _pFrom, xub_StrLen* _pTo,
115         xub_StrLen _nMax);
116 
117     String GetResult() const;
118 };
119 
120 
_ReadFieldParams(const String & _rData)121 _ReadFieldParams::_ReadFieldParams( const String& _rData )
122     : aData( _rData ), nLen( _rData.Len() ), nNext( 0 )
123 {
124     /*
125         erstmal nach einer oeffnenden Klammer oder einer Leerstelle oder einem
126         Anfuehrungszeichen oder einem Backslash suchen, damit der Feldbefehl
127         (also INCLUDEPICTURE bzw EINFUeGENGRAFIK bzw ...) ueberlesen wird
128     */
129     while( (nLen > nNext) && (aData.GetChar( nNext ) == ' ') )
130         ++nNext;
131 
132     sal_Unicode c;
133     while(     nLen > nNext
134             && (c = aData.GetChar( nNext )) != ' '
135             && c != '"'
136             && c != '\\'
137             && c != 132
138             && c != 0x201c )
139         ++nNext;
140 
141     nFnd      = nNext;
142     nSavPtr   = nNext;
143 //  cLastChar = aData.GetChar( nSavPtr );
144 }
145 
146 
~_ReadFieldParams()147 _ReadFieldParams::~_ReadFieldParams()
148 {
149 //  aData.SetChar( nSavPtr, cLastChar );
150 }
151 
152 
GetResult() const153 String _ReadFieldParams::GetResult() const
154 {
155     return    (STRING_NOTFOUND == nFnd)
156             ? aEmptyStr
157             : aData.Copy( nFnd, (nSavPtr - nFnd) );
158 }
159 
160 
GoToTokenParam()161 xub_StrLen _ReadFieldParams::GoToTokenParam()
162 {
163     xub_StrLen nOld = nNext;
164     if( -2 == SkipToNextToken() )
165         return GetTokenSttPtr();
166     nNext = nOld;
167     return STRING_NOTFOUND;
168 }
169 
170 // ret: -2: NOT a '\' parameter but normal Text
SkipToNextToken()171 long _ReadFieldParams::SkipToNextToken()
172 {
173     long nRet = -1;     // Ende
174     if (
175          (STRING_NOTFOUND != nNext) && (nLen > nNext) &&
176          STRING_NOTFOUND != (nFnd = FindNextStringPiece(nNext))
177        )
178     {
179         nSavPtr = nNext;
180 
181         if ('\\' == aData.GetChar(nFnd) && '\\' != aData.GetChar(nFnd + 1))
182         {
183             nRet = aData.GetChar(++nFnd);
184             nNext = ++nFnd;             // und dahinter setzen
185         }
186         else
187         {
188             nRet = -2;
189             if (
190                  (STRING_NOTFOUND != nSavPtr ) &&
191                  (
192                    ('"' == aData.GetChar(nSavPtr - 1)) ||
193                    (0x201d == aData.GetChar(nSavPtr - 1))
194                  )
195                )
196             {
197                 --nSavPtr;
198             }
199         }
200     }
201     return nRet;
202 }
203 
204 // FindNextPara sucht naechsten Backslash-Parameter oder naechste Zeichenkette
205 // bis zum Blank oder naechsten "\" oder zum schliessenden Anfuehrungszeichen
206 // oder zum String-Ende von pStr.
207 //
208 // Ausgabe ppNext (falls ppNext != 0) Suchbeginn fuer naechsten Parameter bzw. 0
209 //
210 // Returnwert: 0 falls String-Ende erreicht,
211 //             ansonsten Anfang des Paramters bzw. der Zeichenkette
212 //
FindNextStringPiece(const xub_StrLen nStart)213 xub_StrLen _ReadFieldParams::FindNextStringPiece(const xub_StrLen nStart)
214 {
215     xub_StrLen  n = ( STRING_NOTFOUND == nStart ) ? nFnd : nStart;  // Anfang
216     xub_StrLen n2;          // Ende
217 
218     nNext = STRING_NOTFOUND;        // Default fuer nicht gefunden
219 
220     while( (nLen > n) && (aData.GetChar( n ) == ' ') )
221         ++n;
222 
223     if( nLen == n )
224         return STRING_NOTFOUND;     // String End reached!
225 
226     if(     (aData.GetChar( n ) == '"')     // Anfuehrungszeichen vor Para?
227         ||  (aData.GetChar( n ) == 0x201c)
228         ||  (aData.GetChar( n ) == 132) )
229     {
230         n++;                        // Anfuehrungszeichen ueberlesen
231         n2 = n;                     // ab hier nach Ende suchen
232         while(     (nLen > n2)
233                 && (aData.GetChar( n2 ) != '"')
234                 && (aData.GetChar( n2 ) != 0x201d)
235                 && (aData.GetChar( n2 ) != 147) )
236             n2++;                   // Ende d. Paras suchen
237     }
238     else                        // keine Anfuehrungszeichen
239     {
240         n2 = n;                     // ab hier nach Ende suchen
241         while( (nLen > n2) && (aData.GetChar( n2 ) != ' ') ) // Ende d. Paras suchen
242         {
243             if( aData.GetChar( n2 ) == '\\' )
244             {
245                 if( aData.GetChar( n2+1 ) == '\\' )
246                     n2 += 2;        // Doppel-Backslash -> OK
247                 else
248                 {
249                     if( n2 > n )
250                         n2--;
251                     break;          // einfach-Backslash -> Ende
252                 }
253             }
254             else
255                 n2++;               // kein Backslash -> OK
256         }
257     }
258     if( nLen > n2 )
259     {
260         if(aData.GetChar( n2 ) != ' ') n2++;
261         nNext = n2;
262     }
263     return n;
264 }
265 
266 
267 
268 // read parameters "1-3" or 1-3 with both values between 1 and nMax
GetTokenSttFromTo(sal_uInt16 * pFrom,sal_uInt16 * pTo,sal_uInt16 nMax)269 bool _ReadFieldParams::GetTokenSttFromTo(sal_uInt16* pFrom, sal_uInt16* pTo, sal_uInt16 nMax)
270 {
271     sal_uInt16 nStart = 0;
272     sal_uInt16 nEnd   = 0;
273     xub_StrLen n = GoToTokenParam();
274     if( STRING_NOTFOUND != n )
275     {
276 
277         String sParams( GetResult() );
278 
279         xub_StrLen nIndex = 0;
280         String sStart( sParams.GetToken(0, '-', nIndex) );
281         if( STRING_NOTFOUND != nIndex )
282         {
283             nStart = static_cast<sal_uInt16>(sStart.ToInt32());
284             nEnd   = static_cast<sal_uInt16>(sParams.Copy(nIndex).ToInt32());
285         }
286     }
287     if( pFrom ) *pFrom = nStart;
288     if( pTo )   *pTo   = nEnd;
289 
290     return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd);
291 }
292 
293 //----------------------------------------
294 //              Bookmarks
295 //----------------------------------------
296 
297 namespace
298 {
299     // #120879# - helper method to identify a bookmark name to match the internal TOC bookmark naming convention
IsTOCBookmarkName(const::rtl::OUString & rName)300     bool IsTOCBookmarkName( const ::rtl::OUString& rName )
301     {
302         static const ::rtl::OUString cTOCBookmarkNamePrefix = ::rtl::OUString::createFromAscii("_Toc");
303 
304         return rName.match(cTOCBookmarkNamePrefix);
305     }
306 }
307 
Read_Book(WW8PLCFManResult *)308 long SwWW8ImplReader::Read_Book(WW8PLCFManResult*)
309 {
310     // muesste auch ueber pRes.nCo2OrIdx gehen
311     WW8PLCFx_Book* pB = pPlcxMan->GetBook();
312     if( !pB )
313     {
314         ASSERT( pB, "WW8PLCFx_Book - Pointer nicht da" );
315         return 0;
316     }
317 
318     eBookStatus eB = pB->GetStatus();
319     if (eB & BOOK_IGNORE)
320         return 0;                               // Bookmark zu ignorieren
321 
322     if (pB->GetIsEnd())
323     {
324         pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true,
325             pB->GetHandle(), (eB & BOOK_FIELD)!=0);
326         return 0;
327     }
328 
329     // "_Hlt*" are unnecessary
330     const String* pName = pB->GetName();
331     // Now, as we read the TOC field completely, we also need the hyperlinks inside keep available.
332     // So the hidden bookmarks inside for hyperlink jumping also should be kept.
333     if ( !pName ||
334          pName->EqualsIgnoreCaseAscii( "_Hlt", 0, 4 ) )
335     {
336         return 0;
337     }
338 
339     //JP 16.11.98: ToUpper darf auf keinen Fall gemacht werden, weil der
340     //Bookmark- name ein Hyperlink-Ziel sein kann!
341 
342     String aVal;
343     if( SwFltGetFlag( nFieldFlags, SwFltControlStack::BOOK_TO_VAR_REF ) )
344     {
345         // Fuer UEbersetzung Bookmark -> Variable setzen
346         long nLen = pB->GetLen();
347         if( nLen > MAX_FIELDLEN )
348             nLen = MAX_FIELDLEN;
349 
350         long nOldPos = pStrm->Tell();
351         nLen = pSBase->WW8ReadString( *pStrm, aVal, pB->GetStartPos(), nLen,
352                                         eStructCharSet );
353         pStrm->Seek( nOldPos );
354 
355         // JP 19.03.2001 - now here the implementation of the old
356         //              "QuoteString" and I hope with a better performance
357         //              as before. It's also only needed if the filterflags
358         //              say we will convert bookmarks to SetExpFields! And
359         //              this the exception!
360 
361         String sHex(CREATE_CONST_ASC( "\\x" ));
362         bool bSetAsHex;
363         bool bAllowCr = SwFltGetFlag(nFieldFlags,
364             SwFltControlStack::ALLOW_FLD_CR) ? true : false;
365 
366         sal_Unicode cChar;
367 
368         for( xub_StrLen nI = 0;
369                 nI < aVal.Len() && aVal.Len() < (MAX_FIELDLEN - 4); ++nI )
370         {
371             switch( cChar = aVal.GetChar( nI ) )
372             {
373             case 0x0b:
374             case 0x0c:
375             case 0x0d:
376                 if( bAllowCr )
377                     aVal.SetChar( nI, '\n' ), bSetAsHex = false;
378                 else
379                     bSetAsHex = true;
380                 break;
381 
382             case 0xFE:
383             case 0xFF:
384                 bSetAsHex = true;
385                 break;
386 
387             default:
388                 bSetAsHex = 0x20 > cChar;
389                 break;
390             }
391 
392             if( bSetAsHex )
393             {
394                 //all Hex-Numbers with \x before
395                 String sTmp( sHex );
396                 if( cChar < 0x10 )
397                     sTmp += '0';
398                 sTmp += String::CreateFromInt32( cChar, 16 );
399                 aVal.Replace( nI, 1 , sTmp );
400                 nI += sTmp.Len() - 1;
401             }
402         }
403 
404         if( aVal.Len() > (MAX_FIELDLEN - 4))
405             aVal.Erase( MAX_FIELDLEN - 4 );
406     }
407 
408     //e.g. inserting bookmark around field result, so we need to put
409     //it around the entire writer field, as we don't have the separation
410     //of field and field result of word, see #i16941#
411     SwPosition aStart(*pPaM->GetPoint());
412     if (!maFieldStack.empty())
413     {
414         const FieldEntry &rTest = maFieldStack.back();
415         aStart = rTest.maStartPos;
416     }
417 
418     const String sOrigName = BookmarkToWriter(*pName);
419     pReffedStck->NewAttr( aStart,
420                           SwFltBookmark( sOrigName, aVal, pB->GetHandle(), IsTOCBookmarkName( sOrigName ) ));
421     return 0;
422 }
423 
424 //----------------------------------------------------------------------
425 //    allgemeine Hilfsroutinen zum Auseinanderdroeseln der Parameter
426 //----------------------------------------------------------------------
427 
428 // ConvertFFileName uebersetzt FeldParameter-Namen u. ae. in den
429 // System-Zeichensatz.
430 // Gleichzeitig werden doppelte Backslashes in einzelne uebersetzt.
ConvertFFileName(String & rName,const String & rOrg)431 void SwWW8ImplReader::ConvertFFileName( String& rName, const String& rOrg )
432 {
433     rName = rOrg;
434     rName.SearchAndReplaceAllAscii( "\\\\", String( '\\' ));
435     rName.SearchAndReplaceAllAscii( "%20", String( ' ' ));
436 
437     // ggfs. anhaengende Anfuehrungszeichen entfernen
438     if( rName.Len() &&  '"' == rName.GetChar( rName.Len()-1 ))
439         rName.Erase( rName.Len()-1, 1);
440 
441     //#82900# Need the more sophisticated url converter. cmc
442     if (rName.Len())
443         rName = URIHelper::SmartRel2Abs(
444             INetURLObject(sBaseURL), rName, Link(), false);
445 }
446 
447 // ConvertUFNneme uebersetzt FeldParameter-Namen u. ae. in den
448 // System-Zeichensatz und Upcased sie ( z.B. fuer Ref-Felder )
449 namespace
450 {
ConvertUFName(String & rName)451     void ConvertUFName( String& rName )
452     {
453         GetAppCharClass().toUpper( rName );
454     }
455 }
456 
lcl_ConvertSequenceName(String & rSequenceName)457 static void lcl_ConvertSequenceName(String& rSequenceName)
458 {
459     ConvertUFName(rSequenceName);
460     if ('0' <= rSequenceName.GetChar(0) && '9' >= rSequenceName.GetChar(0))
461         rSequenceName.Insert('_', 0);
462 }
463 
464 // FindParaStart() finds 1st Parameter that follows '\' and cToken
465 // and returns start of this parameter or STRING_NOT_FOUND.
FindParaStart(const String & rStr,sal_Unicode cToken,sal_Unicode cToken2)466 xub_StrLen FindParaStart( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 )
467 {
468     bool bStr = false;          // innerhalb String ignorieren
469 
470     for( xub_StrLen nBuf=0; nBuf+1 < rStr.Len(); nBuf++ )
471     {
472         if( rStr.GetChar( nBuf ) == '"' )
473             bStr = !bStr;
474 
475         if(    !bStr
476             && rStr.GetChar( nBuf ) == '\\'
477             && (    rStr.GetChar( nBuf + 1 ) == cToken
478                  || rStr.GetChar( nBuf + 1 ) == cToken2 ) )
479         {
480             nBuf += 2;
481             // skip spaces between cToken and it's parameters
482             while(    nBuf < rStr.Len()
483                    && rStr.GetChar( nBuf ) == ' ' )
484                 nBuf++;
485             // return start of parameters
486             return nBuf < rStr.Len() ? nBuf : STRING_NOTFOUND;
487         }
488     }
489     return STRING_NOTFOUND;
490 }
491 
492 // FindPara() findet den ersten Parameter mit '\' und cToken. Es wird
493 // ein neuer String allokiert ( der vom Aufrufer deallokiert werden muss )
494 // und alles, was zum Parameter gehoert, wird in ihm zurueckgeliefert.
FindPara(const String & rStr,sal_Unicode cToken,sal_Unicode cToken2)495 String FindPara( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 )
496 {
497     xub_StrLen n2;                                          // Ende
498     xub_StrLen n = FindParaStart( rStr, cToken, cToken2 );  // Anfang
499     if( STRING_NOTFOUND == n )
500         return aEmptyStr;
501 
502     if(    rStr.GetChar( n ) == '"'
503         || rStr.GetChar( n ) == 132 )
504     {                               // Anfuehrungszeichen vor Para
505         n++;                        // Anfuehrungszeichen ueberlesen
506         n2 = n;                     // ab hier nach Ende suchen
507         while(     n2 < rStr.Len()
508                 && rStr.GetChar( n2 ) != 147
509                 && rStr.GetChar( n2 ) != '"' )
510             n2++;                   // Ende d. Paras suchen
511     }
512     else
513     {                           // keine Anfuehrungszeichen
514         n2 = n;                     // ab hier nach Ende suchen
515         while(     n2 < rStr.Len()
516                 && rStr.GetChar( n2 ) != ' ' )
517             n2++;                   // Ende d. Paras suchen
518     }
519     return rStr.Copy( n, n2-n );
520 }
521 
522 
GetNumTypeFromName(const String & rStr,bool bAllowPageDesc=false)523 static SvxExtNumType GetNumTypeFromName(const String& rStr,
524     bool bAllowPageDesc = false)
525 {
526     SvxExtNumType eTyp = bAllowPageDesc ? SVX_NUM_PAGEDESC : SVX_NUM_ARABIC;
527     if( rStr.EqualsIgnoreCaseAscii( "Arabi", 0, 5 ) )  // Arabisch, Arabic
528         eTyp = SVX_NUM_ARABIC;
529     else if( rStr.EqualsAscii( "misch", 2, 5 ) )    // r"omisch
530         eTyp = SVX_NUM_ROMAN_LOWER;
531     else if( rStr.EqualsAscii( "MISCH", 2, 5 ) )    // R"OMISCH
532         eTyp = SVX_NUM_ROMAN_UPPER;
533     else if( rStr.EqualsIgnoreCaseAscii( "alphabeti", 0, 9 ) )// alphabetisch, alphabetic
534         eTyp =  ( rStr.GetChar( 0 ) == 'A' )
535                 ? SVX_NUM_CHARS_UPPER_LETTER_N
536                 : SVX_NUM_CHARS_LOWER_LETTER_N;
537     else if( rStr.EqualsIgnoreCaseAscii( "roman", 0, 5 ) )  // us
538         eTyp =  ( rStr.GetChar( 0 ) == 'R' )
539                 ? SVX_NUM_ROMAN_UPPER
540                 : SVX_NUM_ROMAN_LOWER;
541     return eTyp;
542 }
543 
GetNumberPara(String & rStr,bool bAllowPageDesc=false)544 static SvxExtNumType GetNumberPara(String& rStr, bool bAllowPageDesc = false)
545 {
546     String s( FindPara( rStr, '*', '*' ) );     // Ziffernart
547     SvxExtNumType aType = GetNumTypeFromName( s, bAllowPageDesc );
548     return aType;
549 }
550 
551 
552 
553 
ForceFieldLanguage(SwField & rFld,sal_uInt16 nLang)554 bool SwWW8ImplReader::ForceFieldLanguage(SwField &rFld, sal_uInt16 nLang)
555 {
556     bool bRet(false);
557 
558     const SvxLanguageItem *pLang =
559         (const SvxLanguageItem*)GetFmtAttr(RES_CHRATR_LANGUAGE);
560     ASSERT(pLang, "impossible");
561     sal_uInt16 nDefault =  pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
562 
563     if (nLang != nDefault)
564     {
565         rFld.SetAutomaticLanguage(false);
566         rFld.SetLanguage(nLang);
567         bRet = true;
568     }
569 
570     return bRet;
571 }
572 
GetWordDefaultDateStringAsUS(SvNumberFormatter * pFormatter,sal_uInt16 nLang)573 String GetWordDefaultDateStringAsUS(SvNumberFormatter* pFormatter, sal_uInt16 nLang)
574 {
575     //Get the system date in the correct final language layout, convert to
576     //a known language and modify the 2 digit year part to be 4 digit, and
577     //convert back to the correct language layout.
578     sal_uLong nIndex = pFormatter->GetFormatIndex(NF_DATE_SYSTEM_SHORT, nLang);
579 
580     SvNumberformat aFormat = const_cast<SvNumberformat &>
581         (*(pFormatter->GetEntry(nIndex)));
582     aFormat.ConvertLanguage(*pFormatter, nLang, LANGUAGE_ENGLISH_US);
583 
584     String sParams(aFormat.GetFormatstring());
585     // --> OD 2007-02-09 #i36594#
586     // Fix provided by mloiseleur@openoffice.org.
587     // A default date can have already 4 year digits, in some case
588     const xub_StrLen pos = sParams.Search( CREATE_CONST_ASC("YYYY") );
589     if ( pos == STRING_NOTFOUND )
590     {
591         sParams.SearchAndReplace(CREATE_CONST_ASC("YY"), CREATE_CONST_ASC("YYYY"));
592     }
593     // <--
594     return sParams;
595 }
596 
GetTimeDatePara(String & rStr,sal_uInt32 & rFormat,sal_uInt16 & rLang,int nWhichDefault,bool bHijri)597 short SwWW8ImplReader::GetTimeDatePara(String& rStr, sal_uInt32& rFormat,
598     sal_uInt16 &rLang, int nWhichDefault, bool bHijri)
599 {
600     bool bRTL = false;
601     if (pPlcxMan && !bVer67)
602     {
603         const sal_uInt8 *pResult = pPlcxMan->HasCharSprm(0x85A);
604         if (pResult && *pResult)
605             bRTL = true;
606     }
607     RES_CHRATR eLang = bRTL ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
608     const SvxLanguageItem *pLang = (SvxLanguageItem*)GetFmtAttr( static_cast< sal_uInt16 >(eLang));
609     ASSERT(pLang, "impossible");
610     rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
611 
612     SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
613     String sParams( FindPara( rStr, '@', '@' ) );// Date/Time
614     if (!sParams.Len())
615     {
616         bool bHasTime = false;
617         switch (nWhichDefault)
618         {
619             case ww::ePRINTDATE:
620             case ww::eSAVEDATE:
621                 sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang);
622                 sParams.APPEND_CONST_ASC(" HH:MM:SS AM/PM");
623                 bHasTime = true;
624                 break;
625             case ww::eCREATEDATE:
626                 sParams.ASSIGN_CONST_ASC("DD/MM/YYYY HH:MM:SS");
627                 bHasTime = true;
628                 break;
629             default:
630             case ww::eDATE:
631                 sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang);
632                 break;
633         }
634 
635         if (bHijri)
636             sParams.Insert(CREATE_CONST_ASC("[~hijri]"), 0);
637 
638         sal_uInt16 nCheckPos = 0;
639         sal_Int16 nType = NUMBERFORMAT_DEFINED;
640         rFormat = 0;
641 
642         pFormatter->PutandConvertEntry(sParams, nCheckPos, nType, rFormat,
643             LANGUAGE_ENGLISH_US, rLang);
644 
645         return bHasTime ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE;
646     }
647 
648     sal_uLong nFmtIdx =
649         sw::ms::MSDateTimeFormatToSwFormat(sParams, pFormatter, rLang, bHijri);
650     short nNumFmtType = NUMBERFORMAT_UNDEFINED;
651     if (nFmtIdx)
652         nNumFmtType = pFormatter->GetType(nFmtIdx);
653     rFormat = nFmtIdx;
654 
655     return nNumFmtType;
656 }
657 
658 //-----------------------------------------
659 //              Felder
660 //-----------------------------------------
661 // Am Ende des Einlesens entsprechende Felder updaten ( z.Zt. die Referenzen )
UpdateFields()662 void SwWW8ImplReader::UpdateFields()
663 {
664 //  rDoc.GetSysFldType( RES_GETREFFLD )->UpdateFlds();  // Referenzen
665 //  rDoc.UpdateFlds();                                  // SetExp-Fields
666 //  rDoc.UpdateFlds();              // alles ???
667 //  rDoc.UpdateExpFlds();                               // SetExp-Fields
668     rDoc.SetUpdateExpFldStat(true);                 // JP: neu fuer alles wichtige
669     rDoc.SetInitDBFields(true);             // Datenbank-Felder auch
670 }
671 
End_Field()672 sal_uInt16 SwWW8ImplReader::End_Field()
673 {
674     sal_uInt16 nRet = 0;
675     WW8PLCFx_FLD* pF = pPlcxMan->GetFld();
676     ASSERT(pF, "WW8PLCFx_FLD - Pointer nicht da");
677     WW8_CP nCP = 0;
678     if (!pF || !pF->EndPosIsFieldEnd(nCP))
679         return nRet;
680 
681     const SvtFilterOptions* pOpt = SvtFilterOptions::Get();
682     sal_Bool bUseEnhFields=(pOpt && pOpt->IsUseEnhancedFields());
683 
684     ASSERT(!maFieldStack.empty(), "Empty field stack\n");
685     if (!maFieldStack.empty())
686     {
687         /*
688         only hyperlinks currently need to be handled like this, for the other
689         cases we have inserted a field not an attribute with an unknown end
690         point
691         */
692         nRet = maFieldStack.back().mnFieldId;
693         switch (nRet)
694         {
695         case 70:
696         if (bUseEnhFields && pPaM!=NULL && pPaM->GetPoint()!=NULL) {
697             SwPosition aEndPos = *pPaM->GetPoint();
698             SwPaM aFldPam( maFieldStack.back().GetPtNode(), maFieldStack.back().GetPtCntnt(), aEndPos.nNode, aEndPos.nContent.GetIndex());
699             IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess( );
700             IFieldmark *pFieldmark = dynamic_cast<IFieldmark*>( pMarksAccess->makeFieldBookmark(
701                         aFldPam, maFieldStack.back().GetBookmarkName(), ::rtl::OUString::createFromAscii(ODF_FORMTEXT ) ) );
702             ASSERT(pFieldmark!=NULL, "hmmm; why was the bookmark not created?");
703             if (pFieldmark!=NULL) {
704                 const IFieldmark::parameter_map_t& pParametersToAdd = maFieldStack.back().getParameters();
705                 pFieldmark->GetParameters()->insert(pParametersToAdd.begin(), pParametersToAdd.end());
706             }
707         }
708         break;
709             // Doing corresponding status management for TOX field, index field, hyperlink field and page reference field
710             case 13://TOX
711             case 8://index
712                 if ( mbLoadingTOXCache )
713                 {
714                     if ( mnEmbeddedTOXLevel > 0 )
715                     {
716                         --mnEmbeddedTOXLevel;
717                     }
718                     else
719                     {
720                         maTOXEndCps.insert( nCP );
721                         mbLoadingTOXCache = false;
722                         if ( pPaM->End()
723                              && pPaM->End()->nNode.GetNode().GetTxtNode()
724                              && pPaM->End()->nNode.GetNode().GetTxtNode()->Len() == 0 )
725                         {
726                             JoinNode( *pPaM );
727                         }
728                         else
729                         {
730                             mbCareLastParaEndInToc = true;
731                         }
732 
733                         if ( mpPosAfterTOC )
734                         {
735                             *pPaM = *mpPosAfterTOC;
736                             delete mpPosAfterTOC;
737                             mpPosAfterTOC = 0;
738                         }
739                     }
740                 }
741                 break;
742             case 37://REF
743                 if (mbLoadingTOXCache && !mbLoadingTOXHyperlink)
744                 {
745                     pCtrlStck->SetAttr(*pPaM->GetPoint(),RES_TXTATR_INETFMT);
746                 }
747                 break;
748             case 88:
749                 if (mbLoadingTOXHyperlink)
750                     mbLoadingTOXHyperlink = false;
751                 pCtrlStck->SetAttr(*pPaM->GetPoint(),RES_TXTATR_INETFMT);
752                 break;
753             case 36:
754             case 68:
755                 //Move outside the section associated with this type of field
756                 *pPaM->GetPoint() = maFieldStack.back().maStartPos;
757                 break;
758             default:
759                 break;
760         }
761         maFieldStack.pop_back();
762     }
763     return nRet;
764 }
765 
AcceptableNestedField(sal_uInt16 nFieldCode)766 bool AcceptableNestedField(sal_uInt16 nFieldCode)
767 {
768     switch (nFieldCode)
769     {
770         case 8:  // allow recursive field in TOC...
771         case 13: // allow recursive field in TOC...
772         case 36:
773         case 68:
774         case 79:
775         case 88:
776         // Accept AutoTextList field as nested field.
777         // Thus, the field result is imported as plain text.
778         case 89:
779             return true;
780         default:
781             return false;
782     }
783 }
784 
FieldEntry(SwPosition & rPos,sal_uInt16 nFieldId)785 FieldEntry::FieldEntry(SwPosition &rPos, sal_uInt16 nFieldId) throw()
786     : maStartPos(rPos), mnFieldId(nFieldId)
787 {
788 }
789 
FieldEntry(const FieldEntry & rOther)790 FieldEntry::FieldEntry(const FieldEntry &rOther) throw()
791     : maStartPos(rOther.maStartPos), mnFieldId(rOther.mnFieldId)
792 {
793 }
794 
Swap(FieldEntry & rOther)795 void FieldEntry::Swap(FieldEntry &rOther) throw()
796 {
797     std::swap(maStartPos, rOther.maStartPos);
798     std::swap(mnFieldId, rOther.mnFieldId);
799 }
800 
operator =(const FieldEntry & rOther)801 FieldEntry &FieldEntry::operator=(const FieldEntry &rOther) throw()
802 {
803     FieldEntry aTemp(rOther);
804     Swap(aTemp);
805     return *this;
806 }
807 
GetBookmarkName()808 ::rtl::OUString FieldEntry::GetBookmarkName()
809 {
810     return msBookmarkName;
811 }
812 
GetBookmarkType()813 ::rtl::OUString FieldEntry::GetBookmarkType()
814 {
815     return msMarkType;
816 }
817 
SetBookmarkName(::rtl::OUString bookmarkName)818 void FieldEntry::SetBookmarkName(::rtl::OUString bookmarkName)
819 {
820     msBookmarkName=bookmarkName;
821 }
822 
SetBookmarkType(::rtl::OUString bookmarkType)823 void FieldEntry::SetBookmarkType(::rtl::OUString bookmarkType)
824 {
825     msMarkType=bookmarkType;
826 }
827 
828 
getParameters()829 ::sw::mark::IFieldmark::parameter_map_t& FieldEntry::getParameters() {
830     return maParams;
831 }
832 
833 
834 // Read_Field liest ein Feld ein oder, wenn es nicht gelesen werden kann,
835 // wird 0 zurueckgegeben, so dass das Feld vom Aufrufer textuell gelesen wird.
836 // Returnwert: Gesamtlaenge des Feldes ( zum UEberlesen )
Read_Field(WW8PLCFManResult * pRes)837 long SwWW8ImplReader::Read_Field(WW8PLCFManResult* pRes)
838 {
839     typedef eF_ResT (SwWW8ImplReader:: *FNReadField)( WW8FieldDesc*, String& );
840     enum Limits {eMax = 96};
841     static FNReadField aWW8FieldTab[eMax+1] =
842     {
843         0,
844         0,
845         0,
846         &SwWW8ImplReader::Read_F_Ref,               // 3
847         0,
848         0,
849         &SwWW8ImplReader::Read_F_Set,               // 6
850         0,
851         &SwWW8ImplReader::Read_F_Tox,               // 8
852         0,
853         0,
854         0,
855         &SwWW8ImplReader::Read_F_Seq,               // 12
856         &SwWW8ImplReader::Read_F_Tox,               // 13
857         &SwWW8ImplReader::Read_F_DocInfo,           // 14
858         &SwWW8ImplReader::Read_F_DocInfo,           // 15
859         &SwWW8ImplReader::Read_F_DocInfo,           // 16
860         &SwWW8ImplReader::Read_F_Author,            // 17
861         &SwWW8ImplReader::Read_F_DocInfo,           // 18
862         &SwWW8ImplReader::Read_F_DocInfo,           // 19
863         &SwWW8ImplReader::Read_F_DocInfo,           // 20
864         &SwWW8ImplReader::Read_F_DocInfo,           // 21
865         &SwWW8ImplReader::Read_F_DocInfo,           // 22
866         &SwWW8ImplReader::Read_F_DocInfo,           // 23
867         &SwWW8ImplReader::Read_F_DocInfo,           // 24
868         &SwWW8ImplReader::Read_F_DocInfo,           // 25
869         &SwWW8ImplReader::Read_F_Anz,               // 26
870         &SwWW8ImplReader::Read_F_Anz,               // 27
871         &SwWW8ImplReader::Read_F_Anz,               // 28
872         &SwWW8ImplReader::Read_F_FileName,          // 29
873         &SwWW8ImplReader::Read_F_TemplName,         // 30
874         &SwWW8ImplReader::Read_F_DateTime,          // 31
875         &SwWW8ImplReader::Read_F_DateTime,          // 32
876         &SwWW8ImplReader::Read_F_CurPage,           // 33
877         0,
878         0,
879         &SwWW8ImplReader::Read_F_IncludeText,       // 36
880         &SwWW8ImplReader::Read_F_PgRef,             // 37
881         &SwWW8ImplReader::Read_F_InputVar,          // 38
882         &SwWW8ImplReader::Read_F_Input,             // 39
883         0,
884         &SwWW8ImplReader::Read_F_DBNext,            // 41
885         0,
886         0,
887         &SwWW8ImplReader::Read_F_DBNum,             // 44
888         0,
889         0,
890         0,
891         0,
892         &SwWW8ImplReader::Read_F_Equation,          // 49
893         0,
894         &SwWW8ImplReader::Read_F_Macro,             // 51
895         &SwWW8ImplReader::Read_F_ANumber,           // 52
896         &SwWW8ImplReader::Read_F_ANumber,           // 53
897         &SwWW8ImplReader::Read_F_ANumber,           // 54
898         0,
899 
900 
901         0,      // 56: VERKNUePFUNG     // fehlt noch !!!!!!!!!!!!!!!!!!!!!!!
902 
903 
904         &SwWW8ImplReader::Read_F_Symbol,            // 57
905         &SwWW8ImplReader::Read_F_Embedd,            // 58
906         &SwWW8ImplReader::Read_F_DBField,           // 59
907         0,
908         0,
909         0,
910         0,
911         0,
912         0,
913         0,
914         &SwWW8ImplReader::Read_F_IncludePicture,    // 67
915         &SwWW8ImplReader::Read_F_IncludeText,       // 68
916         0,
917         &SwWW8ImplReader::Read_F_FormTextBox,       // 70
918         &SwWW8ImplReader::Read_F_FormCheckBox,      // 71
919         &SwWW8ImplReader::Read_F_NoteReference,     // 72
920         0, /*&SwWW8ImplReader::Read_F_Tox*/
921         0,
922         0,
923         0,
924         0,
925         0,
926         0,
927         0,
928         0,
929         0,
930         &SwWW8ImplReader::Read_F_FormListBox,       // 83
931         0,                                          // 84
932         &SwWW8ImplReader::Read_F_DocInfo,           // 85
933         0,                                          // 86
934         &SwWW8ImplReader::Read_F_OCX,               // 87
935         &SwWW8ImplReader::Read_F_Hyperlink,         // 88
936         0,                                          // 89
937         0,                                          // 90
938         0,                                          // 91
939         0,                                          // 92
940         0,                                          // 93
941         0,                                          // 94
942         &SwWW8ImplReader::Read_F_Shape,             // 95
943         0                                           // eMax - Dummy leer Methode
944     };
945     ASSERT( ( sizeof( aWW8FieldTab ) / sizeof( *aWW8FieldTab ) == eMax+1 ),
946             "FeldFunc-Tabelle stimmt nicht" );
947 
948     WW8PLCFx_FLD* pF = pPlcxMan->GetFld();
949     ASSERT(pF, "WW8PLCFx_FLD - Pointer nicht da");
950 
951     if (!pF || !pF->StartPosIsFieldStart())
952         return 0;
953 
954     bool bNested = false;
955     if (!maFieldStack.empty())
956     {
957         mycFieldIter aEnd = maFieldStack.end();
958         for(mycFieldIter aIter = maFieldStack.begin(); aIter != aEnd; ++aIter)
959         {
960             bNested = !AcceptableNestedField(aIter->mnFieldId);
961             if (bNested)
962                 break;
963         }
964     }
965 
966     WW8FieldDesc aF;
967     bool bOk = pF->GetPara(pRes->nCp2OrIdx, aF);
968 
969     ASSERT(bOk, "WW8: Bad Field!\n");
970     if (aF.nId == 33) aF.bCodeNest=false; //#124716#: do not recurse into nested page fields
971 
972     maFieldStack.push_back(FieldEntry(*pPaM->GetPoint(), aF.nId));
973 
974     if (bNested)
975         return 0;
976 
977     sal_uInt16 n = (aF.nId <= eMax) ? aF.nId : static_cast<sal_uInt16>(eMax);
978     sal_uInt16 nI = n / 32;                     // # des sal_uInt32
979     sal_uLong nMask = 1 << ( n % 32 );          // Maske fuer Bits
980 
981     if ((sizeof(nFieldTagAlways)/sizeof(nFieldTagAlways[0])) <= nI)
982     {   // if indexes larger than 95 are needed, then a new configuration
983         // item has to be added, and nFieldTagAlways/nFieldTagBad expanded!
984         return aF.nLen;
985     }
986 
987     if( nFieldTagAlways[nI] & nMask )       // Flag: Tag it
988         return Read_F_Tag( &aF );           // Resultat nicht als Text
989 
990     if( !bOk || !aF.nId )                   // Feld kaputt
991         return aF.nLen;                     // -> ignorieren
992 
993     if( aF.nId > eMax - 1)                        // WW: Nested Field
994     {
995         if( nFieldTagBad[nI] & nMask )      // Flag: Tag it when bad
996             return Read_F_Tag( &aF );       // Resultat nicht als Text
997         else
998             return aF.nLen;
999     }
1000 
1001     //Only one type of field (hyperlink) in drawing textboxes exists
1002     if (aF.nId != 88 && pPlcxMan && pPlcxMan->GetDoingDrawTextBox())
1003         return aF.nLen;
1004 
1005     // keine Routine vorhanden
1006     if (bNested || !aWW8FieldTab[aF.nId] || aF.bCodeNest)
1007     {
1008         if( nFieldTagBad[nI] & nMask )      // Flag: Tag it when bad
1009             return Read_F_Tag( &aF );       // Resultat nicht als Text
1010                                             // Lese nur Resultat
1011         if (aF.bResNest && !AcceptableNestedField(aF.nId))
1012             return aF.nLen;                 // Result nested -> nicht brauchbar
1013 
1014         long nOldPos = pStrm->Tell();
1015         String aStr;
1016         aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+
1017             aF.nSCode, aF.nLCode, eTextCharSet );
1018         pStrm->Seek( nOldPos );
1019 
1020         //#124725# field codes which contain '/' or '.' are not displayed in WinWord
1021         // skip if it is formula field or found space before. see #i119446, #i119585.
1022         const xub_StrLen nDotPos = aStr.Search('.');
1023         const xub_StrLen nSlashPos = aStr.Search('/');
1024         xub_StrLen nSpacePos = aStr.Search( ' ', 1 );
1025         if ( nSpacePos == STRING_NOTFOUND )
1026             nSpacePos = aStr.Len();
1027 
1028         if ( !( aStr.EqualsAscii( "=", 1, 1 ) ) &&
1029             ((( nDotPos != STRING_NOTFOUND ) && ( nDotPos < nSpacePos )) ||
1030             (( nSlashPos != STRING_NOTFOUND ) && ( nSlashPos < nSpacePos ))))
1031             return aF.nLen;
1032         else
1033             return aF.nLen - aF.nLRes - 1;  // so viele ueberlesen, das Resultfeld
1034                                             // wird wie Haupttext eingelesen
1035     }
1036     else
1037     {                                   // Lies Feld
1038         long nOldPos = pStrm->Tell();
1039         String aStr;
1040         aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+
1041             aF.nSCode, aF.nLCode, eTextCharSet );
1042 
1043         // --> OD 2005-07-25 #i51312# - graphics inside field code not supported
1044         // by Writer. Thus, delete character 0x01, which stands for such a graphic.
1045         if (aF.nId==51) //#i56768# only do it for the MACROBUTTON field, since DropListFields need the 0x01.
1046         {
1047             aStr.EraseAllChars( 0x01 );
1048         }
1049         // <--
1050 
1051         eF_ResT eRes = (this->*aWW8FieldTab[aF.nId])( &aF, aStr );
1052         pStrm->Seek( nOldPos );
1053 
1054         switch ( eRes )
1055         {
1056             case FLD_OK:
1057                 return aF.nLen;                     // alles OK
1058             case FLD_TAGTXT:
1059                 if ((nFieldTagBad[nI] & nMask)) // Flag: Tag bad
1060                     return Read_F_Tag(&aF);       // Taggen
1061                 //fall through...
1062             case FLD_TEXT:
1063                 // so viele ueberlesen, das Resultfeld wird wie Haupttext
1064                 // eingelesen
1065                 // JP 15.07.99: attributes can start at char 0x14 so skip one
1066                 // char more back == "-2"
1067                 if (aF.nLRes)
1068                     return aF.nLen - aF.nLRes - 2;
1069                 else
1070                     return aF.nLen;
1071             case FLD_TAGIGN:
1072                 if(  ( nFieldTagBad[nI] & nMask ) ) // Flag: Tag bad
1073                     return Read_F_Tag( &aF );       // Taggen
1074                 return aF.nLen;                 // oder ignorieren
1075             case FLD_READ_FSPA:
1076                 return aF.nLen - aF.nLRes - 2; // auf Char 1 positionieren
1077             default:
1078                 return aF.nLen;                     // ignorieren
1079         }
1080     }
1081 }
1082 
1083 //-----------------------------------------
1084 //        Felder Taggen
1085 //-----------------------------------------
1086 
1087 // MakeTagString() gibt als Returnwert die Position des ersten
1088 // CR / Zeilenende / Seitenumbruch in pText und wandelt auch nur bis dort
1089 // Wenn keins dieser Sonderzeichen enthalten ist, wird 0 zurueckgeliefert.
MakeTagString(String & rStr,const String & rOrg)1090 void SwWW8ImplReader::MakeTagString( String& rStr, const String& rOrg )
1091 {
1092     String sHex( CREATE_CONST_ASC( "\\x" ));
1093     bool bAllowCr = SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_IN_TEXT )
1094                 || SwFltGetFlag( nFieldFlags, SwFltControlStack::ALLOW_FLD_CR );
1095     sal_Unicode cChar;
1096     rStr = rOrg;
1097 
1098     for( xub_StrLen nI = 0;
1099             nI < rStr.Len() && rStr.Len() < (MAX_FIELDLEN - 4); ++nI )
1100     {
1101         bool bSetAsHex = false;
1102         switch( cChar = rStr.GetChar( nI ) )
1103         {
1104             case 132:                       // Typographische Anfuehrungszeichen
1105             case 148:                       // gegen normale tauschen
1106             case 147:
1107                 rStr.SetChar( nI, '"' );
1108                 break;
1109             case 19:
1110                 rStr.SetChar( nI, '{' );
1111                 break;  // 19..21 zu {|}
1112             case 20:
1113                 rStr.SetChar( nI, '|' );
1114                 break;
1115             case 21:
1116                 rStr.SetChar( nI, '}' );
1117                 break;
1118             case '\\':                      // \{|} per \ Taggen
1119             case '{':
1120             case '|':
1121             case '}':
1122                 rStr.Insert( nI, '\\' );
1123                 ++nI;
1124                 break;
1125             case 0x0b:
1126             case 0x0c:
1127             case 0x0d:
1128                 if( bAllowCr )
1129                     rStr.SetChar( nI, '\n' );
1130                 else
1131                     bSetAsHex = true;
1132                 break;
1133             case 0xFE:
1134             case 0xFF:
1135                 bSetAsHex = true;
1136                 break;
1137             default:
1138                 bSetAsHex = 0x20 > cChar;
1139                 break;
1140         }
1141 
1142         if( bSetAsHex )
1143         {
1144             //all Hex-Numbers with \x before
1145             String sTmp( sHex );
1146             if( cChar < 0x10 )
1147                 sTmp += '0';
1148             sTmp += String::CreateFromInt32( cChar, 16 );
1149             rStr.Replace( nI, 1 , sTmp );
1150             nI += sTmp.Len() - 1;
1151         }
1152     }
1153 
1154     if( rStr.Len() > (MAX_FIELDLEN - 4))
1155         rStr.Erase( MAX_FIELDLEN - 4 );
1156 }
1157 
InsertTagField(const sal_uInt16 nId,const String & rTagText)1158 void SwWW8ImplReader::InsertTagField( const sal_uInt16 nId, const String& rTagText )
1159 {
1160     String aName( CREATE_CONST_ASC( "WwFieldTag" ) );
1161     if( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_DO_ID ) ) // Nummer?
1162         aName += String::CreateFromInt32( nId );                    // ausgeben ?
1163 
1164     if( SwFltGetFlag(nFieldFlags, SwFltControlStack::TAGS_IN_TEXT))
1165     {
1166         aName += rTagText;      // als Txt taggen
1167         rDoc.InsertString(*pPaM, aName,
1168                 IDocumentContentOperations::INS_NOHINTEXPAND);
1169     }
1170     else
1171     {                                                   // normal tagggen
1172 
1173         SwFieldType* pFT = rDoc.InsertFldType(
1174                                 SwSetExpFieldType( &rDoc, aName, nsSwGetSetExpType::GSE_STRING ) );
1175         SwSetExpField aFld( (SwSetExpFieldType*)pFT, rTagText );                            // SUB_INVISIBLE
1176         sal_uInt16 nSubType = ( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_VISIBLE ) ) ? 0 : nsSwExtendedSubType::SUB_INVISIBLE;
1177         aFld.SetSubType(nSubType | nsSwGetSetExpType::GSE_STRING);
1178 
1179         rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1180     }
1181 }
1182 
Read_F_Tag(WW8FieldDesc * pF)1183 long SwWW8ImplReader::Read_F_Tag( WW8FieldDesc* pF )
1184 {
1185     long nOldPos = pStrm->Tell();
1186 
1187     WW8_CP nStart = pF->nSCode - 1;         // mit 0x19 am Anfang
1188     long nL = pF->nLen;                     // Gesamtlaenge mit Resultat u. Nest
1189     if( nL > MAX_FIELDLEN )
1190         nL = MAX_FIELDLEN;                  // MaxLaenge, durch Quoten
1191                                             // max. 4* so gross
1192     String sFTxt;
1193     nL = pSBase->WW8ReadString( *pStrm, sFTxt,
1194                                 pPlcxMan->GetCpOfs() + nStart, nL, eStructCharSet);
1195 
1196 
1197     String aTagText;
1198     MakeTagString( aTagText, sFTxt );
1199     InsertTagField( pF->nId, aTagText );
1200 
1201     pStrm->Seek( nOldPos );
1202     return pF->nLen;
1203 }
1204 
1205 
1206 //-----------------------------------------
1207 //        normale Felder
1208 //-----------------------------------------
1209 
Read_F_Input(WW8FieldDesc * pF,String & rStr)1210 eF_ResT SwWW8ImplReader::Read_F_Input( WW8FieldDesc* pF, String& rStr )
1211 {
1212     String aDef;
1213     String aQ;
1214     long nRet;
1215     _ReadFieldParams aReadParam( rStr );
1216     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1217     {
1218         switch( nRet )
1219         {
1220         case -2:
1221             if( !aQ.Len() )
1222                 aQ = aReadParam.GetResult();
1223             break;
1224         case 'd':
1225         case 'D':
1226             {
1227                 xub_StrLen n = aReadParam.GoToTokenParam();
1228                 if( STRING_NOTFOUND != n )
1229                     aDef = aReadParam.GetResult();
1230             }
1231             break;
1232         }
1233     }
1234     if( !aDef.Len() )
1235         aDef = GetFieldResult( pF );
1236 
1237     SwInputField aFld( static_cast<SwInputFieldType*>(rDoc.GetSysFldType( RES_INPUTFLD )),
1238                         aDef, aQ, INP_TXT, 0, false );
1239     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1240 
1241     return FLD_OK;
1242 }
1243 
1244 // GetFieldResult alloziert einen String und liest das Feld-Resultat ein
GetFieldResult(WW8FieldDesc * pF)1245 String SwWW8ImplReader::GetFieldResult( WW8FieldDesc* pF )
1246 {
1247     long nOldPos = pStrm->Tell();
1248 
1249     WW8_CP nStart = pF->nSRes;              // Start Resultat
1250     long nL = pF->nLRes;                    // Laenge Resultat
1251     if( !nL )
1252         return aEmptyStr;                           // kein Resultat
1253 
1254     if( nL > MAX_FIELDLEN )
1255         nL = MAX_FIELDLEN;                  // MaxLaenge, durch Quoten
1256                                             // max. 4* so gross
1257 
1258     String sRes;
1259     nL = pSBase->WW8ReadString( *pStrm, sRes, pPlcxMan->GetCpOfs() + nStart,
1260                                 nL, eStructCharSet );
1261 
1262     pStrm->Seek( nOldPos );
1263 
1264     //replace CR 0x0D with LF 0x0A
1265     sRes.SearchAndReplaceAll(0x0D, 0x0A);
1266     //replace VT 0x0B with LF 0x0A
1267     sRes.SearchAndReplaceAll(0x0B, 0x0A);
1268     return sRes;
1269 }
1270 
1271 /*
1272 Bookmarks can be set with fields SET and ASK, and they can be referenced with
1273 REF. When set, they behave like variables in writer, otherwise they behave
1274 like normal bookmarks. We can check whether we should use a show variable
1275 instead of a normal bookmark ref by converting to "show variable" at the end
1276 of the document those refs which look for the content of a bookmark but whose
1277 bookmarks were set with SET or ASK. (See SwWW8FltRefStack)
1278 
1279 The other piece of the puzzle is that refs that point to the "location" of the
1280 bookmark will in word actually point to the last location where the bookmark
1281 was set with SET or ASK, not the actual bookmark. This is only noticeable when
1282 a document sets the bookmark more than once. This is because word places the
1283 true bookmark at the location of the last set, but the refs will display the
1284 position of the first set before the ref.
1285 
1286 So what we will do is
1287 
1288 1) keep a list of all bookmarks that were set, any bookmark names mentioned
1289 here that are refed by content will be converted to show variables.
1290 
1291 2) create pseudo bookmarks for every position that a bookmark is set with SET
1292 or ASK but has no existing bookmark. We can then keep a map from the original
1293 bookmark name to the new one. As we parse the document new pseudo names will
1294 replace the older ones, so the map always contains the bookmark of the
1295 location that msword itself would use.
1296 
1297 3) word's bookmarks are case insensitive, writers are not. So we need to
1298 map case different versions together, regardless of whether they are
1299 variables or not.
1300 
1301 4) when a reference is (first) SET or ASK, the bookmark associated with it
1302 is placed around the 0x14 0x15 result part of the field. We will fiddle
1303 the placement to be the writer equivalent of directly before and after
1304 the field, which gives the same effect and meaning, to do so we must
1305 get any bookmarks in the field range, and begin them immediately before
1306 the set/ask field, and end them directly afterwards. MapBookmarkVariables
1307 returns an identifier of the bookmark attribute to close after inserting
1308 the appropriate set/ask field.
1309 */
MapBookmarkVariables(const WW8FieldDesc * pF,String & rOrigName,const String & rData)1310 long SwWW8ImplReader::MapBookmarkVariables(const WW8FieldDesc* pF,
1311     String &rOrigName, const String &rData)
1312 {
1313     ASSERT(pPlcxMan,"No pPlcxMan");
1314     long nNo;
1315     /*
1316     If there was no bookmark associated with this set field, then we create a
1317     pseudo one and insert it in the document.
1318     */
1319     sal_uInt16 nIndex;
1320     pPlcxMan->GetBook()->MapName(rOrigName);
1321     String sName = pPlcxMan->GetBook()->GetBookmark(
1322         pF->nSCode, pF->nSCode + pF->nLen, nIndex);
1323     if (sName.Len())
1324     {
1325         pPlcxMan->GetBook()->SetStatus(nIndex, BOOK_IGNORE);
1326         nNo = nIndex;
1327     }
1328     else
1329     {
1330         sName = CREATE_CONST_ASC("WWSetBkmk");
1331         nNo = pReffingStck->aFieldVarNames.size()+1;
1332         sName += String::CreateFromInt32(nNo);
1333         nNo += pPlcxMan->GetBook()->GetIMax();
1334     }
1335     pReffedStck->NewAttr(*pPaM->GetPoint(),
1336         SwFltBookmark( BookmarkToWriter(sName), rData, nNo ));
1337     pReffingStck->aFieldVarNames[rOrigName] = sName;
1338     return nNo;
1339 }
1340 
1341 /*
1342 Word can set a bookmark with set or with ask, such a bookmark is equivalent to
1343 our variables, but until the end of a document we cannot be sure if a bookmark
1344 is a variable or not, at the end we will have a list of reference names which
1345 were set or asked, all bookmarks using the content of those bookmarks are
1346 converted to show variables, those that reference the position of the field
1347 can be left as references, because a bookmark is also inserted at the position
1348 of a set or ask field, either by word, or in some special cases by the import
1349 filter itself.
1350 */
RefToVar(const SwField * pFld,SwFltStackEntry * pEntry)1351 SwFltStackEntry *SwWW8FltRefStack::RefToVar(const SwField* pFld,
1352     SwFltStackEntry *pEntry)
1353 {
1354     SwFltStackEntry *pRet=0;
1355     if (pFld && RES_GETREFFLD == pFld->Which())
1356     {
1357         //Get the name of the ref field, and see if actually a variable
1358         const String &rName = pFld->GetPar1();
1359         ::std::map<String,String,SwWW8::ltstr>::const_iterator
1360             aResult = aFieldVarNames.find(rName);
1361 
1362         if (aResult != aFieldVarNames.end())
1363         {
1364             SwGetExpField aFld( (SwGetExpFieldType*)
1365                 pDoc->GetSysFldType(RES_GETEXPFLD), rName, nsSwGetSetExpType::GSE_STRING, 0);
1366             delete pEntry->pAttr;
1367             SwFmtFld aTmp(aFld);
1368             pEntry->pAttr = aTmp.Clone();
1369             pRet = pEntry;
1370         }
1371     }
1372     return pRet;
1373 }
1374 
GetMappedBookmark(const String & rOrigName)1375 String SwWW8ImplReader::GetMappedBookmark(const String &rOrigName)
1376 {
1377     String sName(BookmarkToWriter(rOrigName));
1378     ASSERT(pPlcxMan,"no pPlcxMan");
1379     pPlcxMan->GetBook()->MapName(sName);
1380 
1381     //See if there has been a variable set with this name, if so get
1382     //the pseudo bookmark name that was set with it.
1383     ::std::map<String,String,SwWW8::ltstr>::const_iterator aResult =
1384             pReffingStck->aFieldVarNames.find(sName);
1385 
1386     const String &rBkmName = (aResult == pReffingStck->aFieldVarNames.end())
1387         ? sName : (*aResult).second;
1388 
1389     return rBkmName;
1390 }
1391 
1392 // "ASK"
Read_F_InputVar(WW8FieldDesc * pF,String & rStr)1393 eF_ResT SwWW8ImplReader::Read_F_InputVar( WW8FieldDesc* pF, String& rStr )
1394 {
1395     String sOrigName;
1396     String aQ;
1397     String aDef;
1398     long nRet;
1399     _ReadFieldParams aReadParam( rStr );
1400     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1401     {
1402         switch( nRet )
1403         {
1404         case -2:
1405             if (!sOrigName.Len())
1406                 sOrigName = aReadParam.GetResult();
1407             else if( !aQ.Len() )
1408                 aQ = aReadParam.GetResult();
1409             break;
1410         case 'd':
1411         case 'D':
1412             if (STRING_NOTFOUND != aReadParam.GoToTokenParam())
1413                 aDef = aReadParam.GetResult();
1414             break;
1415         }
1416     }
1417 
1418     if( !sOrigName.Len() )
1419         return FLD_TAGIGN;  // macht ohne Textmarke keinen Sinn
1420 
1421     String aResult(GetFieldResult(pF));
1422 
1423     //#i24377#, munge Default Text into title as we have only one slot
1424     //available for aResult and aDef otherwise
1425     if (aDef.Len())
1426     {
1427         if (aQ.Len())
1428             aQ.APPEND_CONST_ASC(" - ");
1429         aQ.Append(aDef);
1430     }
1431 
1432     long nNo = MapBookmarkVariables(pF, sOrigName, aResult);
1433 
1434     SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType(
1435         SwSetExpFieldType(&rDoc, sOrigName, nsSwGetSetExpType::GSE_STRING));
1436     SwSetExpField aFld(pFT, aResult);
1437     aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING);
1438     aFld.SetInputFlag(true);
1439     aFld.SetPromptText( aQ );
1440 
1441     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1442 
1443     pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo);
1444     return FLD_OK;
1445 }
1446 
1447 // "AUTONR"
Read_F_ANumber(WW8FieldDesc *,String & rStr)1448 eF_ResT SwWW8ImplReader::Read_F_ANumber( WW8FieldDesc*, String& rStr )
1449 {
1450     if( !pNumFldType ){     // 1. Mal
1451         SwSetExpFieldType aT( &rDoc, CREATE_CONST_ASC("AutoNr"), nsSwGetSetExpType::GSE_SEQ );
1452         pNumFldType = rDoc.InsertFldType( aT );
1453     }
1454     SwSetExpField aFld( (SwSetExpFieldType*)pNumFldType, aEmptyStr,
1455                         GetNumberPara( rStr ) );
1456     aFld.SetValue( ++nFldNum );
1457     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1458     return FLD_OK;
1459 }
1460 
1461 // "SEQ"
Read_F_Seq(WW8FieldDesc *,String & rStr)1462 eF_ResT SwWW8ImplReader::Read_F_Seq( WW8FieldDesc*, String& rStr )
1463 {
1464     String aSequenceName;
1465     String aBook;
1466     bool bHidden    = false;
1467     bool bFormat    = false;
1468     bool bShowLast  = false;
1469     bool bCountOn   = true;
1470     String sStart;
1471     SvxExtNumType eNumFormat = SVX_NUM_ARABIC;
1472     long nRet;
1473     _ReadFieldParams aReadParam( rStr );
1474     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1475     {
1476         switch( nRet )
1477         {
1478         case -2:
1479             if( !aSequenceName.Len() )
1480                 aSequenceName = aReadParam.GetResult();
1481             else if( !aBook.Len() )
1482                 aBook = aReadParam.GetResult();
1483             break;
1484 
1485         case 'h':
1486             if( !bFormat )
1487                 bHidden = true;             // Hidden-Flag aktivieren
1488             break;
1489 
1490         case '*':
1491             bFormat = true;                 // Format-Flag aktivieren
1492             bHidden = false;                // Hidden-Flag deaktivieren
1493             nRet = aReadParam.SkipToNextToken();
1494             if( -2 == nRet && !( aReadParam.GetResult().EqualsAscii("MERGEFORMAT") || aReadParam.GetResult().EqualsAscii("CHARFORMAT") ))
1495                 eNumFormat = GetNumTypeFromName( aReadParam.GetResult() );
1496             break;
1497 
1498         case 'r':
1499             bShowLast = false;              // Zaehler neu setzen
1500             bCountOn  = false;
1501             nRet = aReadParam.SkipToNextToken();
1502             if( -2 == nRet )
1503                 sStart = aReadParam.GetResult();
1504             break;
1505 
1506         case 'c':
1507             bShowLast = true;           // zuletzt verwendete Nummer anzeigen
1508             bCountOn  = false;
1509             break;
1510 
1511         case 'n':
1512             bCountOn  = true;               // Nummer um eins erhoehen (default)
1513             bShowLast = false;
1514             break;
1515 
1516         case 's':                       // Outline Level
1517             //#i19682, what am I to do with this value
1518             break;
1519         }
1520     }
1521     if (!aSequenceName.Len() && !aBook.Len())
1522         return FLD_TAGIGN;
1523 
1524     SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType(
1525                         SwSetExpFieldType( &rDoc, aSequenceName, nsSwGetSetExpType::GSE_SEQ ) );
1526     SwSetExpField aFld( pFT, aEmptyStr, eNumFormat );
1527 
1528 	//Bug 120654: Add for /h flag(/h: Hiden the field result.)
1529 	if (bHidden)
1530 	aFld.SetSubType(aFld.GetSubType() | nsSwExtendedSubType::SUB_INVISIBLE);
1531 	//Bug 120654(End)
1532 
1533 
1534     if (sStart.Len())
1535         aFld.SetFormula( ( aSequenceName += '=' ) += sStart );
1536     else if (!bCountOn)
1537         aFld.SetFormula(aSequenceName);
1538 
1539     rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1540     return FLD_OK;
1541 }
1542 
Read_F_DocInfo(WW8FieldDesc * pF,String & rStr)1543 eF_ResT SwWW8ImplReader::Read_F_DocInfo( WW8FieldDesc* pF, String& rStr )
1544 {
1545     sal_uInt16 nSub=0;
1546     // RegInfoFormat, DefaultFormat fuer DocInfoFelder
1547     sal_uInt16 nReg = DI_SUB_AUTHOR;
1548     bool bDateTime = false;
1549 
1550     if( 85 == pF->nId )
1551     {
1552         String aDocProperty;
1553         _ReadFieldParams aReadParam( rStr );
1554         long nRet;
1555         while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1556         {
1557             switch( nRet )
1558             {
1559                 case -2:
1560                     if( !aDocProperty.Len() )
1561                         aDocProperty = aReadParam.GetResult();
1562                     break;
1563                 case '*':
1564                     //Skip over MERGEFORMAT
1565                     aReadParam.SkipToNextToken();
1566                     break;
1567             }
1568         }
1569         aDocProperty.EraseAllChars('"');
1570 
1571         /*
1572         There are up to 26 fields that may be meant by 'DocumentProperty'.
1573         Which of them is to be inserted here ?
1574         This Problem can only be solved by implementing a name matching
1575         method that compares the given Parameter String with the four
1576         possible name sets (english, german, french, spanish)
1577         */
1578 
1579         static const sal_Char* aName10 = "\x0F"; // SW field code
1580         static const sal_Char* aName11 // German
1581             = "TITEL";
1582         static const sal_Char* aName12 // French
1583             = "TITRE";
1584         static const sal_Char* aName13 // English
1585             = "TITLE";
1586         static const sal_Char* aName14 // Spanish
1587             = "TITRO";
1588         static const sal_Char* aName20 = "\x15"; // SW filed code
1589         static const sal_Char* aName21 // German
1590             = "ERSTELLDATUM";
1591         static const sal_Char* aName22 // French
1592             = "CR\xC9\xC9";
1593         static const sal_Char* aName23 // English
1594             = "CREATED";
1595         static const sal_Char* aName24 // Spanish
1596             = "CREADO";
1597         static const sal_Char* aName30 = "\x16"; // SW filed code
1598         static const sal_Char* aName31 // German
1599             = "ZULETZTGESPEICHERTZEIT";
1600         static const sal_Char* aName32 // French
1601             = "DERNIERENREGISTREMENT";
1602         static const sal_Char* aName33 // English
1603             = "SAVED";
1604         static const sal_Char* aName34 // Spanish
1605             = "MODIFICADO";
1606         static const sal_Char* aName40 = "\x17"; // SW filed code
1607         static const sal_Char* aName41 // German
1608             = "ZULETZTGEDRUCKT";
1609         static const sal_Char* aName42 // French
1610             = "DERNI\xC8" "REIMPRESSION";
1611         static const sal_Char* aName43 // English
1612             = "LASTPRINTED";
1613         static const sal_Char* aName44 // Spanish
1614             = "HUPS PUPS";
1615         static const sal_Char* aName50 = "\x18"; // SW filed code
1616         static const sal_Char* aName51 // German
1617             = "\xDC" "BERARBEITUNGSNUMMER";
1618         static const sal_Char* aName52 // French
1619             = "NUM\xC9" "RODEREVISION";
1620         static const sal_Char* aName53 // English
1621             = "REVISIONNUMBER";
1622         static const sal_Char* aName54 // Spanish
1623             = "SNUBBEL BUBBEL";
1624         static const sal_uInt16 nFldCnt  = 5;
1625 
1626         // additional fields are to be coded soon!   :-)
1627 
1628         static const sal_uInt16 nLangCnt = 4;
1629         static const sal_Char *aNameSet_26[nFldCnt][nLangCnt+1] =
1630         {
1631             {aName10, aName11, aName12, aName13, aName14},
1632             {aName20, aName21, aName22, aName23, aName24},
1633             {aName30, aName31, aName32, aName33, aName34},
1634             {aName40, aName41, aName42, aName43, aName44},
1635             {aName50, aName51, aName52, aName53, aName54}
1636         };
1637 
1638         bool bFldFound= false;
1639         sal_uInt16 nFIdx;
1640         for(sal_uInt16 nLIdx=1; !bFldFound && (nLangCnt > nLIdx); ++nLIdx)
1641         {
1642             for(nFIdx = 0;  !bFldFound && (nFldCnt  > nFIdx); ++nFIdx)
1643             {
1644                 if( aDocProperty.Equals( String( aNameSet_26[nFIdx][nLIdx],
1645                     RTL_TEXTENCODING_MS_1252 ) ) )
1646                 {
1647                     bFldFound = true;
1648                     pF->nId   = aNameSet_26[nFIdx][0][0];
1649                 }
1650             }
1651         }
1652 
1653         if( !bFldFound )
1654         {
1655 /*
1656             SwUserFieldType aTmp( &rDoc, aDocProperty );
1657             aTmp.SetContent(GetFieldResult( pF ));
1658             SwUserField aUFld( (SwUserFieldType*)rDoc.InsertFldType( aTmp ));
1659             aUFld.ChangeFormat( UF_STRING );
1660             rDoc.Insert( *pPaM, SwFmtFld( aUFld ), 0);
1661 */
1662             SwDocInfoField aFld( (SwDocInfoFieldType*)
1663                 rDoc.GetSysFldType( RES_DOCINFOFLD ), DI_CUSTOM|nReg, aDocProperty, GetFieldResult( pF ) );
1664             rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1665 
1666             return FLD_OK;
1667         }
1668     }
1669 
1670     switch( pF->nId )
1671     {
1672         case 14:
1673             /* kann alle INFO-Vars!! */
1674             nSub = DI_KEYS;
1675             break;
1676         case 15:
1677             nSub = DI_TITEL;
1678             break;
1679         case 16:
1680             nSub = DI_THEMA;
1681             break;
1682         case 18:
1683             nSub = DI_KEYS;
1684             break;
1685         case 19:
1686             nSub = DI_COMMENT;
1687             break;
1688         case 20:
1689             nSub = DI_CHANGE;
1690             nReg = DI_SUB_AUTHOR;
1691             break;
1692         case 21:
1693             nSub = DI_CREATE;
1694             nReg = DI_SUB_DATE;
1695             bDateTime = true;
1696             break;
1697         case 23:
1698             nSub = DI_PRINT;
1699             nReg = DI_SUB_DATE;
1700             bDateTime = true;
1701             break;
1702         case 24:
1703             nSub = DI_DOCNO;
1704             break;
1705         case 22:
1706             nSub = DI_CHANGE;
1707             nReg = DI_SUB_DATE;
1708             bDateTime = true;
1709             break;
1710         case 25:
1711             nSub = DI_CHANGE;
1712             nReg = DI_SUB_TIME;
1713             bDateTime = true;
1714             break;
1715     }
1716 
1717     sal_uInt32 nFormat = 0;
1718 
1719     sal_uInt16 nLang(0);
1720     if (bDateTime)
1721     {
1722         short nDT = GetTimeDatePara(rStr, nFormat, nLang, pF->nId);
1723         switch (nDT)
1724         {
1725             case NUMBERFORMAT_DATE:
1726                 nReg = DI_SUB_DATE;
1727                 break;
1728             case NUMBERFORMAT_TIME:
1729                 nReg = DI_SUB_TIME;
1730                 break;
1731             case NUMBERFORMAT_DATETIME:
1732                 nReg = DI_SUB_DATE;
1733                 break;
1734             default:
1735                 nReg = DI_SUB_DATE;
1736                 break;
1737         }
1738     }
1739 
1740     SwDocInfoField aFld( (SwDocInfoFieldType*)
1741         rDoc.GetSysFldType( RES_DOCINFOFLD ), nSub|nReg, String(), nFormat );
1742     if (bDateTime)
1743         ForceFieldLanguage(aFld, nLang);
1744     rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1745 
1746     return FLD_OK;
1747 }
1748 
Read_F_Author(WW8FieldDesc *,String &)1749 eF_ResT SwWW8ImplReader::Read_F_Author( WW8FieldDesc*, String& )
1750 {
1751         // SH: Das SwAuthorField bezeichnet nicht den urspruenglichen
1752         // Autor, sondern den aktuellen Benutzer, also besser ueber DocInfo
1753         // (#56149)
1754     SwDocInfoField aFld( (SwDocInfoFieldType*)
1755                      rDoc.GetSysFldType( RES_DOCINFOFLD ),
1756                      DI_CREATE|DI_SUB_AUTHOR, String() );
1757     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1758     return FLD_OK;
1759 }
1760 
Read_F_TemplName(WW8FieldDesc *,String &)1761 eF_ResT SwWW8ImplReader::Read_F_TemplName( WW8FieldDesc*, String& )
1762 {
1763     SwTemplNameField aFld( (SwTemplNameFieldType*)
1764                      rDoc.GetSysFldType( RES_TEMPLNAMEFLD ), FF_NAME );
1765     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1766     return FLD_OK;
1767 }
1768 
1769 // Sowohl das Datum- wie auch das Uhrzeit-Feld kann fuer Datum, fuer Uhrzeit
1770 // oder fuer beides benutzt werden.
Read_F_DateTime(WW8FieldDesc * pF,String & rStr)1771 eF_ResT SwWW8ImplReader::Read_F_DateTime( WW8FieldDesc*pF, String& rStr )
1772 {
1773     bool bHijri = false;
1774     bool bSaka = false;
1775     _ReadFieldParams aReadParam(rStr);
1776     long nTok;
1777     while (-1 != (nTok = aReadParam.SkipToNextToken()))
1778     {
1779         switch (nTok)
1780         {
1781             default:
1782             case 'l':
1783             case -2:
1784                 break;
1785             case 'h':
1786                 bHijri = true;
1787                 break;
1788             case 's':
1789                 bSaka = true;
1790                 break;
1791         }
1792     }
1793 
1794     sal_uInt32 nFormat = 0;
1795 
1796     sal_uInt16 nLang(0);
1797     short nDT = GetTimeDatePara(rStr, nFormat, nLang, ww::eDATE, bHijri);
1798 
1799     if( NUMBERFORMAT_UNDEFINED == nDT )             // no D/T-Formatstring
1800     {
1801         if (32 == pF->nId)
1802         {
1803             nDT     = NUMBERFORMAT_TIME;
1804             nFormat = rDoc.GetNumberFormatter()->GetFormatIndex(
1805                         NF_TIME_START, LANGUAGE_SYSTEM );
1806         }
1807         else
1808         {
1809             nDT     = NUMBERFORMAT_DATE;
1810             nFormat = rDoc.GetNumberFormatter()->GetFormatIndex(
1811                         NF_DATE_START, LANGUAGE_SYSTEM );
1812         }
1813     }
1814 
1815     if (nDT & NUMBERFORMAT_DATE)
1816     {
1817         SwDateTimeField aFld((SwDateTimeFieldType*)
1818             rDoc.GetSysFldType(RES_DATETIMEFLD ), DATEFLD, nFormat);
1819         ForceFieldLanguage(aFld, nLang);
1820         rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1821     }
1822     else if (nDT == NUMBERFORMAT_TIME)
1823     {
1824         SwDateTimeField aFld((SwDateTimeFieldType*)
1825             rDoc.GetSysFldType(RES_DATETIMEFLD), TIMEFLD, nFormat);
1826         ForceFieldLanguage(aFld, nLang);
1827         rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1828     }
1829 
1830     return FLD_OK;
1831 }
1832 
Read_F_FileName(WW8FieldDesc *,String & rStr)1833 eF_ResT SwWW8ImplReader::Read_F_FileName(WW8FieldDesc*, String &rStr)
1834 {
1835     SwFileNameFormat eType = FF_NAME;
1836     long nRet;
1837     _ReadFieldParams aReadParam(rStr);
1838     while (-1 != (nRet = aReadParam.SkipToNextToken()))
1839     {
1840         switch (nRet)
1841         {
1842             case 'p':
1843                 eType = FF_PATHNAME;
1844                 break;
1845             case '*':
1846                 //Skip over MERGEFORMAT
1847                 aReadParam.SkipToNextToken();
1848                 break;
1849             default:
1850                 ASSERT(sal_False, "unknown option in FileName field");
1851                 break;
1852         }
1853     }
1854 
1855     SwFileNameField aFld(
1856         (SwFileNameFieldType*)rDoc.GetSysFldType(RES_FILENAMEFLD), eType);
1857     rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
1858     return FLD_OK;
1859 }
1860 
Read_F_Anz(WW8FieldDesc * pF,String & rStr)1861 eF_ResT SwWW8ImplReader::Read_F_Anz( WW8FieldDesc* pF, String& rStr )
1862 {                                               // SeitenZahl - Feld
1863     sal_uInt16 nSub = DS_PAGE;
1864     switch ( pF->nId ){
1865     case 27: nSub = DS_WORD; break;             // Wordzahl
1866     case 28: nSub = DS_CHAR; break;             // Zeichenzahl
1867     }
1868     SwDocStatField aFld( (SwDocStatFieldType*)
1869                          rDoc.GetSysFldType( RES_DOCSTATFLD ), nSub,
1870                          GetNumberPara( rStr ) );
1871     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1872     return FLD_OK;
1873 }
1874 
Read_F_CurPage(WW8FieldDesc *,String & rStr)1875 eF_ResT SwWW8ImplReader::Read_F_CurPage( WW8FieldDesc*, String& rStr )
1876 {
1877     // zusaetzlich mit Kapitelnummer?
1878     if( bPgChpLevel )
1879     {
1880         SwChapterField aFld( (SwChapterFieldType*)
1881                     rDoc.GetSysFldType( RES_CHAPTERFLD ), CF_NUMBER );
1882         aFld.SetLevel( nPgChpLevel );
1883         rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1884 
1885         static const sal_Char aDelim[] = "-.:\x97\x96";
1886         sal_uInt8 nDelim = nPgChpDelim;
1887         if( nDelim > 4 )
1888             nDelim = 0;
1889 
1890         sal_Unicode c = ByteString::ConvertToUnicode( aDelim[ nDelim ],
1891                                         RTL_TEXTENCODING_MS_1252 );
1892         if( '-' == c )
1893         {
1894             rDoc.InsertString( *pPaM, CHAR_HARDHYPHEN );
1895         }
1896         else
1897         {
1898             rDoc.InsertString( *pPaM, c ); // maybe insert ZWNBSP?
1899         }
1900     }
1901 
1902     // Seitennummer
1903     SwPageNumberField aFld( (SwPageNumberFieldType*)
1904         rDoc.GetSysFldType( RES_PAGENUMBERFLD ), PG_RANDOM,
1905         GetNumberPara(rStr, true));
1906 
1907     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
1908     return FLD_OK;
1909 }
1910 
Read_F_Symbol(WW8FieldDesc *,String & rStr)1911 eF_ResT SwWW8ImplReader::Read_F_Symbol( WW8FieldDesc*, String& rStr )
1912 {
1913     //e.g. #i20118#
1914     String aQ;
1915     String aName;
1916     sal_Int32 nSize = 0;
1917     long nRet;
1918     _ReadFieldParams aReadParam( rStr );
1919     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1920     {
1921         switch( nRet )
1922         {
1923         case -2:
1924             if( !aQ.Len() )
1925                 aQ = aReadParam.GetResult();
1926             break;
1927         case 'f':
1928         case 'F':
1929             {
1930                 xub_StrLen n = aReadParam.GoToTokenParam();
1931                 if( STRING_NOTFOUND != n )
1932                     aName = aReadParam.GetResult();
1933             }
1934             break;
1935         case 's':
1936         case 'S':
1937             {
1938                 String aSiz;
1939                 xub_StrLen n = aReadParam.GoToTokenParam();
1940                 if (STRING_NOTFOUND != n)
1941                     aSiz = aReadParam.GetResult();
1942                 if (aSiz.Len())
1943                     nSize = aSiz.ToInt32() * 20; // pT -> twip
1944             }
1945             break;
1946         }
1947     }
1948     if( !aQ.Len() )
1949         return FLD_TAGIGN;                      // -> kein 0-Zeichen in Text
1950 
1951     if (sal_Unicode cChar = static_cast<sal_Unicode>(aQ.ToInt32()))
1952     {
1953         if (aName.Len())                           // Font Name set ?
1954         {
1955             SvxFontItem aFont(FAMILY_DONTKNOW, aName, aEmptyStr,
1956                 PITCH_DONTKNOW, RTL_TEXTENCODING_SYMBOL, RES_CHRATR_FONT);
1957             NewAttr(aFont);                       // new Font
1958         }
1959 
1960         if (nSize > 0)  //#i20118#
1961         {
1962             SvxFontHeightItem aSz(nSize, 100, RES_CHRATR_FONTSIZE);
1963             NewAttr(aSz);
1964         }
1965 
1966         rDoc.InsertString(*pPaM, cChar);
1967 
1968         if (nSize > 0)
1969             pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONTSIZE);
1970         if (aName.Len())
1971             pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONT);
1972     }
1973     else
1974     {
1975         rDoc.InsertString(*pPaM, CREATE_CONST_ASC("###"));
1976     }
1977 
1978     return FLD_OK;
1979 }
1980 
1981 // "EINBETTEN"
Read_F_Embedd(WW8FieldDesc *,String & rStr)1982 eF_ResT SwWW8ImplReader::Read_F_Embedd( WW8FieldDesc*, String& rStr )
1983 {
1984     String sHost;
1985 
1986     long nRet;
1987     _ReadFieldParams aReadParam( rStr );
1988     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
1989     {
1990         switch( nRet )
1991         {
1992         case -2:
1993             sHost = aReadParam.GetResult();
1994             break;
1995 
1996         case 's':
1997             // use ObjectSize
1998             break;
1999         }
2000     }
2001 
2002     if( bObj && nPicLocFc )
2003         nObjLocFc = nPicLocFc;
2004     bEmbeddObj = true;
2005     return FLD_TEXT;
2006 }
2007 
2008 
2009 // "SET"
Read_F_Set(WW8FieldDesc * pF,String & rStr)2010 eF_ResT SwWW8ImplReader::Read_F_Set( WW8FieldDesc* pF, String& rStr )
2011 {
2012     String sOrigName;
2013     String sVal;
2014     long nRet;
2015     _ReadFieldParams aReadParam( rStr );
2016     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2017     {
2018         switch( nRet )
2019         {
2020         case -2:
2021             if( !sOrigName.Len() )
2022                 sOrigName = aReadParam.GetResult();
2023             else if( !sVal.Len() )
2024                 sVal = aReadParam.GetResult();
2025             break;
2026         }
2027     }
2028 
2029     long nNo = MapBookmarkVariables(pF,sOrigName,sVal);
2030 
2031     SwFieldType* pFT = rDoc.InsertFldType( SwSetExpFieldType( &rDoc, sOrigName,
2032         nsSwGetSetExpType::GSE_STRING ) );
2033     SwSetExpField aFld( (SwSetExpFieldType*)pFT, sVal, ULONG_MAX );
2034     aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING);
2035 
2036     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2037 
2038     pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo);
2039 
2040     return FLD_OK;
2041 }
2042 
2043 // "REF"
Read_F_Ref(WW8FieldDesc *,String & rStr)2044 eF_ResT SwWW8ImplReader::Read_F_Ref( WW8FieldDesc*, String& rStr )
2045 {                                                       // Reference - Field
2046     String sOrigBkmName;
2047     bool bChapterNr = false;
2048     bool bAboveBelow = false;
2049 
2050     long nRet;
2051     _ReadFieldParams aReadParam( rStr );
2052     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2053     {
2054         switch( nRet )
2055         {
2056         case -2:
2057             if( !sOrigBkmName.Len() ) // get name of bookmark
2058                 sOrigBkmName = aReadParam.GetResult();
2059             break;
2060         case 'n':
2061         case 'r':
2062         case 'w':
2063             bChapterNr = true; // activate flag 'Chapter Number'
2064             break;
2065 
2066         case 'p':
2067             bAboveBelow = true;
2068             break;
2069         case 'h':
2070             break;
2071         default:
2072             // unimplemented switch: just do 'nix nought nothing'  :-)
2073             break;
2074         }
2075     }
2076 
2077     String sBkmName(GetMappedBookmark(sOrigBkmName));
2078 
2079     if (!bAboveBelow || bChapterNr)
2080     {
2081         if (bChapterNr)
2082         {
2083             SwGetRefField aFld(
2084                 (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ),
2085                 sBkmName,REF_BOOKMARK,0,REF_CHAPTER);
2086             rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2087         }
2088         else
2089         {
2090             /*
2091             If we are just inserting the contents of the bookmark, then it
2092             is possible that the bookmark is actually a variable, so we
2093             must store it until the end of the document to see if it was,
2094             in which case we'll turn it into a show variable
2095             */
2096             SwGetRefField aFld(
2097                 (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ),
2098                 sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT);
2099             pReffingStck->NewAttr( *pPaM->GetPoint(), SwFmtFld(aFld) );
2100             pReffingStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_FIELD);
2101         }
2102     }
2103 
2104     if( bAboveBelow )
2105     {
2106         SwGetRefField aFld( (SwGetRefFieldType*)
2107             rDoc.GetSysFldType( RES_GETREFFLD ), sBkmName, REF_BOOKMARK, 0,
2108             REF_UPDOWN );
2109         rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
2110     }
2111     return FLD_OK;
2112 }
2113 
2114 // Note Reference - Field
Read_F_NoteReference(WW8FieldDesc *,String & rStr)2115 eF_ResT SwWW8ImplReader::Read_F_NoteReference( WW8FieldDesc*, String& rStr )
2116 {
2117     String aBkmName;
2118     bool bChapterNr = false;
2119     bool bAboveBelow = false;
2120 
2121     long nRet;
2122     _ReadFieldParams aReadParam( rStr );
2123     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2124     {
2125         switch( nRet )
2126         {
2127         case -2:
2128             if( !aBkmName.Len() ) // get name of foot/endnote
2129                 aBkmName = aReadParam.GetResult();
2130             break;
2131         case 'r':
2132             bChapterNr = true; // activate flag 'Chapter Number'
2133             break;
2134         case 'p':
2135             bAboveBelow = true;
2136             break;
2137         case 'h':
2138             break;
2139         default:
2140             // unimplemented switch: just do 'nix nought nothing'  :-)
2141             break;
2142         }
2143     }
2144 
2145     // set Sequence No of corresponding Foot-/Endnote to Zero
2146     // (will be corrected in
2147     SwGetRefField aFld( (SwGetRefFieldType*)
2148         rDoc.GetSysFldType( RES_GETREFFLD ), aBkmName, REF_FOOTNOTE, 0,
2149         REF_ONLYNUMBER );
2150     pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld));
2151     pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD);
2152     if (bAboveBelow)
2153     {
2154         SwGetRefField aFld2( (SwGetRefFieldType*)
2155             rDoc.GetSysFldType( RES_GETREFFLD ),aBkmName, REF_FOOTNOTE, 0,
2156             REF_UPDOWN );
2157         pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld2));
2158         pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD);
2159     }
2160     return FLD_OK;
2161 }
2162 
2163 // "SEITENREF"
Read_F_PgRef(WW8FieldDesc *,String & rStr)2164 eF_ResT SwWW8ImplReader::Read_F_PgRef( WW8FieldDesc*, String& rStr )
2165 {
2166     String sOrigName;
2167     long nRet;
2168     _ReadFieldParams aReadParam( rStr );
2169     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2170     {
2171         if ( nRet == -2 &&
2172              !sOrigName.Len() )
2173         {
2174             sOrigName = aReadParam.GetResult();
2175         }
2176     }
2177 
2178     const String sName(GetMappedBookmark(sOrigName));
2179 
2180     // loading page reference field in TOX
2181     if (mbLoadingTOXCache )
2182     {
2183         // insert page ref representation as plain text --> return FLD_TEXT
2184         // if there is no hyperlink settings for current toc and referenced bookmark is available,
2185         // assign link to current ref area
2186         if ( !mbLoadingTOXHyperlink && sName.Len() > 0 )
2187         {
2188             // #120879# add cross reference bookmark name prefix, if it matches internal TOC bookmark naming convention
2189             String sBookmarkName;
2190             if ( IsTOCBookmarkName( sName ) )
2191             {
2192                 sBookmarkName = String( IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix() );
2193                 sBookmarkName += sName;
2194                 // track <sBookmarkName> as referenced TOC bookmark.
2195                 pReffedStck->aReferencedTOCBookmarks.insert( sBookmarkName );
2196             }
2197             else
2198             {
2199                 sBookmarkName = sName;
2200             }
2201             String sURL = INET_MARK_TOKEN;
2202             sURL += sBookmarkName;
2203             const String sTarget;
2204             SwFmtINetFmt aURL( sURL, sTarget );
2205             const String sLinkStyle = String::CreateFromAscii("Index Link");
2206             const sal_uInt16 nPoolId =
2207                 SwStyleNameMapper::GetPoolIdFromUIName( sLinkStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
2208             aURL.SetVisitedFmtAndId( sLinkStyle, nPoolId);
2209             aURL.SetINetFmtAndId( sLinkStyle, nPoolId );
2210             pCtrlStck->NewAttr( *pPaM->GetPoint(), aURL );
2211         }
2212         return FLD_TEXT;
2213     }
2214 
2215     // #120879# add cross reference bookmark name prefix, if it matches internal TOC bookmark naming convention
2216     String sPageRefBookmarkName;
2217     if ( IsTOCBookmarkName( sName ) )
2218     {
2219         sPageRefBookmarkName = IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix();
2220         sPageRefBookmarkName += sName;
2221         // track <sPageRefBookmarkName> as referenced TOC bookmark.
2222         pReffedStck->aReferencedTOCBookmarks.insert( sPageRefBookmarkName );
2223     }
2224     else
2225     {
2226         sPageRefBookmarkName = sName;
2227     }
2228     SwGetRefField aFld( (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ),
2229                         sPageRefBookmarkName, REF_BOOKMARK, 0, REF_PAGE );
2230     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2231 
2232     return FLD_OK;
2233 }
2234 //helper function
2235 //For MS MacroButton field, the symbol in plain text is always "(" (0x28),
2236 //which should be mapped according to the macro type
ConvertMacroSymbol(const String & rName,String & rReference)2237 bool ConvertMacroSymbol( const String& rName, String& rReference )
2238 {
2239 	bool bConverted = false;
2240 	if( rReference.EqualsAscii( "(" ) )
2241 	{
2242 		bConverted = true;
2243 		sal_Unicode cSymbol = 0x0000;
2244 		if( rName.EqualsAscii( "CheckIt" ) )
2245 			cSymbol = 0xF06F;
2246 		else if( rName.EqualsAscii( "UncheckIt" ) )
2247 			cSymbol = 0xF0FE;
2248 		else if( rName.EqualsAscii( "ShowExample" ) )
2249 			cSymbol = 0xF02A;
2250 		//else if... : todo
2251 		else
2252 			bConverted = false;
2253 
2254 		if( bConverted )
2255 			rReference = cSymbol;
2256 	}
2257 	return bConverted;
2258 }
2259 //end
2260 
2261 // "MACROSCHALTFL"ACHE"
Read_F_Macro(WW8FieldDesc *,String & rStr)2262 eF_ResT SwWW8ImplReader::Read_F_Macro( WW8FieldDesc*, String& rStr)
2263 {
2264     String aName;
2265     String aVText;
2266     long nRet;
2267     bool bNewVText = true;
2268     bool bBracket  = false;
2269     _ReadFieldParams aReadParam( rStr );
2270 
2271     xub_StrLen nOffset = 0;
2272 
2273     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2274     {
2275         switch( nRet )
2276         {
2277         case -2:
2278             if( !aName.Len() )
2279                 aName = aReadParam.GetResult();
2280             else if( !aVText.Len() || bBracket )
2281             {
2282                 nOffset = aReadParam.GetTokenSttPtr() + 1;
2283 
2284                 if( bBracket )
2285                     aVText += ' ';
2286                 aVText += aReadParam.GetResult();
2287                 if (bNewVText)
2288                 {
2289                     bBracket = aVText.EqualsIgnoreCaseAscii('[', 1, 0)
2290                         ? true : false;
2291                     bNewVText = false;
2292                 }
2293                 else if( aVText.GetChar( aVText.Len()-1 ) == ']' )
2294                     bBracket  = false;
2295             }
2296             break;
2297         }
2298     }
2299     if( !aName.Len() )
2300         return FLD_TAGIGN;  // makes no sense without Makro-Name
2301 
2302 	//try converting macro symbol according to macro name
2303 	bool bApplyWingdings = ConvertMacroSymbol( aName, aVText );
2304     aName.InsertAscii( "StarOffice.Standard.Modul1.", 0 );
2305 
2306     SwMacroField aFld( (SwMacroFieldType*)
2307                     rDoc.GetSysFldType( RES_MACROFLD ), aName, aVText );
2308 
2309 	if( !bApplyWingdings )
2310 	{
2311 
2312 		rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2313 		WW8_CP nOldCp = pPlcxMan->Where();
2314 		WW8_CP nCp = nOldCp + nOffset;
2315 
2316 		SwPaM aPaM(*pPaM);
2317 		aPaM.SetMark();
2318 		aPaM.Move(fnMoveBackward);
2319 		aPaM.Exchange();
2320 
2321 		mpPostProcessAttrsInfo = new WW8PostProcessAttrsInfo(nCp, nCp, aPaM);
2322 	}
2323 	else
2324 	{
2325 		//set Wingdings font
2326 		sal_uInt16 i = 0;
2327 		for ( ; i < pFonts->GetMax(); i++ )
2328 		{
2329 			FontFamily eFamily;
2330 			String aFontName;
2331 			FontPitch ePitch;
2332 			CharSet eSrcCharSet;
2333 			if( GetFontParams( i, eFamily, aFontName, ePitch, eSrcCharSet )
2334 				&& aFontName.EqualsAscii("Wingdings") )
2335 			{
2336 				break;
2337 			}
2338 		}
2339 
2340 		if ( i < pFonts->GetMax() )
2341 		{
2342 
2343 			SetNewFontAttr( i, true, RES_CHRATR_FONT );
2344 			rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2345 			pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_CHRATR_FONT );
2346 			ResetCharSetVars();
2347 		}
2348 	}
2349 
2350     return FLD_OK;
2351 }
2352 
WW8PostProcessAttrsInfo(WW8_CP nCpStart,WW8_CP nCpEnd,SwPaM & rPaM)2353 WW8PostProcessAttrsInfo::WW8PostProcessAttrsInfo(WW8_CP nCpStart, WW8_CP nCpEnd,
2354                                                  SwPaM & rPaM)
2355 : mbCopy(false),
2356   mnCpStart(nCpStart),
2357   mnCpEnd(nCpEnd),
2358   mPaM(*rPaM.GetPoint(), *rPaM.GetMark()),
2359   mItemSet(rPaM.GetDoc()->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END - 1)
2360 {
2361 }
2362 
CanUseRemoteLink(const String & rGrfName)2363 bool CanUseRemoteLink(const String &rGrfName)
2364 {
2365     bool bUseRemote = false;
2366     try
2367     {
2368         ::ucbhelper::Content aCnt(rGrfName,
2369             uno::Reference<
2370             ucb::XCommandEnvironment >() );
2371         rtl::OUString   aTitle;
2372 
2373         aCnt.getPropertyValue(rtl::OUString::createFromAscii("Title" ))
2374             >>= aTitle;
2375         bUseRemote = (aTitle.getLength() > 0);
2376     }
2377     catch ( ... )
2378     {
2379         // this file did not exist, so we will not set this as graphiclink
2380         bUseRemote = false;
2381     }
2382     return bUseRemote;
2383 }
2384 
2385 // "EINF"UGENGRAFIK"
Read_F_IncludePicture(WW8FieldDesc *,String & rStr)2386 eF_ResT SwWW8ImplReader::Read_F_IncludePicture( WW8FieldDesc*, String& rStr )
2387 {
2388     String aGrfName;
2389     bool bEmbedded = true;
2390 
2391     long nRet;
2392     _ReadFieldParams aReadParam( rStr );
2393     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2394     {
2395         switch( nRet )
2396         {
2397         case -2:
2398             if (!aGrfName.Len())
2399                 ConvertFFileName(aGrfName, aReadParam.GetResult());
2400             break;
2401 
2402         case 'd':
2403             bEmbedded = false;          // Embedded-Flag deaktivieren
2404             break;
2405 
2406         case 'c':// den Converter-Namen ueberlesen
2407             aReadParam.FindNextStringPiece();
2408             break;
2409         }
2410     }
2411 
2412     if (!bEmbedded)
2413         bEmbedded = !CanUseRemoteLink(aGrfName);
2414 
2415     if (!bEmbedded)
2416     {
2417         /*
2418             Besonderheit:
2419 
2420             Wir setzen jetzt den Link ins Doc und merken uns den SwFlyFrmFmt.
2421             Da wir ja unten auf jjeden Fall mit Return-Wert FLD_READ_FSPA enden,
2422             wird der Skip-Wert so bemessen, dass das folgende Char-1 eingelesen
2423             wird.
2424             Wenn wir dann in SwWW8ImplReader::ImportGraf() reinlaufen, wird
2425             erkannt, dass wir soeben einen Grafik-Link inserted haben und
2426             das passende SwAttrSet wird ins Frame-Format eingesetzt.
2427         */
2428         SfxItemSet aFlySet( rDoc.GetAttrPool(), RES_FRMATR_BEGIN,
2429             RES_FRMATR_END-1 );
2430         aFlySet.Put( SwFmtAnchor( FLY_AS_CHAR ) );
2431         aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
2432         pFlyFmtOfJustInsertedGraphic = rDoc.Insert( *pPaM,
2433                                                     aGrfName,
2434                                                     aEmptyStr,
2435                                                     0,          // Graphic*
2436                                                     &aFlySet,
2437                                                     0, 0);         // SwFrmFmt*
2438         maGrfNameGenerator.SetUniqueGraphName(pFlyFmtOfJustInsertedGraphic,
2439             INetURLObject(aGrfName).GetBase());
2440     }
2441     return FLD_READ_FSPA;
2442 }
2443 
2444 
UniqueName()2445 String wwSectionNamer::UniqueName()
2446 {
2447     String aName(msFileLinkSeed);
2448     aName += String::CreateFromInt32(++mnFileSectionNo);
2449     return mrDoc.GetUniqueSectionName(&aName);
2450 }
2451 
2452 // "EINFUEGENTEXT"
Read_F_IncludeText(WW8FieldDesc *,String & rStr)2453 eF_ResT SwWW8ImplReader::Read_F_IncludeText( WW8FieldDesc* /*pF*/, String& rStr )
2454 {
2455     String aPara;
2456     String aBook;
2457     long nRet;
2458     _ReadFieldParams aReadParam( rStr );
2459     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2460     {
2461         switch( nRet )
2462         {
2463             case -2:
2464                 if( !aPara.Len() )
2465                     aPara = aReadParam.GetResult();
2466                 else if( !aBook.Len() )
2467                     aBook = aReadParam.GetResult();
2468                 break;
2469             case '*':
2470                 //Skip over MERGEFORMAT
2471                 aReadParam.SkipToNextToken();
2472                 break;
2473         }
2474     }
2475     ConvertFFileName(aPara, aPara);
2476 
2477     if (aBook.Len() && aBook.GetChar( 0 ) != '\\')
2478     {
2479         // Bereich aus Quelle ( kein Switch ) ?
2480         ConvertUFName(aBook);
2481         aPara += sfx2::cTokenSeperator;
2482         aPara += sfx2::cTokenSeperator;
2483         aPara += aBook;
2484     }
2485 
2486     /*
2487     ##509##
2488     What we will do is insert a section to be linked to a file, but just in
2489     case the file is not available we will fill in the section with the stored
2490     content of this winword field as a fallback.
2491     */
2492     SwPosition aTmpPos(*pPaM->GetPoint());
2493 
2494     SwSectionData aSection(FILE_LINK_SECTION,
2495             maSectionNameGenerator.UniqueName());
2496     aSection.SetLinkFileName( aPara );
2497     aSection.SetProtectFlag(true);
2498 
2499     SwSection *const pSection =
2500         rDoc.InsertSwSection(*pPaM, aSection, 0, 0, false);
2501     ASSERT(pSection, "no section inserted");
2502     if (!pSection)
2503         return FLD_TEXT;
2504     const SwSectionNode* pSectionNode = pSection->GetFmt()->GetSectionNode();
2505     ASSERT(pSectionNode, "no section node!");
2506     if (!pSectionNode)
2507         return FLD_TEXT;
2508 
2509     pPaM->GetPoint()->nNode = pSectionNode->GetIndex()+1;
2510     pPaM->GetPoint()->nContent.Assign(pPaM->GetCntntNode(), 0 );
2511 
2512     //we have inserted a section before this point, so adjust pos
2513     //for future page/section segment insertion
2514     maSectionManager.PrependedInlineNode(aTmpPos, *pPaM->GetNode());
2515 
2516     return FLD_TEXT;
2517 }
2518 
2519 // "SERIENDRUCKFELD"
Read_F_DBField(WW8FieldDesc * pF,String & rStr)2520 eF_ResT SwWW8ImplReader::Read_F_DBField( WW8FieldDesc* pF, String& rStr )
2521 {
2522     String aName;
2523     long nRet;
2524     _ReadFieldParams aReadParam( rStr );
2525     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
2526     {
2527         switch( nRet )
2528         {
2529         case -2:
2530             if( !aName.Len() )
2531                 aName = aReadParam.GetResult();
2532             break;
2533         }
2534     }
2535     SwDBFieldType aD( &rDoc, aName, SwDBData() );   // Datenbank: Nichts
2536 
2537     SwFieldType* pFT = rDoc.InsertFldType( aD );
2538     SwDBField aFld( (SwDBFieldType*)pFT );
2539     aFld.SetFieldCode( rStr );
2540 
2541     String aResult;
2542     pSBase->WW8ReadString( *pStrm, aResult, pPlcxMan->GetCpOfs()+
2543                            pF->nSRes, pF->nLRes, eTextCharSet );
2544 
2545     aFld.InitContent(aResult);
2546 
2547     rDoc.InsertPoolItem(*pPaM, SwFmtFld( aFld ), 0);
2548 
2549     return FLD_OK;
2550 }
2551 
2552 // "N"ACHSTER"
Read_F_DBNext(WW8FieldDesc *,String &)2553 eF_ResT SwWW8ImplReader::Read_F_DBNext( WW8FieldDesc*, String& )
2554 {
2555     SwDBNextSetFieldType aN;
2556     SwFieldType* pFT = rDoc.InsertFldType( aN );
2557     SwDBNextSetField aFld( (SwDBNextSetFieldType*)pFT, aEmptyStr, aEmptyStr,
2558                             SwDBData() );       // Datenbank: Nichts
2559     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2560     return FLD_OK;
2561 }
2562 
2563 // "DATENSATZ"
Read_F_DBNum(WW8FieldDesc *,String &)2564 eF_ResT SwWW8ImplReader::Read_F_DBNum( WW8FieldDesc*, String& )
2565 {
2566     SwDBSetNumberFieldType aN;
2567     SwFieldType* pFT = rDoc.InsertFldType( aN );
2568     SwDBSetNumberField aFld( (SwDBSetNumberFieldType*)pFT,
2569                            SwDBData() );            // Datenbank: Nichts
2570     rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 );
2571     return FLD_OK;
2572 }
2573 
2574 /*
2575     EQ , only the usage for
2576     a. Combined Characters supported, must be exactly in the form that word
2577     only accepts as combined charactersm, i.e.
2578     eq \o(\s\up Y(XXX),\s\do Y(XXX))
2579     b. Ruby Text supported, must be in the form that word recognizes as being
2580     ruby text
2581     ...
2582 */
Read_F_Equation(WW8FieldDesc *,String & rStr)2583 eF_ResT SwWW8ImplReader::Read_F_Equation( WW8FieldDesc*, String& rStr )
2584 {
2585     _ReadFieldParams aReadParam( rStr );
2586     long cChar = aReadParam.SkipToNextToken();
2587     if ('o' == cChar || 'O' == cChar)
2588         Read_SubF_Combined(aReadParam);
2589     else if ('*' == cChar)
2590         Read_SubF_Ruby(aReadParam);
2591     return FLD_OK;
2592 }
2593 
Read_SubF_Combined(_ReadFieldParams & rReadParam)2594 void SwWW8ImplReader::Read_SubF_Combined( _ReadFieldParams& rReadParam)
2595 {
2596     String sCombinedCharacters;
2597     _ReadFieldParams aOriFldParam = rReadParam;
2598     long cGetChar = rReadParam.SkipToNextToken();
2599     switch( cGetChar )
2600     {
2601     case 'a':
2602     case 'A':
2603         {
2604             String sTemp = rReadParam.GetResult();
2605             if ( !sTemp.EqualsIgnoreCaseAscii("d", 1, 0) )
2606             {
2607                 break;
2608             }
2609             rReadParam.SkipToNextToken();
2610         }
2611     case -2:
2612         {
2613             if ( rReadParam.GetResult().EqualsIgnoreCaseAscii('(', 1, 0) )
2614             {
2615                 for (int i=0;i<2;i++)
2616                 {
2617                     if ('s' == rReadParam.SkipToNextToken())
2618                     {
2619                         long cChar = rReadParam.SkipToNextToken();
2620                         if (-2 != rReadParam.SkipToNextToken())
2621                             break;
2622                         String sF = rReadParam.GetResult();
2623                         if ((('u' == cChar) && sF.EqualsIgnoreCaseAscii('p', 1, 0))
2624                             || (('d' == cChar) && sF.EqualsIgnoreCaseAscii('o', 1, 0)))
2625                         {
2626                             if (-2 == rReadParam.SkipToNextToken())
2627                             {
2628                                 String sPart = rReadParam.GetResult();
2629                                 xub_StrLen nBegin = sPart.Search('(');
2630 
2631                                 //Word disallows brackets in this field, which
2632                                 //aids figuring out the case of an end of )) vs )
2633                                 xub_StrLen nEnd = sPart.Search(')');
2634 
2635                                 if ((nBegin != STRING_NOTFOUND) &&
2636                                     (nEnd != STRING_NOTFOUND))
2637                                 {
2638                                     sCombinedCharacters +=
2639                                         sPart.Copy(nBegin+1,nEnd-nBegin-1);
2640                                 }
2641                             }
2642                         }
2643                     }
2644                 }
2645                 if (sCombinedCharacters.Len())
2646                 {
2647                     SwCombinedCharField aFld((SwCombinedCharFieldType*)
2648                         rDoc.GetSysFldType(RES_COMBINED_CHARS),sCombinedCharacters);
2649                     rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0);
2650                 }
2651                 else
2652                 {
2653                     const String sPart = aOriFldParam.GetResult();
2654                     xub_StrLen nBegin = sPart.Search('(');
2655                     xub_StrLen nEnd = sPart.Search(',');
2656                     if ( nEnd == STRING_NOTFOUND )
2657                     {
2658                         nEnd = sPart.Search(')');
2659                     }
2660                     if ( (nBegin != STRING_NOTFOUND) && (nEnd != STRING_NOTFOUND) )
2661                     {
2662                         // skip certain leading characters
2663                         for (int i = nBegin;i < nEnd-1;i++)
2664                         {
2665                             const sal_Unicode cC = sPart.GetChar(nBegin+1);
2666                             if ( cC < 32 )
2667                             {
2668                                 nBegin++;
2669                             }
2670                             else
2671                                 break;
2672                         }
2673                         sCombinedCharacters = sPart.Copy( nBegin+1, nEnd-nBegin-1 );
2674                         if ( sCombinedCharacters.Len() )
2675                         {
2676                             SwInputField aFld( static_cast<SwInputFieldType*>(rDoc.GetSysFldType( RES_INPUTFLD )),
2677                                 sCombinedCharacters, sCombinedCharacters, INP_TXT, 0, false );
2678                             rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); // insert input field
2679                         }
2680                     }
2681                 }
2682             }
2683         }
2684     default:
2685         break;
2686     }
2687 }
2688 
Read_SubF_Ruby(_ReadFieldParams & rReadParam)2689 void SwWW8ImplReader::Read_SubF_Ruby( _ReadFieldParams& rReadParam)
2690 {
2691     sal_uInt16 nJustificationCode=0;
2692     String sFontName;
2693     sal_uInt32 nFontSize=0;
2694     String sRuby;
2695     String sText;
2696     long nRet;
2697     while( -1 != ( nRet = rReadParam.SkipToNextToken() ))
2698     {
2699         switch( nRet )
2700         {
2701         case -2:
2702             {
2703                 String sTemp = rReadParam.GetResult();
2704                 if( sTemp.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
2705                 {
2706                     sTemp.Erase(0,2);
2707                     nJustificationCode = static_cast<sal_uInt16>(sTemp.ToInt32());
2708                 }
2709                 else if( sTemp.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
2710                 {
2711                     sTemp.Erase(0,3);
2712                     nFontSize= static_cast<sal_uInt32>(sTemp.ToInt32());
2713                 }
2714                 else if( sTemp.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
2715                 {
2716                     sTemp.Erase(0,5);
2717                     sFontName = sTemp;
2718                 }
2719             }
2720             break;
2721         case '*':
2722             break;
2723         case 'o':
2724             while( -1 != ( nRet = rReadParam.SkipToNextToken() ))
2725             {
2726                 if ('u' == nRet)
2727                 {
2728                     if (-2 == rReadParam.SkipToNextToken() &&
2729                       (rReadParam.GetResult().EqualsIgnoreCaseAscii('p', 1, 0)))
2730                     {
2731                         if (-2 == rReadParam.SkipToNextToken())
2732                         {
2733                             String sPart = rReadParam.GetResult();
2734                             xub_StrLen nBegin = sPart.Search('(');
2735 
2736                             //Word disallows brackets in this field,
2737                             xub_StrLen nEnd = sPart.Search(')');
2738 
2739                             if ((nBegin != STRING_NOTFOUND) &&
2740                                 (nEnd != STRING_NOTFOUND))
2741                             {
2742                                 sRuby = sPart.Copy(nBegin+1,nEnd-nBegin-1);
2743                             }
2744                             if (STRING_NOTFOUND ==
2745                                 (nBegin = sPart.Search(',',nEnd)))
2746                             {
2747                                 nBegin = sPart.Search(';',nEnd);
2748                             }
2749                             nEnd = sPart.SearchBackward(')');
2750                             if ((nBegin != STRING_NOTFOUND) &&
2751                                 (nEnd != STRING_NOTFOUND))
2752                             {
2753                                 sText = sPart.Copy(nBegin+1,nEnd-nBegin-1);
2754                             }
2755                         }
2756                     }
2757                 }
2758 
2759             }
2760             break;
2761         }
2762     }
2763 
2764     //Translate and apply
2765     if (sRuby.Len() && sText.Len() && sFontName.Len() && nFontSize)
2766     {
2767         switch (nJustificationCode)
2768         {
2769             case 0:
2770                 nJustificationCode=1;
2771                 break;
2772             case 1:
2773                 nJustificationCode=3;
2774                 break;
2775             case 2:
2776                 nJustificationCode=4;
2777                 break;
2778             default:
2779             case 3:
2780                 nJustificationCode=0;
2781                 break;
2782             case 4:
2783                 nJustificationCode=2;
2784                 break;
2785         }
2786 
2787         SwFmtRuby aRuby(sRuby);
2788         const SwCharFmt *pCharFmt=0;
2789         //Make a guess at which of asian of western we should be setting
2790         sal_uInt16 nScript;
2791         if (pBreakIt->GetBreakIter().is())
2792             nScript = pBreakIt->GetBreakIter()->getScriptType(sRuby, 0);
2793         else
2794             nScript = i18n::ScriptType::ASIAN;
2795 
2796         //Check to see if we already have a ruby charstyle that this fits
2797         std::vector<const SwCharFmt*>::const_iterator aEnd =
2798             aRubyCharFmts.end();
2799         for(std::vector<const SwCharFmt*>::const_iterator aIter
2800             = aRubyCharFmts.begin(); aIter != aEnd; ++aIter)
2801         {
2802             const SvxFontHeightItem &rFH =
2803                 ItemGet<SvxFontHeightItem>(*(*aIter),
2804                 GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript));
2805             if (rFH.GetHeight() == nFontSize*10)
2806             {
2807                 const SvxFontItem &rF = ItemGet<SvxFontItem>(*(*aIter),
2808                     GetWhichOfScript(RES_CHRATR_FONT,nScript));
2809                 if (rF.GetFamilyName().Equals(sFontName))
2810                 {
2811                     pCharFmt=*aIter;
2812                     break;
2813                 }
2814             }
2815         }
2816 
2817         //Create a new char style if necessary
2818         if (!pCharFmt)
2819         {
2820             SwCharFmt *pFmt=0;
2821             String aNm;
2822             //Take this as the base name
2823             SwStyleNameMapper::FillUIName(RES_POOLCHR_RUBYTEXT,aNm);
2824             aNm+=String::CreateFromInt32(aRubyCharFmts.size()+1);
2825             pFmt = rDoc.MakeCharFmt(aNm,(SwCharFmt*)rDoc.GetDfltCharFmt());
2826             SvxFontHeightItem aHeightItem(nFontSize*10, 100, RES_CHRATR_FONTSIZE);
2827             SvxFontItem aFontItem(FAMILY_DONTKNOW,sFontName,
2828                 aEmptyStr,PITCH_DONTKNOW,RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT);
2829             aHeightItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript));
2830             aFontItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONT,nScript));
2831             pFmt->SetFmtAttr(aHeightItem);
2832             pFmt->SetFmtAttr(aFontItem);
2833             aRubyCharFmts.push_back(pFmt);
2834             pCharFmt = pFmt;
2835         }
2836 
2837         //Set the charstyle and justification
2838         aRuby.SetCharFmtName(pCharFmt->GetName());
2839         aRuby.SetCharFmtId(pCharFmt->GetPoolFmtId());
2840         aRuby.SetAdjustment(nJustificationCode);
2841 
2842         NewAttr(aRuby);
2843         rDoc.InsertString( *pPaM, sText );
2844         pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_CJK_RUBY );
2845     }
2846 }
2847 
2848 //-----------------------------------------
2849 //        Verzeichnis-Felder
2850 //-----------------------------------------
2851 
lcl_toxMatchACSwitch(SwWW8ImplReader &,SwDoc & rDoc,SwTOXBase & rBase,_ReadFieldParams & rParam,SwCaptionDisplay eCaptionType)2852 void lcl_toxMatchACSwitch(  SwWW8ImplReader& /*rReader*/,
2853                             SwDoc& rDoc,
2854                             SwTOXBase& rBase,
2855                             _ReadFieldParams& rParam,
2856                             SwCaptionDisplay eCaptionType)
2857 {
2858     xub_StrLen n = rParam.GoToTokenParam();
2859     if( STRING_NOTFOUND != n )
2860     {
2861         SwTOXType* pType = (SwTOXType*)rDoc.GetTOXType( TOX_ILLUSTRATIONS, 0);
2862         rBase.RegisterToTOXType( *pType );
2863         rBase.SetCaptionDisplay( eCaptionType );
2864         // Read Sequence Name and store in TOXBase
2865         String sSeqName( rParam.GetResult() );
2866         lcl_ConvertSequenceName( sSeqName );
2867         rBase.SetSequenceName( sSeqName );
2868     }
2869 }
2870 
2871 
EnsureMaxLevelForTemplates(SwTOXBase & rBase)2872 static void EnsureMaxLevelForTemplates(SwTOXBase& rBase)
2873 {
2874     //If the TOC contains Template entries at levels > the evaluation level
2875     //that was initially taken from the max normal outline level of the word TOC
2876     //then we cannot use that for the evaluation level because writer cuts off
2877     //all styles above that level, while word just cuts off the "standard"
2878     //outline styles, we have no option but to expand to the highest level
2879     //Word included.
2880     if ((rBase.GetLevel() != MAXLEVEL) && (nsSwTOXElement::TOX_TEMPLATE & rBase.GetCreateType()))
2881     {
2882         for (sal_uInt16 nI = MAXLEVEL; nI > 0; --nI)
2883         {
2884             String sStyles(rBase.GetStyleNames(nI-1));
2885             if (rBase.GetStyleNames(nI-1).Len())
2886             {
2887                 rBase.SetLevel(nI);
2888                 break;
2889             }
2890         }
2891     }
2892 }
2893 
lcl_toxMatchTSwitch(SwWW8ImplReader & rReader,SwTOXBase & rBase,_ReadFieldParams & rParam)2894 void lcl_toxMatchTSwitch(SwWW8ImplReader& rReader, SwTOXBase& rBase,
2895     _ReadFieldParams& rParam)
2896 {
2897     xub_StrLen n = rParam.GoToTokenParam();
2898     if( STRING_NOTFOUND != n )
2899     {
2900         String sParams( rParam.GetResult() );
2901         if( sParams.Len() )
2902         {
2903             xub_StrLen nIndex = 0;
2904 
2905             //#92940# Delimiters between styles and style levels appears to
2906             //allow both ; and ,
2907 
2908             String sTemplate( sParams.GetToken(0, ';', nIndex) );
2909             if( STRING_NOTFOUND == nIndex )
2910             {
2911                 nIndex=0;
2912                 sTemplate = sParams.GetToken(0, ',', nIndex);
2913             }
2914             if( STRING_NOTFOUND == nIndex )
2915             {
2916                 const SwFmt* pStyle = rReader.GetStyleWithOrgWWName(sTemplate);
2917                 if( pStyle )
2918                     sTemplate = pStyle->GetName();
2919                 // Store Style for Level 0 into TOXBase
2920                 rBase.SetStyleNames( sTemplate, 0 );
2921             }
2922             else while( STRING_NOTFOUND != nIndex )
2923             {
2924                 xub_StrLen nOldIndex=nIndex;
2925                 sal_uInt16 nLevel = static_cast<sal_uInt16>(
2926                     sParams.GetToken(0, ';', nIndex).ToInt32());
2927                 if( STRING_NOTFOUND == nIndex )
2928                 {
2929                     nIndex = nOldIndex;
2930                     nLevel = static_cast<sal_uInt16>(
2931                         sParams.GetToken(0, ',', nIndex).ToInt32());
2932                 }
2933 
2934                 if( (0 < nLevel) && (MAXLEVEL >= nLevel) )
2935                 {
2936                     nLevel--;
2937                     // Store Style and Level into TOXBase
2938                     const SwFmt* pStyle
2939                             = rReader.GetStyleWithOrgWWName( sTemplate );
2940 
2941                     if( pStyle )
2942                         sTemplate = pStyle->GetName();
2943 
2944                     String sStyles( rBase.GetStyleNames( nLevel ) );
2945                     if( sStyles.Len() )
2946                         sStyles += TOX_STYLE_DELIMITER;
2947                     sStyles += sTemplate;
2948                     rBase.SetStyleNames( sStyles, nLevel );
2949                 }
2950                 // read next style name...
2951                 nOldIndex = nIndex;
2952                 sTemplate = sParams.GetToken(0, ';', nIndex);
2953                 if( STRING_NOTFOUND == nIndex )
2954                 {
2955                     nIndex=nOldIndex;
2956                     sTemplate = sParams.GetToken(0, ',', nIndex);
2957                 }
2958             }
2959         }
2960     }
2961 }
2962 
CurrentSectionColCount() const2963 sal_uInt16 wwSectionManager::CurrentSectionColCount() const
2964 {
2965     sal_uInt16 nIndexCols = 1;
2966     if (!maSegments.empty())
2967         nIndexCols = maSegments.back().maSep.ccolM1 + 1;
2968     return nIndexCols;
2969 }
2970 
2971 //Will there be a new pagebreak at this position (don't know what type
2972 //until later)
WillHavePageDescHere(SwNodeIndex aIdx) const2973 bool wwSectionManager::WillHavePageDescHere(SwNodeIndex aIdx) const
2974 {
2975     bool bRet = false;
2976     if (!maSegments.empty())
2977     {
2978         if (!maSegments.back().IsContinous() &&
2979             maSegments.back().maStart == aIdx)
2980         {
2981             bRet = true;
2982         }
2983     }
2984     return bRet;
2985 }
2986 
lcl_GetMaxValidWordTOCLevel(const SwForm & rForm)2987 sal_uInt16 lcl_GetMaxValidWordTOCLevel(const SwForm &rForm)
2988 {
2989     // GetFormMax() returns level + 1, hence the -1
2990     sal_uInt16 nRet = rForm.GetFormMax()-1;
2991 
2992     // If the max of this type of TOC is greater than the max of a word
2993     // possible toc, then clip to the word max
2994     if (nRet > WW8ListManager::nMaxLevel)
2995         nRet = WW8ListManager::nMaxLevel;
2996 
2997     return nRet;
2998 }
2999 
Read_F_Tox(WW8FieldDesc * pF,String & rStr)3000 eF_ResT SwWW8ImplReader::Read_F_Tox( WW8FieldDesc* pF, String& rStr )
3001 {
3002     if ( !mbLoadingTOXCache )
3003     {
3004         mbLoadingTOXCache = true;
3005     }
3006     else
3007     {
3008         // Embedded TOX --> continue reading its content, but no further TOX field
3009         ++mnEmbeddedTOXLevel;
3010         return FLD_TEXT;
3011     }
3012 
3013     if (pF->nLRes < 3)
3014         return FLD_TEXT;      // ignore (#i25440#)
3015 
3016     TOXTypes eTox;                              // Baue ToxBase zusammen
3017     switch( pF->nId )
3018     {
3019         case  8:
3020             eTox = TOX_INDEX;
3021             break;
3022         case 13:
3023             eTox = TOX_CONTENT;
3024             break;
3025         default:
3026             eTox = TOX_USER;
3027             break;
3028     }
3029 
3030     sal_uInt16 nCreateOf = (eTox == TOX_CONTENT) ? nsSwTOXElement::TOX_OUTLINELEVEL : nsSwTOXElement::TOX_MARK;
3031 
3032     sal_uInt16 nIndexCols = 1;
3033 
3034     const SwTOXType* pType = rDoc.GetTOXType( eTox, 0 );
3035     SwForm aOrigForm(eTox);
3036     SwTOXBase* pBase = new SwTOXBase( pType, aOrigForm, nCreateOf, aEmptyStr );
3037     pBase->SetProtected(maSectionManager.CurrentSectionIsProtected());
3038     switch( eTox ){
3039     case TOX_INDEX:
3040         {
3041             sal_uInt16 eOptions = nsSwTOIOptions::TOI_SAME_ENTRY | nsSwTOIOptions::TOI_CASE_SENSITIVE;
3042 
3043             // TOX_OUTLINELEVEL setzen wir genau dann, wenn
3044             // die Parameter \o in 1 bis 9 liegen
3045             // oder der Parameter \f existiert
3046             // oder GARKEINE Switches Parameter angegeben sind.
3047             long nRet;
3048             _ReadFieldParams aReadParam( rStr );
3049             while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3050             {
3051                 switch( nRet )
3052                 {
3053                 case 'c':
3054                     {
3055                         xub_StrLen n = aReadParam.GoToTokenParam();
3056                         if( STRING_NOTFOUND != n )
3057                         {
3058                             String sParams( aReadParam.GetResult() );
3059                             // if NO String just ignore the \c
3060                             if( sParams.Len() )
3061                             {
3062                                 nIndexCols =
3063                                     static_cast<sal_uInt16>(sParams.ToInt32());
3064                             }
3065                         }
3066                     }
3067                     break;
3068                 case 'e':
3069                     {
3070                         xub_StrLen n = aReadParam.GoToTokenParam();
3071                         if( STRING_NOTFOUND != n )  // if NO String just ignore the \e
3072                         {
3073                             String sDelimiter( aReadParam.GetResult() );
3074                             SwForm aForm( pBase->GetTOXForm() );
3075 
3076                             // Attention: if TOX_CONTENT brave
3077                             //            GetFormMax() returns MAXLEVEL + 1  !!
3078                             sal_uInt16 nEnd = aForm.GetFormMax()-1;
3079 
3080                             for(sal_uInt16 nLevel = 1;
3081                                    nLevel <= nEnd;
3082                                    ++nLevel)
3083                             {
3084                                 // Levels count from 1
3085                                 // Level 0 is reserved for CAPTION
3086 
3087                                 // Delimiter statt Tabstop vor der Seitenzahl einsetzen,
3088                                 // falls es eine Seitenzahl gibt:
3089                                 FormTokenType ePrevType = TOKEN_END;
3090                                 FormTokenType eType;
3091                                 // -> #i21237#
3092                                 SwFormTokens aPattern =
3093                                     aForm.GetPattern(nLevel);
3094                                 SwFormTokens::iterator aIt = aPattern.begin();
3095                                 do
3096                                 {
3097                                     eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3098 
3099                                     if (eType == TOKEN_PAGE_NUMS)
3100                                     {
3101                                         if (TOKEN_TAB_STOP == ePrevType)
3102                                         {
3103                                             aIt--;
3104 
3105                                             if(0x09 == sDelimiter.GetChar(0))
3106                                                 aIt->eTabAlign = SVX_TAB_ADJUST_END;
3107                                             else
3108                                             {
3109                                                 SwFormToken aToken(TOKEN_TEXT);
3110                                                 aToken.sText = sDelimiter;
3111                                                 *aIt = aToken;
3112                                             }
3113                                             aForm.SetPattern(nLevel, aPattern);
3114                                         }
3115 
3116                                         eType = TOKEN_END;
3117                                     }
3118 
3119                                     ePrevType = eType;
3120                                 }
3121                                 while (TOKEN_END != eType);
3122                                 // <- #i21237#
3123                             }
3124                             pBase->SetTOXForm( aForm );
3125                         }
3126                     }
3127                     break;
3128                 case 'h':
3129                     {
3130                         eOptions |= nsSwTOIOptions::TOI_ALPHA_DELIMITTER;
3131                     }
3132                     break;
3133                 }
3134             }
3135             pBase->SetOptions( eOptions );
3136         }
3137         break;
3138 
3139     case TOX_CONTENT:
3140         {
3141             bool bIsHyperlink = false;
3142             bool bShowPage = true;
3143             // TOX_OUTLINELEVEL setzen wir genau dann, wenn
3144             // die Parameter \o in 1 bis 9 liegen
3145             // oder der Parameter \f existiert
3146             // oder GARKEINE Switches Parameter angegeben sind.
3147             sal_uInt16 eCreateFrom = 0;
3148             sal_uInt16 nMaxLevel = 0;
3149             long nRet;
3150             _ReadFieldParams aReadParam( rStr );
3151             while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3152             {
3153                 switch( nRet )
3154                 {
3155                 case 'h':
3156                     bIsHyperlink = true;
3157                     break;
3158                 case 'a':
3159                 case 'c':
3160                     lcl_toxMatchACSwitch(*this, rDoc, *pBase, aReadParam,
3161                                            ('c' == nRet)
3162                                          ? CAPTION_COMPLETE
3163                                          : CAPTION_TEXT );
3164                     break;
3165                 case 'o':
3166                     {
3167                         sal_uInt16 nVal;
3168                         if( !aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) )
3169                             nVal = lcl_GetMaxValidWordTOCLevel(aOrigForm);
3170                         if( nMaxLevel < nVal )
3171                             nMaxLevel = nVal;
3172                         eCreateFrom |= nsSwTOXElement::TOX_OUTLINELEVEL;
3173                     }
3174                     break;
3175                 case 'f':
3176                     eCreateFrom |= nsSwTOXElement::TOX_MARK;
3177                     break;
3178                 case 'l':
3179                     {
3180                         sal_uInt16 nVal;
3181                         if( aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) )
3182                         {
3183                             if( nMaxLevel < nVal )
3184                                 nMaxLevel = nVal;
3185                             eCreateFrom |= nsSwTOXElement::TOX_MARK;
3186                         }
3187                     }
3188                     break;
3189                 case 't': // paragraphs using special styles shall
3190                           // provide the TOX's content
3191                     lcl_toxMatchTSwitch(*this, *pBase, aReadParam);
3192                     eCreateFrom |= nsSwTOXElement::TOX_TEMPLATE;
3193                     break;
3194                 case 'p':
3195                     {
3196                         xub_StrLen n = aReadParam.GoToTokenParam();
3197                         if( STRING_NOTFOUND != n )  // if NO String just ignore the \p
3198                         {
3199                             String sDelimiter( aReadParam.GetResult() );
3200                             SwForm aForm( pBase->GetTOXForm() );
3201 
3202                             // Attention: if TOX_CONTENT brave
3203                             //            GetFormMax() returns MAXLEVEL + 1  !!
3204                             sal_uInt16 nEnd = aForm.GetFormMax()-1;
3205 
3206                             for(sal_uInt16 nLevel = 1;
3207                                    nLevel <= nEnd;
3208                                    ++nLevel)
3209                             {
3210                                 // Levels count from 1
3211                                 // Level 0 is reserved for CAPTION
3212 
3213                                 // Delimiter statt Tabstop vor der Seitenzahl einsetzen,
3214                                 // falls es eine Seitenzahl gibt:
3215                                 FormTokenType ePrevType = TOKEN_END;
3216                                 FormTokenType eType;
3217 
3218                                 // -> #i21237#
3219                                 SwFormTokens aPattern = aForm.GetPattern(nLevel);
3220                                 SwFormTokens::iterator aIt = aPattern.begin();
3221                                 do
3222                                 {
3223                                     eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3224 
3225                                     if (eType == TOKEN_PAGE_NUMS)
3226                                     {
3227                                         if (TOKEN_TAB_STOP == ePrevType)
3228                                         {
3229                                             aIt--;
3230 
3231                                             SwFormToken aToken(TOKEN_TEXT);
3232                                             aToken.sText = sDelimiter;
3233 
3234                                             *aIt = aToken;
3235                                             aForm.SetPattern(nLevel,
3236                                                              aPattern);
3237                                         }
3238                                         eType = TOKEN_END;
3239                                     }
3240                                     ePrevType = eType;
3241                                 }
3242                                 while( TOKEN_END != eType );
3243                                 // <- #i21237#
3244                             }
3245                             pBase->SetTOXForm( aForm );
3246                         }
3247                     }
3248                     break;
3249                 case 'n': // don't print page numbers
3250                     {
3251                         // read START and END param
3252                         bShowPage = false;
3253                         sal_uInt16 nStart, nEnd;
3254                         if( !aReadParam.GetTokenSttFromTo(  &nStart, &nEnd,
3255                             WW8ListManager::nMaxLevel ) )
3256                         {
3257                             nStart = 1;
3258                             nEnd = aOrigForm.GetFormMax()-1;
3259                         }
3260                         // remove page numbers from this levels
3261                         SwForm aForm( pBase->GetTOXForm() );
3262                         if (aForm.GetFormMax() <= nEnd)
3263                             nEnd = aForm.GetFormMax()-1;
3264                         for (
3265                               sal_uInt16 nLevel = nStart; nLevel <= nEnd;
3266                               ++nLevel
3267                             )
3268                         {
3269                             // Levels count from 1
3270                             // Level 0 is reserved for CAPTION
3271 
3272                             // Seitenzahl und ggfs. davorstehenden Tabstop
3273                             // entfernen:
3274                             FormTokenType eType;
3275                             // -> #i21237#
3276                             SwFormTokens aPattern = aForm.GetPattern(nLevel);
3277                             SwFormTokens::iterator aIt = aPattern.begin();
3278                             do
3279                             {
3280                                 eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType;
3281 
3282                                 if (eType == TOKEN_PAGE_NUMS)
3283                                 {
3284                                     aIt = aPattern.erase(aIt);
3285                                     aIt--;
3286                                     if (
3287                                          TOKEN_TAB_STOP ==
3288                                          aIt->eTokenType
3289                                        )
3290                                     {
3291                                         aPattern.erase(aIt);
3292                                         aForm.SetPattern(nLevel, aPattern);
3293                                     }
3294                                     eType = TOKEN_END;
3295                                 }
3296                             }
3297                             while (TOKEN_END != eType);
3298                             // <- #i21237#
3299                         }
3300                         pBase->SetTOXForm( aForm );
3301                     }
3302                     break;
3303 
3304                 /*
3305                 // the following switches are not (yet) supported
3306                 // by good old StarWriter:
3307                 case 'b':
3308                 case 's':
3309                 case 'd':
3310                     break;
3311                 */
3312                 }
3313             }
3314 
3315             // For loading the expression of TOC field, we need to mapping its parameters to TOX entries tokens
3316             // also include the hyperlinks and page references
3317             SwFormToken aLinkStart(TOKEN_LINK_START);
3318             SwFormToken aLinkEnd(TOKEN_LINK_END);
3319             aLinkStart.sCharStyleName = String::CreateFromAscii("Index Link");
3320             aLinkEnd.sCharStyleName = String::CreateFromAscii("Index Link");
3321             SwForm aForm(pBase->GetTOXForm());
3322             sal_uInt16 nEnd = aForm.GetFormMax()-1;
3323 
3324             for(sal_uInt16 nLevel = 1; nLevel <= nEnd; ++nLevel)
3325             {
3326                 SwFormTokens aPattern = aForm.GetPattern(nLevel);
3327                 if ( bIsHyperlink )
3328                 {
3329                     aPattern.insert(aPattern.begin(), aLinkStart);
3330                 }
3331                 else if ( bShowPage )
3332                 {
3333                     for (SwFormTokens::iterator aItr = aPattern.begin();aItr!= aPattern.end();aItr++)
3334                     {
3335                         if (aItr->eTokenType == TOKEN_PAGE_NUMS)
3336                         {
3337                             aPattern.insert(aItr,aLinkStart);
3338                             break;
3339                         }
3340                     }
3341                 }
3342                 aPattern.push_back(aLinkEnd);
3343                 aForm.SetPattern(nLevel, aPattern);
3344             }
3345             pBase->SetTOXForm(aForm);
3346 
3347             if (!nMaxLevel)
3348                 nMaxLevel = WW8ListManager::nMaxLevel;
3349             pBase->SetLevel(nMaxLevel);
3350 
3351             const TOXTypes eType = pBase->GetTOXType()->GetType();
3352             switch( eType )
3353             {
3354                 case TOX_CONTENT:
3355                     {
3356                         //If we would be created from outlines, either explicitly or by default
3357                         //then see if we need extra styles added to the outlines
3358                         sal_uInt16 eEffectivelyFrom = eCreateFrom ? eCreateFrom : nsSwTOXElement::TOX_OUTLINELEVEL;
3359                         if (eEffectivelyFrom & nsSwTOXElement::TOX_OUTLINELEVEL)
3360                         {
3361                             // #i19683# Insert a text token " " between the number and entry token.
3362                             // In an ideal world we could handle the tab stop between the number and
3363                             // the entry correctly, but I currently have no clue how to obtain the tab stop position.
3364                             // It is _not_ set at the paragraph style.
3365                             SwForm* pForm = 0;
3366                             for (sal_uInt16 nI = 0; nI < nColls; ++nI)
3367                             {
3368                                 const SwWW8StyInf& rSI = pCollA[nI];
3369                                 if (rSI.IsOutlineNumbered())
3370                                 {
3371                                     sal_uInt16 nStyleLevel = rSI.mnWW8OutlineLevel;
3372                                     const SwNumFmt& rFmt = rSI.GetOutlineNumrule()->Get( nStyleLevel );
3373                                     if ( SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType() )
3374                                     {
3375                                         ++nStyleLevel;
3376 
3377                                         if ( !pForm )
3378                                             pForm = new SwForm( pBase->GetTOXForm() );
3379 
3380                                         SwFormTokens aPattern = pForm->GetPattern(nStyleLevel);
3381                                         SwFormTokens::iterator aIt =
3382                                                 find_if(aPattern.begin(), aPattern.end(),
3383                                                 SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO));
3384 
3385                                         if ( aIt != aPattern.end() )
3386                                         {
3387                                             SwFormToken aNumberEntrySeparator( TOKEN_TEXT );
3388                                             aNumberEntrySeparator.sText = String::CreateFromAscii(" ");
3389                                             aPattern.insert( ++aIt, aNumberEntrySeparator );
3390                                             pForm->SetPattern( nStyleLevel, aPattern );
3391                                         }
3392                                     }
3393                                 }
3394                             }
3395                             if ( pForm )
3396                             {
3397                                 pBase->SetTOXForm( *pForm );
3398                                 delete pForm;
3399                             }
3400                         }
3401 
3402                         if (eCreateFrom)
3403                             pBase->SetCreate(eCreateFrom);
3404                         EnsureMaxLevelForTemplates(*pBase);
3405                     }
3406                     break;
3407                 case TOX_ILLUSTRATIONS:
3408                     {
3409                         if( !eCreateFrom )
3410                             eCreateFrom = nsSwTOXElement::TOX_SEQUENCE;
3411                         pBase->SetCreate( eCreateFrom );
3412 
3413                         /*
3414                         #91214#
3415                         We don't know until here if we are an illustration
3416                         or not, and so have being used a TOX_CONTENT so far
3417                         which has 10 levels, while TOX has only two, this
3418                         level is set only in the constructor of SwForm, so
3419                         create a new one and copy over anything that could
3420                         be set in the old one, and remove entries from the
3421                         pattern which do not apply to illustration indices
3422                         */
3423                         SwForm aOldForm( pBase->GetTOXForm() );
3424                         SwForm aForm( eType );
3425                         sal_uInt16 nEnd = aForm.GetFormMax()-1;
3426 
3427                         // -> #i21237#
3428                         for(sal_uInt16 nLevel = 1; nLevel <= nEnd; ++nLevel)
3429                         {
3430                             SwFormTokens aPattern = aOldForm.GetPattern(nLevel);
3431                             SwFormTokens::iterator new_end =
3432                                 remove_if(aPattern.begin(), aPattern.end(), SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO));
3433                             aPattern.erase(new_end, aPattern.end() ); // #124710#: table index imported with wrong page number format
3434                             aForm.SetPattern( nLevel, aPattern );
3435                             aForm.SetTemplate( nLevel, aOldForm.GetTemplate(nLevel) );
3436                         }
3437                         // <- #i21237#
3438 
3439                         pBase->SetTOXForm( aForm );
3440                     }
3441                     break;
3442                 default:
3443                     ASSERT(sal_False, "Unhandled toc options!");
3444                     break;
3445             }
3446         }
3447         break;
3448     case TOX_USER:
3449         break;
3450     default:
3451         ASSERT(sal_False, "Unhandled toc options!");
3452         break;
3453     } // ToxBase fertig
3454 
3455     // #i21237# - propagate tab stops from paragraph styles used in TOX to patterns of the TOX
3456     pBase->AdjustTabStops( rDoc );
3457 
3458     //#i10028# inserting a toc implicltly acts like a parabreak in word and writer
3459     if ( pPaM->End() &&
3460          pPaM->End()->nNode.GetNode().GetTxtNode() &&
3461          pPaM->End()->nNode.GetNode().GetTxtNode()->Len() != 0 )
3462     {
3463         mbCareFirstParaEndInToc = true;
3464     }
3465 
3466     if (pPaM->GetPoint()->nContent.GetIndex())
3467         AppendTxtNode(*pPaM->GetPoint());
3468 
3469     const SwPosition* pPos = pPaM->GetPoint();
3470 
3471     SwFltTOX aFltTOX( pBase, nIndexCols );
3472 
3473     // test if there is already a break item on this node
3474     if(SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode())
3475     {
3476         const SfxItemSet* pSet = pNd->GetpSwAttrSet();
3477         if( pSet )
3478         {
3479             if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false))
3480                 aFltTOX.SetHadBreakItem(true);
3481             if (SFX_ITEM_SET == pSet->GetItemState(RES_PAGEDESC, false))
3482                 aFltTOX.SetHadPageDescItem(true);
3483         }
3484     }
3485 
3486     //Will there be a new pagebreak at this position (don't know what type
3487     //until later)
3488     if (maSectionManager.WillHavePageDescHere(pPos->nNode))
3489         aFltTOX.SetHadPageDescItem(true);
3490 
3491     // Setze Anfang in Stack
3492     pReffedStck->NewAttr( *pPos, aFltTOX );
3493 
3494     rDoc.InsertTableOf(*pPaM->GetPoint(), *aFltTOX.GetBase());
3495 
3496     //The TOC field representation contents should be inserted into TOC section, but not after TOC section.
3497     //So we need update the document position when loading TOC representation and after loading TOC;
3498     if (mpPosAfterTOC)
3499     {
3500         delete mpPosAfterTOC;
3501     }
3502     mpPosAfterTOC = new SwPaM(*pPaM);
3503     (*pPaM).Move(fnMoveBackward);
3504     SwPaM aRegion(*pPaM);
3505 
3506     ASSERT(rDoc.GetCurTOX(*aRegion.GetPoint()), "Misunderstood how toc works");
3507     if (SwTOXBase* pBase2 = (SwTOXBase*)rDoc.GetCurTOX(*aRegion.GetPoint()))
3508     {
3509         pBase2->SetMSTOCExpression(rStr);
3510 
3511         if ( nIndexCols > 1 )
3512         {
3513             // Set the column number for index
3514             SfxItemSet aSet( rDoc.GetAttrPool(), RES_COL, RES_COL );
3515             SwFmtCol aCol;
3516             aCol.Init( nIndexCols, 708, USHRT_MAX );
3517             aSet.Put( aCol );
3518             pBase2->SetAttrSet( aSet );
3519         }
3520 
3521         // inserting a toc inserts a section before this point, so adjust pos
3522         // for future page/section segment insertion
3523         maSectionManager.PrependedInlineNode( *mpPosAfterTOC->GetPoint(), *aRegion.GetNode() );
3524     }
3525 
3526     // Setze Ende in Stack
3527     pReffedStck->SetAttr( *pPos, RES_FLTR_TOX );
3528 
3529     if (!maApos.back()) //a para end in apo doesn't count
3530         bWasParaEnd = true;
3531 
3532     //Return FLD_TEXT, instead of FLD_OK
3533     //FLD_TEXT means the following content, commonly indicate the field representation content should be parsed
3534     //FLD_OK means the current field loading is finished. The rest part should be ignored.
3535     return FLD_TEXT;
3536 }
3537 
Read_F_Shape(WW8FieldDesc *,String &)3538 eF_ResT SwWW8ImplReader::Read_F_Shape(WW8FieldDesc* /*pF*/, String& /*rStr*/)
3539 {
3540     /*
3541     #i3958# 0x8 followed by 0x1 where the shape is the 0x8 and its anchoring
3542     to be ignored followed by a 0x1 with an empty drawing. Detect in inserting
3543     the drawing that we are in the Shape field and respond accordingly
3544     */
3545     return FLD_TEXT;
3546  }
3547 
Read_F_Hyperlink(WW8FieldDesc *,String & rStr)3548 eF_ResT SwWW8ImplReader::Read_F_Hyperlink( WW8FieldDesc* /*pF*/, String& rStr )
3549 {
3550     String sURL, sTarget, sMark;
3551     bool bDataImport = false;
3552     //HYPERLINk "filename" [switches]
3553     bool bOptions=false;
3554 
3555     rStr.EraseTrailingChars( 1 );
3556 
3557     if (!bDataImport)
3558     {
3559         long nRet;
3560         _ReadFieldParams aReadParam( rStr );
3561         while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3562         {
3563             switch( nRet )
3564             {
3565                 case -2:
3566                     if (!sURL.Len() & !bOptions)
3567                         ConvertFFileName(sURL, aReadParam.GetResult());
3568                     break;
3569 
3570                 case 'n':
3571                     sTarget.ASSIGN_CONST_ASC( "_blank" );
3572                     bOptions = true;
3573                     break;
3574 
3575                 case 'l':
3576                     nRet = aReadParam.SkipToNextToken();
3577                     bOptions = true;
3578                     if( -2 == nRet )
3579                     {
3580                         sMark = aReadParam.GetResult();
3581                         if( sMark.Len() > 0 && '"' == sMark.GetChar( sMark.Len()-1 ) )
3582                         {
3583                             sMark.Erase( sMark.Len() - 1 );
3584                         }
3585                         // #120879# add cross reference bookmark name prefix, if it matches internal TOC bookmark naming convention
3586                         if ( IsTOCBookmarkName( sMark ) )
3587                         {
3588                             String sTmp = IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix();
3589                             sTmp += sMark;
3590                             sMark = sTmp;
3591                             // track <sMark> as referenced TOC bookmark.
3592                             pReffedStck->aReferencedTOCBookmarks.insert( sMark );
3593                         }
3594 
3595                         if (mbLoadingTOXCache)
3596                         {
3597                             mbLoadingTOXHyperlink = true;//on loading a TOX field nested hyperlink field
3598                         }
3599                     }
3600                     break;
3601                 case 't':
3602                     nRet = aReadParam.SkipToNextToken();
3603                     bOptions = true;
3604                     if (-2 == nRet)
3605                         sTarget = aReadParam.GetResult();
3606                     break;
3607                 case 'h':
3608                 case 'm':
3609                     ASSERT( sal_False, "Evaluation is still missing - data unknown" );
3610                 case 's':   //worthless fake anchor option
3611                     bOptions = true;
3612                     break;
3613             }
3614         }
3615     }
3616 
3617     // das Resultat uebernehmen
3618     ASSERT((sURL.Len() || sMark.Len()), "WW8: Empty URL")
3619 
3620     if( sMark.Len() )
3621         ( sURL += INET_MARK_TOKEN ) += sMark;
3622 
3623     SwFmtINetFmt aURL( sURL, sTarget );
3624     // If on loading TOX field, change the default style into the "index link"
3625     if (mbLoadingTOXCache)
3626     {
3627         String sLinkStyle = String::CreateFromAscii("Index Link");
3628         sal_uInt16 nPoolId =
3629             SwStyleNameMapper::GetPoolIdFromUIName( sLinkStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
3630         aURL.SetVisitedFmtAndId( sLinkStyle, nPoolId );
3631         aURL.SetINetFmtAndId( sLinkStyle, nPoolId );
3632     }
3633 
3634     //As an attribute this needs to be closed, and that'll happen from
3635     //EndExtSprm in conjunction with the maFieldStack If there are are flyfrms
3636     //between the start and begin, their hyperlinks will be set at that time
3637     //as well.
3638     pCtrlStck->NewAttr( *pPaM->GetPoint(), aURL );
3639     return FLD_TEXT;
3640 }
3641 
lcl_ImportTox(SwDoc & rDoc,SwPaM & rPaM,const String & rStr,bool bIdx)3642 void lcl_ImportTox(SwDoc &rDoc, SwPaM &rPaM, const String &rStr, bool bIdx)
3643 {
3644     TOXTypes eTox = ( !bIdx ) ? TOX_CONTENT : TOX_INDEX;    // Default
3645 
3646     sal_uInt16 nLevel = 1;
3647 
3648     xub_StrLen n;
3649     String sFldTxt;
3650     long nRet;
3651     _ReadFieldParams aReadParam(rStr);
3652     while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
3653         switch( nRet )
3654         {
3655         case -2:
3656             if( !sFldTxt.Len() )
3657             {
3658                 // PrimaryKey ohne ":", 2nd dahinter
3659                 sFldTxt = aReadParam.GetResult();
3660             }
3661             break;
3662 
3663         case 'f':
3664             n = aReadParam.GoToTokenParam();
3665             if( STRING_NOTFOUND != n )
3666             {
3667                 String sParams( aReadParam.GetResult() );
3668                 if( 'C' != sParams.GetChar(0) && 'c' != sParams.GetChar(0) )
3669                     eTox = TOX_USER;
3670             }
3671             break;
3672 
3673         case 'l':
3674             n = aReadParam.GoToTokenParam();
3675             if( STRING_NOTFOUND != n )
3676             {
3677                 String sParams( aReadParam.GetResult() );
3678                 if(    sParams.Len() // if NO String just ignore the \l
3679                     && sParams.GetChar( 0 ) > '0'
3680                     && sParams.GetChar( 0 ) <= '9' )
3681                 {
3682                     nLevel = (sal_uInt16)sParams.ToInt32();
3683                 }
3684             }
3685             break;
3686         }
3687 
3688     ASSERT( rDoc.GetTOXTypeCount( eTox ), "Doc.GetTOXTypeCount() == 0  :-(" );
3689 
3690     const SwTOXType* pT = rDoc.GetTOXType( eTox, 0 );
3691     SwTOXMark aM( pT );
3692 
3693     if( eTox != TOX_INDEX )
3694         aM.SetLevel( nLevel );
3695     else
3696     {
3697         xub_StrLen nFnd = sFldTxt.Search( WW8_TOX_LEVEL_DELIM );
3698         if( STRING_NOTFOUND != nFnd )  // it exist levels
3699         {
3700             aM.SetPrimaryKey( sFldTxt.Copy( 0, nFnd ) );
3701             xub_StrLen nScndFnd =
3702                 sFldTxt.Search( WW8_TOX_LEVEL_DELIM, nFnd+1 );
3703             if( STRING_NOTFOUND != nScndFnd )
3704             {
3705                 aM.SetSecondaryKey(  sFldTxt.Copy( nFnd+1, nScndFnd - nFnd - 1 ));
3706                 nFnd = nScndFnd;
3707             }
3708             sFldTxt.Erase( 0, nFnd+1 );
3709         }
3710     }
3711 
3712     if (sFldTxt.Len())
3713     {
3714         aM.SetAlternativeText( sFldTxt );
3715         rDoc.InsertPoolItem( rPaM, aM, 0 );
3716     }
3717 }
3718 
ImportXE(SwDoc & rDoc,SwPaM & rPaM,const String & rStr)3719 void sw::ms::ImportXE(SwDoc &rDoc, SwPaM &rPaM, const String &rStr)
3720 {
3721     lcl_ImportTox(rDoc, rPaM, rStr, true);
3722 }
3723 
ImportTox(int nFldId,String aStr)3724 void SwWW8ImplReader::ImportTox( int nFldId, String aStr )
3725 {
3726     bool bIdx = (nFldId != 9);
3727     lcl_ImportTox(rDoc, *pPaM, aStr, bIdx);
3728 }
3729 
Read_FldVanish(sal_uInt16,const sal_uInt8 *,short nLen)3730 void SwWW8ImplReader::Read_FldVanish( sal_uInt16, const sal_uInt8*, short nLen )
3731 {
3732     //Meaningless in a style
3733     if (pAktColl || !pPlcxMan)
3734         return;
3735 
3736     const int nChunk = 64;  //number of characters to read at one time
3737 
3738     // Vorsicht: Bei Feldnamen mit Umlauten geht das MEMICMP nicht!
3739     const static sal_Char *aFldNames[] = {  "\x06""INHALT", "\x02""XE", // dt.
3740                                             "\x02""TC"  };              // us
3741     const static sal_uInt8  aFldId[] = { 9, 4, 9 };
3742 
3743     if( nLen < 0 )
3744     {
3745         bIgnoreText = false;
3746         return;
3747     }
3748 
3749     // our methode was called from
3750     // ''Skip attributes of field contents'' loop within ReadTextAttr()
3751     if( bIgnoreText )
3752         return;
3753 
3754     bIgnoreText = true;
3755     long nOldPos = pStrm->Tell();
3756 
3757     WW8_CP nStartCp = pPlcxMan->Where() + pPlcxMan->GetCpOfs();
3758 
3759     String sFieldName;
3760     sal_uInt16 nFieldLen = pSBase->WW8ReadString( *pStrm, sFieldName, nStartCp,
3761         nChunk, eStructCharSet );
3762     nStartCp+=nFieldLen;
3763 
3764     xub_StrLen nC = 0;
3765     //If the first chunk did not start with a field start then
3766     //reset the stream position and give up
3767     if( !nFieldLen || (0x13 != sFieldName.GetChar( nC ))) // Field Start Mark
3768     {
3769         // If Field End Mark found
3770         if( nFieldLen && (0x15 == sFieldName.GetChar( nC )))
3771             bIgnoreText = false;
3772         pStrm->Seek( nOldPos );
3773         return;                 // kein Feld zu finden
3774     }
3775 
3776     xub_StrLen nFnd;
3777     //If this chunk does not contain a field end, keep reading chunks
3778     //until we find one, or we run out of text,
3779     while (STRING_NOTFOUND == (nFnd = sFieldName.Search(0x15)))
3780     {
3781         String sTemp;
3782         nFieldLen = pSBase->WW8ReadString( *pStrm, sTemp,
3783         nStartCp, nChunk, eStructCharSet );
3784         sFieldName+=sTemp;
3785         nStartCp+=nFieldLen;
3786         if (!nFieldLen)
3787             break;
3788     }
3789 
3790     pStrm->Seek( nOldPos );
3791 
3792     //if we have no 0x15 give up, otherwise erase everything from the 0x15
3793     //onwards
3794     if (STRING_NOTFOUND == nFnd)
3795         return;
3796     else
3797         sFieldName.Erase(nFnd);
3798 
3799     nC++;
3800     while( ' '  == sFieldName.GetChar( nC ))
3801         nC++;
3802 
3803     for( int i = 0; i < 3; i++ )
3804     {
3805         const sal_Char* pName = aFldNames[i];
3806         sal_uInt16 nNameLen = *pName++;
3807         if( sFieldName.EqualsIgnoreCaseAscii( pName, nC, nNameLen ) )
3808         {
3809             ImportTox( aFldId[i], sFieldName.Copy( nC + nNameLen ) );
3810             break;                  // keine Mehrfachnennungen moeglich
3811         }
3812     }
3813     bIgnoreText = true;
3814     pStrm->Seek( nOldPos );
3815 }
3816 
3817 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
3818