/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
// This class holds the dir entry data and maintains dirty flags for both // the entry and the data.
// Transacted mode for streams: On the first write, a temp stream pTmpStrm // is created and operated on. A commit moves pTmpStrm to pCurStrm, which // is used for subsequent reads. A new write creates a new copy of pTmpStrm // based on pCurStrm. Reverting throws away pTmpStrm. // Transacted mode for storages: A copy of the dir ents is kept in aSave. // Committing means copying aEntry to aSave. Reverting means to copy aSave // to aEntry, delete newly created entries and to reactivate removed entries.
// Problem of implementation: No hierarchical commits. Therefore only // overall transaction-oriented or direct.
// Enumerate the entry numbers. // n is incremented to show the total # of entries. // These number are later used as page numbers when storing // the TOC tree into the TOC stream. Remember that aSave is // stored, not aEntry.
void StgDirEntry::OpenStream( StgIo& rIo )
{
sal_Int32 nThreshold = static_cast<sal_uInt16>(rIo.m_aHdr.GetThreshold()); delete m_pStgStrm; if( m_aEntry.GetSize() < nThreshold )
m_pStgStrm = new StgSmallStrm( rIo, *this ); else
m_pStgStrm = new StgDataStrm( rIo, *this ); if( m_bInvalid && m_aEntry.GetSize() )
{ // This entry has invalid data, so delete that data
SetSize( 0 ); // bRemoved = bInvalid = false;
}
m_nPos = 0;
}
// Close the open stream without committing. If the entry is marked as // temporary, delete it. // Do not delete pCurStrm here! // (TLX:??? At least pStgStrm must be deleted.)
// Was this stream committed internally and reopened in direct mode? if( m_bDirect && ( m_pCurStrm || m_pTmpStrm ) && !Tmp2Strm() ) return 0; // Is this stream opened in transacted mode? Do we have to make a copy? if( !m_bDirect && !m_pTmpStrm && !Strm2Tmp() ) return 0;
OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" ); if ( !m_pStgStrm ) return 0;
// Copy the temp stream to the stg stream during the final commit
bool StgDirEntry::Tmp2Strm()
{ // We did commit once, but have not written since then if( !m_pTmpStrm )
{
m_pTmpStrm = m_pCurStrm;
m_pCurStrm = nullptr;
} if( m_pTmpStrm )
{
OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" ); if ( !m_pStgStrm ) returnfalse;
sal_uInt64 n = m_pTmpStrm->GetSize();
std::unique_ptr<StgStrm> pNewStrm;
StgIo& rIo = m_pStgStrm->GetIo();
sal_uInt64 nThreshold = rIo.m_aHdr.GetThreshold(); if( n < nThreshold )
pNewStrm.reset(new StgSmallStrm( rIo, STG_EOF )); else
pNewStrm.reset(new StgDataStrm( rIo, STG_EOF )); if( pNewStrm->SetSize( n ) )
{
sal_uInt8 p[ 4096 ];
m_pTmpStrm->Seek( 0 ); while( n )
{
sal_uInt64 nn = n; if( nn > 4096 )
nn = 4096; if (m_pTmpStrm->ReadBytes( p, nn ) != nn) break; if( static_cast<sal_uInt64>(pNewStrm->Write( p, nn )) != nn ) break;
n -= nn;
} if( n )
{
m_pTmpStrm->Seek( m_nPos );
m_pStgStrm->GetIo().SetError( m_pTmpStrm->GetError() ); returnfalse;
} else
{
m_pStgStrm->SetSize( 0 ); delete m_pStgStrm;
m_pStgStrm = pNewStrm.release();
m_pStgStrm->SetEntry(*this);
m_pStgStrm->Pos2Page(m_nPos); delete m_pTmpStrm; delete m_pCurStrm;
m_pTmpStrm = m_pCurStrm = nullptr;
m_aSave = m_aEntry;
}
}
} returntrue;
}
// Invalidate all open entries by setting the RefCount to 0. If the bDel // flag is set, also set the invalid flag to indicate deletion during the // next dir stream flush.
//fdo#41642
StgDirEntry *pUp = pUpper; while (pUp)
{ if (pUp->m_aEntry.GetLeaf(STG_CHILD) == nLeaf)
{
SAL_WARN("sot", "Leaf node of upper StgDirEntry is same as current StgDirEntry's leaf node. Circular entry chain, discarding link"); return;
}
pUp = pUp->m_pUp;
}
if( StgAvlNode::Insert
( reinterpret_cast<StgAvlNode**>( pUpper ? &pUpper->m_pDown : &m_pRoot ), pCur.get() ) )
{
pCur->m_pUp = pUpper;
} else
{ // bnc#682484: There are some really broken docs out there // that contain duplicate entries in 'Directory' section // so don't set the error flag here and just skip those // (was: rIo.SetError( SVSTREAM_CANNOT_MAKE );) return;
}
SetupEntry( nLeft, pUpper );
SetupEntry( nRight, pUpper );
SetupEntry( nLeaf, pCur.release() );
}
// Extend or shrink the directory stream.
bool StgDirStrm::SetSize( sal_Int32 nBytes )
{ // Always allocate full pages if ( nBytes < 0 )
nBytes = 0;
// Save the TOC stream into a new substream after saving all data streams
bool StgDirStrm::Store()
{ if( !m_pRoot || !m_pRoot->IsDirty() ) returntrue; if( !m_pRoot->StoreStreams( m_rIo ) ) returnfalse; // After writing all streams, the data FAT stream has changed, // so we have to commit the root again
m_pRoot->Commit(); // We want a completely new stream, so fake an empty stream
sal_Int32 nOldStart = m_nStart; // save for later deletion
sal_Int32 nOldSize = m_nSize;
m_nStart = m_nPage = STG_EOF;
m_nSize = 0;
SetPos(0, true);
m_nOffset = 0; // Delete all temporary entries
m_pRoot->DelTemp( false ); // set the entry numbers
sal_Int32 n = 0;
m_pRoot->Enum( n ); if( !SetSize( n * STGENTRY_SIZE ) )
{
m_nStart = nOldStart; m_nSize = nOldSize;
m_pRoot->RevertAll(); returnfalse;
} // set up the cache elements for the new stream if( !Copy( STG_FREE, m_nSize ) )
{
m_pRoot->RevertAll(); returnfalse;
} // Write the data to the new stream if( !m_pRoot->Store( *this ) )
{
m_pRoot->RevertAll(); returnfalse;
} // fill any remaining entries with empty data
sal_Int32 ne = m_nSize / STGENTRY_SIZE;
StgEntry aEmpty;
aEmpty.Init(); while( n < ne )
{ void* p = GetEntry( n++, true ); if( !p )
{
m_pRoot->RevertAll(); returnfalse;
}
aEmpty.Store( p );
} // Now we can release the old stream
m_pFat->FreePages( nOldStart, true );
m_rIo.m_aHdr.SetTOCStart( m_nStart ); returntrue;
}
// Get a dir entry.
void* StgDirStrm::GetEntry( sal_Int32 n, bool bDirty )
{ return n < 0 || n >= m_nSize / STGENTRY_SIZE
? nullptr : GetPtr( n * STGENTRY_SIZE, bDirty );
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.