| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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( sal_uInt16 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; |
| |
| sal_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 = sal_True; |
| bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR = |
| bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock = |
| bOrganizerMode = sal_False; |
| } |
| |
| sal_Bool Writer::CopyNextPam( SwPaM ** ppPam ) |
| { |
| if( (*ppPam)->GetNext() == pOrigPam ) |
| { |
| *ppPam = pOrigPam; // wieder auf den Anfangs-Pam setzen |
| return sal_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 sal_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->getAllMarksBegin(), |
| pMarkAccess->getAllMarksEnd(), |
| rPos, |
| ::boost::bind(&::sw::mark::IMark::StartsBefore, _1, _2)); // find the first Mark that does not start before |
| if(ppBkmk != pMarkAccess->getAllMarksEnd()) |
| return ppBkmk - pMarkAccess->getAllMarksBegin(); |
| return -1; |
| } |
| |
| |
| SwPaM * |
| Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx) |
| { |
| SwNodes *const pNds = &rDoc.GetNodes(); |
| |
| 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, sal_uLong nHex, sal_uInt8 nLen ) |
| { // in einen Stream aus |
| // Pointer an das Bufferende setzen |
| sal_Char* pStr = aNToABuf + (NTOABUFLEN-1); |
| for( sal_uInt8 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, sal_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; |
| } |
| |
| |
| sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName ) |
| { |
| if ( IsStgWriter() ) |
| { |
| SotStorageRef aRef = new SotStorage( rStrm ); |
| sal_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; |
| |
| sal_uLong nRet = WriteStream(); |
| |
| ResetWriter(); |
| |
| return nRet; |
| } |
| |
| sal_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 ); |
| } |
| |
| sal_uLong Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* ) |
| { |
| ASSERT( !this, "Schreiben in Storages auf einem Stream?" ); |
| return ERR_SWG_WRITE_ERROR; |
| } |
| |
| sal_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; |
| } |
| |
| sal_Bool Writer::CopyLocalFileToINet( String& rFileNm ) |
| { |
| if( !pOrigFileName ) // can be happen, by example if we |
| return sal_False; // write into the clipboard |
| |
| sal_Bool bRet = sal_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 |
| sal_uInt16 nPos; |
| if (m_pImpl->pSrcArr->Seek_Entry( &rFileNm, &nPos )) |
| { |
| rFileNm = *(*m_pImpl->pDestArr)[ nPos ]; |
| return sal_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, sal_False ); |
| SfxMedium aDstFile( *pDest, STREAM_WRITE | STREAM_SHARE_DENYNONE, sal_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(); |
| // <-- |
| sal_Bool bCheck = sal_False; |
| |
| for( sal_uInt16 nGet = rListTbl.Count(); nGet; ) |
| if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] ))) |
| for( sal_uInt8 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 = sal_True; |
| |
| _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(), |
| pFont->GetName(), pFont->GetStyleName(), |
| pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT )); |
| } |
| } |
| |
| void Writer::PutEditEngFontsInAttrPool( sal_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, sal_uInt16 nW ) |
| { |
| const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW ); |
| _AddFontItem( rPool, *pFont ); |
| |
| if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) ) |
| _AddFontItem( rPool, *pFont ); |
| |
| sal_uInt32 nMaxItem = rPool.GetItemCount2( nW ); |
| for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet ) |
| if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem2( 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 |
| sal_uInt16 Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt, |
| xub_StrLen nEnd, SvPtrarr& rArr) |
| { |
| ASSERT( !rArr.Count(), "es sind noch Eintraege vorhanden" ); |
| |
| sal_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 |
| { |
| sal_uInt16 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 |
| |
| sal_uLong StgWriter::WriteStream() |
| { |
| ASSERT( !this, "Schreiben in Streams auf einem Storage?" ); |
| return ERR_SWG_WRITE_ERROR; |
| } |
| |
| sal_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; |
| |
| sal_uLong nRet = WriteStorage(); |
| |
| pStg = NULL; |
| ResetWriter(); |
| |
| return nRet; |
| } |
| |
| sal_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; |
| |
| sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage(); |
| |
| pStg = NULL; |
| ResetWriter(); |
| |
| return nRet; |
| } |
| |