summaryrefslogtreecommitdiff
path: root/sw/source/filter/writer/writer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/writer/writer.cxx')
-rw-r--r--sw/source/filter/writer/writer.cxx628
1 files changed, 628 insertions, 0 deletions
diff --git a/sw/source/filter/writer/writer.cxx b/sw/source/filter/writer/writer.cxx
new file mode 100644
index 000000000000..d70b6d6c754e
--- /dev/null
+++ b/sw/source/filter/writer/writer.cxx
@@ -0,0 +1,628 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * 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"
+#include <hintids.hxx>
+
+#define _SVSTDARR_STRINGSSORTDTOR
+#include <svl/svstdarr.hxx>
+
+#include <sot/storage.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/urihelper.hxx>
+#include <svtools/filter.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <shellio.hxx>
+#include <pam.hxx>
+#include <doc.hxx>
+#include <docary.hxx>
+#include <IMark.hxx>
+#include <numrule.hxx>
+#include <swerror.h>
+#include <boost/bind.hpp>
+
+using namespace ::com::sun::star;
+
+
+// Stringbuffer fuer die umgewandelten Zahlen
+static sal_Char aNToABuf[] = "0000000000000000000000000";
+#define NTOABUFLEN (sizeof(aNToABuf))
+
+DECLARE_TABLE( SwBookmarkNodeTable, SvPtrarr* )
+
+struct Writer_Impl
+{
+ SvStream * m_pStream;
+
+ SvStringsSortDtor *pSrcArr, *pDestArr;
+ SvPtrarr* pFontRemoveLst, *pBkmkArr;
+ SwBookmarkNodeTable* pBkmkNodePos;
+
+ Writer_Impl();
+ ~Writer_Impl();
+
+ void RemoveFontList( SwDoc& rDoc );
+ void InsertBkmk( const ::sw::mark::IMark& rBkmk );
+};
+
+Writer_Impl::Writer_Impl()
+ : m_pStream(0)
+ , pSrcArr( 0 ), pDestArr( 0 ), pFontRemoveLst( 0 ), pBkmkNodePos( 0 )
+{
+}
+
+Writer_Impl::~Writer_Impl()
+{
+ delete pSrcArr;
+ delete pDestArr;
+ delete pFontRemoveLst;
+
+ if( pBkmkNodePos )
+ {
+ for( SvPtrarr* p = pBkmkNodePos->First(); p; p = pBkmkNodePos->Next() )
+ delete p;
+ delete pBkmkNodePos;
+ }
+}
+
+void Writer_Impl::RemoveFontList( SwDoc& rDoc )
+{
+ ASSERT( pFontRemoveLst, "wo ist die FontListe?" );
+ for( USHORT i = pFontRemoveLst->Count(); i; )
+ {
+ SvxFontItem* pItem = (SvxFontItem*)(*pFontRemoveLst)[ --i ];
+ rDoc.GetAttrPool().Remove( *pItem );
+ }
+}
+
+void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
+{
+ if( !pBkmkNodePos )
+ pBkmkNodePos = new SwBookmarkNodeTable;
+
+ ULONG nNd = rBkmk.GetMarkPos().nNode.GetIndex();
+ SvPtrarr* pArr = pBkmkNodePos->Get( nNd );
+ if( !pArr )
+ {
+ pArr = new SvPtrarr( 1, 4 );
+ pBkmkNodePos->Insert( nNd, pArr );
+ }
+
+ void* p = (void*)&rBkmk;
+ pArr->Insert( p, pArr->Count() );
+
+ if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
+ {
+ nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
+ pArr = pBkmkNodePos->Get( nNd );
+ if( !pArr )
+ {
+ pArr = new SvPtrarr( 1, 4 );
+ pBkmkNodePos->Insert( nNd, pArr );
+ }
+ pArr->Insert( p, pArr->Count() );
+ }
+}
+
+/*
+ * Dieses Modul ist die Zentrale-Sammelstelle fuer alle Write-Filter
+ * und ist eine DLL !
+ *
+ * Damit der Writer mit den unterschiedlichen Writern arbeiten kann,
+ * muessen fuer diese die Ausgabe-Funktionen der Inhalts tragenden
+ * Objecte auf die verschiedenen Ausgabe-Funktionen gemappt werden.
+ *
+ * Dazu kann fuer jedes Object ueber den Which-Wert in einen Tabelle ge-
+ * griffen werden, um seine Ausgabe-Funktion zu erfragen.
+ * Diese Funktionen stehen in den entsprechenden Writer-DLL's.
+ */
+
+Writer::Writer()
+ : m_pImpl(new Writer_Impl)
+ , pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
+{
+ bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
+ bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
+ bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
+ bOrganizerMode = false;
+ bExportPargraphNumbering = sal_True;
+}
+
+Writer::~Writer()
+{
+}
+
+/*
+ * Document Interface Access
+ */
+IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return pDoc; }
+const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return pDoc; }
+IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return pDoc; }
+const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return pDoc; }
+
+void Writer::ResetWriter()
+{
+ if (m_pImpl->pFontRemoveLst)
+ {
+ m_pImpl->RemoveFontList( *pDoc );
+ }
+ m_pImpl.reset(new Writer_Impl);
+
+ if( pCurPam )
+ {
+ while( pCurPam->GetNext() != pCurPam )
+ delete pCurPam->GetNext();
+ delete pCurPam;
+ }
+ pCurPam = 0;
+ pOrigFileName = 0;
+ pDoc = 0;
+
+ bShowProgress = bUCS2_WithStartChar = TRUE;
+ bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
+ bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
+ bOrganizerMode = FALSE;
+}
+
+BOOL Writer::CopyNextPam( SwPaM ** ppPam )
+{
+ if( (*ppPam)->GetNext() == pOrigPam )
+ {
+ *ppPam = pOrigPam; // wieder auf den Anfangs-Pam setzen
+ return FALSE; // Ende vom Ring
+ }
+
+ // ansonsten kopiere den die Werte aus dem naechsten Pam
+ *ppPam = ((SwPaM*)(*ppPam)->GetNext() );
+
+ *pCurPam->GetPoint() = *(*ppPam)->Start();
+ *pCurPam->GetMark() = *(*ppPam)->End();
+
+ return TRUE;
+}
+
+// suche die naechste Bookmark-Position aus der Bookmark-Tabelle
+
+sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
+{
+ const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
+ const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
+ pMarkAccess->getMarksBegin(),
+ pMarkAccess->getMarksEnd(),
+ rPos,
+ ::boost::bind(&::sw::mark::IMark::StartsBefore, _1, _2)); // find the first Mark that does not start before
+ if(ppBkmk != pMarkAccess->getMarksEnd())
+ return ppBkmk - pMarkAccess->getMarksBegin();
+ return -1;
+}
+
+
+SwPaM* Writer::NewSwPaM( SwDoc & rDoc, ULONG nStartIdx, ULONG nEndIdx,
+ BOOL bNodesArray )
+{
+ SwNodes* pNds = bNodesArray ? &rDoc.GetNodes() : (SwNodes*)rDoc.GetUndoNds();
+
+ SwNodeIndex aStt( *pNds, nStartIdx );
+ SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
+ if( !pCNode && 0 == ( pCNode = pNds->GoNext( &aStt )) )
+ {
+ ASSERT( false, "An StartPos kein ContentNode mehr" );
+ }
+
+ SwPaM* pNew = new SwPaM( aStt );
+ pNew->SetMark();
+ aStt = nEndIdx;
+ if( 0 == (pCNode = aStt.GetNode().GetCntntNode()) &&
+ 0 == (pCNode = pNds->GoPrevious( &aStt )) )
+ {
+ ASSERT( false, "An StartPos kein ContentNode mehr" );
+ }
+ pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
+ pNew->GetPoint()->nNode = aStt;
+ return pNew;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+// Stream-spezifisches
+SvStream& Writer::Strm()
+{
+ ASSERT( m_pImpl->m_pStream, "Oh-oh. Writer with no Stream!" );
+ return *m_pImpl->m_pStream;
+}
+
+void Writer::SetStream(SvStream *const pStream)
+{ m_pImpl->m_pStream = pStream; }
+
+
+SvStream& Writer::OutHex( SvStream& rStrm, ULONG nHex, BYTE nLen )
+{ // in einen Stream aus
+ // Pointer an das Bufferende setzen
+ sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
+ for( BYTE n = 0; n < nLen; ++n )
+ {
+ *(--pStr) = (sal_Char)(nHex & 0xf ) + 48;
+ if( *pStr > '9' )
+ *pStr += 39;
+ nHex >>= 4;
+ }
+ return rStrm << pStr;
+}
+
+SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
+{
+ // Pointer an das Bufferende setzen
+ sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
+
+ int bNeg = nVal < 0;
+ if( bNeg )
+ nVal = -nVal;
+
+ do {
+ *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
+ nVal /= 10;
+ } while( nVal );
+
+ // Ist Zahl negativ, dann noch -
+ if( bNeg )
+ *(--pStr) = '-';
+
+ return rStrm << pStr;
+}
+
+SvStream& Writer::OutULong( SvStream& rStrm, ULONG nVal )
+{
+ // Pointer an das Bufferende setzen
+ sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
+
+ do {
+ *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
+ nVal /= 10;
+ } while ( nVal );
+ return rStrm << pStr;
+}
+
+
+ULONG Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName )
+{
+ if ( IsStgWriter() )
+ {
+ SotStorageRef aRef = new SotStorage( rStrm );
+ ULONG nResult = Write( rPaM, *aRef, pFName );
+ if ( nResult == ERRCODE_NONE )
+ aRef->Commit();
+ return nResult;
+ }
+
+ pDoc = rPaM.GetDoc();
+ pOrigFileName = pFName;
+ m_pImpl->m_pStream = &rStrm;
+
+ // PaM kopieren, damit er veraendert werden kann
+ pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
+ // zum Vergleich auf den akt. Pam sichern
+ pOrigPam = &rPaM;
+
+ ULONG nRet = WriteStream();
+
+ ResetWriter();
+
+ return nRet;
+}
+
+ULONG Writer::Write( SwPaM& rPam, SfxMedium& rMed, const String* pFileName )
+{
+ // This method must be overloaded in SwXMLWriter a storage from medium will be used there.
+ // The microsoft format can write to storage but the storage will be based on the stream.
+ return Write( rPam, *rMed.GetOutStream(), pFileName );
+}
+
+ULONG Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
+{
+ ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
+ return ERR_SWG_WRITE_ERROR;
+}
+
+ULONG Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
+{
+ ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
+ return ERR_SWG_WRITE_ERROR;
+}
+
+BOOL Writer::CopyLocalFileToINet( String& rFileNm )
+{
+ if( !pOrigFileName ) // can be happen, by example if we
+ return FALSE; // write into the clipboard
+
+ BOOL bRet = FALSE;
+ INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
+
+// JP 01.11.00: what is the correct question for the portal??
+// if( aFileUrl.GetProtocol() == aFileUrl.GetProtocol() )
+// return bRet;
+// this is our old without the Mail-Export
+ if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
+ INET_PROT_FILE != aTargetUrl.GetProtocol() &&
+ INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
+ INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
+ return bRet;
+
+ if (m_pImpl->pSrcArr)
+ {
+ // wurde die Datei schon verschoben
+ USHORT nPos;
+ if (m_pImpl->pSrcArr->Seek_Entry( &rFileNm, &nPos ))
+ {
+ rFileNm = *(*m_pImpl->pDestArr)[ nPos ];
+ return TRUE;
+ }
+ }
+ else
+ {
+ m_pImpl->pSrcArr = new SvStringsSortDtor( 4, 4 );
+ m_pImpl->pDestArr = new SvStringsSortDtor( 4, 4 );
+ }
+
+ String *pSrc = new String( rFileNm );
+ String *pDest = new String( aTargetUrl.GetPartBeforeLastName() );
+ *pDest += String(aFileUrl.GetName());
+
+ SfxMedium aSrcFile( *pSrc, STREAM_READ, FALSE );
+ SfxMedium aDstFile( *pDest, STREAM_WRITE | STREAM_SHARE_DENYNONE, FALSE );
+
+ *aDstFile.GetOutStream() << *aSrcFile.GetInStream();
+
+ aSrcFile.Close();
+ aDstFile.Commit();
+
+ bRet = 0 == aDstFile.GetError();
+
+ if( bRet )
+ {
+ m_pImpl->pSrcArr->Insert( pSrc );
+ m_pImpl->pDestArr->Insert( pDest );
+ rFileNm = *pDest;
+ }
+ else
+ {
+ delete pSrc;
+ delete pDest;
+ }
+
+ return bRet;
+}
+
+void Writer::PutNumFmtFontsInAttrPool()
+{
+ // dann gibt es noch in den NumRules ein paar Fonts
+ // Diese in den Pool putten. Haben sie danach einen RefCount > 1
+ // kann es wieder entfernt werden - ist schon im Pool
+ SfxItemPool& rPool = pDoc->GetAttrPool();
+ const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
+ const SwNumRule* pRule;
+ const SwNumFmt* pFmt;
+ // --> OD 2006-06-27 #b644095#
+// const Font *pFont, *pDefFont = &SwNumRule::GetDefBulletFont();
+ const Font* pFont;
+ const Font* pDefFont = &numfunc::GetDefBulletFont();
+ // <--
+ BOOL bCheck = FALSE;
+
+ for( USHORT nGet = rListTbl.Count(); nGet; )
+ if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
+ for( BYTE nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
+ if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
+ SVX_NUM_BITMAP == pFmt->GetNumberingType() )
+ {
+ if( 0 == ( pFont = pFmt->GetBulletFont() ) )
+ pFont = pDefFont;
+
+ if( bCheck )
+ {
+ if( *pFont == *pDefFont )
+ continue;
+ }
+ else if( *pFont == *pDefFont )
+ bCheck = TRUE;
+
+ _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
+ pFont->GetName(), pFont->GetStyleName(),
+ pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
+ }
+}
+
+void Writer::PutEditEngFontsInAttrPool( BOOL bIncl_CJK_CTL )
+{
+ SfxItemPool& rPool = pDoc->GetAttrPool();
+ if( rPool.GetSecondaryPool() )
+ {
+ _AddFontItems( rPool, EE_CHAR_FONTINFO );
+ if( bIncl_CJK_CTL )
+ {
+ _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
+ _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
+ }
+ }
+}
+
+void Writer::PutCJKandCTLFontsInAttrPool()
+{
+ SfxItemPool& rPool = pDoc->GetAttrPool();
+ _AddFontItems( rPool, RES_CHRATR_CJK_FONT );
+ _AddFontItems( rPool, RES_CHRATR_CTL_FONT );
+}
+
+
+void Writer::_AddFontItems( SfxItemPool& rPool, USHORT nW )
+{
+ const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
+ _AddFontItem( rPool, *pFont );
+
+ if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
+ _AddFontItem( rPool, *pFont );
+
+ USHORT nMaxItem = rPool.GetItemCount( nW );
+ for( USHORT nGet = 0; nGet < nMaxItem; ++nGet )
+ if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem( nW, nGet )) )
+ _AddFontItem( rPool, *pFont );
+}
+
+void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
+{
+ const SvxFontItem* pItem;
+ if( RES_CHRATR_FONT != rFont.Which() )
+ {
+ SvxFontItem aFont( rFont );
+ aFont.SetWhich( RES_CHRATR_FONT );
+ pItem = (SvxFontItem*)&rPool.Put( aFont );
+ }
+ else
+ pItem = (SvxFontItem*)&rPool.Put( rFont );
+
+ if( 1 < pItem->GetRefCount() )
+ rPool.Remove( *pItem );
+ else
+ {
+ if (!m_pImpl->pFontRemoveLst)
+ {
+ m_pImpl->pFontRemoveLst = new SvPtrarr( 0, 10 );
+ }
+
+ void* p = (void*)pItem;
+ m_pImpl->pFontRemoveLst->Insert( p, m_pImpl->pFontRemoveLst->Count() );
+ }
+}
+
+// build a bookmark table, which is sort by the node position. The
+// OtherPos of the bookmarks also inserted.
+void Writer::CreateBookmarkTbl()
+{
+ const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
+ for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
+ ppBkmk != pMarkAccess->getBookmarksEnd();
+ ++ppBkmk)
+ {
+ m_pImpl->InsertBkmk(**ppBkmk);
+ }
+}
+
+
+// search alle Bookmarks in the range and return it in the Array
+USHORT Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
+ xub_StrLen nEnd, SvPtrarr& rArr)
+{
+ ASSERT( !rArr.Count(), "es sind noch Eintraege vorhanden" );
+
+ ULONG nNd = rNd.GetIndex();
+ SvPtrarr* pArr = (m_pImpl->pBkmkNodePos) ?
+ m_pImpl->pBkmkNodePos->Get( nNd ) : 0;
+ if( pArr )
+ {
+ // there exist some bookmarks, search now all which is in the range
+ if( !nStt && nEnd == rNd.Len() )
+ // all
+ rArr.Insert( pArr, 0 );
+ else
+ {
+ USHORT n;
+ xub_StrLen nCntnt;
+ for( n = 0; n < pArr->Count(); ++n )
+ {
+ void* p = (*pArr)[ n ];
+ const ::sw::mark::IMark& rBkmk = *(::sw::mark::IMark *)p;
+ if( rBkmk.GetMarkPos().nNode == nNd &&
+ (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
+ nCntnt < nEnd )
+ {
+ rArr.Insert( p, rArr.Count() );
+ }
+ else if( rBkmk.IsExpanded() && nNd ==
+ rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
+ rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
+ nCntnt < nEnd )
+ {
+ rArr.Insert( p, rArr.Count() );
+ }
+ }
+ }
+ }
+ return rArr.Count();
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+// Storage-spezifisches
+
+ULONG StgWriter::WriteStream()
+{
+ ASSERT( !this, "Schreiben in Streams auf einem Storage?" );
+ return ERR_SWG_WRITE_ERROR;
+}
+
+ULONG StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
+{
+ SetStream(0);
+ pStg = &rStg;
+ pDoc = rPaM.GetDoc();
+ pOrigFileName = pFName;
+
+ // PaM kopieren, damit er veraendert werden kann
+ pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
+ // zum Vergleich auf den akt. Pam sichern
+ pOrigPam = &rPaM;
+
+ ULONG nRet = WriteStorage();
+
+ pStg = NULL;
+ ResetWriter();
+
+ return nRet;
+}
+
+ULONG StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
+{
+ SetStream(0);
+ pStg = 0;
+ xStg = rStg;
+ pDoc = rPaM.GetDoc();
+ pOrigFileName = pFName;
+
+ // PaM kopieren, damit er veraendert werden kann
+ pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
+ // zum Vergleich auf den akt. Pam sichern
+ pOrigPam = &rPaM;
+
+ ULONG nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
+
+ pStg = NULL;
+ ResetWriter();
+
+ return nRet;
+}
+