diff options
Diffstat (limited to 'sw/source/filter/ww8/ww8par5.cxx')
-rw-r--r-- | sw/source/filter/ww8/ww8par5.cxx | 3532 |
1 files changed, 3532 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/ww8par5.cxx b/sw/source/filter/ww8/ww8par5.cxx new file mode 100644 index 000000000000..f5f82d879aac --- /dev/null +++ b/sw/source/filter/ww8/ww8par5.cxx @@ -0,0 +1,3532 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ww8par5.cxx,v $ + * $Revision: 1.110.40.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ + + +#include <ctype.h> // tolower +#include <stdio.h> // sscanf() + +#include <sal/types.h> +#include <tools/solar.h> + +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <svtools/urihelper.hxx> +#include <svtools/zforlist.hxx> +#include <svtools/zformat.hxx> +#include <sfx2/linkmgr.hxx> + +#ifndef _UCBHELPER_CONTENT_HXX_ +#include <ucbhelper/content.hxx> +#endif +#ifndef _UCBHELPER_CONTENTBROKER_HXX_ +#include <ucbhelper/contentbroker.hxx> +#endif +#include <ucbhelper/commandenvironment.hxx> + +#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_ +#include <com/sun/star/i18n/ScriptType.hdl> +#endif +#include <hintids.hxx> +#include <svx/fontitem.hxx> +#include <svx/fhgtitem.hxx> +#include <svx/langitem.hxx> +#include <fmtfld.hxx> +#include <fmtanchr.hxx> +#include <pam.hxx> // fuer SwPam +#include <doc.hxx> +#include <charatr.hxx> // class SwFmtFld +#include <flddat.hxx> // class SwDateTimeField +#include <docufld.hxx> // class SwPageNumberField +#include <reffld.hxx> // class SwGetRefField +#include <IMark.hxx> +#include <expfld.hxx> // class SwSetExpField +#include <dbfld.hxx> // class SwDBField +#include <usrfld.hxx> +#include <tox.hxx> +#include <section.hxx> // class SwSection +#include <ndtxt.hxx> +#include <fmtinfmt.hxx> +#include <chpfld.hxx> +#include <ftnidx.hxx> +#include <txtftn.hxx> +#include <viewsh.hxx> +#include <shellres.hxx> +#include <fmtruby.hxx> +#include <charfmt.hxx> +#include <txtatr.hxx> +#include <breakit.hxx> +#include <fmtclds.hxx> +#include <pagedesc.hxx> +#include <SwStyleNameMapper.hxx> + + +#include "ww8scan.hxx" // WW8FieldDesc +#include "ww8par.hxx" +#include "ww8par2.hxx" +#include "writerhelper.hxx" +#include "fields.hxx" + +#include <algorithm> // #i24377# + +#define MAX_FIELDLEN 64000 + +#define WW8_TOX_LEVEL_DELIM ':' + +using namespace ::com::sun::star; +using namespace sw::util; +using namespace std; // #i24377# +using namespace nsSwDocInfoSubType; + + +class _ReadFieldParams +{ +private: + String aData; + xub_StrLen nLen, nFnd, nNext, nSavPtr; +public: + _ReadFieldParams( const String& rData ); + ~_ReadFieldParams(); + + xub_StrLen GoToTokenParam(); + long SkipToNextToken(); + xub_StrLen GetTokenSttPtr() const { return nFnd; } + + xub_StrLen FindNextStringPiece( xub_StrLen _nStart = STRING_NOTFOUND ); + bool GetTokenSttFromTo(xub_StrLen* _pFrom, xub_StrLen* _pTo, + xub_StrLen _nMax); + + String GetResult() const; +}; + + +_ReadFieldParams::_ReadFieldParams( const String& _rData ) + : aData( _rData ), nLen( _rData.Len() ), nNext( 0 ) +{ + /* + erstmal nach einer oeffnenden Klammer oder einer Leerstelle oder einem + Anfuehrungszeichen oder einem Backslash suchen, damit der Feldbefehl + (also INCLUDEPICTURE bzw EINFUeGENGRAFIK bzw ...) ueberlesen wird + */ + while( (nLen > nNext) && (aData.GetChar( nNext ) == ' ') ) + ++nNext; + + sal_Unicode c; + while( nLen > nNext + && (c = aData.GetChar( nNext )) != ' ' + && c != '"' + && c != '\\' + && c != 132 + && c != 0x201c ) + ++nNext; + + nFnd = nNext; + nSavPtr = nNext; +// cLastChar = aData.GetChar( nSavPtr ); +} + + +_ReadFieldParams::~_ReadFieldParams() +{ +// aData.SetChar( nSavPtr, cLastChar ); +} + + +String _ReadFieldParams::GetResult() const +{ + return (STRING_NOTFOUND == nFnd) + ? aEmptyStr + : aData.Copy( nFnd, (nSavPtr - nFnd) ); +} + + +xub_StrLen _ReadFieldParams::GoToTokenParam() +{ + xub_StrLen nOld = nNext; + if( -2 == SkipToNextToken() ) + return GetTokenSttPtr(); + nNext = nOld; + return STRING_NOTFOUND; +} + +// ret: -2: NOT a '\' parameter but normal Text +long _ReadFieldParams::SkipToNextToken() +{ + long nRet = -1; // Ende + if ( + (STRING_NOTFOUND != nNext) && (nLen > nNext) && + STRING_NOTFOUND != (nFnd = FindNextStringPiece(nNext)) + ) + { + nSavPtr = nNext; + + if ('\\' == aData.GetChar(nFnd) && '\\' != aData.GetChar(nFnd + 1)) + { + nRet = aData.GetChar(++nFnd); + nNext = ++nFnd; // und dahinter setzen + } + else + { + nRet = -2; + if ( + (STRING_NOTFOUND != nSavPtr ) && + ( + ('"' == aData.GetChar(nSavPtr - 1)) || + (0x201d == aData.GetChar(nSavPtr - 1)) + ) + ) + { + --nSavPtr; + } + } + } + return nRet; +} + +// FindNextPara sucht naechsten Backslash-Parameter oder naechste Zeichenkette +// bis zum Blank oder naechsten "\" oder zum schliessenden Anfuehrungszeichen +// oder zum String-Ende von pStr. +// +// Ausgabe ppNext (falls ppNext != 0) Suchbeginn fuer naechsten Parameter bzw. 0 +// +// Returnwert: 0 falls String-Ende erreicht, +// ansonsten Anfang des Paramters bzw. der Zeichenkette +// +xub_StrLen _ReadFieldParams::FindNextStringPiece(const xub_StrLen nStart) +{ + xub_StrLen n = ( STRING_NOTFOUND == nStart ) ? nFnd : nStart; // Anfang + xub_StrLen n2; // Ende + + nNext = STRING_NOTFOUND; // Default fuer nicht gefunden + + while( (nLen > n) && (aData.GetChar( n ) == ' ') ) + ++n; + + if( nLen == n ) + return STRING_NOTFOUND; // String End reached! + + if( (aData.GetChar( n ) == '"') // Anfuehrungszeichen vor Para? + || (aData.GetChar( n ) == 0x201c) + || (aData.GetChar( n ) == 132) ) + { + n++; // Anfuehrungszeichen ueberlesen + n2 = n; // ab hier nach Ende suchen + while( (nLen > n2) + && (aData.GetChar( n2 ) != '"') + && (aData.GetChar( n2 ) != 0x201d) + && (aData.GetChar( n2 ) != 147) ) + n2++; // Ende d. Paras suchen + } + else // keine Anfuehrungszeichen + { + n2 = n; // ab hier nach Ende suchen + while( (nLen > n2) && (aData.GetChar( n2 ) != ' ') ) // Ende d. Paras suchen + { + if( aData.GetChar( n2 ) == '\\' ) + { + if( aData.GetChar( n2+1 ) == '\\' ) + n2 += 2; // Doppel-Backslash -> OK + else + { + if( n2 > n ) + n2--; + break; // einfach-Backslash -> Ende + } + } + else + n2++; // kein Backslash -> OK + } + } + if( nLen > n2 ) + { + if(aData.GetChar( n2 ) != ' ') n2++; + nNext = n2; + } + return n; +} + + + +// read parameters "1-3" or 1-3 with both values between 1 and nMax +bool _ReadFieldParams::GetTokenSttFromTo(USHORT* pFrom, USHORT* pTo, USHORT nMax) +{ + USHORT nStart = 0; + USHORT nEnd = 0; + xub_StrLen n = GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + + String sParams( GetResult() ); + + xub_StrLen nIndex = 0; + String sStart( sParams.GetToken(0, '-', nIndex) ); + if( STRING_NOTFOUND != nIndex ) + { + nStart = static_cast<USHORT>(sStart.ToInt32()); + nEnd = static_cast<USHORT>(sParams.Copy(nIndex).ToInt32()); + } + } + if( pFrom ) *pFrom = nStart; + if( pTo ) *pTo = nEnd; + + return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd); +} + +//---------------------------------------- +// Bookmarks +//---------------------------------------- + +long SwWW8ImplReader::Read_Book(WW8PLCFManResult*) +{ + // muesste auch ueber pRes.nCo2OrIdx gehen + WW8PLCFx_Book* pB = pPlcxMan->GetBook(); + if( !pB ) + { + ASSERT( pB, "WW8PLCFx_Book - Pointer nicht da" ); + return 0; + } + + eBookStatus eB = pB->GetStatus(); + if (eB & BOOK_IGNORE) + return 0; // Bookmark zu ignorieren + + if (pB->GetIsEnd()) + { + pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, + pB->GetHandle(), (eB & BOOK_FIELD)!=0); + return 0; + } + + //"_Toc*" and "_Hlt*" are unnecessary + const String* pName = pB->GetName(); + if( !pName || pName->EqualsIgnoreCaseAscii( "_Toc", 0, 4 ) + || pName->EqualsIgnoreCaseAscii( "_Hlt", 0, 4 ) ) + return 0; + + //JP 16.11.98: ToUpper darf auf keinen Fall gemacht werden, weil der + //Bookmark- name ein Hyperlink-Ziel sein kann! + + String aVal; + if( SwFltGetFlag( nFieldFlags, SwFltControlStack::BOOK_TO_VAR_REF ) ) + { + // Fuer UEbersetzung Bookmark -> Variable setzen + long nLen = pB->GetLen(); + if( nLen > MAX_FIELDLEN ) + nLen = MAX_FIELDLEN; + + long nOldPos = pStrm->Tell(); + nLen = pSBase->WW8ReadString( *pStrm, aVal, pB->GetStartPos(), nLen, + eStructCharSet ); + pStrm->Seek( nOldPos ); + + // JP 19.03.2001 - now here the implementation of the old + // "QuoteString" and I hope with a better performance + // as before. It's also only needed if the filterflags + // say we will convert bookmarks to SetExpFields! And + // this the exception! + + String sHex(CREATE_CONST_ASC( "\\x" )); + bool bSetAsHex; + bool bAllowCr = SwFltGetFlag(nFieldFlags, + SwFltControlStack::ALLOW_FLD_CR) ? true : false; + + sal_Unicode cChar; + + for( xub_StrLen nI = 0; + nI < aVal.Len() && aVal.Len() < (MAX_FIELDLEN - 4); ++nI ) + { + switch( cChar = aVal.GetChar( nI ) ) + { + case 0x0b: + case 0x0c: + case 0x0d: + if( bAllowCr ) + aVal.SetChar( nI, '\n' ), bSetAsHex = false; + else + bSetAsHex = true; + break; + + case 0xFE: + case 0xFF: + bSetAsHex = true; + break; + + default: + bSetAsHex = 0x20 > cChar; + break; + } + + if( bSetAsHex ) + { + //all Hex-Numbers with \x before + String sTmp( sHex ); + if( cChar < 0x10 ) + sTmp += '0'; + sTmp += String::CreateFromInt32( cChar, 16 ); + aVal.Replace( nI, 1 , sTmp ); + nI += sTmp.Len() - 1; + } + } + + if( aVal.Len() > (MAX_FIELDLEN - 4)) + aVal.Erase( MAX_FIELDLEN - 4 ); + } + + //e.g. inserting bookmark around field result, so we need to put + //it around the entire writer field, as we don't have the seperation + //of field and field result of word, see #i16941# + SwPosition aStart(*pPaM->GetPoint()); + if (!maFieldStack.empty()) + { + const FieldEntry &rTest = maFieldStack.back(); + aStart = rTest.maStartPos; + } + + pReffedStck->NewAttr(aStart, SwFltBookmark(BookmarkToWriter(*pName), aVal, + pB->GetHandle(), 0)); + return 0; +} + +//---------------------------------------------------------------------- +// allgemeine Hilfsroutinen zum Auseinanderdroeseln der Parameter +//---------------------------------------------------------------------- + +// ConvertFFileName uebersetzt FeldParameter-Namen u. ae. in den +// System-Zeichensatz. +// Gleichzeitig werden doppelte Backslashes in einzelne uebersetzt. +void SwWW8ImplReader::ConvertFFileName( String& rName, const String& rOrg ) +{ + rName = rOrg; + rName.SearchAndReplaceAllAscii( "\\\\", String( '\\' )); + rName.SearchAndReplaceAllAscii( "%20", String( ' ' )); + + // ggfs. anhaengende Anfuehrungszeichen entfernen + if( rName.Len() && '"' == rName.GetChar( rName.Len()-1 )) + rName.Erase( rName.Len()-1, 1); + + //#82900# Need the more sophisticated url converter. cmc + if (rName.Len()) + rName = URIHelper::SmartRel2Abs( + INetURLObject(sBaseURL), rName, Link(), false); +} + +// ConvertUFNneme uebersetzt FeldParameter-Namen u. ae. in den +// System-Zeichensatz und Upcased sie ( z.B. fuer Ref-Felder ) +namespace +{ + void ConvertUFName( String& rName ) + { + GetAppCharClass().toUpper( rName ); + } +} + +static void lcl_ConvertSequenceName(String& rSequenceName) +{ + ConvertUFName(rSequenceName); + if ('0' <= rSequenceName.GetChar(0) && '9' >= rSequenceName.GetChar(0)) + rSequenceName.Insert('_', 0); +} + +// FindParaStart() finds 1st Parameter that follows '\' and cToken +// and returns start of this parameter or STRING_NOT_FOUND. +xub_StrLen FindParaStart( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 ) +{ + bool bStr = false; // innerhalb String ignorieren + + for( xub_StrLen nBuf=0; nBuf+1 < rStr.Len(); nBuf++ ) + { + if( rStr.GetChar( nBuf ) == '"' ) + bStr = !bStr; + + if( !bStr + && rStr.GetChar( nBuf ) == '\\' + && ( rStr.GetChar( nBuf + 1 ) == cToken + || rStr.GetChar( nBuf + 1 ) == cToken2 ) ) + { + nBuf += 2; + // skip spaces between cToken and it's parameters + while( nBuf < rStr.Len() + && rStr.GetChar( nBuf ) == ' ' ) + nBuf++; + // return start of parameters + return nBuf < rStr.Len() ? nBuf : STRING_NOTFOUND; + } + } + return STRING_NOTFOUND; +} + +// FindPara() findet den ersten Parameter mit '\' und cToken. Es wird +// ein neuer String allokiert ( der vom Aufrufer deallokiert werden muss ) +// und alles, was zum Parameter gehoert, wird in ihm zurueckgeliefert. +String FindPara( const String& rStr, sal_Unicode cToken, sal_Unicode cToken2 ) +{ + xub_StrLen n2; // Ende + xub_StrLen n = FindParaStart( rStr, cToken, cToken2 ); // Anfang + if( STRING_NOTFOUND == n ) + return aEmptyStr; + + if( rStr.GetChar( n ) == '"' + || rStr.GetChar( n ) == 132 ) + { // Anfuehrungszeichen vor Para + n++; // Anfuehrungszeichen ueberlesen + n2 = n; // ab hier nach Ende suchen + while( n2 < rStr.Len() + && rStr.GetChar( n2 ) != 147 + && rStr.GetChar( n2 ) != '"' ) + n2++; // Ende d. Paras suchen + } + else + { // keine Anfuehrungszeichen + n2 = n; // ab hier nach Ende suchen + while( n2 < rStr.Len() + && rStr.GetChar( n2 ) != ' ' ) + n2++; // Ende d. Paras suchen + } + return rStr.Copy( n, n2-n ); +} + + +static SvxExtNumType GetNumTypeFromName(const String& rStr, + bool bAllowPageDesc = false) +{ + SvxExtNumType eTyp = bAllowPageDesc ? SVX_NUM_PAGEDESC : SVX_NUM_ARABIC; + if( rStr.EqualsIgnoreCaseAscii( "Arabi", 0, 5 ) ) // Arabisch, Arabic + eTyp = SVX_NUM_ARABIC; + else if( rStr.EqualsAscii( "misch", 2, 5 ) ) // r"omisch + eTyp = SVX_NUM_ROMAN_LOWER; + else if( rStr.EqualsAscii( "MISCH", 2, 5 ) ) // R"OMISCH + eTyp = SVX_NUM_ROMAN_UPPER; + else if( rStr.EqualsIgnoreCaseAscii( "alphabeti", 0, 9 ) )// alphabetisch, alphabetic + eTyp = ( rStr.GetChar( 0 ) == 'A' ) + ? SVX_NUM_CHARS_UPPER_LETTER_N + : SVX_NUM_CHARS_LOWER_LETTER_N; + else if( rStr.EqualsIgnoreCaseAscii( "roman", 0, 5 ) ) // us + eTyp = ( rStr.GetChar( 0 ) == 'R' ) + ? SVX_NUM_ROMAN_UPPER + : SVX_NUM_ROMAN_LOWER; + return eTyp; +} + +static SvxExtNumType GetNumberPara(String& rStr, bool bAllowPageDesc = false) +{ + String s( FindPara( rStr, '*', '*' ) ); // Ziffernart + SvxExtNumType aType = GetNumTypeFromName( s, bAllowPageDesc ); + return aType; +} + + + + +bool SwWW8ImplReader::ForceFieldLanguage(SwField &rFld, USHORT nLang) +{ + bool bRet(false); + + const SvxLanguageItem *pLang = + (const SvxLanguageItem*)GetFmtAttr(RES_CHRATR_LANGUAGE); + ASSERT(pLang, "impossible"); + USHORT nDefault = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US; + + if (nLang != nDefault) + { + rFld.SetAutomaticLanguage(false); + rFld.SetLanguage(nLang); + bRet = true; + } + + return bRet; +} + +String GetWordDefaultDateStringAsUS(SvNumberFormatter* pFormatter, USHORT nLang) +{ + //Get the system date in the correct final language layout, convert to + //a known language and modify the 2 digit year part to be 4 digit, and + //convert back to the correct language layout. + ULONG nIndex = pFormatter->GetFormatIndex(NF_DATE_SYSTEM_SHORT, nLang); + + SvNumberformat aFormat = const_cast<SvNumberformat &> + (*(pFormatter->GetEntry(nIndex))); + aFormat.ConvertLanguage(*pFormatter, nLang, LANGUAGE_ENGLISH_US); + + String sParams(aFormat.GetFormatstring()); + // --> OD 2007-02-09 #i36594# + // Fix provided by mloiseleur@openoffice.org. + // A default date can have already 4 year digits, in some case + const xub_StrLen pos = sParams.Search( CREATE_CONST_ASC("YYYY") ); + if ( pos == STRING_NOTFOUND ) + { + sParams.SearchAndReplace(CREATE_CONST_ASC("YY"), CREATE_CONST_ASC("YYYY")); + } + // <-- + return sParams; +} + +short SwWW8ImplReader::GetTimeDatePara(String& rStr, sal_uInt32& rFormat, + USHORT &rLang, int nWhichDefault, bool bHijri) +{ + bool bRTL = false; + if (pPlcxMan && !bVer67) + { + const BYTE *pResult = pPlcxMan->HasCharSprm(0x85A); + if (pResult && *pResult) + bRTL = true; + } + RES_CHRATR eLang = bRTL ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE; + const SvxLanguageItem *pLang = (SvxLanguageItem*)GetFmtAttr( static_cast< USHORT >(eLang)); + ASSERT(pLang, "impossible"); + rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US; + + SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter(); + String sParams( FindPara( rStr, '@', '@' ) );// Date/Time + if (!sParams.Len()) + { + bool bHasTime = false; + switch (nWhichDefault) + { + case ww::ePRINTDATE: + case ww::eSAVEDATE: + sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang); + sParams.APPEND_CONST_ASC(" HH:MM:SS AM/PM"); + bHasTime = true; + break; + case ww::eCREATEDATE: + sParams.ASSIGN_CONST_ASC("DD/MM/YYYY HH:MM:SS"); + bHasTime = true; + break; + default: + case ww::eDATE: + sParams = GetWordDefaultDateStringAsUS(pFormatter, rLang); + break; + } + + if (bHijri) + sParams.Insert(CREATE_CONST_ASC("[~hijri]"), 0); + + UINT16 nCheckPos = 0; + INT16 nType = NUMBERFORMAT_DEFINED; + rFormat = 0; + + pFormatter->PutandConvertEntry(sParams, nCheckPos, nType, rFormat, + LANGUAGE_ENGLISH_US, rLang); + + return bHasTime ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE; + } + + ULONG nFmtIdx = + sw::ms::MSDateTimeFormatToSwFormat(sParams, pFormatter, rLang, bHijri); + short nNumFmtType = NUMBERFORMAT_UNDEFINED; + if (nFmtIdx) + nNumFmtType = pFormatter->GetType(nFmtIdx); + rFormat = nFmtIdx; + + return nNumFmtType; +} + +//----------------------------------------- +// Felder +//----------------------------------------- +// Am Ende des Einlesens entsprechende Felder updaten ( z.Zt. die Referenzen ) +void SwWW8ImplReader::UpdateFields() +{ +// rDoc.GetSysFldType( RES_GETREFFLD )->UpdateFlds(); // Referenzen +// rDoc.UpdateFlds(); // SetExp-Fields +// rDoc.UpdateFlds(); // alles ??? +// rDoc.UpdateExpFlds(); // SetExp-Fields + rDoc.SetUpdateExpFldStat(true); // JP: neu fuer alles wichtige + rDoc.SetInitDBFields(true); // Datenbank-Felder auch +} + +sal_uInt16 SwWW8ImplReader::End_Field() +{ + sal_uInt16 nRet = 0; + WW8PLCFx_FLD* pF = pPlcxMan->GetFld(); + ASSERT(pF, "WW8PLCFx_FLD - Pointer nicht da"); + if (!pF || !pF->EndPosIsFieldEnd()) + return nRet; + + ASSERT(!maFieldStack.empty(), "Empty field stack\n"); + if (!maFieldStack.empty()) + { + /* + only hyperlinks currently need to be handled like this, for the other + cases we have inserted a field not an attribute with an unknown end + point + */ + nRet = maFieldStack.back().mnFieldId; + switch (nRet) + { + case 88: + pCtrlStck->SetAttr(*pPaM->GetPoint(),RES_TXTATR_INETFMT); + break; + case 36: + case 68: + //Move outside the section associated with this type of field + *pPaM->GetPoint() = maFieldStack.back().maStartPos; + break; + default: + break; + } + maFieldStack.pop_back(); + } + return nRet; +} + +bool AcceptableNestedField(sal_uInt16 nFieldCode) +{ + switch (nFieldCode) + { + case 36: + case 68: + case 79: + case 88: + // --> OD 2007-01-02 #b6504125# + // Accept AutoTextList field as nested field. + // Thus, the field result is imported as plain text. + case 89: + // <-- + return true; + default: + return false; + } +} + +FieldEntry::FieldEntry(SwPosition &rPos, sal_uInt16 nFieldId) throw() + : maStartPos(rPos), mnFieldId(nFieldId) +{ +} + +FieldEntry::FieldEntry(const FieldEntry &rOther) throw() + : maStartPos(rOther.maStartPos), mnFieldId(rOther.mnFieldId) +{ +} + +void FieldEntry::Swap(FieldEntry &rOther) throw() +{ + std::swap(maStartPos, rOther.maStartPos); + std::swap(mnFieldId, rOther.mnFieldId); +} + +FieldEntry &FieldEntry::operator=(const FieldEntry &rOther) throw() +{ + FieldEntry aTemp(rOther); + Swap(aTemp); + return *this; +} + +// Read_Field liest ein Feld ein oder, wenn es nicht gelesen werden kann, +// wird 0 zurueckgegeben, so dass das Feld vom Aufrufer textuell gelesen wird. +// Returnwert: Gesamtlaenge des Feldes ( zum UEberlesen ) +long SwWW8ImplReader::Read_Field(WW8PLCFManResult* pRes) +{ + typedef eF_ResT (SwWW8ImplReader:: *FNReadField)( WW8FieldDesc*, String& ); + enum Limits {eMax = 96}; + static FNReadField aWW8FieldTab[eMax+1] = + { + 0, + 0, + 0, + &SwWW8ImplReader::Read_F_Ref, // 3 + 0, + 0, + &SwWW8ImplReader::Read_F_Set, // 6 + 0, + &SwWW8ImplReader::Read_F_Tox, // 8 + 0, + 0, + 0, + &SwWW8ImplReader::Read_F_Seq, // 12 + &SwWW8ImplReader::Read_F_Tox, // 13 + &SwWW8ImplReader::Read_F_DocInfo, // 14 + &SwWW8ImplReader::Read_F_DocInfo, // 15 + &SwWW8ImplReader::Read_F_DocInfo, // 16 + &SwWW8ImplReader::Read_F_Author, // 17 + &SwWW8ImplReader::Read_F_DocInfo, // 18 + &SwWW8ImplReader::Read_F_DocInfo, // 19 + &SwWW8ImplReader::Read_F_DocInfo, // 20 + &SwWW8ImplReader::Read_F_DocInfo, // 21 + &SwWW8ImplReader::Read_F_DocInfo, // 22 + &SwWW8ImplReader::Read_F_DocInfo, // 23 + &SwWW8ImplReader::Read_F_DocInfo, // 24 + &SwWW8ImplReader::Read_F_DocInfo, // 25 + &SwWW8ImplReader::Read_F_Anz, // 26 + &SwWW8ImplReader::Read_F_Anz, // 27 + &SwWW8ImplReader::Read_F_Anz, // 28 + &SwWW8ImplReader::Read_F_FileName, // 29 + &SwWW8ImplReader::Read_F_TemplName, // 30 + &SwWW8ImplReader::Read_F_DateTime, // 31 + &SwWW8ImplReader::Read_F_DateTime, // 32 + &SwWW8ImplReader::Read_F_CurPage, // 33 + 0, + 0, + &SwWW8ImplReader::Read_F_IncludeText, // 36 + &SwWW8ImplReader::Read_F_PgRef, // 37 + &SwWW8ImplReader::Read_F_InputVar, // 38 + &SwWW8ImplReader::Read_F_Input, // 39 + 0, + &SwWW8ImplReader::Read_F_DBNext, // 41 + 0, + 0, + &SwWW8ImplReader::Read_F_DBNum, // 44 + 0, + 0, + 0, + 0, + &SwWW8ImplReader::Read_F_Equation, // 49 + 0, + &SwWW8ImplReader::Read_F_Macro, // 51 + &SwWW8ImplReader::Read_F_ANumber, // 52 + &SwWW8ImplReader::Read_F_ANumber, // 53 + &SwWW8ImplReader::Read_F_ANumber, // 54 + 0, + + + 0, // 56: VERKNUePFUNG // fehlt noch !!!!!!!!!!!!!!!!!!!!!!! + + + &SwWW8ImplReader::Read_F_Symbol, // 57 + &SwWW8ImplReader::Read_F_Embedd, // 58 + &SwWW8ImplReader::Read_F_DBField, // 59 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &SwWW8ImplReader::Read_F_IncludePicture, // 67 + &SwWW8ImplReader::Read_F_IncludeText, // 68 + 0, + &SwWW8ImplReader::Read_F_FormTextBox, // 70 + &SwWW8ImplReader::Read_F_FormCheckBox, // 71 + &SwWW8ImplReader::Read_F_NoteReference, // 72 + 0, /*&SwWW8ImplReader::Read_F_Tox*/ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &SwWW8ImplReader::Read_F_FormListBox, // 83 + 0, // 84 + &SwWW8ImplReader::Read_F_DocInfo, // 85 + 0, // 86 + &SwWW8ImplReader::Read_F_OCX, // 87 + &SwWW8ImplReader::Read_F_Hyperlink, // 88 + 0, // 89 + 0, // 90 + 0, // 91 + 0, // 92 + 0, // 93 + 0, // 94 + &SwWW8ImplReader::Read_F_Shape, // 95 + 0 // eMax - Dummy leer Methode + }; + ASSERT( ( sizeof( aWW8FieldTab ) / sizeof( *aWW8FieldTab ) == eMax+1 ), + "FeldFunc-Tabelle stimmt nicht" ); + + WW8PLCFx_FLD* pF = pPlcxMan->GetFld(); + ASSERT(pF, "WW8PLCFx_FLD - Pointer nicht da"); + + if (!pF || !pF->StartPosIsFieldStart()) + return 0; + + bool bNested = false; + if (!maFieldStack.empty()) + { + mycFieldIter aEnd = maFieldStack.end(); + for(mycFieldIter aIter = maFieldStack.begin(); aIter != aEnd; ++aIter) + { + bNested = !AcceptableNestedField(aIter->mnFieldId); + if (bNested) + break; + } + } + + WW8FieldDesc aF; + bool bOk = pF->GetPara(pRes->nCp2OrIdx, aF); + + ASSERT(bOk, "WW8: Bad Field!\n"); + if (aF.nId == 33) aF.bCodeNest=false; //#124716#: do not recurse into nested page fields + + maFieldStack.push_back(FieldEntry(*pPaM->GetPoint(), aF.nId)); + + if (bNested) + return 0; + + USHORT n = ( aF.nId <= eMax ) ? aF.nId : static_cast< USHORT >(eMax); // alle > 91 werden 92 + USHORT nI = n / 32; // # des UINT32 + ULONG nMask = 1 << ( n % 32 ); // Maske fuer Bits + + if( nFieldTagAlways[nI] & nMask ) // Flag: Tag it + return Read_F_Tag( &aF ); // Resultat nicht als Text + + if( !bOk || !aF.nId ) // Feld kaputt + return aF.nLen; // -> ignorieren + + if( aF.nId > eMax - 1) // WW: Nested Field + { + if( nFieldTagBad[nI] & nMask ) // Flag: Tag it when bad + return Read_F_Tag( &aF ); // Resultat nicht als Text + else + return aF.nLen; + } + + //Only one type of field (hyperlink) in drawing textboxes exists + if (aF.nId != 88 && pPlcxMan && pPlcxMan->GetDoingDrawTextBox()) + return aF.nLen; + + // keine Routine vorhanden + if (bNested || !aWW8FieldTab[aF.nId] || aF.bCodeNest) + { + if( nFieldTagBad[nI] & nMask ) // Flag: Tag it when bad + return Read_F_Tag( &aF ); // Resultat nicht als Text + // Lese nur Resultat + if (aF.bResNest && !AcceptableNestedField(aF.nId)) + return aF.nLen; // Result nested -> nicht brauchbar + + long nOldPos = pStrm->Tell(); + String aStr; + aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+ + aF.nSCode, aF.nLCode, eTextCharSet ); + pStrm->Seek( nOldPos ); + + //#124725# field codes which contain '/' or '.' are not displayed in WinWord + if (!aStr.EqualsAscii(" ADDIN", 0, 6) && + (aStr.Search('.') != STRING_NOTFOUND || + aStr.Search('/') != STRING_NOTFOUND)) + return aF.nLen; + else + return aF.nLen - aF.nLRes - 1; // so viele ueberlesen, das Resultfeld + // wird wie Haupttext eingelesen + } + else + { // Lies Feld + long nOldPos = pStrm->Tell(); + String aStr; + aF.nLCode = pSBase->WW8ReadString( *pStrm, aStr, pPlcxMan->GetCpOfs()+ + aF.nSCode, aF.nLCode, eTextCharSet ); + + // --> OD 2005-07-25 #i51312# - graphics inside field code not supported + // by Writer. Thus, delete character 0x01, which stands for such a graphic. + if (aF.nId==51) //#i56768# only do it for the MACROBUTTON field, since DropListFields need the 0x01. + { + aStr.EraseAllChars( 0x01 ); + } + // <-- + + eF_ResT eRes = (this->*aWW8FieldTab[aF.nId])( &aF, aStr ); + pStrm->Seek( nOldPos ); + + switch ( eRes ) + { + case FLD_OK: + return aF.nLen; // alles OK + case FLD_TAGTXT: + if ((nFieldTagBad[nI] & nMask)) // Flag: Tag bad + return Read_F_Tag(&aF); // Taggen + //fall through... + case FLD_TEXT: + // so viele ueberlesen, das Resultfeld wird wie Haupttext + // eingelesen + // JP 15.07.99: attributes can start at char 0x14 so skip one + // char more back == "-2" + if (aF.nLRes) + return aF.nLen - aF.nLRes - 2; + else + return aF.nLen; + case FLD_TAGIGN: + if( ( nFieldTagBad[nI] & nMask ) ) // Flag: Tag bad + return Read_F_Tag( &aF ); // Taggen + return aF.nLen; // oder ignorieren + case FLD_READ_FSPA: + return aF.nLen - aF.nLRes - 2; // auf Char 1 positionieren + default: + return aF.nLen; // ignorieren + } + } +} + +//----------------------------------------- +// Felder Taggen +//----------------------------------------- + +// MakeTagString() gibt als Returnwert die Position des ersten +// CR / Zeilenende / Seitenumbruch in pText und wandelt auch nur bis dort +// Wenn keins dieser Sonderzeichen enthalten ist, wird 0 zurueckgeliefert. +void SwWW8ImplReader::MakeTagString( String& rStr, const String& rOrg ) +{ + String sHex( CREATE_CONST_ASC( "\\x" )); + bool bAllowCr = SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_IN_TEXT ) + || SwFltGetFlag( nFieldFlags, SwFltControlStack::ALLOW_FLD_CR ); + sal_Unicode cChar; + rStr = rOrg; + + for( xub_StrLen nI = 0; + nI < rStr.Len() && rStr.Len() < (MAX_FIELDLEN - 4); ++nI ) + { + bool bSetAsHex = false; + switch( cChar = rStr.GetChar( nI ) ) + { + case 132: // Typographische Anfuehrungszeichen + case 148: // gegen normale tauschen + case 147: + rStr.SetChar( nI, '"' ); + break; + case 19: + rStr.SetChar( nI, '{' ); + break; // 19..21 zu {|} + case 20: + rStr.SetChar( nI, '|' ); + break; + case 21: + rStr.SetChar( nI, '}' ); + break; + case '\\': // \{|} per \ Taggen + case '{': + case '|': + case '}': + rStr.Insert( nI, '\\' ); + ++nI; + break; + case 0x0b: + case 0x0c: + case 0x0d: + if( bAllowCr ) + rStr.SetChar( nI, '\n' ); + else + bSetAsHex = true; + break; + case 0xFE: + case 0xFF: + bSetAsHex = true; + break; + default: + bSetAsHex = 0x20 > cChar; + break; + } + + if( bSetAsHex ) + { + //all Hex-Numbers with \x before + String sTmp( sHex ); + if( cChar < 0x10 ) + sTmp += '0'; + sTmp += String::CreateFromInt32( cChar, 16 ); + rStr.Replace( nI, 1 , sTmp ); + nI += sTmp.Len() - 1; + } + } + + if( rStr.Len() > (MAX_FIELDLEN - 4)) + rStr.Erase( MAX_FIELDLEN - 4 ); +} + +void SwWW8ImplReader::InsertTagField( const USHORT nId, const String& rTagText ) +{ + String aName( CREATE_CONST_ASC( "WwFieldTag" ) ); + if( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_DO_ID ) ) // Nummer? + aName += String::CreateFromInt32( nId ); // ausgeben ? + + if( SwFltGetFlag(nFieldFlags, SwFltControlStack::TAGS_IN_TEXT)) + { + aName += rTagText; // als Txt taggen + rDoc.InsertString(*pPaM, aName, + IDocumentContentOperations::INS_NOHINTEXPAND); + } + else + { // normal tagggen + + SwFieldType* pFT = rDoc.InsertFldType( + SwSetExpFieldType( &rDoc, aName, nsSwGetSetExpType::GSE_STRING ) ); + SwSetExpField aFld( (SwSetExpFieldType*)pFT, rTagText ); // SUB_INVISIBLE + USHORT nSubType = ( SwFltGetFlag( nFieldFlags, SwFltControlStack::TAGS_VISIBLE ) ) ? 0 : nsSwExtendedSubType::SUB_INVISIBLE; + aFld.SetSubType(nSubType | nsSwGetSetExpType::GSE_STRING); + + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + } +} + +long SwWW8ImplReader::Read_F_Tag( WW8FieldDesc* pF ) +{ + long nOldPos = pStrm->Tell(); + + WW8_CP nStart = pF->nSCode - 1; // mit 0x19 am Anfang + long nL = pF->nLen; // Gesamtlaenge mit Resultat u. Nest + if( nL > MAX_FIELDLEN ) + nL = MAX_FIELDLEN; // MaxLaenge, durch Quoten + // max. 4* so gross + String sFTxt; + nL = pSBase->WW8ReadString( *pStrm, sFTxt, + pPlcxMan->GetCpOfs() + nStart, nL, eStructCharSet); + + + String aTagText; + MakeTagString( aTagText, sFTxt ); + InsertTagField( pF->nId, aTagText ); + + pStrm->Seek( nOldPos ); + return pF->nLen; +} + + +//----------------------------------------- +// normale Felder +//----------------------------------------- + +eF_ResT SwWW8ImplReader::Read_F_Input( WW8FieldDesc* pF, String& rStr ) +{ + String aDef; + String aQ; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aQ.Len() ) + aQ = aReadParam.GetResult(); + break; + case 'd': + case 'D': + { + xub_StrLen n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + aDef = aReadParam.GetResult(); + } + break; + } + } + if( !aDef.Len() ) + aDef = GetFieldResult( pF ); + + SwInputField aFld( (SwInputFieldType*)rDoc.GetSysFldType( RES_INPUTFLD ), + aDef, aQ, INP_TXT, 0 ); // sichtbar ( geht z.Zt. nicht anders ) + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + + return FLD_OK; +} + +// GetFieldResult alloziert einen String und liest das Feld-Resultat ein +String SwWW8ImplReader::GetFieldResult( WW8FieldDesc* pF ) +{ + long nOldPos = pStrm->Tell(); + + WW8_CP nStart = pF->nSRes; // Start Resultat + long nL = pF->nLRes; // Laenge Resultat + if( !nL ) + return aEmptyStr; // kein Resultat + + if( nL > MAX_FIELDLEN ) + nL = MAX_FIELDLEN; // MaxLaenge, durch Quoten + // max. 4* so gross + + String sRes; + nL = pSBase->WW8ReadString( *pStrm, sRes, pPlcxMan->GetCpOfs() + nStart, + nL, eStructCharSet ); + + pStrm->Seek( nOldPos ); + + //replace CR 0x0D with LF 0x0A + sRes.SearchAndReplaceAll(0x0D, 0x0A); + //replace VT 0x0B with LF 0x0A + sRes.SearchAndReplaceAll(0x0B, 0x0A); + return sRes; +} + +/* +Bookmarks can be set with fields SET and ASK, and they can be referenced with +REF. When set, they behave like variables in writer, otherwise they behave +like normal bookmarks. We can check whether we should use a show variable +instead of a normal bookmark ref by converting to "show variable" at the end +of the document those refs which look for the content of a bookmark but whose +bookmarks were set with SET or ASK. (See SwWW8FltRefStack) + +The other piece of the puzzle is that refs that point to the "location" of the +bookmark will in word actually point to the last location where the bookmark +was set with SET or ASK, not the actual bookmark. This is only noticable when +a document sets the bookmark more than once. This is because word places the +true bookmark at the location of the last set, but the refs will display the +position of the first set before the ref. + +So what we will do is + +1) keep a list of all bookmarks that were set, any bookmark names mentioned +here that are refed by content will be converted to show variables. + +2) create pseudo bookmarks for every position that a bookmark is set with SET +or ASK but has no existing bookmark. We can then keep a map from the original +bookmark name to the new one. As we parse the document new pseudo names will +replace the older ones, so the map always contains the bookmark of the +location that msword itself would use. + +3) word's bookmarks are case insensitive, writers are not. So we need to +map case different versions together, regardless of whether they are +variables or not. + +4) when a reference is (first) SET or ASK, the bookmark associated with it +is placed around the 0x14 0x15 result part of the field. We will fiddle +the placement to be the writer equivalent of directly before and after +the field, which gives the same effect and meaning, to do so we must +get any bookmarks in the field range, and begin them immediately before +the set/ask field, and end them directly afterwards. MapBookmarkVariables +returns an identifier of the bookmark attribute to close after inserting +the appropiate set/ask field. +*/ +long SwWW8ImplReader::MapBookmarkVariables(const WW8FieldDesc* pF, + String &rOrigName, const String &rData) +{ + ASSERT(pPlcxMan,"No pPlcxMan"); + long nNo; + /* + If there was no bookmark associated with this set field, then we create a + pseudo one and insert it in the document. + */ + USHORT nIndex; + pPlcxMan->GetBook()->MapName(rOrigName); + String sName = pPlcxMan->GetBook()->GetBookmark( + pF->nSCode, pF->nSCode + pF->nLen, nIndex); + if (sName.Len()) + { + pPlcxMan->GetBook()->SetStatus(nIndex, BOOK_IGNORE); + nNo = nIndex; + } + else + { + sName = CREATE_CONST_ASC("WWSetBkmk"); + nNo = pReffingStck->aFieldVarNames.size()+1; + sName += String::CreateFromInt32(nNo); + nNo += pPlcxMan->GetBook()->GetIMax(); + } + pReffedStck->NewAttr(*pPaM->GetPoint(), + SwFltBookmark(BookmarkToWriter(sName), rData, nNo, 0)); + pReffingStck->aFieldVarNames[rOrigName] = sName; + return nNo; +} + +/* +Word can set a bookmark with set or with ask, such a bookmark is equivalent to +our variables, but until the end of a document we cannot be sure if a bookmark +is a variable or not, at the end we will have a list of reference names which +were set or asked, all bookmarks using the content of those bookmarks are +converted to show variables, those that reference the position of the field +can be left as references, because a bookmark is also inserted at the position +of a set or ask field, either by word, or in some special cases by the import +filter itself. +*/ +SwFltStackEntry *SwWW8FltRefStack::RefToVar(const SwField* pFld, + SwFltStackEntry *pEntry) +{ + SwFltStackEntry *pRet=0; + if (pFld && RES_GETREFFLD == pFld->Which()) + { + //Get the name of the ref field, and see if actually a variable + const String &rName = pFld->GetPar1(); + ::std::map<String,String,SwWW8FltRefStack::ltstr>::const_iterator + aResult = aFieldVarNames.find(rName); + + if (aResult != aFieldVarNames.end()) + { + SwGetExpField aFld( (SwGetExpFieldType*) + pDoc->GetSysFldType(RES_GETEXPFLD), rName, nsSwGetSetExpType::GSE_STRING, 0); + delete pEntry->pAttr; + SwFmtFld aTmp(aFld); + pEntry->pAttr = aTmp.Clone(); + pRet = pEntry; + } + } + return pRet; +} + +String SwWW8ImplReader::GetMappedBookmark(const String &rOrigName) +{ + String sName(BookmarkToWriter(rOrigName)); + ASSERT(pPlcxMan,"no pPlcxMan"); + pPlcxMan->GetBook()->MapName(sName); + + //See if there has been a variable set with this name, if so get + //the pseudo bookmark name that was set with it. + ::std::map<String,String,SwWW8FltRefStack::ltstr>::const_iterator aResult = + pReffingStck->aFieldVarNames.find(sName); + + const String &rBkmName = (aResult == pReffingStck->aFieldVarNames.end()) + ? sName : (*aResult).second; + + return rBkmName; +} + +// "ASK" +eF_ResT SwWW8ImplReader::Read_F_InputVar( WW8FieldDesc* pF, String& rStr ) +{ + String sOrigName; + String aQ; + String aDef; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if (!sOrigName.Len()) + sOrigName = aReadParam.GetResult(); + else if( !aQ.Len() ) + aQ = aReadParam.GetResult(); + break; + case 'd': + case 'D': + if (STRING_NOTFOUND != aReadParam.GoToTokenParam()) + aDef = aReadParam.GetResult(); + break; + } + } + + if( !sOrigName.Len() ) + return FLD_TAGIGN; // macht ohne Textmarke keinen Sinn + + String aResult(GetFieldResult(pF)); + + //#i24377#, munge Default Text into title as we have only one slot + //available for aResult and aDef otherwise + if (aDef.Len()) + { + if (aQ.Len()) + aQ.APPEND_CONST_ASC(" - "); + aQ.Append(aDef); + } + + long nNo = MapBookmarkVariables(pF, sOrigName, aResult); + + SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType( + SwSetExpFieldType(&rDoc, sOrigName, nsSwGetSetExpType::GSE_STRING)); + SwSetExpField aFld(pFT, aResult); + aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING); + aFld.SetInputFlag(true); + aFld.SetPromptText( aQ ); + + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + + pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo); + return FLD_OK; +} + +// "AUTONR" +eF_ResT SwWW8ImplReader::Read_F_ANumber( WW8FieldDesc*, String& rStr ) +{ + if( !pNumFldType ){ // 1. Mal + SwSetExpFieldType aT( &rDoc, CREATE_CONST_ASC("AutoNr"), nsSwGetSetExpType::GSE_SEQ ); + pNumFldType = rDoc.InsertFldType( aT ); + } + SwSetExpField aFld( (SwSetExpFieldType*)pNumFldType, aEmptyStr, + GetNumberPara( rStr ) ); + aFld.SetValue( ++nFldNum ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +// "SEQ" +eF_ResT SwWW8ImplReader::Read_F_Seq( WW8FieldDesc*, String& rStr ) +{ + String aSequenceName; + String aBook; + bool bHidden = false; + bool bFormat = false; + bool bShowLast = false; + bool bCountOn = true; + String sStart; + SvxExtNumType eNumFormat = SVX_NUM_ARABIC; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aSequenceName.Len() ) + aSequenceName = aReadParam.GetResult(); + else if( !aBook.Len() ) + aBook = aReadParam.GetResult(); + break; + + case 'h': + if( !bFormat ) + bHidden = true; // Hidden-Flag aktivieren + break; + + case '*': + bFormat = true; // Format-Flag aktivieren + bHidden = false; // Hidden-Flag deaktivieren + nRet = aReadParam.SkipToNextToken(); + if( -2 == nRet ) + eNumFormat = GetNumTypeFromName( aReadParam.GetResult() ); + break; + + case 'r': + bShowLast = false; // Zaehler neu setzen + bCountOn = false; + nRet = aReadParam.SkipToNextToken(); + if( -2 == nRet ) + sStart = aReadParam.GetResult(); + break; + + case 'c': + bShowLast = true; // zuletzt verwendete Nummer anzeigen + bCountOn = false; + break; + + case 'n': + bCountOn = true; // Nummer um eins erhoehen (default) + bShowLast = false; + break; + + case 's': // Outline Level + //#i19682, what am I to do with this value + break; + } + } + if (!aSequenceName.Len() && !aBook.Len()) + return FLD_TAGIGN; + + SwSetExpFieldType* pFT = (SwSetExpFieldType*)rDoc.InsertFldType( + SwSetExpFieldType( &rDoc, aSequenceName, nsSwGetSetExpType::GSE_SEQ ) ); + SwSetExpField aFld( pFT, aEmptyStr, eNumFormat ); + + if (sStart.Len()) + aFld.SetFormula( ( aSequenceName += '=' ) += sStart ); + else if (!bCountOn) + aFld.SetFormula(aSequenceName); + + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_DocInfo( WW8FieldDesc* pF, String& rStr ) +{ + USHORT nSub=0; + // RegInfoFormat, DefaultFormat fuer DocInfoFelder + USHORT nReg = DI_SUB_AUTHOR; + bool bDateTime = false; + + if( 85 == pF->nId ) + { + String aDocProperty; + _ReadFieldParams aReadParam( rStr ); + long nRet; + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aDocProperty.Len() ) + aDocProperty = aReadParam.GetResult(); + break; + case '*': + //Skip over MERGEFORMAT + aReadParam.SkipToNextToken(); + break; + } + } + aDocProperty.EraseAllChars('"'); + + /* + There are up to 26 fields that may be meant by 'DocumentProperty'. + Which of them is to be inserted here ? + This Problem can only be solved by implementing a name matching + method that compares the given Parameter String with the four + possible name sets (english, german, french, spanish) + */ + + static const sal_Char* aName10 = "\x0F"; // SW field code + static const sal_Char* aName11 // German + = "TITEL"; + static const sal_Char* aName12 // French + = "TITRE"; + static const sal_Char* aName13 // English + = "TITLE"; + static const sal_Char* aName14 // Spanish + = "TITRO"; + static const sal_Char* aName20 = "\x15"; // SW filed code + static const sal_Char* aName21 // German + = "ERSTELLDATUM"; + static const sal_Char* aName22 // French + = "CR\xC9\xC9"; + static const sal_Char* aName23 // English + = "CREATED"; + static const sal_Char* aName24 // Spanish + = "CREADO"; + static const sal_Char* aName30 = "\x16"; // SW filed code + static const sal_Char* aName31 // German + = "ZULETZTGESPEICHERTZEIT"; + static const sal_Char* aName32 // French + = "DERNIERENREGISTREMENT"; + static const sal_Char* aName33 // English + = "SAVED"; + static const sal_Char* aName34 // Spanish + = "MODIFICADO"; + static const sal_Char* aName40 = "\x17"; // SW filed code + static const sal_Char* aName41 // German + = "ZULETZTGEDRUCKT"; + static const sal_Char* aName42 // French + = "DERNI\xC8" "REIMPRESSION"; + static const sal_Char* aName43 // English + = "LASTPRINTED"; + static const sal_Char* aName44 // Spanish + = "HUPS PUPS"; + static const sal_Char* aName50 = "\x18"; // SW filed code + static const sal_Char* aName51 // German + = "\xDC" "BERARBEITUNGSNUMMER"; + static const sal_Char* aName52 // French + = "NUM\xC9" "RODEREVISION"; + static const sal_Char* aName53 // English + = "REVISIONNUMBER"; + static const sal_Char* aName54 // Spanish + = "SNUBBEL BUBBEL"; + static const USHORT nFldCnt = 5; + + // additional fields are to be coded soon! :-) + + static const USHORT nLangCnt = 4; + static const sal_Char *aNameSet_26[nFldCnt][nLangCnt+1] = + { + {aName10, aName11, aName12, aName13, aName14}, + {aName20, aName21, aName22, aName23, aName24}, + {aName30, aName31, aName32, aName33, aName34}, + {aName40, aName41, aName42, aName43, aName44}, + {aName50, aName51, aName52, aName53, aName54} + }; + + bool bFldFound= false; + USHORT nFIdx; + for(USHORT nLIdx=1; !bFldFound && (nLangCnt > nLIdx); ++nLIdx) + { + for(nFIdx = 0; !bFldFound && (nFldCnt > nFIdx); ++nFIdx) + { + if( aDocProperty.Equals( String( aNameSet_26[nFIdx][nLIdx], + RTL_TEXTENCODING_MS_1252 ) ) ) + { + bFldFound = true; + pF->nId = aNameSet_26[nFIdx][0][0]; + } + } + } + + if( !bFldFound ) + { +/* + SwUserFieldType aTmp( &rDoc, aDocProperty ); + aTmp.SetContent(GetFieldResult( pF )); + SwUserField aUFld( (SwUserFieldType*)rDoc.InsertFldType( aTmp )); + aUFld.ChangeFormat( UF_STRING ); + rDoc.Insert( *pPaM, SwFmtFld( aUFld ), 0); +*/ + SwDocInfoField aFld( (SwDocInfoFieldType*) + rDoc.GetSysFldType( RES_DOCINFOFLD ), DI_CUSTOM|nReg, aDocProperty, GetFieldResult( pF ) ); + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + + return FLD_OK; + } + } + + switch( pF->nId ) + { + case 14: + /* kann alle INFO-Vars!! */ + nSub = DI_KEYS; + break; + case 15: + nSub = DI_TITEL; + break; + case 16: + nSub = DI_THEMA; + break; + case 18: + nSub = DI_KEYS; + break; + case 19: + nSub = DI_COMMENT; + break; + case 20: + nSub = DI_CHANGE; + nReg = DI_SUB_AUTHOR; + break; + case 21: + nSub = DI_CREATE; + nReg = DI_SUB_DATE; + bDateTime = true; + break; + case 23: + nSub = DI_PRINT; + nReg = DI_SUB_DATE; + bDateTime = true; + break; + case 24: + nSub = DI_DOCNO; + break; + case 22: + nSub = DI_CHANGE; + nReg = DI_SUB_DATE; + bDateTime = true; + break; + case 25: + nSub = DI_CHANGE; + nReg = DI_SUB_TIME; + bDateTime = true; + break; + } + + sal_uInt32 nFormat = 0; + + USHORT nLang(0); + if (bDateTime) + { + short nDT = GetTimeDatePara(rStr, nFormat, nLang, pF->nId); + switch (nDT) + { + case NUMBERFORMAT_DATE: + nReg = DI_SUB_DATE; + break; + case NUMBERFORMAT_TIME: + nReg = DI_SUB_TIME; + break; + case NUMBERFORMAT_DATETIME: + nReg = DI_SUB_DATE; + break; + default: + nReg = DI_SUB_DATE; + break; + } + } + + SwDocInfoField aFld( (SwDocInfoFieldType*) + rDoc.GetSysFldType( RES_DOCINFOFLD ), nSub|nReg, String(), nFormat ); + if (bDateTime) + ForceFieldLanguage(aFld, nLang); + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_Author( WW8FieldDesc*, String& ) +{ + // SH: Das SwAuthorField bezeichnet nicht den urspruenglichen + // Autor, sondern den aktuellen Benutzer, also besser ueber DocInfo + // (#56149) + SwDocInfoField aFld( (SwDocInfoFieldType*) + rDoc.GetSysFldType( RES_DOCINFOFLD ), + DI_CREATE|DI_SUB_AUTHOR, String() ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_TemplName( WW8FieldDesc*, String& ) +{ + SwTemplNameField aFld( (SwTemplNameFieldType*) + rDoc.GetSysFldType( RES_TEMPLNAMEFLD ), FF_NAME ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +// Sowohl das Datum- wie auch das Uhrzeit-Feld kann fuer Datum, fuer Uhrzeit +// oder fuer beides benutzt werden. +eF_ResT SwWW8ImplReader::Read_F_DateTime( WW8FieldDesc*pF, String& rStr ) +{ + bool bHijri = false; + bool bSaka = false; + _ReadFieldParams aReadParam(rStr); + long nTok; + while (-1 != (nTok = aReadParam.SkipToNextToken())) + { + switch (nTok) + { + default: + case 'l': + case -2: + break; + case 'h': + bHijri = true; + break; + case 's': + bSaka = true; + break; + } + } + + sal_uInt32 nFormat = 0; + + USHORT nLang(0); + short nDT = GetTimeDatePara(rStr, nFormat, nLang, ww::eDATE, bHijri); + + if( NUMBERFORMAT_UNDEFINED == nDT ) // no D/T-Formatstring + { + if (32 == pF->nId) + { + nDT = NUMBERFORMAT_TIME; + nFormat = rDoc.GetNumberFormatter()->GetFormatIndex( + NF_TIME_START, LANGUAGE_SYSTEM ); + } + else + { + nDT = NUMBERFORMAT_DATE; + nFormat = rDoc.GetNumberFormatter()->GetFormatIndex( + NF_DATE_START, LANGUAGE_SYSTEM ); + } + } + + if (nDT & NUMBERFORMAT_DATE) + { + SwDateTimeField aFld((SwDateTimeFieldType*) + rDoc.GetSysFldType(RES_DATETIMEFLD ), DATEFLD, nFormat); + ForceFieldLanguage(aFld, nLang); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + } + else if (nDT == NUMBERFORMAT_TIME) + { + SwDateTimeField aFld((SwDateTimeFieldType*) + rDoc.GetSysFldType(RES_DATETIMEFLD), TIMEFLD, nFormat); + ForceFieldLanguage(aFld, nLang); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + } + + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_FileName(WW8FieldDesc*, String &rStr) +{ + SwFileNameFormat eType = FF_NAME; + long nRet; + _ReadFieldParams aReadParam(rStr); + while (-1 != (nRet = aReadParam.SkipToNextToken())) + { + switch (nRet) + { + case 'p': + eType = FF_PATHNAME; + break; + case '*': + //Skip over MERGEFORMAT + aReadParam.SkipToNextToken(); + break; + default: + ASSERT(!this, "unknown option in FileName field"); + break; + } + } + + SwFileNameField aFld( + (SwFileNameFieldType*)rDoc.GetSysFldType(RES_FILENAMEFLD), eType); + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_Anz( WW8FieldDesc* pF, String& rStr ) +{ // SeitenZahl - Feld + USHORT nSub = DS_PAGE; + switch ( pF->nId ){ + case 27: nSub = DS_WORD; break; // Wordzahl + case 28: nSub = DS_CHAR; break; // Zeichenzahl + } + SwDocStatField aFld( (SwDocStatFieldType*) + rDoc.GetSysFldType( RES_DOCSTATFLD ), nSub, + GetNumberPara( rStr ) ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_CurPage( WW8FieldDesc*, String& rStr ) +{ + // zusaetzlich mit Kapitelnummer? + if( bPgChpLevel ) + { + SwChapterField aFld( (SwChapterFieldType*) + rDoc.GetSysFldType( RES_CHAPTERFLD ), CF_NUMBER ); + aFld.SetLevel( nPgChpLevel ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + + static const sal_Char aDelim[] = "-.:\x97\x96"; + BYTE nDelim = nPgChpDelim; + if( nDelim > 4 ) + nDelim = 0; + + sal_Unicode c = ByteString::ConvertToUnicode( aDelim[ nDelim ], + RTL_TEXTENCODING_MS_1252 ); + if( '-' == c ) + { + rDoc.InsertString( *pPaM, CHAR_HARDHYPHEN ); + } + else + { + rDoc.InsertString( *pPaM, c ); // maybe insert ZWNBSP? + } + } + + // Seitennummer + SwPageNumberField aFld( (SwPageNumberFieldType*) + rDoc.GetSysFldType( RES_PAGENUMBERFLD ), PG_RANDOM, + GetNumberPara(rStr, true)); + + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_Symbol( WW8FieldDesc*, String& rStr ) +{ + //e.g. #i20118# + String aQ; + String aName; + sal_Int32 nSize = 0; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aQ.Len() ) + aQ = aReadParam.GetResult(); + break; + case 'f': + case 'F': + { + xub_StrLen n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + aName = aReadParam.GetResult(); + } + break; + case 's': + case 'S': + { + String aSiz; + xub_StrLen n = aReadParam.GoToTokenParam(); + if (STRING_NOTFOUND != n) + aSiz = aReadParam.GetResult(); + if (aSiz.Len()) + nSize = aSiz.ToInt32() * 20; // pT -> twip + } + break; + } + } + if( !aQ.Len() ) + return FLD_TAGIGN; // -> kein 0-Zeichen in Text + + if (sal_Unicode cChar = static_cast<sal_Unicode>(aQ.ToInt32())) + { + if (aName.Len()) // Font Name set ? + { + SvxFontItem aFont(FAMILY_DONTKNOW, aName, aEmptyStr, + PITCH_DONTKNOW, RTL_TEXTENCODING_SYMBOL, RES_CHRATR_FONT); + NewAttr(aFont); // new Font + } + + if (nSize > 0) //#i20118# + { + SvxFontHeightItem aSz(nSize, 100, RES_CHRATR_FONTSIZE); + NewAttr(aSz); + } + + rDoc.InsertString(*pPaM, cChar); + + if (nSize > 0) + pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONTSIZE); + if (aName.Len()) + pCtrlStck->SetAttr(*pPaM->GetPoint(), RES_CHRATR_FONT); + } + else + { + rDoc.InsertString(*pPaM, CREATE_CONST_ASC("###")); + } + + return FLD_OK; +} + +// "EINBETTEN" +eF_ResT SwWW8ImplReader::Read_F_Embedd( WW8FieldDesc*, String& rStr ) +{ + String sHost; + + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + sHost = aReadParam.GetResult(); + break; + + case 's': + // use ObjectSize + break; + } + } + + if( bObj && nPicLocFc ) + nObjLocFc = nPicLocFc; + bEmbeddObj = true; + return FLD_TEXT; +} + + +// "SET" +eF_ResT SwWW8ImplReader::Read_F_Set( WW8FieldDesc* pF, String& rStr ) +{ + String sOrigName; + String sVal; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !sOrigName.Len() ) + sOrigName = aReadParam.GetResult(); + else if( !sVal.Len() ) + sVal = aReadParam.GetResult(); + break; + } + } + + long nNo = MapBookmarkVariables(pF,sOrigName,sVal); + + SwFieldType* pFT = rDoc.InsertFldType( SwSetExpFieldType( &rDoc, sOrigName, + nsSwGetSetExpType::GSE_STRING ) ); + SwSetExpField aFld( (SwSetExpFieldType*)pFT, sVal, ULONG_MAX ); + aFld.SetSubType(nsSwExtendedSubType::SUB_INVISIBLE | nsSwGetSetExpType::GSE_STRING); + + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + + pReffedStck->SetAttr(*pPaM->GetPoint(), RES_FLTR_BOOKMARK, true, nNo); + + return FLD_OK; +} + +// "REF" +eF_ResT SwWW8ImplReader::Read_F_Ref( WW8FieldDesc*, String& rStr ) +{ // Reference - Field + String sOrigBkmName; + bool bChapterNr = false; + bool bAboveBelow = false; + + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !sOrigBkmName.Len() ) // get name of bookmark + sOrigBkmName = aReadParam.GetResult(); + break; + case 'n': + case 'r': + case 'w': + bChapterNr = true; // activate flag 'Chapter Number' + break; + + case 'p': + bAboveBelow = true; + break; + case 'h': + break; + default: + // unimplemented switch: just do 'nix nought nothing' :-) + break; + } + } + + String sBkmName(GetMappedBookmark(sOrigBkmName)); + + if (!bAboveBelow || bChapterNr) + { + if (bChapterNr) + { + SwGetRefField aFld( + (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ), + sBkmName,REF_BOOKMARK,0,REF_CHAPTER); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + } + else + { + /* + If we are just inserting the contents of the bookmark, then it + is possible that the bookmark is actually a variable, so we + must store it until the end of the document to see if it was, + in which case we'll turn it into a show variable + */ + SwGetRefField aFld( + (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ), + sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT); + pReffingStck->NewAttr( *pPaM->GetPoint(), SwFmtFld(aFld) ); + pReffingStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_FIELD); + } + } + + if( bAboveBelow ) + { + SwGetRefField aFld( (SwGetRefFieldType*) + rDoc.GetSysFldType( RES_GETREFFLD ), sBkmName, REF_BOOKMARK, 0, + REF_UPDOWN ); + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + } + return FLD_OK; +} + +// Note Reference - Field +eF_ResT SwWW8ImplReader::Read_F_NoteReference( WW8FieldDesc*, String& rStr ) +{ + String aBkmName; + bool bChapterNr = false; + bool bAboveBelow = false; + + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aBkmName.Len() ) // get name of foot/endnote + aBkmName = aReadParam.GetResult(); + break; + case 'r': + bChapterNr = true; // activate flag 'Chapter Number' + break; + case 'p': + bAboveBelow = true; + break; + case 'h': + break; + default: + // unimplemented switch: just do 'nix nought nothing' :-) + break; + } + } + + // set Sequence No of corresponding Foot-/Endnote to Zero + // (will be corrected in + SwGetRefField aFld( (SwGetRefFieldType*) + rDoc.GetSysFldType( RES_GETREFFLD ), aBkmName, REF_FOOTNOTE, 0, + REF_ONLYNUMBER ); + pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld)); + pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD); + if (bAboveBelow) + { + SwGetRefField aFld2( (SwGetRefFieldType*) + rDoc.GetSysFldType( RES_GETREFFLD ),aBkmName, REF_FOOTNOTE, 0, + REF_UPDOWN ); + pReffingStck->NewAttr(*pPaM->GetPoint(), SwFmtFld(aFld2)); + pReffingStck->SetAttr(*pPaM->GetPoint(), RES_TXTATR_FIELD); + } + return FLD_OK; +} + +// "SEITENREF" +eF_ResT SwWW8ImplReader::Read_F_PgRef( WW8FieldDesc*, String& rStr ) +{ + String sOrigName; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !sOrigName.Len() ) + sOrigName = aReadParam.GetResult(); + break; + } + } + + String sName(GetMappedBookmark(sOrigName)); + + SwGetRefField aFld( + (SwGetRefFieldType*)rDoc.GetSysFldType( RES_GETREFFLD ), sName, + REF_BOOKMARK, 0, REF_PAGE ); + + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +// "MACROSCHALTFL"ACHE" +eF_ResT SwWW8ImplReader::Read_F_Macro( WW8FieldDesc*, String& rStr) +{ + String aName; + String aVText; + long nRet; + bool bNewVText = true; + bool bBracket = false; + _ReadFieldParams aReadParam( rStr ); + + xub_StrLen nOffset = 0; + + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aName.Len() ) + aName = aReadParam.GetResult(); + else if( !aVText.Len() || bBracket ) + { + nOffset = aReadParam.GetTokenSttPtr() + 1; + + if( bBracket ) + aVText += ' '; + aVText += aReadParam.GetResult(); + if (bNewVText) + { + bBracket = aVText.EqualsIgnoreCaseAscii('[', 1, 0) + ? true : false; + bNewVText = false; + } + else if( aVText.GetChar( aVText.Len()-1 ) == ']' ) + bBracket = false; + } + break; + } + } + if( !aName.Len() ) + return FLD_TAGIGN; // makes no sense without Makro-Name + + aName.InsertAscii( "StarOffice.Standard.Modul1.", 0 ); + + SwMacroField aFld( (SwMacroFieldType*) + rDoc.GetSysFldType( RES_MACROFLD ), aName, aVText ); + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + + + WW8_CP nOldCp = pPlcxMan->Where(); + WW8_CP nCp = nOldCp + nOffset; + + SwPaM aPaM(*pPaM); + aPaM.SetMark(); + aPaM.Move(fnMoveBackward); + aPaM.Exchange(); + + mpPostProcessAttrsInfo = new WW8PostProcessAttrsInfo(nCp, nCp, aPaM); + + return FLD_OK; +} + +WW8PostProcessAttrsInfo::WW8PostProcessAttrsInfo(WW8_CP nCpStart, WW8_CP nCpEnd, + SwPaM & rPaM) +: mbCopy(false), + mnCpStart(nCpStart), + mnCpEnd(nCpEnd), + mPaM(*rPaM.GetPoint(), *rPaM.GetMark()), + mItemSet(rPaM.GetDoc()->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END - 1) +{ +} + +bool CanUseRemoteLink(const String &rGrfName) +{ + bool bUseRemote = false; + try + { + ::ucbhelper::Content aCnt(rGrfName, + uno::Reference< + ucb::XCommandEnvironment >() ); + rtl::OUString aTitle; + + aCnt.getPropertyValue(rtl::OUString::createFromAscii("Title" )) + >>= aTitle; + bUseRemote = (aTitle.getLength() > 0); + } + catch ( ... ) + { + // this file did not exist, so we will not set this as graphiclink + bUseRemote = false; + } + return bUseRemote; +} + +// "EINF"UGENGRAFIK" +eF_ResT SwWW8ImplReader::Read_F_IncludePicture( WW8FieldDesc*, String& rStr ) +{ + String aGrfName; + bool bEmbedded = true; + + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if (!aGrfName.Len()) + ConvertFFileName(aGrfName, aReadParam.GetResult()); + break; + + case 'd': + bEmbedded = false; // Embedded-Flag deaktivieren + break; + + case 'c':// den Converter-Namen ueberlesen + aReadParam.FindNextStringPiece(); + break; + } + } + + if (!bEmbedded) + bEmbedded = !CanUseRemoteLink(aGrfName); + + if (!bEmbedded) + { + /* + Besonderheit: + + Wir setzen jetzt den Link ins Doc und merken uns den SwFlyFrmFmt. + Da wir ja unten auf jjeden Fall mit Return-Wert FLD_READ_FSPA enden, + wird der Skip-Wert so bemessen, dass das folgende Char-1 eingelesen + wird. + Wenn wir dann in SwWW8ImplReader::ImportGraf() reinlaufen, wird + erkannt, dass wir soeben einen Grafik-Link inserted haben und + das passende SwAttrSet wird ins Frame-Format eingesetzt. + */ + SfxItemSet aFlySet( rDoc.GetAttrPool(), RES_FRMATR_BEGIN, + RES_FRMATR_END-1 ); + aFlySet.Put( SwFmtAnchor( FLY_IN_CNTNT ) ); + aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME )); + pFlyFmtOfJustInsertedGraphic = rDoc.Insert( *pPaM, + aGrfName, + aEmptyStr, + 0, // Graphic* + &aFlySet, + 0, 0); // SwFrmFmt* + maGrfNameGenerator.SetUniqueGraphName(pFlyFmtOfJustInsertedGraphic, + INetURLObject(aGrfName).GetBase()); + } + return FLD_READ_FSPA; +} + + +String wwSectionNamer::UniqueName() +{ + String aName(msFileLinkSeed); + aName += String::CreateFromInt32(++mnFileSectionNo); + return mrDoc.GetUniqueSectionName(&aName); +} + +// "EINFUEGENTEXT" +eF_ResT SwWW8ImplReader::Read_F_IncludeText( WW8FieldDesc* /*pF*/, String& rStr ) +{ + String aPara; + String aBook; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aPara.Len() ) + aPara = aReadParam.GetResult(); + else if( !aBook.Len() ) + aBook = aReadParam.GetResult(); + break; + case '*': + //Skip over MERGEFORMAT + aReadParam.SkipToNextToken(); + break; + } + } + ConvertFFileName(aPara, aPara); + + if (aBook.Len() && aBook.GetChar( 0 ) != '\\') + { + // Bereich aus Quelle ( kein Switch ) ? + ConvertUFName(aBook); + aPara += sfx2::cTokenSeperator; + aPara += sfx2::cTokenSeperator; + aPara += aBook; + } + + /* + ##509## + What we will do is insert a section to be linked to a file, but just in + case the file is not available we will fill in the section with the stored + content of this winword field as a fallback. + */ + SwPosition aTmpPos(*pPaM->GetPoint()); + + SwSection aSection(FILE_LINK_SECTION, maSectionNameGenerator.UniqueName()); + aSection.SetLinkFileName( aPara ); + aSection.SetProtect(true); + + SwSection*const pSection = rDoc.InsertSwSection(*pPaM, aSection, 0, false); + ASSERT(pSection, "no section inserted"); + if (!pSection) + return FLD_TEXT; + const SwSectionNode* pSectionNode = pSection->GetFmt()->GetSectionNode(); + ASSERT(pSectionNode, "no section node!"); + if (!pSectionNode) + return FLD_TEXT; + + pPaM->GetPoint()->nNode = pSectionNode->GetIndex()+1; + pPaM->GetPoint()->nContent.Assign(pPaM->GetCntntNode(), 0 ); + + //we have inserted a section before this point, so adjust pos + //for future page/section segment insertion + maSectionManager.PrependedInlineNode(aTmpPos, *pPaM->GetNode()); + + return FLD_TEXT; +} + +// "SERIENDRUCKFELD" +eF_ResT SwWW8ImplReader::Read_F_DBField( WW8FieldDesc* pF, String& rStr ) +{ + String aName; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if( !aName.Len() ) + aName = aReadParam.GetResult(); + break; + } + } + SwDBFieldType aD( &rDoc, aName, SwDBData() ); // Datenbank: Nichts + + SwFieldType* pFT = rDoc.InsertFldType( aD ); + SwDBField aFld( (SwDBFieldType*)pFT ); + aFld.SetFieldCode( rStr ); + + String aResult; + pSBase->WW8ReadString( *pStrm, aResult, pPlcxMan->GetCpOfs()+ + pF->nSRes, pF->nLRes, eTextCharSet ); + + aFld.InitContent(aResult); + + rDoc.InsertPoolItem(*pPaM, SwFmtFld( aFld ), 0); + + return FLD_OK; +} + +// "N"ACHSTER" +eF_ResT SwWW8ImplReader::Read_F_DBNext( WW8FieldDesc*, String& ) +{ + SwDBNextSetFieldType aN; + SwFieldType* pFT = rDoc.InsertFldType( aN ); + SwDBNextSetField aFld( (SwDBNextSetFieldType*)pFT, aEmptyStr, aEmptyStr, + SwDBData() ); // Datenbank: Nichts + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +// "DATENSATZ" +eF_ResT SwWW8ImplReader::Read_F_DBNum( WW8FieldDesc*, String& ) +{ + SwDBSetNumberFieldType aN; + SwFieldType* pFT = rDoc.InsertFldType( aN ); + SwDBSetNumberField aFld( (SwDBSetNumberFieldType*)pFT, + SwDBData() ); // Datenbank: Nichts + rDoc.InsertPoolItem( *pPaM, SwFmtFld( aFld ), 0 ); + return FLD_OK; +} + +/* + EQ , only the usage for + a. Combined Characters supported, must be exactly in the form that word + only accepts as combined charactersm, i.e. + eq \o(\s\up Y(XXX),\s\do Y(XXX)) + b. Ruby Text supported, must be in the form that word recognizes as being + ruby text + ... +*/ +eF_ResT SwWW8ImplReader::Read_F_Equation( WW8FieldDesc*, String& rStr ) +{ + _ReadFieldParams aReadParam( rStr ); + long cChar = aReadParam.SkipToNextToken(); + if ('o' == cChar) + Read_SubF_Combined(aReadParam); + else if ('*' == cChar) + Read_SubF_Ruby(aReadParam); + return FLD_OK; +} + +void SwWW8ImplReader::Read_SubF_Combined( _ReadFieldParams& rReadParam) +{ + String sCombinedCharacters; + if ((-2 == rReadParam.SkipToNextToken()) && + rReadParam.GetResult().EqualsIgnoreCaseAscii('(', 1, 0)) + { + for (int i=0;i<2;i++) + { + if ('s' == rReadParam.SkipToNextToken()) + { + long cChar = rReadParam.SkipToNextToken(); + if (-2 != rReadParam.SkipToNextToken()) + break; + String sF = rReadParam.GetResult(); + if ((('u' == cChar) && sF.EqualsIgnoreCaseAscii('p', 1, 0)) + || (('d' == cChar) && sF.EqualsIgnoreCaseAscii('o', 1, 0))) + { + if (-2 == rReadParam.SkipToNextToken()) + { + String sPart = rReadParam.GetResult(); + xub_StrLen nBegin = sPart.Search('('); + + //Word disallows brackets in this field, which + //aids figuring out the case of an end of )) vs ) + xub_StrLen nEnd = sPart.Search(')'); + + if ((nBegin != STRING_NOTFOUND) && + (nEnd != STRING_NOTFOUND)) + { + sCombinedCharacters += + sPart.Copy(nBegin+1,nEnd-nBegin-1); + } + } + } + } + } + } + if (sCombinedCharacters.Len()) + { + SwCombinedCharField aFld((SwCombinedCharFieldType*) + rDoc.GetSysFldType(RES_COMBINED_CHARS),sCombinedCharacters); + rDoc.InsertPoolItem(*pPaM, SwFmtFld(aFld), 0); + } +} + +void SwWW8ImplReader::Read_SubF_Ruby( _ReadFieldParams& rReadParam) +{ + USHORT nJustificationCode=0; + String sFontName; + UINT32 nFontSize=0; + String sRuby; + String sText; + long nRet; + while( -1 != ( nRet = rReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + { + String sTemp = rReadParam.GetResult(); + if( sTemp.EqualsIgnoreCaseAscii( "jc", 0, 2 ) ) + { + sTemp.Erase(0,2); + nJustificationCode = static_cast<USHORT>(sTemp.ToInt32()); + } + else if( sTemp.EqualsIgnoreCaseAscii( "hps", 0, 3 ) ) + { + sTemp.Erase(0,3); + nFontSize= static_cast<UINT32>(sTemp.ToInt32()); + } + else if( sTemp.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) ) + { + sTemp.Erase(0,5); + sFontName = sTemp; + } + } + break; + case '*': + break; + case 'o': + while( -1 != ( nRet = rReadParam.SkipToNextToken() )) + { + if ('u' == nRet) + { + if (-2 == rReadParam.SkipToNextToken() && + (rReadParam.GetResult().EqualsIgnoreCaseAscii('p', 1, 0))) + { + if (-2 == rReadParam.SkipToNextToken()) + { + String sPart = rReadParam.GetResult(); + xub_StrLen nBegin = sPart.Search('('); + + //Word disallows brackets in this field, + xub_StrLen nEnd = sPart.Search(')'); + + if ((nBegin != STRING_NOTFOUND) && + (nEnd != STRING_NOTFOUND)) + { + sRuby = sPart.Copy(nBegin+1,nEnd-nBegin-1); + } + if (STRING_NOTFOUND == + (nBegin = sPart.Search(',',nEnd))) + { + nBegin = sPart.Search(';',nEnd); + } + nEnd = sPart.SearchBackward(')'); + if ((nBegin != STRING_NOTFOUND) && + (nEnd != STRING_NOTFOUND)) + { + sText = sPart.Copy(nBegin+1,nEnd-nBegin-1); + } + } + } + } + + } + break; + } + } + + //Translate and apply + if (sRuby.Len() && sText.Len() && sFontName.Len() && nFontSize) + { + switch (nJustificationCode) + { + case 0: + nJustificationCode=1; + break; + case 1: + nJustificationCode=3; + break; + case 2: + nJustificationCode=4; + break; + default: + case 3: + nJustificationCode=0; + break; + case 4: + nJustificationCode=2; + break; + } + + SwFmtRuby aRuby(sRuby); + const SwCharFmt *pCharFmt=0; + //Make a guess at which of asian of western we should be setting + USHORT nScript; + if (pBreakIt->GetBreakIter().is()) + nScript = pBreakIt->GetBreakIter()->getScriptType(sRuby, 0); + else + nScript = i18n::ScriptType::ASIAN; + + //Check to see if we already have a ruby charstyle that this fits + std::vector<const SwCharFmt*>::const_iterator aEnd = + aRubyCharFmts.end(); + for(std::vector<const SwCharFmt*>::const_iterator aIter + = aRubyCharFmts.begin(); aIter != aEnd; ++aIter) + { + const SvxFontHeightItem &rFH = + ItemGet<SvxFontHeightItem>(*(*aIter), + GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript)); + if (rFH.GetHeight() == nFontSize*10) + { + const SvxFontItem &rF = ItemGet<SvxFontItem>(*(*aIter), + GetWhichOfScript(RES_CHRATR_FONT,nScript)); + if (rF.GetFamilyName().Equals(sFontName)) + { + pCharFmt=*aIter; + break; + } + } + } + + //Create a new char style if necessary + if (!pCharFmt) + { + SwCharFmt *pFmt=0; + String aNm; + //Take this as the base name + SwStyleNameMapper::FillUIName(RES_POOLCHR_RUBYTEXT,aNm); + aNm+=String::CreateFromInt32(aRubyCharFmts.size()+1); + pFmt = rDoc.MakeCharFmt(aNm,(SwCharFmt*)rDoc.GetDfltCharFmt()); + SvxFontHeightItem aHeightItem(nFontSize*10, 100, RES_CHRATR_FONTSIZE); + SvxFontItem aFontItem(FAMILY_DONTKNOW,sFontName, + aEmptyStr,PITCH_DONTKNOW,RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT); + aHeightItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONTSIZE,nScript)); + aFontItem.SetWhich(GetWhichOfScript(RES_CHRATR_FONT,nScript)); + pFmt->SetFmtAttr(aHeightItem); + pFmt->SetFmtAttr(aFontItem); + aRubyCharFmts.push_back(pFmt); + pCharFmt = pFmt; + } + + //Set the charstyle and justification + aRuby.SetCharFmtName(pCharFmt->GetName()); + aRuby.SetCharFmtId(pCharFmt->GetPoolFmtId()); + aRuby.SetAdjustment(nJustificationCode); + + NewAttr(aRuby); + rDoc.InsertString( *pPaM, sText ); + pCtrlStck->SetAttr( *pPaM->GetPoint(), RES_TXTATR_CJK_RUBY ); + } +} + +//----------------------------------------- +// Verzeichnis-Felder +//----------------------------------------- + +void lcl_toxMatchACSwitch( SwWW8ImplReader& /*rReader*/, + SwDoc& rDoc, + SwTOXBase& rBase, + _ReadFieldParams& rParam, + SwCaptionDisplay eCaptionType) +{ + xub_StrLen n = rParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + SwTOXType* pType = (SwTOXType*)rDoc.GetTOXType( TOX_ILLUSTRATIONS, 0); + pType->Add( &rBase ); + rBase.SetCaptionDisplay( eCaptionType ); + // Read Sequence Name and store in TOXBase + String sSeqName( rParam.GetResult() ); + lcl_ConvertSequenceName( sSeqName ); + rBase.SetSequenceName( sSeqName ); + } +} + +//For all outline styles that are not in the outline numbering add them here as +//custom extra styles +bool SwWW8ImplReader::AddExtraOutlinesAsExtraStyles(SwTOXBase& rBase) +{ + bool bExtras = false; + //This is the case if the winword outline numbering is set while the + //writer one is not + for (USHORT nI = 0; nI < nColls; ++nI) + { + SwWW8StyInf& rSI = pCollA[nI]; + if (rSI.IsOutline()) + { + const SwTxtFmtColl *pFmt = (const SwTxtFmtColl*)(rSI.pFmt); + sal_uInt16 nStyleLevel = rSI.nOutlineLevel; + sal_uInt16 nMaxLevel = rBase.GetLevel(); + if ( + //nStyleLevel != pFmt->GetOutlineLevel() && //#outline level,zhaojianwei + nStyleLevel != (pFmt->GetAttrOutlineLevel()-1) && //<-end,zhaojianwei + nStyleLevel < nMaxLevel + ) + { + String sStyles(rBase.GetStyleNames(rSI.nOutlineLevel)); + if( sStyles.Len()) + sStyles += TOX_STYLE_DELIMITER; + sStyles += pFmt->GetName(); + rBase.SetStyleNames(sStyles, rSI.nOutlineLevel); + bExtras = true; + } + } + } + return bExtras; +} + +static void EnsureMaxLevelForTemplates(SwTOXBase& rBase) +{ + //If the TOC contains Template entries at levels > the evaluation level + //that was initially taken from the max normal outline level of the word TOC + //then we cannot use that for the evaluation level because writer cuts off + //all styles above that level, while word just cuts off the "standard" + //outline styles, we have no option but to expand to the highest level + //Word included. + if ((rBase.GetLevel() != MAXLEVEL) && (nsSwTOXElement::TOX_TEMPLATE & rBase.GetCreateType())) + { + for (USHORT nI = MAXLEVEL; nI > 0; --nI) + { + String sStyles(rBase.GetStyleNames(nI-1)); + if (rBase.GetStyleNames(nI-1).Len()) + { + rBase.SetLevel(nI); + break; + } + } + } +} + +void lcl_toxMatchTSwitch(SwWW8ImplReader& rReader, SwTOXBase& rBase, + _ReadFieldParams& rParam) +{ + xub_StrLen n = rParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + String sParams( rParam.GetResult() ); + if( sParams.Len() ) + { + xub_StrLen nIndex = 0; + + //#92940# Delimiters between styles and style levels appears to + //allow both ; and , + + String sTemplate( sParams.GetToken(0, ';', nIndex) ); + if( STRING_NOTFOUND == nIndex ) + { + nIndex=0; + sTemplate = sParams.GetToken(0, ',', nIndex); + } + if( STRING_NOTFOUND == nIndex ) + { + const SwFmt* pStyle = rReader.GetStyleWithOrgWWName(sTemplate); + if( pStyle ) + sTemplate = pStyle->GetName(); + // Store Style for Level 0 into TOXBase + rBase.SetStyleNames( sTemplate, 0 ); + } + else while( STRING_NOTFOUND != nIndex ) + { + xub_StrLen nOldIndex=nIndex; + USHORT nLevel = static_cast<USHORT>( + sParams.GetToken(0, ';', nIndex).ToInt32()); + if( STRING_NOTFOUND == nIndex ) + { + nIndex = nOldIndex; + nLevel = static_cast<USHORT>( + sParams.GetToken(0, ',', nIndex).ToInt32()); + } + + if( (0 < nLevel) && (MAXLEVEL >= nLevel) ) + { + nLevel--; + // Store Style and Level into TOXBase + const SwFmt* pStyle + = rReader.GetStyleWithOrgWWName( sTemplate ); + + if( pStyle ) + sTemplate = pStyle->GetName(); + + String sStyles( rBase.GetStyleNames( nLevel ) ); + if( sStyles.Len() ) + sStyles += TOX_STYLE_DELIMITER; + sStyles += sTemplate; + rBase.SetStyleNames( sStyles, nLevel ); + } + // read next style name... + nOldIndex = nIndex; + sTemplate = sParams.GetToken(0, ';', nIndex); + if( STRING_NOTFOUND == nIndex ) + { + nIndex=nOldIndex; + sTemplate = sParams.GetToken(0, ',', nIndex); + } + } + } + } +} + +USHORT wwSectionManager::CurrentSectionColCount() const +{ + USHORT nIndexCols = 1; + if (!maSegments.empty()) + nIndexCols = maSegments.back().maSep.ccolM1 + 1; + return nIndexCols; +} + +//Will there be a new pagebreak at this position (don't know what type +//until later) +bool wwSectionManager::WillHavePageDescHere(SwNodeIndex aIdx) const +{ + bool bRet = false; + if (!maSegments.empty()) + { + if (!maSegments.back().IsContinous() && + maSegments.back().maStart == aIdx) + { + bRet = true; + } + } + return bRet; +} + +USHORT lcl_GetMaxValidWordTOCLevel(const SwForm &rForm) +{ + // GetFormMax() returns level + 1, hence the -1 + USHORT nRet = rForm.GetFormMax()-1; + + // If the max of this type of TOC is greater than the max of a word + // possible toc, then clip to the word max + if (nRet > WW8ListManager::nMaxLevel) + nRet = WW8ListManager::nMaxLevel; + + return nRet; +} + +eF_ResT SwWW8ImplReader::Read_F_Tox( WW8FieldDesc* pF, String& rStr ) +{ + if (pF->nLRes < 3) + return FLD_TEXT; // ignore (#i25440#) + + TOXTypes eTox; // Baue ToxBase zusammen + switch( pF->nId ) + { + case 8: + eTox = TOX_INDEX; + break; + case 13: + eTox = TOX_CONTENT; + break; + default: + eTox = TOX_USER; + break; + } + + USHORT nCreateOf = (eTox == TOX_CONTENT) ? nsSwTOXElement::TOX_OUTLINELEVEL : nsSwTOXElement::TOX_MARK; + + USHORT nIndexCols = 1; + + const SwTOXType* pType = rDoc.GetTOXType( eTox, 0 ); + SwForm aOrigForm(eTox); + SwTOXBase* pBase = new SwTOXBase( pType, aOrigForm, nCreateOf, aEmptyStr ); + pBase->SetProtected(maSectionManager.CurrentSectionIsProtected()); + switch( eTox ){ + case TOX_INDEX: + { + USHORT eOptions = nsSwTOIOptions::TOI_SAME_ENTRY | nsSwTOIOptions::TOI_CASE_SENSITIVE; + + // TOX_OUTLINELEVEL setzen wir genau dann, wenn + // die Parameter \o in 1 bis 9 liegen + // oder der Parameter \f existiert + // oder GARKEINE Switches Parameter angegeben sind. + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case 'c': + { + xub_StrLen n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + String sParams( aReadParam.GetResult() ); + // if NO String just ignore the \c + if( sParams.Len() ) + { + nIndexCols = + static_cast<USHORT>(sParams.ToInt32()); + } + } + } + break; + case 'e': + { + xub_StrLen n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) // if NO String just ignore the \e + { + String sDelimiter( aReadParam.GetResult() ); + SwForm aForm( pBase->GetTOXForm() ); + + // Attention: if TOX_CONTENT brave + // GetFormMax() returns MAXLEVEL + 1 !! + USHORT nEnd = aForm.GetFormMax()-1; + + for(USHORT nLevel = 1; + nLevel <= nEnd; + ++nLevel) + { + // Levels count from 1 + // Level 0 is reserved for CAPTION + + // Delimiter statt Tabstop vor der Seitenzahl einsetzen, + // falls es eine Seitenzahl gibt: + FormTokenType ePrevType = TOKEN_END; + FormTokenType eType; + // -> #i21237# + SwFormTokens aPattern = + aForm.GetPattern(nLevel); + SwFormTokens::iterator aIt = aPattern.begin(); + do + { + eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType; + + if (eType == TOKEN_PAGE_NUMS) + { + if (TOKEN_TAB_STOP == ePrevType) + { + aIt--; + + if(0x09 == sDelimiter.GetChar(0)) + aIt->eTabAlign = SVX_TAB_ADJUST_END; + else + { + SwFormToken aToken(TOKEN_TEXT); + aToken.sText = sDelimiter; + *aIt = aToken; + } + aForm.SetPattern(nLevel, aPattern); + } + + eType = TOKEN_END; + } + + ePrevType = eType; + } + while (TOKEN_END != eType); + // <- #i21237# + } + pBase->SetTOXForm( aForm ); + } + } + break; + case 'h': + { + eOptions |= nsSwTOIOptions::TOI_ALPHA_DELIMITTER; + } + break; + } + } + pBase->SetOptions( eOptions ); + } + break; + + case TOX_CONTENT: + { + bool bIsHyperlink = false; + // TOX_OUTLINELEVEL setzen wir genau dann, wenn + // die Parameter \o in 1 bis 9 liegen + // oder der Parameter \f existiert + // oder GARKEINE Switches Parameter angegeben sind. + USHORT eCreateFrom = 0; + USHORT nMaxLevel = 0; + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case 'h': + bIsHyperlink = true; + break; + case 'a': + case 'c': + lcl_toxMatchACSwitch(*this, rDoc, *pBase, aReadParam, + ('c' == nRet) + ? CAPTION_COMPLETE + : CAPTION_TEXT ); + break; + case 'o': + { + USHORT nVal; + if( !aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) ) + nVal = lcl_GetMaxValidWordTOCLevel(aOrigForm); + if( nMaxLevel < nVal ) + nMaxLevel = nVal; + eCreateFrom |= nsSwTOXElement::TOX_OUTLINELEVEL; + } + break; + case 'f': + eCreateFrom |= nsSwTOXElement::TOX_MARK; + break; + case 'l': + { + USHORT nVal; + if( aReadParam.GetTokenSttFromTo(0, &nVal, WW8ListManager::nMaxLevel) ) + { + if( nMaxLevel < nVal ) + nMaxLevel = nVal; + eCreateFrom |= nsSwTOXElement::TOX_MARK; + } + } + break; + case 't': // paragraphs using special styles shall + // provide the TOX's content + lcl_toxMatchTSwitch(*this, *pBase, aReadParam); + eCreateFrom |= nsSwTOXElement::TOX_TEMPLATE; + break; + case 'p': + { + xub_StrLen n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) // if NO String just ignore the \p + { + String sDelimiter( aReadParam.GetResult() ); + SwForm aForm( pBase->GetTOXForm() ); + + // Attention: if TOX_CONTENT brave + // GetFormMax() returns MAXLEVEL + 1 !! + USHORT nEnd = aForm.GetFormMax()-1; + + for(USHORT nLevel = 1; + nLevel <= nEnd; + ++nLevel) + { + // Levels count from 1 + // Level 0 is reserved for CAPTION + + // Delimiter statt Tabstop vor der Seitenzahl einsetzen, + // falls es eine Seitenzahl gibt: + FormTokenType ePrevType = TOKEN_END; + FormTokenType eType; + + // -> #i21237# + SwFormTokens aPattern = aForm.GetPattern(nLevel); + SwFormTokens::iterator aIt = aPattern.begin(); + do + { + eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType; + + if (eType == TOKEN_PAGE_NUMS) + { + if (TOKEN_TAB_STOP == ePrevType) + { + aIt--; + + SwFormToken aToken(TOKEN_TEXT); + aToken.sText = sDelimiter; + + *aIt = aToken; + aForm.SetPattern(nLevel, + aPattern); + } + eType = TOKEN_END; + } + ePrevType = eType; + } + while( TOKEN_END != eType ); + // <- #i21237# + } + pBase->SetTOXForm( aForm ); + } + } + break; + case 'n': // don't print page numbers + { + // read START and END param + USHORT nStart, nEnd; + if( !aReadParam.GetTokenSttFromTo( &nStart, &nEnd, + WW8ListManager::nMaxLevel ) ) + { + nStart = 1; + nEnd = aOrigForm.GetFormMax()-1; + } + // remove page numbers from this levels + SwForm aForm( pBase->GetTOXForm() ); + if (aForm.GetFormMax() <= nEnd) + nEnd = aForm.GetFormMax()-1; + for ( + USHORT nLevel = nStart; nLevel <= nEnd; + ++nLevel + ) + { + // Levels count from 1 + // Level 0 is reserved for CAPTION + + // Seitenzahl und ggfs. davorstehenden Tabstop + // entfernen: + FormTokenType eType; + // -> #i21237# + SwFormTokens aPattern = aForm.GetPattern(nLevel); + SwFormTokens::iterator aIt = aPattern.begin(); + do + { + eType = ++aIt == aPattern.end() ? TOKEN_END : aIt->eTokenType; + + if (eType == TOKEN_PAGE_NUMS) + { + aIt = aPattern.erase(aIt); + aIt--; + if ( + TOKEN_TAB_STOP == + aIt->eTokenType + ) + { + aPattern.erase(aIt); + aForm.SetPattern(nLevel, aPattern); + } + eType = TOKEN_END; + } + } + while (TOKEN_END != eType); + // <- #i21237# + } + pBase->SetTOXForm( aForm ); + } + break; + + /* + // the following switches are not (yet) supported + // by good old StarWriter: + case 'b': + case 's': + case 'd': + break; + */ + } + } + + if (bIsHyperlink) + { + SwForm aForm(pBase->GetTOXForm()); + USHORT nEnd = aForm.GetFormMax()-1; + SwFormToken aLinkStart(TOKEN_LINK_START); + SwFormToken aLinkEnd(TOKEN_LINK_END); + + // -> #i21237# + for(USHORT nLevel = 1; nLevel <= nEnd; ++nLevel) + { + SwFormTokens aPattern = aForm.GetPattern(nLevel); + + aPattern.insert(aPattern.begin(), aLinkStart); + aPattern.push_back(aLinkEnd); + + aForm.SetPattern(nLevel, aPattern); + + } + // <- #i21237# + pBase->SetTOXForm(aForm); + } + + if (!nMaxLevel) + nMaxLevel = WW8ListManager::nMaxLevel; + pBase->SetLevel(nMaxLevel); + + const TOXTypes eType = pBase->GetTOXType()->GetType(); + switch( eType ) + { + case TOX_CONTENT: + { + //If we would be created from outlines, either explictly or by default + //then see if we need extra styles added to the outlines + USHORT eEffectivelyFrom = eCreateFrom ? eCreateFrom : nsSwTOXElement::TOX_OUTLINELEVEL; + if (eEffectivelyFrom & nsSwTOXElement::TOX_OUTLINELEVEL) + { + if (AddExtraOutlinesAsExtraStyles(*pBase)) + eCreateFrom |= (nsSwTOXElement::TOX_TEMPLATE | nsSwTOXElement::TOX_OUTLINELEVEL); + + // --> FME 2004-12-16 #i19683# Insert a text token " " between the + // number and entry token. In an ideal world we could handle the + // tab stop between the number and the entry correctly, but I + // currently have no clue how to obtain the tab stop position. + // It is _not_ set at the paragraph style. + SwForm* pForm = 0; + for (USHORT nI = 0; nI < nColls; ++nI) + { + const SwWW8StyInf& rSI = pCollA[nI]; + if (rSI.IsOutlineNumbered()) + { + sal_uInt16 nStyleLevel = rSI.nOutlineLevel; + const SwNumFmt& rFmt = rSI.GetOutlineNumrule()->Get( nStyleLevel ); + if ( SVX_NUM_NUMBER_NONE != rFmt.GetNumberingType() ) + { + ++nStyleLevel; + + if ( !pForm ) + pForm = new SwForm( pBase->GetTOXForm() ); + + SwFormTokens aPattern = pForm->GetPattern(nStyleLevel); + SwFormTokens::iterator aIt = + find_if(aPattern.begin(), aPattern.end(), + SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO)); + + if ( aIt != aPattern.end() ) + { + SwFormToken aNumberEntrySeparator( TOKEN_TEXT ); + aNumberEntrySeparator.sText = String::CreateFromAscii(" "); + aPattern.insert( ++aIt, aNumberEntrySeparator ); + pForm->SetPattern( nStyleLevel, aPattern ); + } + } + } + } + if ( pForm ) + pBase->SetTOXForm( *pForm ); + // <-- + } + + if (eCreateFrom) + pBase->SetCreate(eCreateFrom); + EnsureMaxLevelForTemplates(*pBase); + } + break; + case TOX_ILLUSTRATIONS: + { + if( !eCreateFrom ) + eCreateFrom = nsSwTOXElement::TOX_SEQUENCE; + pBase->SetCreate( eCreateFrom ); + + /* + #91214# + We don't know until here if we are an illustration + or not, and so have being used a TOX_CONTENT so far + which has 10 levels, while TOX has only two, this + level is set only in the constructor of SwForm, so + create a new one and copy over anything that could + be set in the old one, and remove entries from the + pattern which do not apply to illustration indices + */ + SwForm aOldForm( pBase->GetTOXForm() ); + SwForm aForm( eType ); + USHORT nEnd = aForm.GetFormMax()-1; + + // -> #i21237# + for(USHORT nLevel = 1; nLevel <= nEnd; ++nLevel) + { + SwFormTokens aPattern = aOldForm.GetPattern(nLevel); + + SwFormTokens::iterator new_end=remove_if(aPattern.begin(), aPattern.end(), + SwFormTokenEqualToFormTokenType(TOKEN_ENTRY_NO)); + + aPattern.erase (new_end, aPattern.end() ); // #124710#: table index imported with wrong page number format + + aForm.SetPattern(nLevel, aPattern); + + aForm.SetTemplate( nLevel, + aOldForm.GetTemplate(nLevel)); + } + // <- #i21237# + + pBase->SetTOXForm( aForm ); + } + break; + default: + ASSERT(!this, "Unhandled toc options!"); + break; + } + } + break; + case TOX_USER: + break; + default: + ASSERT(!this, "Unhandled toc options!"); + break; + } // ToxBase fertig + + // Update fuer TOX anstossen + rDoc.SetUpdateTOX(true); + + // #i21237# + // propagate tab stops from paragraph styles used in TOX to + // patterns of the TOX + pBase->AdjustTabStops(rDoc, TRUE); + + //#i10028# inserting a toc implicltly acts like a parabreak + //in word and writer + if (pPaM->GetPoint()->nContent.GetIndex()) + AppendTxtNode(*pPaM->GetPoint()); + + const SwPosition* pPos = pPaM->GetPoint(); + + SwFltTOX aFltTOX( pBase, nIndexCols ); + + // test if there is already a break item on this node + if(SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode()) + { + const SfxItemSet* pSet = pNd->GetpSwAttrSet(); + if( pSet ) + { + if (SFX_ITEM_SET == pSet->GetItemState(RES_BREAK, false)) + aFltTOX.SetHadBreakItem(true); + if (SFX_ITEM_SET == pSet->GetItemState(RES_PAGEDESC, false)) + aFltTOX.SetHadPageDescItem(true); + } + } + + //Will there be a new pagebreak at this position (don't know what type + //until later) + if (maSectionManager.WillHavePageDescHere(pPos->nNode)) + aFltTOX.SetHadPageDescItem(true); + + // Setze Anfang in Stack + pReffedStck->NewAttr( *pPos, aFltTOX ); + + rDoc.InsertTableOf(*pPaM->GetPoint(), *aFltTOX.GetBase()); + + //inserting a toc inserts a section before this point, so adjust pos + //for future page/section segment insertion + SwPaM aRegion(*pPaM); + aRegion.Move(fnMoveBackward); + ASSERT(rDoc.GetCurTOX(*aRegion.GetPoint()), "Misunderstood how toc works"); + if (SwTOXBase* pBase2 = (SwTOXBase*)rDoc.GetCurTOX(*aRegion.GetPoint())) + { + if(nIndexCols>1) + { + // Set the column number for index + SfxItemSet aSet( rDoc.GetAttrPool(), RES_COL, RES_COL ); + SwFmtCol aCol; + aCol.Init( nIndexCols, 708, USHRT_MAX ); + aSet.Put( aCol ); + pBase2->SetAttrSet( aSet ); + } + + maSectionManager.PrependedInlineNode(*pPaM->GetPoint(), + *aRegion.GetNode()); + } + + // Setze Ende in Stack + pReffedStck->SetAttr( *pPos, RES_FLTR_TOX ); + + if (!maApos.back()) //a para end in apo doesn't count + bWasParaEnd = true; + return FLD_OK; +} + +eF_ResT SwWW8ImplReader::Read_F_Shape(WW8FieldDesc* /*pF*/, String& /*rStr*/) +{ + /* + #i3958# 0x8 followed by 0x1 where the shape is the 0x8 and its anchoring + to be ignored followed by a 0x1 with an empty drawing. Detect in inserting + the drawing that we are in the Shape field and respond accordingly + */ + return FLD_TEXT; + } + +eF_ResT SwWW8ImplReader::Read_F_Hyperlink( WW8FieldDesc* /*pF*/, String& rStr ) +{ + String sURL, sTarget, sMark; + bool bDataImport = false; + //HYPERLINk "filename" [switches] + bool bOptions=false; + + rStr.EraseTrailingChars( 1 ); + + if (!bDataImport) + { + long nRet; + _ReadFieldParams aReadParam( rStr ); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + { + switch( nRet ) + { + case -2: + if (!sURL.Len() & !bOptions) + ConvertFFileName(sURL, aReadParam.GetResult()); + break; + + case 'n': + sTarget.ASSIGN_CONST_ASC( "_blank" ); + bOptions = true; + break; + + case 'l': + nRet = aReadParam.SkipToNextToken(); + bOptions = true; + if( -2 == nRet ) + { + sMark = aReadParam.GetResult(); + if( sMark.Len() && '"' == sMark.GetChar( sMark.Len()-1 )) + sMark.Erase( sMark.Len() - 1 ); + + } + break; + case 't': + nRet = aReadParam.SkipToNextToken(); + bOptions = true; + if (-2 == nRet) + sTarget = aReadParam.GetResult(); + break; + case 'h': + case 'm': + ASSERT( !this, "Auswertung fehlt noch - Daten unbekannt" ); + case 's': //worthless fake anchor option + bOptions = true; + break; + } + } + } + + // das Resultat uebernehmen + ASSERT((sURL.Len() || sMark.Len()), "WW8: Empty URL") + + if( sMark.Len() ) + ( sURL += INET_MARK_TOKEN ) += sMark; + + SwFmtINetFmt aURL( sURL, sTarget ); + + //As an attribute this needs to be closed, and that'll happen from + //EndExtSprm in conjunction with the maFieldStack If there are are flyfrms + //between the start and begin, their hyperlinks will be set at that time + //as well. + pCtrlStck->NewAttr( *pPaM->GetPoint(), aURL ); + return FLD_TEXT; +} + +void lcl_ImportTox(SwDoc &rDoc, SwPaM &rPaM, const String &rStr, bool bIdx) +{ + TOXTypes eTox = ( !bIdx ) ? TOX_CONTENT : TOX_INDEX; // Default + + USHORT nLevel = 1; + + xub_StrLen n; + String sFldTxt; + long nRet; + _ReadFieldParams aReadParam(rStr); + while( -1 != ( nRet = aReadParam.SkipToNextToken() )) + switch( nRet ) + { + case -2: + if( !sFldTxt.Len() ) + { + // PrimaryKey ohne ":", 2nd dahinter + sFldTxt = aReadParam.GetResult(); + } + break; + + case 'f': + n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + String sParams( aReadParam.GetResult() ); + if( 'C' != sParams.GetChar(0) && 'c' != sParams.GetChar(0) ) + eTox = TOX_USER; + } + break; + + case 'l': + n = aReadParam.GoToTokenParam(); + if( STRING_NOTFOUND != n ) + { + String sParams( aReadParam.GetResult() ); + if( sParams.Len() // if NO String just ignore the \l + && sParams.GetChar( 0 ) > '0' + && sParams.GetChar( 0 ) <= '9' ) + { + nLevel = (USHORT)sParams.ToInt32(); + } + } + break; + } + + ASSERT( rDoc.GetTOXTypeCount( eTox ), "Doc.GetTOXTypeCount() == 0 :-(" ); + + const SwTOXType* pT = rDoc.GetTOXType( eTox, 0 ); + SwTOXMark aM( pT ); + + if( eTox != TOX_INDEX ) + aM.SetLevel( nLevel ); + else + { + xub_StrLen nFnd = sFldTxt.Search( WW8_TOX_LEVEL_DELIM ); + if( STRING_NOTFOUND != nFnd ) // it exist levels + { + aM.SetPrimaryKey( sFldTxt.Copy( 0, nFnd ) ); + xub_StrLen nScndFnd = + sFldTxt.Search( WW8_TOX_LEVEL_DELIM, nFnd+1 ); + if( STRING_NOTFOUND != nScndFnd ) + { + aM.SetSecondaryKey( sFldTxt.Copy( nFnd+1, nScndFnd - nFnd - 1 )); + nFnd = nScndFnd; + } + sFldTxt.Erase( 0, nFnd+1 ); + } + } + + if (sFldTxt.Len()) + { + aM.SetAlternativeText( sFldTxt ); + rDoc.InsertPoolItem( rPaM, aM, 0 ); + } +} + +void sw::ms::ImportXE(SwDoc &rDoc, SwPaM &rPaM, const String &rStr) +{ + lcl_ImportTox(rDoc, rPaM, rStr, true); +} + +void SwWW8ImplReader::ImportTox( int nFldId, String aStr ) +{ + bool bIdx = (nFldId != 9); + lcl_ImportTox(rDoc, *pPaM, aStr, bIdx); +} + +void SwWW8ImplReader::Read_FldVanish( USHORT, const BYTE*, short nLen ) +{ + //Meaningless in a style + if (pAktColl || !pPlcxMan) + return; + + const int nChunk = 64; //number of characters to read at one time + + // Vorsicht: Bei Feldnamen mit Umlauten geht das MEMICMP nicht! + const static sal_Char *aFldNames[] = { "\x06""INHALT", "\x02""XE", // dt. + "\x02""TC" }; // us + const static BYTE aFldId[] = { 9, 4, 9 }; + + if( nLen < 0 ) + { + bIgnoreText = false; + return; + } + + // our methode was called from + // ''Skip attributes of field contents'' loop within ReadTextAttr() + if( bIgnoreText ) + return; + + bIgnoreText = true; + long nOldPos = pStrm->Tell(); + + WW8_CP nStartCp = pPlcxMan->Where() + pPlcxMan->GetCpOfs(); + + String sFieldName; + USHORT nFieldLen = pSBase->WW8ReadString( *pStrm, sFieldName, nStartCp, + nChunk, eStructCharSet ); + nStartCp+=nFieldLen; + + xub_StrLen nC = 0; + //If the first chunk did not start with a field start then + //reset the stream position and give up + if( !nFieldLen || (0x13 != sFieldName.GetChar( nC ))) // Field Start Mark + { + // If Field End Mark found + if( nFieldLen && (0x15 == sFieldName.GetChar( nC ))) + bIgnoreText = false; + pStrm->Seek( nOldPos ); + return; // kein Feld zu finden + } + + xub_StrLen nFnd; + //If this chunk does not contain a field end, keep reading chunks + //until we find one, or we run out of text, + while (STRING_NOTFOUND == (nFnd = sFieldName.Search(0x15))) + { + String sTemp; + nFieldLen = pSBase->WW8ReadString( *pStrm, sTemp, + nStartCp, nChunk, eStructCharSet ); + sFieldName+=sTemp; + nStartCp+=nFieldLen; + if (!nFieldLen) + break; + } + + pStrm->Seek( nOldPos ); + + //if we have no 0x15 give up, otherwise erase everything from the 0x15 + //onwards + if (STRING_NOTFOUND == nFnd) + return; + else + sFieldName.Erase(nFnd); + + nC++; + while( ' ' == sFieldName.GetChar( nC )) + nC++; + + for( int i = 0; i < 3; i++ ) + { + const sal_Char* pName = aFldNames[i]; + USHORT nNameLen = *pName++; + if( sFieldName.EqualsIgnoreCaseAscii( pName, nC, nNameLen ) ) + { + ImportTox( aFldId[i], sFieldName.Copy( nC + nNameLen ) ); + break; // keine Mehrfachnennungen moeglich + } + } + bIgnoreText = true; + pStrm->Seek( nOldPos ); +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ |