/*************************************************************************
 *
 *  $RCSfile: wrtww8.cxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000/09/18 17:14:58 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "filt_pch.hxx"
#endif

#pragma hdrstop

#define ITEMID_BOXINFO      SID_ATTR_BORDER_INNER

#include <string.h>				// memcpy()

#ifndef _HINTIDS_HXX
#include <hintids.hxx>
#endif

#ifndef _SV_SALBTYPE_HXX
#include <vcl/salbtype.hxx>
#endif
#ifndef _SVSTOR_HXX
#include <so3/svstor.hxx>
#endif
#ifndef _ZFORMAT_HXX
#include <svtools/zformat.hxx>
#endif
#ifndef _SFXDOCINF_HXX
#include <sfx2/docinf.hxx>
#endif
#ifndef _SVX_TSPTITEM_HXX
#include <svx/tstpitem.hxx>
#endif
#ifndef _SVDMODEL_HXX
#include <svx/svdmodel.hxx>
#endif
#ifndef _SVDPAGE_HXX
#include <svx/svdpage.hxx>
#endif
#ifndef _SVX_HYZNITEM_HXX //autogen
#include <svx/hyznitem.hxx>
#endif

#if SUPD>593
#ifndef _MSOLEEXP_HXX
#include <svx/msoleexp.hxx>
#endif
#endif

#ifndef _OFA_FLTRCFG_HXX
#include <offmgr/fltrcfg.hxx>
#endif
#ifndef _OFF_APP_HXX //autogen
#include <offmgr/app.hxx>
#endif

#ifndef _SWTYPES_HXX
#include <swtypes.hxx>
#endif
#ifndef _SWRECT_HXX
#include <swrect.hxx>
#endif
#ifndef _TXATBASE_HXX
#include <txatbase.hxx>
#endif
#ifndef _FMTCNTNT_HXX
#include <fmtcntnt.hxx>
#endif
#ifndef _FMTPDSC_HXX
#include <fmtpdsc.hxx>
#endif
#ifndef _DOC_HXX
#include <doc.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _PAM_HXX
#include <pam.hxx>
#endif
#ifndef _NDTXT_HXX
#include <ndtxt.hxx>
#endif
#ifndef _SHELLIO_HXX
#include <shellio.hxx>
#endif
#ifndef _DOCSTAT_HXX
#include <docstat.hxx>
#endif
#ifndef _PAGEDESC_HXX
#include <pagedesc.hxx>
#endif
#ifndef _FLYPOS_HXX
#include <flypos.hxx>
#endif
#ifndef _BOOKMRK_HXX
#include <bookmrk.hxx>
#endif
#ifndef _SWTABLE_HXX
#include <swtable.hxx>
#endif
#ifndef _WRTWW8_HXX
#include <wrtww8.hxx>
#endif
#ifndef _WW8STRUC_HXX
#include <ww8struc.hxx>
#endif
#ifndef _WRT_FN_HXX
#include <wrt_fn.hxx>
#endif
#ifndef _FLTINI_HXX
#include <fltini.hxx>
#endif
#ifndef _ERRHDL_HXX
#include <errhdl.hxx>
#endif
#ifndef _SWMODULE_HXX
#include <swmodule.hxx>
#endif
#ifndef _SECTION_HXX
#include <section.hxx>
#endif
#include "poolfmt.hxx"			// RES_POOLCOLL_STANDARD

#ifndef _MDIEXP_HXX
#include <mdiexp.hxx>			// Progress
#endif
#ifndef _STATSTR_HRC
#include <statstr.hrc>			// ResId fuer Statusleiste
#endif

#ifndef SW_FMTLINE_HXX
#include <fmtline.hxx>
#endif


class WW8_WrFkp
{
	BYTE* pFkp;	        // gesamter Fkp ( zuerst nur FCs und Sprms )
	BYTE* pOfs;			// Pointer auf Offset-Bereich, spaeter nach pFkp kopiert
	ePLCFT ePlc;
	short nStartGrp;	// ab hier grpprls
	short nOldStartGrp;
	BYTE nItemSize;
	BYTE nIMax;         // Anzahl der Eintrags-Paare
	BYTE nOldVarLen;
	BOOL bCombined;		// TRUE : Einfuegen verboten

	BYTE SearchSameSprm( USHORT nVarLen, const BYTE* pSprms );
public:
	WW8_WrFkp( ePLCFT ePl, WW8_FC nStartFc, BOOL bWrtWW8 );
	~WW8_WrFkp();
	BOOL Append( WW8_FC nEndFc, USHORT nVarLen = 0, const BYTE* pSprms = 0 );
	BOOL Combine();
	void Write( SvStream& rStrm, SwWW8WrGrf& rGrf );

	BOOL IsEqualPos( WW8_FC nEndFc ) const
	{	return !bCombined && nIMax && nEndFc == ((INT32*)pFkp)[nIMax]; }
	void MergeToNew( short& rVarLen, BYTE *& pNewSprms );
	BOOL IsEmptySprm() const
	{	return !bCombined && nIMax && !nOldVarLen; 	}
	void SetNewEnd( WW8_FC nEnd )
	{	((INT32*)pFkp)[nIMax] = nEnd; }

#ifdef __WW8_NEEDS_COPY
	WW8_FC GetStartFc() const;
	WW8_FC GetEndFc() const;
#else
	WW8_FC GetStartFc() const { return ((INT32*)pFkp)[0]; };
	WW8_FC GetEndFc() const { return ((INT32*)pFkp)[nIMax]; };
#endif // defined __WW8_NEEDS_COPY
};


// -------------------------------------------------------------------------
// class WW8_WrPc sammelt alle Piece-Eintraege fuer ein Piece
// -------------------------------------------------------------------------

class WW8_WrPc
{
	WW8_CP nStartCp;					// Start ZeichenPosition vom Text
	WW8_FC nStartFc;					// Start File Position vom Text
	USHORT nStatus;						// Absatzende im Piece ?

public:
	WW8_WrPc(WW8_FC nSFc, WW8_CP nSCp )
		: nStartCp( nSCp ), nStartFc( nSFc ), nStatus( 0x0040 )
	{}

	void SetStatus()				{ nStatus = 0x0050; }
	USHORT GetStatus()	const		{ return nStatus; }
	WW8_CP GetStartCp()	const		{ return nStartCp; }
	WW8_FC GetStartFc()	const		{ return nStartFc; }
};


class WW8_WrtBookmarks
{
	SvULongs aSttCps, aEndCps;				// Array of Start- and End CPs
	SvStringsDtor aSwBkmkNms;				// Array of Sw - Bookmarknames
//	SvStringsDtor aWWBkmkNms;				// Array of WW - Bookmarknames

	USHORT GetPos( const String& rNm );
public:
	WW8_WrtBookmarks();
	~WW8_WrtBookmarks();

	void Append( WW8_CP nStartCp, const String& rNm );
	void Write( SwWW8Writer& rWrt );

//	String GetWWBkmkName( const String& rName ) const;
};

class WW8_WrtRedlineAuthor
{
	SvStringsDtor aAuthors;				// Array of Sw - Bookmarknames

	USHORT GetPos( const String& rNm );
public:
	WW8_WrtRedlineAuthor() : aAuthors( 0, 4 ) {}

	USHORT AddName( const String& rNm );
	void Write( SwWW8Writer& rWrt );
};


#define ANZ_DEFAULT_STYLES 16

// die Namen der StorageStreams
#define sMainStream 		String::CreateFromAscii( \
								RTL_CONSTASCII_STRINGPARAM( "WordDocument" ))
#define sDataStream 		String::CreateFromAscii( \
								RTL_CONSTASCII_STRINGPARAM( "Data" ))
#define sTableStream 		String::CreateFromAscii( \
								RTL_CONSTASCII_STRINGPARAM( "1Table" ))


SV_IMPL_VARARR( WW8Bytes, BYTE )
SV_IMPL_PTRARR( WW8_WrFkpPtrs, WW8_FkpPtr )

typedef WW8_WrPc* WW8_WrPcPtr;
SV_DECL_PTRARR_DEL( WW8_WrPcPtrs, WW8_WrPcPtr, 4, 4 )
SV_IMPL_PTRARR( WW8_WrPcPtrs, WW8_WrPcPtr )

static void WriteDop( SwWW8Writer& rWrt )
{
	WW8Dop& rDop = *rWrt.pDop;

	// default TabStop schreiben
	const SvxTabStopItem& rTabStop = (SvxTabStopItem& )rWrt.pDoc->
					GetAttrPool().GetDefaultItem( RES_PARATR_TABSTOP );
	rDop.dxaTab = (USHORT)rTabStop[0].GetTabPos();


	// Werte aus der DocStatistik (werden aufjedenfall fuer die
	// DocStat-Felder benoetigt!)
	rDop.fWCFtnEdn = TRUE; // because they are included in StarWriter

	const SwDocStat& rDStat = rWrt.pDoc->GetDocStat();
	rDop.cWords = rDStat.nWord;
	rDop.cCh    = rDStat.nChar;
	rDop.cPg    = rDStat.nPage;
	rDop.cParas = rDStat.nPara;
	rDop.cLines = rDStat.nPara;

//  auch damit werden die DocStat-Felder in Kopf-/Fusszeilen nicht korrekt
//  berechnet.
//  ( we do not have this fields! )

	// und noch fuer die Header und Footers
	rDop.cWordsFtnEnd	= rDStat.nWord;
	rDop.cChFtnEdn		= rDStat.nChar;
	rDop.cPgFtnEdn		= rDStat.nPage;
	rDop.cParasFtnEdn	= rDStat.nPara;
	rDop.cLinesFtnEdn	= rDStat.nPara;

	rDop.Write( *rWrt.pTableStrm, *rWrt.pFib );
}


// HasItem ist fuer die Zusammenfassung der Doppel-Attribute
// Underline / WordLineMode und Box / Shadow.
// Es kann nur etwas gefunden werden, wenn diese Methode innerhalb
// der aufgerufenen Methoden WW8_SwAttrIter::OutAttr() und
// SwWW8Writer::Out_SfxItemSet() benutzt wird.
const SfxPoolItem* SwWW8Writer::HasItem( USHORT nWhich ) const
{
	const SfxPoolItem* pItem;
	if( pISet )
	{
		// if write a EditEngine text, then the WhichIds are greater as
		// ourer own Ids. So the Id have to translate from ouer into the
		// EditEngine Range
		if( RES_WHICHHINT_END < *pISet->GetRanges() )
			nWhich = TranslateToEditEngineId( nWhich );
		if( SFX_ITEM_SET != pISet->GetItemState( nWhich, TRUE, &pItem ) )
			pItem = 0;
	}
	else if( pChpIter )
		pItem = pChpIter->HasTextItem( nWhich );
	else
	{
		ASSERT( !this, "Wo ist mein ItemSet / pChpIter ?" );
		pItem = 0;
	}
	return pItem;
}

const SfxPoolItem& SwWW8Writer::GetItem( USHORT nWhich ) const
{
	const SfxPoolItem* pItem;
	if( pISet )
	{
		// if write a EditEngine text, then the WhichIds are greater as
		// ourer own Ids. So the Id have to translate from ouer into the
		// EditEngine Range
		if( RES_WHICHHINT_END < *pISet->GetRanges() )
			nWhich = TranslateToEditEngineId( nWhich );
		pItem = &pISet->Get( nWhich, TRUE );
	}
	else if( pChpIter )
		pItem = &pChpIter->GetItem( nWhich );
	else
	{
		ASSERT( !this, "Wo ist mein ItemSet / pChpIter ?" );
		pItem = 0;
	}
	return *pItem;
}

//------------------------------------------------------------------------------

WW8_WrPlc1::WW8_WrPlc1( USHORT nStructSz )
	: aPos( 16, 16 ), aDat( 16 * (int)nStructSz, 16 * (int)nStructSz ),
	nStructSiz( nStructSz )
{
}

void WW8_WrPlc1::Append( WW8_CP nCp, const void* pData )
{
	aPos.Insert( nCp, aPos.Count() );
	aDat.Insert( (BYTE*)pData, nStructSiz, aDat.Count() );
}

void WW8_WrPlc1::Finish( ULONG nLastCp, ULONG nSttCp )
{
	if( aPos.Count() )
	{
		aPos.Insert( nLastCp, aPos.Count() );
		if( nSttCp )
			for( USHORT n = 0; n < aPos.Count(); ++n )
				aPos[ n ] -= nSttCp;
	}
}


void WW8_WrPlc1::Write( SvStream& rStrm )
{
	for( USHORT i = 0; i < aPos.Count(); ++i )
		SwWW8Writer::WriteLong( rStrm, aPos[i] );
	rStrm.Write( aDat.GetData(), aDat.Count() );	// Anz Eintraege
}

//------------------------------------------------------------------------------
//	Klasse WW8_WrPlcFld fuer Felder
//------------------------------------------------------------------------------


BOOL WW8_WrPlcFld::Write( SwWW8Writer& rWrt )
{
	if( WW8_WrPlc1::Count() <= 1 )
		return FALSE;

	long *pfc, *plc;
	switch( nTxtTyp )
	{
	case TXT_MAINTEXT:
		pfc = &rWrt.pFib->fcPlcffldMom;
		plc = &rWrt.pFib->lcbPlcffldMom;
		break;
	case TXT_HDFT:
		pfc = &rWrt.pFib->fcPlcffldHdr;
		plc = &rWrt.pFib->lcbPlcffldHdr;
		break;

	case TXT_FTN:
		pfc = &rWrt.pFib->fcPlcffldFtn;
		plc = &rWrt.pFib->lcbPlcffldFtn;
		break;

	case TXT_EDN:
		pfc = &rWrt.pFib->fcPlcffldEdn;
		plc = &rWrt.pFib->lcbPlcffldEdn;
		break;

	case TXT_TXTBOX:
		pfc = &rWrt.pFib->fcPlcffldTxbx;
		plc = &rWrt.pFib->lcbPlcffldTxbx;
		break;

	case TXT_HFTXTBOX:
		pfc = &rWrt.pFib->fcPlcffldHdrTxbx;
		plc = &rWrt.pFib->lcbPlcffldHdrTxbx;
		break;

	default:
		pfc = plc = 0;
		break;
	}

	if( pfc && plc )
	{
		ULONG nFcStart = rWrt.pTableStrm->Tell();
		WW8_WrPlc1::Write( *rWrt.pTableStrm );
		*pfc = nFcStart;
		*plc = rWrt.pTableStrm->Tell() - nFcStart;
	}
	return TRUE;
}


//--------------------------------------------------------------------------

void SwWW8Writer::FillCount( SvStream& rStrm, ULONG nCount )
{
	static UINT32 __READONLY_DATA aNulls[16] = {
						0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // 64 Byte

	while( nCount > 64 )
	{
		rStrm.Write( aNulls, 64 );			// in 64-Byte-Schritten
		nCount -= 64;
	}
	rStrm.Write( aNulls, nCount );			// Rest ( 0 .. 64 Bytes ) schreiben
}


ULONG SwWW8Writer::FillUntil( SvStream& rStrm, ULONG nEndPos )
{
	ULONG nCurPos = rStrm.Tell();
	if( !nEndPos )							// nEndPos == 0 -> next Page
		nEndPos = nCurPos + 0x1ff & ~0x1ffUL;

	if( nEndPos > nCurPos )
		SwWW8Writer::FillCount( rStrm, nEndPos - nCurPos );
#ifndef PRODUCT
	else
		ASSERT( nEndPos == nCurPos, "Falsches FillUntil()" );
#endif
	return rStrm.Tell();
}


//--------------------------------------------------------------------------
/*  */

WW8_WrPlcPn::WW8_WrPlcPn( SwWW8Writer& rWr, ePLCFT ePl, WW8_FC nStartFc )
	: rWrt( rWr ), ePlc( ePl ), nFkpStartPage( 0 )
{
	WW8_FkpPtr pF = new WW8_WrFkp( ePlc, nStartFc, rWrt.bWrtWW8 );
	aFkps.Insert( pF, aFkps.Count() );
}

WW8_WrPlcPn::~WW8_WrPlcPn()
{
	aFkps.DeleteAndDestroy( 0, aFkps.Count() );
}

void WW8_WrPlcPn::AppendFkpEntry( WW8_FC nEndFc, short nVarLen,
									const BYTE* pSprms )
{
	WW8_FkpPtr pF = aFkps.GetObject( aFkps.Count() - 1 );

	// big sprm? build the sprmPHugePapx
	BYTE* pNewSprms = (BYTE*)pSprms;
	BYTE aHugePapx[ 8 ];
	if( rWrt.bWrtWW8 && PAP == ePlc && 488 < nVarLen )
	{
		BYTE* p = aHugePapx;
		*p++ = *pSprms++;      		// set style Id
		*p++ = *pSprms++;
		nVarLen -= 2;

		long nDataPos = rWrt.pDataStrm->Tell();
		SwWW8Writer::WriteShort( *rWrt.pDataStrm, nVarLen );
		rWrt.pDataStrm->Write( pSprms, nVarLen );

		Set_UInt16( p, 0x6646 );	// set SprmCode
		Set_UInt32( p, nDataPos );	// set startpos (FC) in the datastream
		nVarLen = p - aHugePapx;
		pSprms = pNewSprms = aHugePapx;
	}
	// if append at the same FC-EndPos and there are sprms, then get the old
	// sprms and erase it; they will append now with the new sprms
	else if( nVarLen && pF->IsEqualPos( nEndFc ))
		pF->MergeToNew( nVarLen, pNewSprms );
	// has the prev EndFC an empty sprm and the current is empty too, then
	// expand only the old EndFc to the new EndFc
	else if( !nVarLen && pF->IsEmptySprm() )
	{
		pF->SetNewEnd( nEndFc );
		return ;
	}

	BOOL bOk = pF->Append( nEndFc, nVarLen, pNewSprms );
	if( !bOk )
	{
		pF->Combine();
		pF = new WW8_WrFkp( ePlc, pF->GetEndFc(), rWrt.bWrtWW8 );// Anfang neuer Fkp
													// == Ende alter Fkp
		aFkps.Insert( pF, aFkps.Count() );
		if( !pF->Append( nEndFc, nVarLen, pNewSprms ) )
		{
			ASSERT( !this, "Sprm liess sich nicht einfuegen" );
		}
	}
	if( pNewSprms != pSprms )
		delete pNewSprms;
}

void WW8_WrPlcPn::WriteFkps()
{
	nFkpStartPage = (USHORT) ( SwWW8Writer::FillUntil( rWrt.Strm() ) >> 9 );

	for( USHORT i = 0; i < aFkps.Count(); i++ )
		aFkps.GetObject( i )->Write( rWrt.Strm(), *rWrt.pGrf );

	if( CHP == ePlc )
	{
		rWrt.pFib->pnChpFirst = nFkpStartPage;
		rWrt.pFib->cpnBteChp = aFkps.Count();
	}
	else
	{
		rWrt.pFib->pnPapFirst = nFkpStartPage;
		rWrt.pFib->cpnBtePap = aFkps.Count();
	}
}

void WW8_WrPlcPn::WritePlc()
{
	ULONG nFcStart = rWrt.pTableStrm->Tell();
	USHORT i;

	for( i = 0; i < aFkps.Count(); i++ )
		SwWW8Writer::WriteLong( *rWrt.pTableStrm,
								aFkps.GetObject( i )->GetStartFc() );

	SwWW8Writer::WriteLong( *rWrt.pTableStrm,
								aFkps.GetObject( i - 1 )->GetEndFc() );

	// fuer jedes FKP die Page ausgeben
	if( rWrt.bWrtWW8)  					// fuer WW97 Long-Ausgabe
		for ( i = 0; i < aFkps.Count(); i++)
			SwWW8Writer::WriteLong( *rWrt.pTableStrm, i + nFkpStartPage );
	else							// fuer WW95 Short-Ausgabe
		for ( i = 0; i < aFkps.Count(); i++)
			SwWW8Writer::WriteShort( *rWrt.pTableStrm, i + nFkpStartPage );

	if( CHP == ePlc )
	{
		rWrt.pFib->fcPlcfbteChpx = nFcStart;
		rWrt.pFib->lcbPlcfbteChpx = rWrt.pTableStrm->Tell() - nFcStart;
	}
	else
	{
		rWrt.pFib->fcPlcfbtePapx = nFcStart;
		rWrt.pFib->lcbPlcfbtePapx = rWrt.pTableStrm->Tell() - nFcStart;
	}
}

//--------------------------------------------------------------------------
/*  */

WW8_WrFkp::WW8_WrFkp( ePLCFT ePl, WW8_FC nStartFc, BOOL bWrtWW8 )
	: nItemSize( ( CHP == ePl ) ? 1 : ( bWrtWW8 ? 13 : 7 )),
		 nIMax( 0 ), ePlc( ePl ), bCombined( FALSE ), nStartGrp( 511 ),
	nOldStartGrp( 511 ), nOldVarLen( 0 )
{
	pFkp = (BYTE*)new INT32[128];			// 512 Byte
	pOfs = (BYTE*)new INT32[128];			// 512 Byte
	memset( pFkp, 0, 4 * 128 );
	memset( pOfs, 0, 4 * 128 );
	( (INT32*)pFkp )[0] = nStartFc;			// 0. FC-Eintrag auf nStartFc
}

WW8_WrFkp::~WW8_WrFkp()
{
	delete( pFkp );
	delete( pOfs );
}

BYTE WW8_WrFkp::SearchSameSprm( USHORT nVarLen, const BYTE* pSprms )
{
	if( 3 < nVarLen )
	{
		// if the sprms contained picture-references then never equal!
		for( BYTE n = nVarLen - 1; 3 < n; --n )
			if( pSprms[ n ] == GRF_MAGIC_3 &&
				pSprms[ n-1 ] == GRF_MAGIC_2 &&
				pSprms[ n-2 ] == GRF_MAGIC_1 )
					return 0;
	}

	short i;
	for( i = 0; i < nIMax; i++ )
	{
		BYTE nStart = pOfs[i * nItemSize];
		if( nStart )
		{								// Hat Sprms
			const BYTE* p = pFkp + ( (USHORT)nStart << 1 );
			if( ( CHP == ePlc
					? (*p++ == nVarLen)
					: (((USHORT)*p++ << 1 ) == (( nVarLen+1) & 0xfffe)) )
				&& !memcmp( p, pSprms, nVarLen ) )
					return nStart;						// gefunden
		}
	}
	return 0;			// nicht gefunden
}

BOOL WW8_WrFkp::Append( WW8_FC nEndFc, USHORT nVarLen, const BYTE* pSprms )
{
	ASSERT( !nVarLen || pSprms, "Item-Pointer fehlt" );
	ASSERT( nVarLen < ( ( ePlc == PAP ) ? 497U : 502U ), "Sprms zu lang !" );

	if( bCombined )
	{
		ASSERT( !this, "Fkp::Append: Fkp is already combined" );
		return FALSE;
	}
	INT32 n = ((INT32*)pFkp)[nIMax];		// letzter Eintrag
	if( nEndFc <= n )
	{
		ASSERT( nEndFc >= n, "+Fkp: FC rueckwaerts" );
		ASSERT( !nVarLen || !pSprms || nEndFc != n,
									"+Fkp: selber FC mehrfach benutzt" );
						// selber FC ohne Sprm wird ohne zu mosern ignoriert.

		return TRUE;	// ignorieren, keinen neuen Fkp anlegen
	}

	BYTE nOldP = ( nVarLen ) ? SearchSameSprm( nVarLen, pSprms ) : 0;
											// Kombinieren gleicher Eintraege
	short nOffset, nPos = nStartGrp;
	if( nVarLen && !nOldP )
	{
		nPos = PAP == ePlc
				? ( 13 == nItemSize		// HACK: PAP und bWrtWW8 !!
					 ? (nStartGrp & 0xFFFE ) - nVarLen - 1
					 : (nStartGrp - (((nVarLen + 1) & 0xFFFE)+1)) & 0xFFFE )
				: ((nStartGrp - nVarLen - 1) & 0xFFFE);
		if( nPos < 0 )
			return FALSE;			// Passt absolut nicht
		nOffset = nPos;				// Offset merken (kann auch ungerade sein!)
		nPos &= 0xFFFE;				// Pos fuer Sprms ( gerade Pos )
	}

	if( (USHORT)nPos <= ( nIMax + 2U ) * 4U + ( nIMax + 1U ) * nItemSize )
											// Passt hinter CPs und Offsets ?
		return FALSE;						// Nein

	((INT32*)pFkp)[nIMax + 1] = nEndFc;		// FC eintragen

	nOldVarLen = (BYTE)nVarLen;
	if( nVarLen && !nOldP )
	{				// echt eintragen
		nOldStartGrp = nStartGrp;

		nStartGrp = nPos;
		pOfs[nIMax * nItemSize] = (BYTE)( nStartGrp >> 1 );
											// ( DatenAnfg >> 1 ) eintragen
		BYTE nCnt = CHP == ePlc
						? ( nVarLen < 256 ) ? (BYTE) nVarLen : 255
						: ( ( nVarLen + 1 ) >> 1 );

		pFkp[ nOffset ] = nCnt;						// DatenLaenge eintragen
		memcpy( pFkp + nOffset + 1, pSprms, nVarLen );	// Sprms speichern
	}
	else
	{
		// nicht echt eintragen ( keine Sprms oder Wiederholung )
		// DatenAnfg 0 ( keine Daten ) oder Wiederholung
		pOfs[nIMax * nItemSize] = nOldP;
	}
	nIMax++;
	return TRUE;
}

BOOL WW8_WrFkp::Combine()
{
	if( bCombined )
		return FALSE;
	if( nIMax )
		memcpy( pFkp + ( nIMax + 1 ) * 4, pOfs, nIMax * nItemSize );
	DELETEZ( pOfs );
	((BYTE*)pFkp)[511] = nIMax;
	bCombined = TRUE;

#if defined __BIGENDIAN			// Hier werden nur die FCs gedreht, die
	register USHORT i;			// Sprms muessen an anderer Stelle gedreht
								// werden
	register UINT32* p;
	for( i = 0, p = (UINT32*)pFkp; i <= nIMax; i++, p++ )
		*p = SWAPLONG( *p );
#endif // ifdef __BIGENDIAN

	return TRUE;
}

void WW8_WrFkp::Write( SvStream& rStrm, SwWW8WrGrf& rGrf )
{
	Combine();						// Falls noch nicht Combined

	register BYTE* p;               //	Suche Magic fuer nPicLocFc
	BYTE* pEnd = pFkp + nStartGrp;
	for( p = pFkp + 511 - 4; p >= pEnd; p-- )
	{
		if( *p != GRF_MAGIC_1 )    	// Suche nach Signatur 0x12 0x34 0x56 0xXX
			continue;
		if( *(p+1) != GRF_MAGIC_2 )
			continue;
		if( *(p+2) != GRF_MAGIC_3 )
			continue;

		SVBT32 nPos;				// Signatur gefunden
		LongToSVBT32( rGrf.GetFPos(), nPos );	// FilePos der Grafik
		memcpy( p, nPos, 4 );		// Patche FilePos ueber Signatur
	}
	rStrm.Write( pFkp, 512 );
}

void WW8_WrFkp::MergeToNew( short& rVarLen, BYTE *& rpNewSprms )
{
	BYTE nStart = pOfs[ (nIMax-1) * nItemSize ];
	if( nStart )
	{ 	// Hat Sprms
		BYTE* p = pFkp + ( (USHORT)nStart << 1 );

		// old and new equal? Then copy only one into the new sprms
		if( nOldVarLen == rVarLen && !memcmp( p+1, rpNewSprms, nOldVarLen ))
		{
			BYTE* pNew = new BYTE[ nOldVarLen ];
			memcpy( pNew, p+1, nOldVarLen );
			rpNewSprms = pNew;
		}
		else
		{
			BYTE* pNew = new BYTE[ nOldVarLen + rVarLen ];
			memcpy( pNew, p+1, nOldVarLen );
			memcpy( pNew + nOldVarLen, rpNewSprms, rVarLen );

			rpNewSprms = pNew;
			rVarLen += nOldVarLen;
		}
		--nIMax;
		// if this sprms dont used from others, remove it
		FASTBOOL bFnd = FALSE;
		for( USHORT n = 0; n < nIMax; ++n )
			if( nStart == pOfs[ n * nItemSize ] )
			{
				bFnd = TRUE;
				break;
			}
		if( !bFnd )
		{
			nStartGrp = nOldStartGrp;
			memset( p, 0, nOldVarLen+1 );
		}
	}
}

#ifdef __WW8_NEEDS_COPY

WW8_FC WW8_WrFkp::GetStartFc() const
{
// wenn bCombined, dann ist das Array ab pFkp schon Bytemaessig auf LittleEndian
// umgedreht, d.h. zum Herausholen der Anfangs- und Endpositionen muss
// zurueckgedreht werden.
	if( bCombined )
		return SVBT32ToLong( pFkp );		// 0. Element
	return ((INT32*)pFkp)[0];
}

WW8_FC WW8_WrFkp::GetEndFc() const
{
	if( bCombined )
		return SVBT32ToLong( &(pFkp[nIMax*4]) );	// nIMax-tes SVBT32-Element
	return ((INT32*)pFkp)[nIMax];
}

#endif // defined __WW8_NEEDS_COPY



//--------------------------------------------------------------------------
// Methoden fuer Piece-Table-Verwaltung
//--------------------------------------------------------------------------

WW8_WrPct::WW8_WrPct( WW8_FC nfcMin )
	: nOldFc( nfcMin ),bIsUni( FALSE ), pPcts( new WW8_WrPcPtrs )
{
	AppendPc( nOldFc, bIsUni );
}

WW8_WrPct::~WW8_WrPct()
{
	delete pPcts;
}

// Piece fuellen und neues Piece erzeugen
void WW8_WrPct::AppendPc( WW8_FC nStartFc, BOOL bIsUnicode )
{
	WW8_CP nStartCp = nStartFc - nOldFc;	// Textbeginn abziehen
	if ( !nStartCp )
	{
		if ( 0 != pPcts->Count() )
		{
			ASSERT( 1 == pPcts->Count(), "Leeres Piece !!");
			pPcts->DeleteAndDestroy( pPcts->Count() - 1 , 1);
		}
	}

	nOldFc = nStartFc;						// StartFc als alten merken

	if( bIsUni )
		nStartCp >>= 1;					// Bei Unicode Anzahl der Zeichen / 2


	if ( !bIsUnicode )
	{
		nStartFc <<= 1;					// Adresse * 2
		nStartFc |= 0x40000000;			// Vorletztes Bit setzen fuer !Unicode
	}

	if( pPcts->Count() )
		nStartCp += pPcts->GetObject( pPcts->Count()- 1 )->GetStartCp();

	WW8_WrPcPtr pPc = new WW8_WrPc( nStartFc, nStartCp );
	pPcts->Insert( pPc, pPcts->Count() );

	bIsUni = bIsUnicode;
}


void WW8_WrPct::WritePc( SwWW8Writer& rWrt )
{
	ULONG nPctStart;
	ULONG nOldPos, nEndPos;
	USHORT i;

	nPctStart = rWrt.pTableStrm->Tell();					// Beginn Piece-Table
	*rWrt.pTableStrm << ( char )0x02;						// Statusbyte PCT
	nOldPos = nPctStart + 1;								// Position merken
	SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );			// Laenge folgt
	for( i = 0; i < pPcts->Count(); ++i )					// Bereiche
		SwWW8Writer::WriteLong( *rWrt.pTableStrm,
								pPcts->GetObject( i )->GetStartCp() );


	// die letzte Pos noch errechnen
	ULONG nStartCp = rWrt.pFib->fcMac - nOldFc;
	if( bIsUni )
		nStartCp >>= 1;				// Bei Unicode Anzahl der Zeichen / 2
	nStartCp += pPcts->GetObject( i-1 )->GetStartCp();
	SwWW8Writer::WriteLong( *rWrt.pTableStrm, nStartCp );

	// Pieceverweise
	for ( i = 0; i < pPcts->Count(); ++i )
	{
		WW8_WrPcPtr pPc = pPcts->GetObject( i );

		SwWW8Writer::WriteShort( *rWrt.pTableStrm, pPc->GetStatus());
		SwWW8Writer::WriteLong( *rWrt.pTableStrm, pPc->GetStartFc());
		SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0);			// PRM=0
	}

	// Eintraege im FIB
	rWrt.pFib->fcClx = nPctStart;
	nEndPos = rWrt.pTableStrm->Tell();
	rWrt.pFib->lcbClx = nEndPos - nPctStart;

	// und noch die Laenge eintragen
	SwWW8Writer::WriteLong( *rWrt.pTableStrm, nOldPos,
							nEndPos - nPctStart-5 );

}

void WW8_WrPct::SetParaBreak()
{
	ASSERT( pPcts->Count(),"SetParaBreak : aPcts.Count = 0" );
	pPcts->GetObject( pPcts->Count() - 1)->SetStatus();
}

ULONG WW8_WrPct::Fc2Cp( ULONG nFc ) const
{
	ASSERT( nFc >= (ULONG)nOldFc, "FilePos liegt vorm letzten Piece" );
	ASSERT( pPcts->Count(), "Fc2Cp noch kein Piece vorhanden" );

	nFc -= nOldFc;
	if( bIsUni )
		nFc /= 2;
	return nFc + pPcts->GetObject( pPcts->Count() - 1 )->GetStartCp();
}

//--------------------------------------------------------------------------
/*  */

WW8_WrtBookmarks::WW8_WrtBookmarks()
	: aSttCps( 0, 16 ), aEndCps( 0, 16 ),
	aSwBkmkNms( 0, 16 )
// JP 24.06.99: not used at time 	,aWWBkmkNms( 0, 16 ),
{
}

WW8_WrtBookmarks::~WW8_WrtBookmarks()
{
}

void WW8_WrtBookmarks::Append( WW8_CP nStartCp, const String& rNm )
{
	USHORT nPos = GetPos( rNm );
	if( USHRT_MAX == nPos )
	{
		// new -> insert as start position
		nPos = aSttCps.Count();
		// sort by startposition
		//		theory: write continuous -> then the new position is at end
		while( nPos && aSttCps[ nPos - 1 ] > ULONG( nStartCp ))
			--nPos;

		aSttCps.Insert( nStartCp, nPos );
		aEndCps.Insert( nStartCp, nPos );
		String* p = new String( rNm );
		aSwBkmkNms.Insert( p, nPos );
// JP 24.06.99: not used at time
//		p = new String( GetWWBkmkName(rNm ));
//		aWWBkmkNms.Insert( p, nPos );
	}
	else
	{
		// old -> its the end position
		ASSERT( aEndCps[ nPos ] == aSttCps[ nPos ], "end position is valid" );
		aEndCps.Replace( nStartCp, nPos );
	}
}


void WW8_WrtBookmarks::Write( SwWW8Writer& rWrt )
{
	USHORT nCount = aSttCps.Count(), i;
	if( nCount )
	{
		SvULongs aEndSortTab( 255 < nCount ? 255 : nCount, 4 );
		// sort then endpositions
		for( i = 0; i < nCount; ++i )
		{
			ULONG nCP = aEndCps[ i ];
			USHORT nPos = i;
			while( nPos && aEndSortTab[ nPos - 1 ] > nCP )
				--nPos;
			aEndSortTab.Insert( nCP, nPos );
		}

		// we have some bookmarks found in the document -> write them
		// first the Bookmark Name Stringtable
		rWrt.WriteAsStringTable( (SvStrings&)aSwBkmkNms,
									rWrt.pFib->fcSttbfbkmk,
									rWrt.pFib->lcbSttbfbkmk );

		// second the Bookmark start positions as pcf of longs
		SvStream& rStrm = rWrt.bWrtWW8 ? *rWrt.pTableStrm : rWrt.Strm();
		rWrt.pFib->fcPlcfbkf = rStrm.Tell();
		for( i = 0; i < nCount; ++i )
			SwWW8Writer::WriteLong( rStrm, aSttCps[ i ] );
		SwWW8Writer::WriteLong( rStrm, rWrt.pFib->ccpText );
		for( i = 0; i < nCount; ++i )
		{
			ULONG nEndCP = aEndCps[ i ];
			USHORT nPos = i;
			if( aEndSortTab[ nPos ] > nEndCP )
			{
				while( aEndSortTab[ --nPos ] != nEndCP )
					;
			}
			else if( aEndSortTab[ nPos ] < nEndCP )
				while( aEndSortTab[ ++nPos ] != nEndCP )
					;

			SwWW8Writer::WriteLong( rStrm, nPos );
		}
		rWrt.pFib->lcbPlcfbkf = rStrm.Tell() - rWrt.pFib->fcPlcfbkf;

		// third the Bookmark end positions
		rWrt.pFib->fcPlcfbkl = rStrm.Tell();
		for( i = 0; i < nCount; ++i )
			SwWW8Writer::WriteLong( rStrm, aEndSortTab[ i ] );
		SwWW8Writer::WriteLong( rStrm, rWrt.pFib->ccpText );
		rWrt.pFib->lcbPlcfbkl = rStrm.Tell() - rWrt.pFib->fcPlcfbkl;
	}
}

// JP 24.06.99: not used at time
/*String WW8_WrtBookmarks::GetWWBkmkName( const String& rName ) const
{
	// replace all characters that will WinWord not understand
	return rName;
}
*/

USHORT WW8_WrtBookmarks::GetPos( const String& rNm )
{
	USHORT nRet = USHRT_MAX, n;
	for( n = 0; n < aSttCps.Count(); ++n )
		if( rNm == *aSwBkmkNms.GetObject( n ))
		{
			nRet = n;
			break;
		}
	return nRet;
}

void SwWW8Writer::AppendBookmarks( const SwTxtNode& rNd,
									xub_StrLen nAktPos, xub_StrLen nLen )
{
	SvPtrarr aArr( 8, 8 );
	USHORT nCntnt;
	xub_StrLen nAktEnd = nAktPos + nLen;
	if( GetBookmarks( rNd, nAktPos, nAktEnd, aArr ))
	{
		ULONG nNd = rNd.GetIndex(), nSttCP = Fc2Cp( Strm().Tell() );
		for( USHORT n = 0; n < aArr.Count(); ++n )
		{
			const SwBookmark& rBkmk = *(SwBookmark*)aArr[ n ];
			const SwPosition* pPos = &rBkmk.GetPos(),
							* pOPos = rBkmk.GetOtherPos();
			if( pOPos && pOPos->nNode == pPos->nNode &&
				pOPos->nContent < pPos->nContent )
			{
				pOPos = pPos;
				pPos = rBkmk.GetOtherPos();
			}

			if( !pOPos || ( nNd == pPos->nNode.GetIndex() &&
				( nCntnt = pPos->nContent.GetIndex() ) >= nAktPos &&
				nCntnt < nAktEnd ) )
			{
				ULONG nCp = nSttCP + pPos->nContent.GetIndex() - nAktPos;
				pBkmks->Append( nCp, rBkmk.GetName() );
			}
			if( pOPos && nNd == pOPos->nNode.GetIndex() &&
				( nCntnt = pOPos->nContent.GetIndex() ) >= nAktPos &&
				nCntnt < nAktEnd )
			{
				ULONG nCp = nSttCP + pOPos->nContent.GetIndex() - nAktPos;
				pBkmks->Append( nCp, rBkmk.GetName() );
			}
		}
	}
}

void SwWW8Writer::AppendBookmark( const String& rName, USHORT nOffset )
{
	ULONG nSttCP = Fc2Cp( Strm().Tell() ) + nOffset;
	pBkmks->Append( nSttCP, rName );
}


//--------------------------------------------------------------------------
/*  */

USHORT WW8_WrtRedlineAuthor::AddName( const String& rNm )
{
	for( USHORT n = 0, nCnt = aAuthors.Count(); n < nCnt; ++n )
		if( *aAuthors[ n ] == rNm )
			return n;

	String* pNew = new String( rNm );
	aAuthors.Insert( pNew, n );
	return n;
}

void WW8_WrtRedlineAuthor::Write( SwWW8Writer& rWrt )
{
	rWrt.WriteAsStringTable( (SvStrings&)aAuthors,
								rWrt.pFib->fcSttbfRMark,
								rWrt.pFib->lcbSttbfRMark,
								rWrt.bWrtWW8 ? 0 : 2 );
}

USHORT SwWW8Writer::AddRedlineAuthor( USHORT nId )
{
	if( !pRedlAuthors )
	{
		pRedlAuthors = new WW8_WrtRedlineAuthor;
		pRedlAuthors->AddName( String::CreateFromAscii(
							RTL_CONSTASCII_STRINGPARAM( "Unknown" )));
	}
	return pRedlAuthors->AddName( SW_MOD()->GetRedlineAuthor( nId ) );
}

//--------------------------------------------------------------------------
/*  */

void SwWW8Writer::WriteAsStringTable( const SvStrings& rStrings,
										INT32& rfcSttbf, INT32& rlcbSttbf,
										USHORT nExtraLen )
{
	USHORT n, nCount = rStrings.Count();
	if( nCount )
	{
		// we have some Redlines found in the document -> the
		// Author Name Stringtable
		SvStream& rStrm = bWrtWW8 ? *pTableStrm : Strm();
		rfcSttbf = rStrm.Tell();
		if( bWrtWW8 )
		{
			SwWW8Writer::WriteShort( rStrm, -1 );
			SwWW8Writer::WriteLong( rStrm, nCount );
			for( n = 0; n < nCount; ++n )
			{
				const String& rNm = *rStrings[ n ];
				SwWW8Writer::WriteShort( rStrm, rNm.Len() );
				SwWW8Writer::WriteString16( rStrm, rNm, FALSE );
				if( nExtraLen )
					SwWW8Writer::FillCount( rStrm, nExtraLen );
			}
		}
		else
		{
			SwWW8Writer::WriteShort( rStrm, 0 );
			for( n = 0; n < nCount; ++n )
			{
				const String aNm( rStrings[ n ]->Copy(0, 255 ));
				rStrm << (BYTE)aNm.Len();
				SwWW8Writer::WriteString8( rStrm, aNm, FALSE,
												RTL_TEXTENCODING_MS_1252 );
				if( nExtraLen )
					SwWW8Writer::FillCount( rStrm, nExtraLen );
			}
		}
		rlcbSttbf = rStrm.Tell() - rfcSttbf;
		if( !bWrtWW8 )
			SwWW8Writer::WriteShort( rStrm, rfcSttbf, (USHORT)rlcbSttbf );
	}
}

// WriteShort() traegt an FilePos nPos den Wert nVal ein und seekt auf die
// alte FilePos zurueck. Benutzt zum Nachtragen von Laengen.
void SwWW8Writer::WriteShort( SvStream& rStrm, ULONG nPos, INT16 nVal )
{
	ULONG nOldPos = rStrm.Tell();		// Pos merken
	rStrm.Seek( nPos );
	SwWW8Writer::WriteShort( rStrm, nVal );
	rStrm.Seek( nOldPos );
}

void SwWW8Writer::WriteLong( SvStream& rStrm, ULONG nPos, INT32 nVal )
{
	ULONG nOldPos = rStrm.Tell();		// Pos merken
	rStrm.Seek( nPos );
	SwWW8Writer::WriteLong( rStrm, nVal );
	rStrm.Seek( nOldPos );
}

#ifdef __WW8_NEEDS_COPY

void SwWW8Writer::InsUInt16( WW8Bytes& rO, UINT16 n )
{
	SVBT16 nL;
	ShortToSVBT16( n, nL );
	rO.Insert( nL, 2, rO.Count() );
}
void SwWW8Writer::InsUInt32( WW8Bytes& rO, UINT32 n )
{
	SVBT32 nL;
	LongToSVBT32( n, nL );
	rO.Insert( nL, 4, rO.Count() );
}

#else

void SwWW8Writer::InsUInt16( WW8Bytes& rO, UINT16 n )
{
	rO.Insert( (BYTE*)&n, 2, rO.Count() );
}
void SwWW8Writer::InsUInt32( WW8Bytes& rO, UINT32 n )
{
	rO.Insert( (BYTE*)&n, 4, rO.Count() );
}

#endif // defined __WW8_NEEDS_COPY

void SwWW8Writer::InsAsString16( WW8Bytes& rO, const String& rStr )
{
	for( const sal_Unicode* pStr = rStr.GetBuffer(); *pStr; ++pStr )
		SwWW8Writer::InsUInt16( rO, *pStr );
}

void SwWW8Writer::InsAsString8( WW8Bytes& rO, const String& rStr,
								rtl_TextEncoding eCodeSet )
{
	ByteString sTmp( rStr, eCodeSet );
	rO.Insert( (BYTE*)sTmp.GetBuffer(), sTmp.Len(), rO.Count() );
}

void SwWW8Writer::WriteString16( SvStream& rStrm, const String& rStr,
									BOOL bAddZero )
{
	WW8Bytes aBytes;
	SwWW8Writer::InsAsString16( aBytes, rStr );
	if( bAddZero )
		SwWW8Writer::InsUInt16( aBytes, 0 );
	rStrm.Write( aBytes.GetData(), aBytes.Count() );
}

void SwWW8Writer::WriteString8( SvStream& rStrm, const String& rStr,
								BOOL bAddZero, rtl_TextEncoding eCodeSet )
{
	WW8Bytes aBytes;
	SwWW8Writer::InsAsString8( aBytes, rStr, eCodeSet );
	if( bAddZero )
		aBytes.Insert( (BYTE)0, aBytes.Count() );
	rStrm.Write( aBytes.GetData(), aBytes.Count() );
}

void SwWW8Writer::WriteStringAsPara( const String& rTxt, USHORT nStyleId )
{
	if( rTxt.Len() )
		OutSwString( rTxt, 0, rTxt.Len(), IsUnicode(), RTL_TEXTENCODING_MS_1252 );
	WriteCR();				// CR danach

	WW8Bytes aArr( 10, 10 );
	SwWW8Writer::InsUInt16( aArr, nStyleId );
	if( bOutTable )
	{												// Tab-Attr
		// sprmPFInTable
		if( bWrtWW8 )
			SwWW8Writer::InsUInt16( aArr, 0x2416 );
		else
			aArr.Insert( 24, aArr.Count() );
		aArr.Insert( 1, aArr.Count() );
	}

	ULONG nPos = Strm().Tell();
	pPapPlc->AppendFkpEntry( nPos, aArr.Count(), aArr.GetData() );
	pChpPlc->AppendFkpEntry( nPos );
}

void SwWW8Writer::WriteSpecialText( ULONG nStart, ULONG nEnd, BYTE nTTyp )
{
	BYTE nOldTyp = nTxtTyp;
	nTxtTyp = nTTyp;
	SwPaM* pOldPam = pCurPam;		//!! Einfaches Umsetzen des PaM ohne
	SwPaM* pOldEnd = pOrigPam;			// Wiederherstellen muesste es auch tun
	BOOL bOldPageDescs = bOutPageDescs;
	bOutPageDescs = FALSE;
									// bOutKF wird in WriteKF1 gemerkt / gesetzt
	pCurPam = NewSwPaM( *pDoc, nStart, nEnd );

	// Tabelle in Sonderbereichen erkennen
	if(	   (nStart != pCurPam->GetMark()->nNode.GetIndex())
		&& pDoc->GetNodes()[ nStart ]->IsTableNode() )
		pCurPam->GetMark()->nNode = nStart;

	pOrigPam = pCurPam;
	pCurPam->Exchange();

	WriteText();

	delete pCurPam;                    // Pam wieder loeschen
	bOutPageDescs = bOldPageDescs;
	pCurPam = pOldPam;
	pOrigPam = pOldEnd;
	nTxtTyp = nOldTyp;
}

void SwWW8Writer::OutSwString( const String& rStr, xub_StrLen nStt,
								xub_StrLen nLen, BOOL bUnicode,
								rtl_TextEncoding eChrSet )

{
	if( nLen )
	{
		if ( bUnicode != pPiece->IsUnicode() )
			pPiece->AppendPc ( Strm().Tell(), bUnicode );

		if( nStt || nLen != rStr.Len() )
		{
			String sOut( rStr.Copy( nStt, nLen ) );
			if( bUnicode )
				SwWW8Writer::WriteString16( Strm(), sOut, FALSE );
			else
				SwWW8Writer::WriteString8( Strm(), sOut, FALSE, eChrSet );
		}
		else if( bUnicode )
			SwWW8Writer::WriteString16( Strm(), rStr, FALSE );
		else
			SwWW8Writer::WriteString8( Strm(), rStr, FALSE, eChrSet );
	}
}

void SwWW8Writer::WriteCR()
{
	WriteChar( '\015' );
	pPiece->SetParaBreak();
}

void SwWW8Writer::WriteChar( sal_Unicode c )
{
	if( pPiece->IsUnicode() )
		Strm() << c;
	else
		Strm() << (BYTE)c;
}

long SwWW8Writer::GetDTTM( const DateTime& rDT )
{
/*
mint	short	:6	0000003F	minutes (0-59)
hr		short	:5	000007C0	hours (0-23)
dom		short	:5	0000F800	days of month (1-31)
mon		short	:4	000F0000	months (1-12)
yr		short	:9	1FF00000	years (1900-2411)-1900
wdy		short	:3	E0000000	weekday(Sunday=0
										Monday=1
( wdy can be ignored )					Tuesday=2
										Wednesday=3
										Thursday=4
										Friday=5
										Saturday=6)
*/

	long nDT = ( rDT.GetDayOfWeek() + 1 ) % 7;
	nDT <<= 9;
	nDT += ( rDT.GetYear() - 1900 ) & 0x1ff;
	nDT <<= 4;
	nDT += rDT.GetMonth() & 0xf;
	nDT <<= 5;
	nDT += rDT.GetDay() & 0x1f;
	nDT <<= 5;
	nDT += rDT.GetHour() & 0x1f;
	nDT <<= 6;
	nDT += rDT.GetMin() & 0x3f;
	return nDT;
}

/*  */
//---------------------------------------------------------------------------
// 		 Hilfsroutinen fuer Flys
//---------------------------------------------------------------------------
// Struktur speichert die aktuellen Daten des Writers zwischen, um
// einen anderen Dokument-Teil auszugeben, wie z.B. Header/Footer
WW8SaveData::WW8SaveData( SwWW8Writer& rWriter, ULONG nStt, ULONG nEnd )
	: rWrt( rWriter ),
	pOldPam( rWrt.pCurPam ), pOldEnd( rWrt.GetEndPaM() ),
	pOldFlyFmt( rWrt.pFlyFmt ), pOldPageDesc( rWrt.pAktPageDesc )

{
	pOldFlyOffset = rWrt.pFlyOffset;
	if( rWrt.pO->Count() )
	{
		pOOld = rWrt.pO;
		rWrt.pO = new WW8Bytes( 128, 128 );
	}
	else
		pOOld = 0;
	bOldWriteAll = rWrt.bWriteAll;
	bOldOutTable = rWrt.bOutTable;
	bOldIsInTable= rWrt.bIsInTable;
	bOldFlyFrmAttrs = rWrt.bOutFlyFrmAttrs;
	bOldStartTOX = rWrt.bStartTOX;
	bOldInWriteTOX = rWrt.bInWriteTOX;

	rWrt.pCurPam = rWrt.NewSwPaM( *rWrt.pDoc, nStt, nEnd );

	// Tabelle in Sonderbereichen erkennen
	if( nStt != rWrt.pCurPam->GetMark()->nNode.GetIndex() &&
		rWrt.pDoc->GetNodes()[ nStt ]->IsTableNode() )
		rWrt.pCurPam->GetMark()->nNode = nStt;

	rWrt.SetEndPaM( rWrt.pCurPam );
	rWrt.pCurPam->Exchange( );
	rWrt.bWriteAll = TRUE;
	rWrt.bOutTable = FALSE;
	// Vorsicht:  rWrt.bIsInTable  darf hier NICHT veraendert werden!
	rWrt.bOutFlyFrmAttrs = FALSE;
//	rWrt.pAttrSet = 0;
	rWrt.bStartTOX = FALSE;
	rWrt.bInWriteTOX = FALSE;
}


WW8SaveData::~WW8SaveData()
{
	delete rWrt.pCurPam;					// Pam wieder loeschen

	rWrt.pCurPam = pOldPam;
	rWrt.SetEndPaM( pOldEnd );
	rWrt.bWriteAll = bOldWriteAll;
	rWrt.bOutTable = bOldOutTable;
	rWrt.bIsInTable= bOldIsInTable;
	rWrt.bOutFlyFrmAttrs = bOldFlyFrmAttrs;
	rWrt.bStartTOX = bOldStartTOX;
	rWrt.bInWriteTOX = bOldInWriteTOX;
	rWrt.pFlyFmt = pOldFlyFmt;
	rWrt.pAktPageDesc = pOldPageDesc;
//	rWrt.pAttrSet = pOldAttrSet;
	ASSERT( !rWrt.pO->Count(), " pO ist am Ende von WW8SaveData nicht leer" );
	if( pOOld )
	{
		delete rWrt.pO;
		rWrt.pO = pOOld;
	}
	rWrt.pFlyOffset = pOldFlyOffset;
}


void SwWW8Writer::WriteText()
{
	while( pCurPam->GetPoint()->nNode < pCurPam->GetMark()->nNode ||
			(pCurPam->GetPoint()->nNode == pCurPam->GetMark()->nNode &&
			pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex()) )
	{
		SwNode * pNd = pCurPam->GetNode();

		if( pNd->IsTxtNode() ) // blitzschnelle Methode
		{
			const SwTxtNode* pTxtNode = pNd->GetTxtNode();
			if( pTxtNode->GetpSwAttrSet() )
				Out_SfxBreakItems( *pTxtNode->GetpSwAttrSet(), *pTxtNode );
			if( !bIsInTable )
				OutWW8FlyFrmsInCntnt( *pTxtNode ); // als Zeichen gebundene Flys
		}

		if( pNd->IsCntntNode() )
		{
			SwCntntNode* pCNd = (SwCntntNode*)pNd;

			// erfrage den aktuellen PageDescriptor.
			if( !bInWriteEscher )
				OutFlyFrms( *pCNd );

			const SwPageDesc* pTemp = pCNd->GetSwAttrSet().GetPageDesc().GetPageDesc();
			if( pTemp )
				pAktPageDesc = pTemp;

			pCurPam->GetPoint()->nContent.Assign( pCNd, 0 );
			Out( aWW8NodeFnTab, *pCNd, *this );
		}
		else if( pNd->IsTableNode() && !bIsInTable )
			OutWW8_SwTblNode( *this, *(SwTableNode*)pNd );
		else if( pNd->IsSectionNode() && TXT_MAINTEXT == nTxtTyp )
			OutWW8_SwSectionNode( *this, *pNd->GetSectionNode() );
		else if( TXT_MAINTEXT == nTxtTyp && pNd->IsEndNode() &&
				 pNd->FindStartNode()->IsSectionNode() )
		{
			const SwSection& rSect = pNd->FindStartNode()->GetSectionNode()
										->GetSection();
			if( bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
				bStartTOX = FALSE;

			SwNodeIndex aIdx( *pNd, 1 );
			if(    aIdx.GetNode().IsEndNode()
				&& aIdx.GetNode().FindStartNode()->IsSectionNode() )
				;
			else
			if(    aIdx.GetNode().IsSectionNode() )
				;
			else
			{
				ReplaceCr( (char)0xc ); // Indikator fuer Page/Section-Break

				const SwSectionFmt* pParentFmt = rSect.GetFmt()->GetParent();
				if( !pParentFmt )
					pParentFmt = (SwSectionFmt*)0xFFFFFFFF;

				ULONG nRstLnNum;
				if( aIdx.GetNode().IsCntntNode() )
					nRstLnNum = ((SwCntntNode&)aIdx.GetNode()).GetSwAttrSet().
											GetLineNumber().GetStartValue();
				else
					nRstLnNum = 0;

				pSepx->AppendSep( Fc2Cp( Strm().Tell() ),
									pAktPageDesc, pParentFmt, nRstLnNum );
			}
		}
		else if( pNd == &pNd->GetNodes().GetEndOfContent() )
			break;

		ULONG nPos = pCurPam->GetPoint()->nNode++; 	// Bewegen
		::SetProgressState( nPos, pCurPam->GetDoc()->GetDocShell() );   // Wie weit ?
	}
}

void SwWW8Writer::WriteMainText()
{
	pFib->fcMin = Strm().Tell();

	do {
		WriteText();
	} while( FALSE );		//!! Temporaer nur 1 Bereich
//	} while( CopyNextPam( &pCurPam ) );		// bis alle Pam bearbeitet

	if( 0 == Strm().Tell() - pFib->fcMin ) 	// kein Text ?
		WriteCR();					// dann CR ans Ende ( sonst mault WW )

	pFib->ccpText = Fc2Cp( Strm().Tell() );
	pFldMain->Finish( pFib->ccpText, 0 );

					// ccpText beinhaltet Ftn- und KF-Texte
					// deshalb wird pFib->ccpText evtl. noch geupdated
	// save the StyleId of the last paragraph. Because WW97 take the style
	// from the last CR, that will be write after footer/Header/fontnotes/
	// annotation usw.
	const SwTxtNode* pLastNd = pCurPam->GetMark()->nNode.GetNode().GetTxtNode();
	if( pLastNd )
		nLastFmtId = GetId( (SwTxtFmtColl&)pLastNd->GetAnyFmtColl() );
}

void SwWW8Writer::WriteFkpPlcUsw()
{
	if( !bWrtWW8 )
	{
		static BYTE __READONLY_DATA aSpec[2] = { 117, 1 };

		pChpPlc->AppendFkpEntry( Strm().Tell() );	// Sepx mit fSpecial
		pSepx->WriteSepx( Strm() );					// Slcx.Sepx
		pGrf->Write();								// Grafiken
		pChpPlc->AppendFkpEntry( Strm().Tell(), sizeof( aSpec ), aSpec );

		pChpPlc->WriteFkps();					// Fkp.Chpx
		pPapPlc->WriteFkps();					// Fkp.Papx
		pStyles->OutStyleTab();					// Styles
		pFtn->WritePlc( *this );				// Footnote-Ref & Text Plc
		pEdn->WritePlc( *this );				// Endnote-Ref & Text Plc
		pAtn->WritePlc( *this );				// Annotation-Ref & Text Plc
		pSepx->WritePlcSed( *this );			// Slcx.PlcSed
		pSepx->WritePlcHdd( *this );			// Slcx.PlcHdd
		pChpPlc->WritePlc();					// Plcx.Chpx
		pPapPlc->WritePlc();					// Plcx.Papx
		OutFontTab( *pFib );					// FFNs
		if( pRedlAuthors )
			pRedlAuthors->Write( *this );		// sttbfRMark (RedlineAuthors)
		pFldMain->Write( *this );				// Fields ( Main Text )
		pFldHdFt->Write( *this );				// Fields ( Header/Footer )
		pFldFtn->Write( *this );				// Fields ( FootNotes )
		pFldEdn->Write( *this );				// Fields ( EndNotes )
		pBkmks->Write( *this );					// Bookmarks - sttbfBkmk/
												// plcfBkmkf/plcfBkmkl
		WriteDop( *this );						// Document-Properties

	}
	else
	{
		// Grafiken in den Data-Tream
//???		static BYTE __READONLY_DATA aSpec[] = { 0x55,0x08,0x01 };
//???		pChpPlc->AppendFkpEntry( pDataStrm->Tell() );	// Sepx mit fSpecial

		pGrf->Write();						// Grafiken
//???		pChpPlc->AppendFkpEntry( pDataStrm->Tell(), sizeof( aSpec ), aSpec );

		// Ausgabe in WordDocument-Stream
		pChpPlc->WriteFkps();					// Fkp.Chpx
		pPapPlc->WriteFkps();					// Fkp.Papx
		pSepx->WriteSepx( Strm() );				// Sepx

		// Ausagbe in Table-Stream
		pStyles->OutStyleTab();					// fuer WW8 StyleTab
		pFtn->WritePlc( *this );				// Footnote-Ref & Text Plc
		pEdn->WritePlc( *this );				// Endnote-Ref & Text Plc
		pTxtBxs->WritePlc( *this );				// Textbox Text Plc
		pHFTxtBxs->WritePlc( *this );			// Head/Foot-Textbox Text Plc
		pAtn->WritePlc( *this );				// Annotation-Ref & Text Plc

		pSepx->WritePlcSed( *this );			// Slcx.PlcSed
		pSepx->WritePlcHdd( *this );			// Slcx.PlcHdd

		pChpPlc->WritePlc();					// Plcx.Chpx
		pPapPlc->WritePlc();					// Plcx.Papx

		if( pRedlAuthors )
			pRedlAuthors->Write( *this );		// sttbfRMark (RedlineAuthors)
		pFldMain->Write( *this );				// Fields ( Main Text )
		pFldHdFt->Write( *this );				// Fields ( Header/Footer )
		pFldFtn->Write( *this );				// Fields ( FootNotes )
		pFldEdn->Write( *this );				// Fields ( EndNotes )
		pFldTxtBxs->Write( *this );				// Fields ( Textboxes )
		pFldHFTxtBxs->Write( *this );			// Fields ( Head/Foot-Textboxes )

		// dggInfo - escher stream
		WriteEscher();

		pSdrObjs->WritePlc( *this );
		pHFSdrObjs->WritePlc( *this );
		// spamom - office drawing table
		// spahdr - header office drawing table

		pBkmks->Write( *this );					// Bookmarks - sttbfBkmk/
												// plcfBkmkf/plcfBkmkl

		OutListTab();							// listformats  - LSTF
		OutOverrideListTab();					//   - "" - 	- LFO
		OutListNamesTab();						//   - "" -		- ListNames

		pPiece->WritePc( *this );				// Piece-Table
		OutFontTab( *pFib );					// FFNs
		WriteDop( *this );						// Document-Properties
	}
	Strm().Seek( 0 );

	pFib->Write( Strm() );	// FIB
}

void SwWW8Writer::StoreDoc1()
{
	// Start of Text ( Mangel ueber )
	SwWW8Writer::FillUntil( Strm(), pFib->fcMin );

	WriteMainText();					// HauptText
	pFtn->WriteTxt( *this );			// Footnote-Text
	pSepx->WriteKFTxt( *this );			// K/F-Text
	pAtn->WriteTxt( *this );			// Annotation-Text
	pEdn->WriteTxt( *this );			// EndNote-Text

	// create the escher streams
	if( bWrtWW8 )
		CreateEscher();

	pTxtBxs->WriteTxt( *this );			// Textbox Text Plc
	pHFTxtBxs->WriteTxt( *this );		// Head/Foot-Textbox Text Plc

	WriteStringAsPara( aEmptyStr, nLastFmtId ); // CR ans Ende ( sonst mault WW )

	pSepx->Finish( Fc2Cp( Strm().Tell() ));// Text + Ftn + HdFt als Section-Ende

	pFib->fcMac = Strm().Tell();		// Ende aller Texte

	WriteFkpPlcUsw();					// FKP, PLC, .....
}

ULONG SwWW8Writer::StoreDoc()
{
	nIniFlags = ReadFilterFlags( "WWWR" );
	nCharFmtStart = ANZ_DEFAULT_STYLES;
	nFmtCollStart = nCharFmtStart + pDoc->GetCharFmts()->Count() - 1;

	bStyDef = bBreakBefore = bOutKF =
		bOutFlyFrmAttrs	= bOutPageDescs = bOutTable = bOutFirstPage =
		bIsInTable = bOutGrf = bInWriteEscher = bStartTOX =
		bInWriteTOX = FALSE;

	bFtnAtTxtEnd = bEndAtTxtEnd = TRUE;

	pFlyFmt = 0;
	pFlyOffset = 0;
	nTxtTyp = TXT_MAINTEXT;
	nFlyWidth = nFlyHeight = 0;
	nStyleBeforeFly = nLastFmtId = 0;
	pStyAttr = 0;
	pOutFmtNode = 0;
	pUsedNumTbl = 0;
	pEscher = 0;
	pRedlAuthors = 0;
	if( aTOXArr.Count() )
		aTOXArr.Remove( 0, aTOXArr.Count() );

#if SUPD>593
	if( !pOLEExp )
	{
		UINT32 nSvxMSDffOLEConvFlags = 0;
		const OfaFilterOptions* pOpt = OFF_APP()->GetFilterOptions();
		if( pOpt->IsStarMath2MathType() )
			nSvxMSDffOLEConvFlags |= OLE_STARMATH_2_MATHTYPE;
		if( pOpt->IsStarWriter2WinWord() )
			nSvxMSDffOLEConvFlags |= OLE_STARWRITER_2_WINWORD;
		if( pOpt->IsStarCalc2Excel() )
			nSvxMSDffOLEConvFlags |= OLE_STARCALC_2_EXCEL;
		if( pOpt->IsStarImpress2PowerPoint() )
			nSvxMSDffOLEConvFlags |= OLE_STARIMPRESS_2_POWERPOINT;

		pOLEExp = new SvxMSExportOLEObjects( nSvxMSDffOLEConvFlags );
	}
#endif

	PrepareStorage();

	PutNumFmtFontsInAttrPool();
	PutEditEngFontsInAttrPool();

	pFib = new WW8Fib( bWrtWW8 ? 8 : 6 );

	SvStream* pOldStrm = pStrm;			// JP 19.05.99: wozu das ???
	SvStorageStreamRef xWwStrm( pStg->OpenStream( aMainStg ) );
	SvStorageStreamRef xTableStrm( xWwStrm ), xDataStrm( xWwStrm );
	xWwStrm->SetBufferSize( 32768 );

	if( bWrtWW8 )
	{
		pFib->fWhichTblStm = 1;
		xTableStrm = pStg->OpenStream( sTableStream, STREAM_STD_WRITE );
		xDataStrm = pStg->OpenStream( sDataStream, STREAM_STD_WRITE );

		xDataStrm->SetBufferSize( 32768 );	// fuer Grafiken
		xTableStrm->SetBufferSize( 16384 );	// fuer die Font-/Style-Table, usw.

		xTableStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
		xDataStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
	}

	pStrm = &xWwStrm;
	pTableStrm = &xTableStrm;
	pDataStrm = &xDataStrm;

	pStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );

	pAktPageDesc = &pDoc->GetPageDesc( 0 );		// Default: "Standard"
	pSepx = new WW8_WrPlcSepx;		// Sepx
	{
		const SfxPoolItem* pI;
		const SwNode* pNd = pCurPam->GetCntntNode();
		const SfxItemSet* pSet = pNd ? &((SwCntntNode*)pNd)->GetSwAttrSet()
									 : 0;

		ULONG nRstLnNum =  pSet ? ((SwFmtLineNumber&)pSet->Get(
											RES_LINENUMBER )).GetStartValue()
								: 0;

		const SwTableNode* pTblNd = pCurPam->GetNode()->FindTableNode();
		const SwSectionNode* pSectNd;
		if( pTblNd )
		{
			pSet = &pTblNd->GetTable().GetFrmFmt()->GetAttrSet();
			pNd = pTblNd;
		}
		else if( 0 != ( pSectNd = pNd->FindSectionNode() ) )
		{
			if( TOX_HEADER_SECTION == pSectNd->GetSection().GetType() &&
				pSectNd->FindStartNode()->IsSectionNode() )
				pSectNd = pSectNd->FindStartNode()->GetSectionNode();

			if( TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() )
			{
				pNd = pSectNd;
				pCurPam->GetPoint()->nNode = *pNd;
			}
		}

		// Hole evtl. Pagedesc des 1. Nodes
		if( pSet && SFX_ITEM_ON == pSet->GetItemState(RES_PAGEDESC,TRUE,&pI)
			&& ((SwFmtPageDesc*)pI)->GetPageDesc() )
			pSepx->AppendSep( 0, *(SwFmtPageDesc*)pI, *pNd, nRstLnNum );
		else
			pSepx->AppendSep( 0, pAktPageDesc, 0, nRstLnNum );
	}

	pFtn = new WW8_WrPlcFtnEdn( TXT_FTN );						// Ftn
	pEdn = new WW8_WrPlcFtnEdn( TXT_EDN );						// Edn
	pAtn = new WW8_WrPlcPostIt;									// PostIts
	pTxtBxs = new WW8_WrPlcTxtBoxes( TXT_TXTBOX );
	pHFTxtBxs = new WW8_WrPlcTxtBoxes( TXT_HFTXTBOX );

	pSdrObjs = new WW8_WrPlcDrawObj( TXT_TXTBOX ); 		// Draw-/Fly-Objects
	pHFSdrObjs = new WW8_WrPlcDrawObj( TXT_HFTXTBOX );	// Draw-/Fly-Objects
														// in header or footer

	pBkmks = new WW8_WrtBookmarks;							// Bookmarks
	CreateBookmarkTbl();

	pPapPlc = new WW8_WrPlcPn( *this, PAP, pFib->fcMin );
	pChpPlc = new WW8_WrPlcPn( *this, CHP, pFib->fcMin );
	pO = new WW8Bytes( 128, 128 );
	pStyles = new WW8WrtStyle( *this );
	pFldMain = new WW8_WrPlcFld( 2, TXT_MAINTEXT );
	pFldHdFt = new WW8_WrPlcFld( 2, TXT_HDFT );
	pFldFtn = new WW8_WrPlcFld( 2, TXT_FTN );
	pFldEdn = new WW8_WrPlcFld( 2, TXT_EDN );
	pFldTxtBxs = new WW8_WrPlcFld( 2, TXT_TXTBOX );
	pFldHFTxtBxs = new WW8_WrPlcFld( 2, TXT_HFTXTBOX );

	pGrf = new SwWW8WrGrf( *this );
	pPiece = new WW8_WrPct( pFib->fcMin );
	pDop = new WW8Dop;

	USHORT nRedlineMode = pDoc->GetRedlineMode();
	pDop->fRevMarking = 0 != (REDLINE_ON & nRedlineMode);
	pDop->fRMView = 0 != ( REDLINE_SHOW_DELETE & nRedlineMode );
	if( pDoc->GetRedlineTbl().Count() )
		pDoc->SetRedlineMode( nRedlineMode | REDLINE_SHOW_DELETE |
											REDLINE_SHOW_INSERT );

	// set AutoHyphenation flag if found in default para style
	const SfxPoolItem* pItem;
	SwTxtFmtColl* pStdTxtFmtColl = pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD );
	if(    pStdTxtFmtColl
		&& SFX_ITEM_SET == pStdTxtFmtColl->GetItemState(
										RES_PARATR_HYPHENZONE, FALSE, &pItem ) )
		pDop->fAutoHyphen = ((SvxHyphenZoneItem*)pItem)->IsHyphen();

	// make unique OrdNums (Z-Order) for all drawing-/fly Objects
	if( pDoc->GetDrawModel() )
		pDoc->GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();

	StoreDoc1();

	if( nRedlineMode != pDoc->GetRedlineMode() )
		pDoc->SetRedlineMode( nRedlineMode );

	if( pUsedNumTbl )			// all used NumRules
	{
		// clear array  - it's an auto delete array
		pUsedNumTbl->Remove( 0, pUsedNumTbl->Count() );
		delete pUsedNumTbl;
	}

	DELETEZ( pGrf );
	DELETEZ( pFldFtn );
	DELETEZ( pFldTxtBxs );
	DELETEZ( pFldHFTxtBxs );
	DELETEZ( pFldEdn );
	DELETEZ( pFldHdFt );
	DELETEZ( pFldMain );
	DELETEZ( pStyles );
	DELETEZ( pO );
	DELETEZ( pChpPlc );
	DELETEZ( pPapPlc );
	DELETEZ( pSepx );

	delete pRedlAuthors;
	delete pSdrObjs;
	delete pHFSdrObjs;
	delete pTxtBxs;
	delete pHFTxtBxs;
	delete pAtn;
	delete pEdn;
	delete pFtn;
	delete pBkmks;
	delete pPiece;
	delete pDop;
	delete pFib;
	pStrm = pOldStrm;


	xWwStrm->SetBufferSize( 0 );
	if( bWrtWW8 )
	{
		xTableStrm->SetBufferSize( 0 );
		xDataStrm->SetBufferSize( 0 );
		if( 0 == pDataStrm->Seek( STREAM_SEEK_TO_END ))
		{
			xDataStrm.Clear();
			pDataStrm = 0;
			pStg->Remove( sDataStream );
		}
	}

	return 0;
}


void SwWW8Writer::PrepareStorage()
{
	ULONG nLen;
	const BYTE* pData;
	const char* pName;
	UINT32 nId1;

	if( bWrtWW8 )
	{
		static char __READONLY_DATA aUserName[] = "Microsoft Word-Document";
		static BYTE __READONLY_DATA aCompObj[] = {
			0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
			0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
			0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x46, 0x18, 0x00, 0x00, 0x00,
			0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
			0x74, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x2D, 0x44,
			0x6F, 0x6B, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x00,
			0x0A, 0x00, 0x00, 0x00, 0x4D, 0x53, 0x57, 0x6F,
			0x72, 0x64, 0x44, 0x6F, 0x63, 0x00, 0x10, 0x00,
			0x00, 0x00, 0x57, 0x6F, 0x72, 0x64, 0x2E, 0x44,
			0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2E,
			0x38, 0x00, 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00 };

		pName = aUserName;
		pData = aCompObj;
		nLen = sizeof( aCompObj );
		nId1 = 0x00020906L;
	}
	else
	{
		static char __READONLY_DATA aUserName[] = "Microsoft Word 6.0 Document";
		static BYTE __READONLY_DATA aCompObj[] = {
			0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
			0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x09, 0x02, 0x00,
			0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x46, 0x1C, 0x00, 0x00, 0x00,
			0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
			0x74, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x36,
			0x2E, 0x30, 0x2D, 0x44, 0x6F, 0x6B, 0x75, 0x6D,
			0x65, 0x6E, 0x74, 0x00, 0x0A, 0x00, 0x00, 0x00,
			0x4D, 0x53, 0x57, 0x6F, 0x72, 0x64, 0x44, 0x6F,
			0x63, 0x00, 0x10, 0x00, 0x00, 0x00, 0x57, 0x6F,
			0x72, 0x64, 0x2E, 0x44, 0x6F, 0x63, 0x75, 0x6D,
			0x65, 0x6E, 0x74, 0x2E, 0x36, 0x00, 0x00, 0x00,
			0x00, 0x00 };

		pName = aUserName;
		pData = aCompObj;
		nLen = sizeof( aCompObj );
		nId1 = 0x00020900L;
	}

	SvGlobalName aGName( nId1, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00,
						 0x00, 0x00, 0x00, 0x46 );
	pStg->SetClass( aGName, 0, String::CreateFromAscii( pName ));
	SvStorageStreamRef xStor( pStg->OpenStream( String::CreateFromAscii(
								RTL_CONSTASCII_STRINGPARAM( "\1CompObj" ))));
	xStor->Write( pData, nLen );
				// noch mal ueberplaetten, um auch Clipboardformat zu setzen
	pDoc->GetInfo()->SavePropertySet( pStg );	// DocInfo
}


ULONG SwWW8Writer::WriteStorage()
{
	long nMaxNode = pDoc->GetNodes().Count();
	::StartProgress( STR_STATSTR_W4WWRITE, 0, nMaxNode, pDoc->GetDocShell() );

	// Tabelle am Doc.-Anfang beachten
	{
		SwTableNode * pTNd = pCurPam->GetNode()->FindTableNode();
		if( pTNd && bWriteAll )
			// mit dem TabellenNode anfangen !!
			pCurPam->GetPoint()->nNode = *pTNd;
	}

	// Tabelle fuer die freifliegenden Rahmen erzeugen, aber nur wenn
	// das gesamte Dokument geschrieben wird
	nAktFlyPos = 0;
	SwPosFlyFrms aFlyPos;
	pDoc->GetAllFlyFmts( aFlyPos, bWriteAll ? 0 : pOrigPam, bWrtWW8 );
		// Die Sonderbehandlung fuer Teilausgabe fehlt noch ( siehe RTF )
	pFlyPos = &aFlyPos;

	ULONG nRet = StoreDoc();

	// loesche die Tabelle mit den freifliegenden Rahmen
	for( USHORT i = aFlyPos.Count(); i > 0; )
		delete aFlyPos[ --i ];

	::EndProgress( pDoc->GetDocShell() );
	bWrtWW8 = FALSE;		// sicherheitshalber: Default fuer's naechste Mal
	return nRet;
}

SwWW8Writer::SwWW8Writer( const String& rFltName )
	: pChpIter( 0 ), aMainStg( sMainStream ), pPapPlc( 0 ), pChpPlc( 0 ),
	pO( 0 ), pAktPageDesc( 0 ),	pISet( 0 ), pUsedNumTbl( 0 ), pBmpPal( 0 ),
	pKeyMap( 0 )
#if SUPD>593
	, pOLEExp( 0 )
#endif
{
	bWrtWW8 = rFltName.EqualsAscii( FILTER_WW8 );
}

SwWW8Writer::~SwWW8Writer()
{
	if( pBmpPal )
		delete pBmpPal;
	if( pKeyMap )
	{
		NfKeywordTable* pDel = (NfKeywordTable*)pKeyMap;
		delete [] pDel;
	}
#if SUPD>593
	if( pOLEExp )
		delete pOLEExp;
#endif
}

void GetWW8Writer( const String& rFltName, WriterRef& xRet )
{
	xRet = new SwWW8Writer( rFltName );
}



/*************************************************************************

	  Source Code Control System - Header

	  $Header: /cvs/oo/sw/sw/source/filter/ww8/wrtww8.cxx,v 1.1.1.1 2000/09/18 17:14:58 hr Exp $

	  Source Code Control System - Update

	  $Log: wrtww8.cxx,v $
	  Revision 1.1.1.1  2000/09/18 17:14:58  hr
	  initial import
	
	  Revision 1.54  2000/09/18 16:04:58  willem.vandorp
	  OpenOffice header added.
	
	  Revision 1.53  2000/08/21 10:14:06  khz
	  Export Line Numbering (restart on new section)
	
	  Revision 1.52  2000/07/25 15:16:21  khz
	  #76811# read/write AutoHyphenation flag from/into Document Properties
	
	  Revision 1.51  2000/07/06 15:55:55  khz
	  Document Statistics
	
	  Revision 1.50  2000/07/05 16:07:30  jp
	  new MS Filteroptions - change StarOffice Objects to OLE-Objects
	
	  Revision 1.49  2000/05/15 16:40:34  jp
	  Changes for Unicode

	  Revision 1.48  2000/05/12 16:14:07  jp
	  Changes for Unicode

	  Revision 1.47  2000/03/28 18:47:53  jp
	  Bug #74360#: WrFkp::Append - calculate the correct offset for W95

	  Revision 1.46  2000/03/09 09:23:04  jp
	  Bug #74053#: write sectionbreaks only in maintext

	  Revision 1.45  2000/03/03 16:08:37  pl
	  #73771# workaround for c50 intel compiler

	  Revision 1.44  2000/03/01 14:21:03  jp
	  Bug #73720#: StoreDoc1 - search the TOX content section

	  Revision 1.43  2000/02/11 14:39:55  hr
	  #70473# changes for unicode ( patched by automated patchtool )

	  Revision 1.42  1999/12/20 17:41:33  jp
	  Bug #70749#: Date/Time-Numberformats in german format from the formatter

	  Revision 1.41  1999/12/15 17:06:18  jp
	  Bug #70913#: write Ftn-/EndNoteInfo - at end of section or page/doc

	  Revision 1.40  1999/12/13 13:56:06  jp
	  Bug #70766#: StoreDoc - look for TOX at start of Document

	  Revision 1.39  1999/11/25 21:22:29  jp
	  Bug #70131#: OutFields: append the charattributes of the node to the sprms

	  Revision 1.38  1999/11/22 18:26:07  jp
	  export of TOX and TOX entries

	  Revision 1.37  1999/11/12 13:06:17  jp
	  write correct PAP-Fkps for Version 8

	  Revision 1.36  1999/11/02 09:44:13  jp
	  write sprmPHugePapx

	  Revision 1.35  1999/10/29 17:40:18  jp
	  export of 'complex'(vert. merged) tables

	  Revision 1.34  1999/10/14 21:06:09  jp
	  Bug #68617#,#68705# and other little things

	  Revision 1.33  1999/10/14 11:09:20  jp
	  export Redlines into W95/W97

	  Revision 1.32  1999/10/13 18:09:45  jp
	  write redlines

	  Revision 1.31  1999/10/13 09:08:51  jp
	  write character attributs of SdrObjects

	  Revision 1.30  1999/10/11 11:00:14  jp
	  some changes for export EditEngine text in WW-Format

	  Revision 1.29  1999/10/04 16:44:40  jp
	  Bug #68679#: check content range of bookmarkpos

	  Revision 1.28  1999/09/08 16:29:21  jp
	  Bug #68618#: recognize the write of escher stream

	  Revision 1.27  1999/08/31 07:51:34  JP
	  set NumberFormatInt at streams to littleendian


	  Rev 1.26   31 Aug 1999 09:51:34   JP
   set NumberFormatInt at streams to littleendian

	  Rev 1.25   24 Aug 1999 20:15:50   JP
   Escher Export

	  Rev 1.24   16 Aug 1999 17:16:28   JP
   W97 Export: experimental escher export (1)

	  Rev 1.23   16 Aug 1999 13:05:44   JP
   write EscherObjects - only a testversion!

	  Rev 1.22   21 Jul 1999 18:28:24   JP
   W97 Export: experimental escher export

	  Rev 1.21   06 Jul 1999 14:54:00   JP
   W97-Export corrections

	  Rev 1.20   30 Jun 1999 19:56:42   JP
   W97-Export: Fields/PostIts/References

	  Rev 1.19   24 Jun 1999 22:52:18   JP
   Export of Bookmarks and Hyperlinks

	  Rev 1.18   23 Jun 1999 20:14:40   JP
   W97-Export: write Bookmarks

	  Rev 1.17   23 Jun 1999 12:46:16   JP
   Export of numbers und outlinenumbers

	  Rev 1.16   16 Jun 1999 19:55:20   JP
   Change interface of base class Writer, Export of W97 NumRules

	  Rev 1.15   04 Jun 1999 17:47:52   JP
   WW97-Export: Code aufgeteilt

	  Rev 1.14   03 Jun 1999 21:04:10   JP
   Export von Seitenvorlagen verbessert: Abstaende/Umrandung/ErsteSeite/...

	  Rev 1.13   02 Jun 1999 18:45:40   JP
   WinWord-Export um Kopf-/Fusszeilen erweitert

	  Rev 1.12   31 May 1999 23:14:24   JP
   Erweiterungen/Umstellungen fuer Export

	  Rev 1.11   31 May 1999 18:54:34   JP
   Bug #66446#,#66457#: Asserts entfernt

	  Rev 1.10   28 May 1999 17:09:06   MPA
   WinWord97 Export

	  Rev 1.9   27 May 1999 23:45:06   JP
   PiceTable eingebaut, Schnittstellen angepasst, usw.

	  Rev 1.8   26 May 1999 16:44:28   MPA
   Anfaenge Piece-Table

	  Rev 1.7   26 May 1999 09:39:30   JP
   OutStyleTab entfernt, OutFontTab mit Fib-Ref, WritePlc ohne Flag

	  Rev 1.6   25 May 1999 17:00:10   MPA
   Anpassung PAPX/CHPX WW97

	  Rev 1.5   21 May 1999 19:20:00   JP
   kleinere Korrekturen

	  Rev 1.4   21 May 1999 17:01:00   MPA
   Anf,nge WW97

	  Rev 1.3   21 May 1999 10:51:52   MPA
   SwAttrItr:CTor von Pointer nach Ref

	  Rev 1.2   21 May 1999 02:00:50   JP
   Export von WW97 Format: allgemeine Methoden und FontTabelle

	  Rev 1.1   19 May 1999 19:34:16   JP
   WinWord97-ExportFilter

	  Rev 1.0   19 May 1999 11:20:02   JP
   WinWord97-ExportFilter

*************************************************************************/

