1046d9d1fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3046d9d1fSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4046d9d1fSAndrew Rist * or more contributor license agreements. See the NOTICE file
5046d9d1fSAndrew Rist * distributed with this work for additional information
6046d9d1fSAndrew Rist * regarding copyright ownership. The ASF licenses this file
7046d9d1fSAndrew Rist * to you under the Apache License, Version 2.0 (the
8046d9d1fSAndrew Rist * "License"); you may not use this file except in compliance
9046d9d1fSAndrew Rist * with the License. You may obtain a copy of the License at
10046d9d1fSAndrew Rist *
11046d9d1fSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12046d9d1fSAndrew Rist *
13046d9d1fSAndrew Rist * Unless required by applicable law or agreed to in writing,
14046d9d1fSAndrew Rist * software distributed under the License is distributed on an
15046d9d1fSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16046d9d1fSAndrew Rist * KIND, either express or implied. See the License for the
17046d9d1fSAndrew Rist * specific language governing permissions and limitations
18046d9d1fSAndrew Rist * under the License.
19046d9d1fSAndrew Rist *
20046d9d1fSAndrew Rist *************************************************************/
21046d9d1fSAndrew Rist
22046d9d1fSAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sot.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir #include <string.h> // memcpy()
28cdf0e10cSrcweir
29cdf0e10cSrcweir #include <osl/file.hxx>
30cdf0e10cSrcweir #include <tools/tempfile.hxx>
31cdf0e10cSrcweir #include <tools/debug.hxx>
32*92160db5SArmin Le Grand #include <set>
33cdf0e10cSrcweir
34cdf0e10cSrcweir #include "sot/stg.hxx"
35cdf0e10cSrcweir #include "stgelem.hxx"
36cdf0e10cSrcweir #include "stgcache.hxx"
37cdf0e10cSrcweir #include "stgstrms.hxx"
38cdf0e10cSrcweir #include "stgdir.hxx"
39cdf0e10cSrcweir #include "stgio.hxx"
40cdf0e10cSrcweir
41cdf0e10cSrcweir #define __HUGE
42cdf0e10cSrcweir
43cdf0e10cSrcweir ///////////////////////////// class StgFAT ///////////////////////////////
44cdf0e10cSrcweir
45cdf0e10cSrcweir // The FAT class performs FAT operations on an underlying storage stream.
46cdf0e10cSrcweir // This stream is either the master FAT stream (m == sal_True ) or a normal
47cdf0e10cSrcweir // storage stream, which then holds the FAT for small data allocations.
48cdf0e10cSrcweir
StgFAT(StgStrm & r,sal_Bool m)49cdf0e10cSrcweir StgFAT::StgFAT( StgStrm& r, sal_Bool m ) : rStrm( r )
50cdf0e10cSrcweir {
51cdf0e10cSrcweir bPhys = m;
52cdf0e10cSrcweir nPageSize = rStrm.GetIo().GetPhysPageSize();
53cdf0e10cSrcweir nEntries = nPageSize >> 2;
54cdf0e10cSrcweir nOffset = 0;
55cdf0e10cSrcweir nMaxPage = 0;
56cdf0e10cSrcweir nLimit = 0;
57cdf0e10cSrcweir }
58cdf0e10cSrcweir
59cdf0e10cSrcweir // Retrieve the physical page for a given byte offset.
60cdf0e10cSrcweir
GetPhysPage(sal_Int32 nByteOff)61cdf0e10cSrcweir StgPage* StgFAT::GetPhysPage( sal_Int32 nByteOff )
62cdf0e10cSrcweir {
63cdf0e10cSrcweir StgPage* pPg = NULL;
64cdf0e10cSrcweir // Position within the underlying stream
65cdf0e10cSrcweir // use the Pos2Page() method of the stream
66cdf0e10cSrcweir if( rStrm.Pos2Page( nByteOff ) )
67cdf0e10cSrcweir {
68cdf0e10cSrcweir nOffset = rStrm.GetOffset();
69cdf0e10cSrcweir sal_Int32 nPhysPage = rStrm.GetPage();
70cdf0e10cSrcweir // get the physical page (must be present)
71cdf0e10cSrcweir pPg = rStrm.GetIo().Get( nPhysPage, sal_True );
72cdf0e10cSrcweir }
73cdf0e10cSrcweir return pPg;
74cdf0e10cSrcweir }
75cdf0e10cSrcweir
76cdf0e10cSrcweir // Get the follow page for a certain FAT page.
77cdf0e10cSrcweir
GetNextPage(sal_Int32 nPg)78cdf0e10cSrcweir sal_Int32 StgFAT::GetNextPage( sal_Int32 nPg )
79cdf0e10cSrcweir {
80cdf0e10cSrcweir if( nPg >= 0 )
81cdf0e10cSrcweir {
82297a844aSArmin Le Grand StgPage* pPg = GetPhysPage( nPg << 2 );
83cdf0e10cSrcweir nPg = pPg ? pPg->GetPage( nOffset >> 2 ) : STG_EOF;
84cdf0e10cSrcweir }
85cdf0e10cSrcweir return nPg;
86cdf0e10cSrcweir }
87cdf0e10cSrcweir
88cdf0e10cSrcweir // Find the best fit block for the given size. Return
89cdf0e10cSrcweir // the starting block and its size or STG_EOF and 0.
90cdf0e10cSrcweir // nLastPage is a stopper which tells the current
91cdf0e10cSrcweir // underlying stream size. It is treated as a recommendation
92cdf0e10cSrcweir // to abort the search to inhibit excessive file growth.
93cdf0e10cSrcweir
FindBlock(sal_Int32 & nPgs)94cdf0e10cSrcweir sal_Int32 StgFAT::FindBlock( sal_Int32& nPgs )
95cdf0e10cSrcweir {
96cdf0e10cSrcweir sal_Int32 nMinStart = STG_EOF, nMinLen = 0;
97cdf0e10cSrcweir sal_Int32 nMaxStart = STG_EOF, nMaxLen = 0x7FFFFFFFL;
98cdf0e10cSrcweir sal_Int32 nTmpStart = STG_EOF, nTmpLen = 0;
99cdf0e10cSrcweir sal_Int32 nPages = rStrm.GetSize() >> 2;
100cdf0e10cSrcweir sal_Bool bFound = sal_False;
101cdf0e10cSrcweir StgPage* pPg = NULL;
102cdf0e10cSrcweir short nEntry = 0;
103cdf0e10cSrcweir for( sal_Int32 i = 0; i < nPages; i++, nEntry++ )
104cdf0e10cSrcweir {
105cdf0e10cSrcweir if( !( nEntry % nEntries ) )
106cdf0e10cSrcweir {
107cdf0e10cSrcweir // load the next page for that stream
108cdf0e10cSrcweir nEntry = 0;
109cdf0e10cSrcweir pPg = GetPhysPage( i << 2 );
110cdf0e10cSrcweir if( !pPg )
111cdf0e10cSrcweir return STG_EOF;
112cdf0e10cSrcweir }
113cdf0e10cSrcweir sal_Int32 nCur = pPg->GetPage( nEntry );
114cdf0e10cSrcweir if( nCur == STG_FREE )
115cdf0e10cSrcweir {
116cdf0e10cSrcweir // count the size of this area
117cdf0e10cSrcweir if( nTmpLen )
118cdf0e10cSrcweir nTmpLen++;
119cdf0e10cSrcweir else
120cdf0e10cSrcweir nTmpStart = i,
121cdf0e10cSrcweir nTmpLen = 1;
122cdf0e10cSrcweir if( nTmpLen == nPgs
123cdf0e10cSrcweir // If we already did find a block, stop when reaching the limit
124cdf0e10cSrcweir || ( bFound && ( nEntry >= nLimit ) ) )
125cdf0e10cSrcweir break;
126cdf0e10cSrcweir }
127cdf0e10cSrcweir else if( nTmpLen )
128cdf0e10cSrcweir {
129cdf0e10cSrcweir if( nTmpLen > nPgs && nTmpLen < nMaxLen )
130cdf0e10cSrcweir // block > requested size
131cdf0e10cSrcweir nMaxLen = nTmpLen, nMaxStart = nTmpStart, bFound = sal_True;
132cdf0e10cSrcweir else if( nTmpLen >= nMinLen )
133cdf0e10cSrcweir {
134cdf0e10cSrcweir // block < requested size
135cdf0e10cSrcweir nMinLen = nTmpLen, nMinStart = nTmpStart;
136cdf0e10cSrcweir bFound = sal_True;
137cdf0e10cSrcweir if( nTmpLen == nPgs )
138cdf0e10cSrcweir break;
139cdf0e10cSrcweir }
140cdf0e10cSrcweir nTmpStart = STG_EOF;
141cdf0e10cSrcweir nTmpLen = 0;
142cdf0e10cSrcweir }
143cdf0e10cSrcweir }
144cdf0e10cSrcweir // Determine which block to use.
145cdf0e10cSrcweir if( nTmpLen )
146cdf0e10cSrcweir {
147cdf0e10cSrcweir if( nTmpLen > nPgs && nTmpLen < nMaxLen )
148cdf0e10cSrcweir // block > requested size
149cdf0e10cSrcweir nMaxLen = nTmpLen, nMaxStart = nTmpStart;
150cdf0e10cSrcweir else if( nTmpLen >= nMinLen )
151cdf0e10cSrcweir // block < requested size
152cdf0e10cSrcweir nMinLen = nTmpLen, nMinStart = nTmpStart;
153cdf0e10cSrcweir }
154cdf0e10cSrcweir if( nMinStart != STG_EOF && nMaxStart != STG_EOF )
155cdf0e10cSrcweir {
156cdf0e10cSrcweir // two areas found; return the best fit area
157cdf0e10cSrcweir sal_Int32 nMinDiff = nPgs - nMinLen;
158cdf0e10cSrcweir sal_Int32 nMaxDiff = nMaxLen - nPgs;
159cdf0e10cSrcweir if( nMinDiff > nMaxDiff )
160cdf0e10cSrcweir nMinStart = STG_EOF;
161cdf0e10cSrcweir }
162cdf0e10cSrcweir if( nMinStart != STG_EOF )
163cdf0e10cSrcweir {
164cdf0e10cSrcweir nPgs = nMinLen; return nMinStart;
165cdf0e10cSrcweir }
166cdf0e10cSrcweir else
167cdf0e10cSrcweir {
168cdf0e10cSrcweir return nMaxStart;
169cdf0e10cSrcweir }
170cdf0e10cSrcweir }
171cdf0e10cSrcweir
172cdf0e10cSrcweir // Set up the consecutive chain for a given block.
173cdf0e10cSrcweir
MakeChain(sal_Int32 nStart,sal_Int32 nPgs)174cdf0e10cSrcweir sal_Bool StgFAT::MakeChain( sal_Int32 nStart, sal_Int32 nPgs )
175cdf0e10cSrcweir {
176cdf0e10cSrcweir sal_Int32 nPos = nStart << 2;
177cdf0e10cSrcweir StgPage* pPg = GetPhysPage( nPos );
178cdf0e10cSrcweir if( !pPg || !nPgs )
179cdf0e10cSrcweir return sal_False;
180cdf0e10cSrcweir while( --nPgs )
181cdf0e10cSrcweir {
182cdf0e10cSrcweir if( nOffset >= nPageSize )
183cdf0e10cSrcweir {
184cdf0e10cSrcweir pPg = GetPhysPage( nPos );
185cdf0e10cSrcweir if( !pPg )
186cdf0e10cSrcweir return sal_False;
187cdf0e10cSrcweir }
188cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, ++nStart );
189cdf0e10cSrcweir nOffset += 4;
190cdf0e10cSrcweir nPos += 4;
191cdf0e10cSrcweir }
192cdf0e10cSrcweir if( nOffset >= nPageSize )
193cdf0e10cSrcweir {
194cdf0e10cSrcweir pPg = GetPhysPage( nPos );
195cdf0e10cSrcweir if( !pPg )
196cdf0e10cSrcweir return sal_False;
197cdf0e10cSrcweir }
198cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, STG_EOF );
199cdf0e10cSrcweir return sal_True;
200cdf0e10cSrcweir }
201cdf0e10cSrcweir
202cdf0e10cSrcweir // Allocate a block of data from the given page number on.
203cdf0e10cSrcweir // It the page number is != STG_EOF, chain the block.
204cdf0e10cSrcweir
AllocPages(sal_Int32 nBgn,sal_Int32 nPgs)205cdf0e10cSrcweir sal_Int32 StgFAT::AllocPages( sal_Int32 nBgn, sal_Int32 nPgs )
206cdf0e10cSrcweir {
207cdf0e10cSrcweir sal_Int32 nOrig = nBgn;
208cdf0e10cSrcweir sal_Int32 nLast = nBgn;
209cdf0e10cSrcweir sal_Int32 nBegin = STG_EOF;
210cdf0e10cSrcweir sal_Int32 nAlloc;
211cdf0e10cSrcweir sal_Int32 nPages = rStrm.GetSize() >> 2;
212cdf0e10cSrcweir short nPasses = 0;
213cdf0e10cSrcweir // allow for two passes
214cdf0e10cSrcweir while( nPasses < 2 )
215cdf0e10cSrcweir {
216cdf0e10cSrcweir // try to satisfy the request from the pool of free pages
217cdf0e10cSrcweir while( nPgs )
218cdf0e10cSrcweir {
219cdf0e10cSrcweir nAlloc = nPgs;
220cdf0e10cSrcweir nBegin = FindBlock( nAlloc );
221cdf0e10cSrcweir // no more blocks left in present alloc chain
222cdf0e10cSrcweir if( nBegin == STG_EOF )
223cdf0e10cSrcweir break;
224cdf0e10cSrcweir if( ( nBegin + nAlloc ) > nMaxPage )
225cdf0e10cSrcweir nMaxPage = nBegin + nAlloc;
226cdf0e10cSrcweir if( !MakeChain( nBegin, nAlloc ) )
227cdf0e10cSrcweir return STG_EOF;
228cdf0e10cSrcweir if( nOrig == STG_EOF )
229cdf0e10cSrcweir nOrig = nBegin;
230cdf0e10cSrcweir else
231cdf0e10cSrcweir {
232cdf0e10cSrcweir // Patch the chain
233cdf0e10cSrcweir StgPage* pPg = GetPhysPage( nLast << 2 );
234cdf0e10cSrcweir if( !pPg )
235cdf0e10cSrcweir return STG_EOF;
236cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, nBegin );
237cdf0e10cSrcweir }
238cdf0e10cSrcweir nLast = nBegin + nAlloc - 1;
239cdf0e10cSrcweir nPgs -= nAlloc;
240cdf0e10cSrcweir }
241cdf0e10cSrcweir if( nPgs && !nPasses )
242cdf0e10cSrcweir {
243cdf0e10cSrcweir // we need new, fresh space, so allocate and retry
244cdf0e10cSrcweir if( !rStrm.SetSize( ( nPages + nPgs ) << 2 ) )
245cdf0e10cSrcweir return STG_EOF;
246cdf0e10cSrcweir if( !bPhys && !InitNew( nPages ) )
247cdf0e10cSrcweir return sal_False;
248cdf0e10cSrcweir nPages = rStrm.GetSize() >> 2;
249cdf0e10cSrcweir nPasses++;
250cdf0e10cSrcweir }
251cdf0e10cSrcweir else
252cdf0e10cSrcweir break;
253cdf0e10cSrcweir }
254cdf0e10cSrcweir // now we should have a chain for the complete block
255cdf0e10cSrcweir if( nBegin == STG_EOF || nPgs )
256cdf0e10cSrcweir {
257cdf0e10cSrcweir rStrm.GetIo().SetError( SVSTREAM_FILEFORMAT_ERROR );
258cdf0e10cSrcweir return STG_EOF; // bad structure
259cdf0e10cSrcweir }
260cdf0e10cSrcweir return nOrig;
261cdf0e10cSrcweir }
262cdf0e10cSrcweir
263cdf0e10cSrcweir // Initialize newly allocated pages for a standard FAT stream
264cdf0e10cSrcweir // It can be assumed that the stream size is always on
265cdf0e10cSrcweir // a page boundary
266cdf0e10cSrcweir
InitNew(sal_Int32 nPage1)267cdf0e10cSrcweir sal_Bool StgFAT::InitNew( sal_Int32 nPage1 )
268cdf0e10cSrcweir {
269cdf0e10cSrcweir sal_Int32 n = ( ( rStrm.GetSize() >> 2 ) - nPage1 ) / nEntries;
270297a844aSArmin Le Grand if ( n > 0 )
271cdf0e10cSrcweir {
272297a844aSArmin Le Grand while( n-- )
273297a844aSArmin Le Grand {
274297a844aSArmin Le Grand StgPage* pPg = NULL;
275297a844aSArmin Le Grand // Position within the underlying stream
276297a844aSArmin Le Grand // use the Pos2Page() method of the stream
277297a844aSArmin Le Grand rStrm.Pos2Page( nPage1 << 2 );
278297a844aSArmin Le Grand // Initialize the page
279297a844aSArmin Le Grand pPg = rStrm.GetIo().Copy( rStrm.GetPage(), STG_FREE );
280297a844aSArmin Le Grand if ( !pPg )
281297a844aSArmin Le Grand return sal_False;
282297a844aSArmin Le Grand for( short i = 0; i < nEntries; i++ )
283297a844aSArmin Le Grand pPg->SetPage( i, STG_FREE );
284297a844aSArmin Le Grand nPage1++;
285297a844aSArmin Le Grand }
286cdf0e10cSrcweir }
287cdf0e10cSrcweir return sal_True;
288cdf0e10cSrcweir }
289cdf0e10cSrcweir
290cdf0e10cSrcweir // Release a chain
291cdf0e10cSrcweir
FreePages(sal_Int32 nStart,sal_Bool bAll)292cdf0e10cSrcweir sal_Bool StgFAT::FreePages( sal_Int32 nStart, sal_Bool bAll )
293cdf0e10cSrcweir {
294cdf0e10cSrcweir while( nStart >= 0 )
295cdf0e10cSrcweir {
296cdf0e10cSrcweir StgPage* pPg = GetPhysPage( nStart << 2 );
297cdf0e10cSrcweir if( !pPg )
298cdf0e10cSrcweir return sal_False;
299cdf0e10cSrcweir nStart = pPg->GetPage( nOffset >> 2 );
300cdf0e10cSrcweir // The first released page is either set to EOF or FREE
301cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, bAll ? STG_FREE : STG_EOF );
302cdf0e10cSrcweir bAll = sal_True;
303cdf0e10cSrcweir }
304cdf0e10cSrcweir return sal_True;
305cdf0e10cSrcweir }
306cdf0e10cSrcweir
307cdf0e10cSrcweir ///////////////////////////// class StgStrm ////////////////////////////////
308cdf0e10cSrcweir
309cdf0e10cSrcweir // The base stream class provides basic functionality for seeking
310cdf0e10cSrcweir // and accessing the data on a physical basis. It uses the built-in
311cdf0e10cSrcweir // FAT class for the page allocations.
312cdf0e10cSrcweir
StgStrm(StgIo & r)313cdf0e10cSrcweir StgStrm::StgStrm( StgIo& r ) : rIo( r )
314cdf0e10cSrcweir {
315cdf0e10cSrcweir pFat = NULL;
316cdf0e10cSrcweir nStart = nPage = STG_EOF;
317cdf0e10cSrcweir nOffset = 0;
318cdf0e10cSrcweir pEntry = NULL;
319cdf0e10cSrcweir nPos = nSize = 0;
320cdf0e10cSrcweir nPageSize = rIo.GetPhysPageSize();
321cdf0e10cSrcweir }
322cdf0e10cSrcweir
~StgStrm()323cdf0e10cSrcweir StgStrm::~StgStrm()
324cdf0e10cSrcweir {
325cdf0e10cSrcweir delete pFat;
326cdf0e10cSrcweir }
327cdf0e10cSrcweir
328cdf0e10cSrcweir // Attach the stream to the given entry.
329cdf0e10cSrcweir
SetEntry(StgDirEntry & r)330cdf0e10cSrcweir void StgStrm::SetEntry( StgDirEntry& r )
331cdf0e10cSrcweir {
332cdf0e10cSrcweir r.aEntry.SetLeaf( STG_DATA, nStart );
333cdf0e10cSrcweir r.aEntry.SetSize( nSize );
334cdf0e10cSrcweir pEntry = &r;
335cdf0e10cSrcweir r.SetDirty();
336cdf0e10cSrcweir }
337cdf0e10cSrcweir
338cdf0e10cSrcweir // Compute page number and offset for the given byte position.
339cdf0e10cSrcweir // If the position is behind the size, set the stream right
340cdf0e10cSrcweir // behind the EOF.
341cdf0e10cSrcweir
Pos2Page(sal_Int32 nBytePos)342cdf0e10cSrcweir sal_Bool StgStrm::Pos2Page( sal_Int32 nBytePos )
343cdf0e10cSrcweir {
344297a844aSArmin Le Grand if ( !pFat )
345297a844aSArmin Le Grand return sal_False;
346297a844aSArmin Le Grand
347cdf0e10cSrcweir sal_Int32 nRel, nBgn;
348cdf0e10cSrcweir // Values < 0 seek to the end
349cdf0e10cSrcweir if( nBytePos < 0 || nBytePos >= nSize )
350cdf0e10cSrcweir nBytePos = nSize;
351cdf0e10cSrcweir // Adjust the position back to offset 0
352cdf0e10cSrcweir nPos -= nOffset;
353cdf0e10cSrcweir sal_Int32 nMask = ~( nPageSize - 1 );
354cdf0e10cSrcweir sal_Int32 nOld = nPos & nMask;
355cdf0e10cSrcweir sal_Int32 nNew = nBytePos & nMask;
356cdf0e10cSrcweir nOffset = (short) ( nBytePos & ~nMask );
357cdf0e10cSrcweir nPos = nBytePos;
358cdf0e10cSrcweir if( nOld == nNew )
359cdf0e10cSrcweir return sal_True;
360cdf0e10cSrcweir if( nNew > nOld )
361cdf0e10cSrcweir {
362cdf0e10cSrcweir // the new position is behind the current, so an incremental
363cdf0e10cSrcweir // positioning is OK. Set the page relative position
364cdf0e10cSrcweir nRel = nNew - nOld;
365cdf0e10cSrcweir nBgn = nPage;
366cdf0e10cSrcweir }
367cdf0e10cSrcweir else
368cdf0e10cSrcweir {
369cdf0e10cSrcweir // the new position is before the current, so we have to scan
370cdf0e10cSrcweir // the entire chain.
371cdf0e10cSrcweir nRel = nNew;
372cdf0e10cSrcweir nBgn = nStart;
373cdf0e10cSrcweir }
374cdf0e10cSrcweir // now, traverse the FAT chain.
375cdf0e10cSrcweir nRel /= nPageSize;
376cdf0e10cSrcweir sal_Int32 nLast = STG_EOF;
377cdf0e10cSrcweir while( nRel && nBgn >= 0 )
378cdf0e10cSrcweir {
379cdf0e10cSrcweir nLast = nBgn;
380cdf0e10cSrcweir nBgn = pFat->GetNextPage( nBgn );
381cdf0e10cSrcweir nRel--;
382cdf0e10cSrcweir }
383cdf0e10cSrcweir // special case: seek to 1st byte of new, unallocated page
384cdf0e10cSrcweir // (in case the file size is a multiple of the page size)
385cdf0e10cSrcweir if( nBytePos == nSize && nBgn == STG_EOF && !nRel && !nOffset )
386cdf0e10cSrcweir nBgn = nLast, nOffset = nPageSize;
387cdf0e10cSrcweir if( nBgn < 0 && nBgn != STG_EOF )
388cdf0e10cSrcweir {
389cdf0e10cSrcweir rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
390cdf0e10cSrcweir nBgn = STG_EOF;
391cdf0e10cSrcweir nOffset = nPageSize;
392cdf0e10cSrcweir }
393cdf0e10cSrcweir nPage = nBgn;
394cdf0e10cSrcweir return sal_Bool( nRel == 0 && nPage >= 0 );
395cdf0e10cSrcweir }
396cdf0e10cSrcweir
397cdf0e10cSrcweir // Retrieve the physical page for a given byte offset.
398cdf0e10cSrcweir
GetPhysPage(sal_Int32 nBytePos,sal_Bool bForce)399cdf0e10cSrcweir StgPage* StgStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
400cdf0e10cSrcweir {
401cdf0e10cSrcweir if( !Pos2Page( nBytePos ) )
402cdf0e10cSrcweir return NULL;
403cdf0e10cSrcweir return rIo.Get( nPage, bForce );
404cdf0e10cSrcweir }
405cdf0e10cSrcweir
406cdf0e10cSrcweir // Copy an entire stream. Both streams are allocated in the FAT.
407cdf0e10cSrcweir // The target stream is this stream.
408cdf0e10cSrcweir
Copy(sal_Int32 nFrom,sal_Int32 nBytes)409cdf0e10cSrcweir sal_Bool StgStrm::Copy( sal_Int32 nFrom, sal_Int32 nBytes )
410cdf0e10cSrcweir {
411297a844aSArmin Le Grand if ( !pFat )
412297a844aSArmin Le Grand return sal_False;
413297a844aSArmin Le Grand
414cdf0e10cSrcweir sal_Int32 nTo = nStart;
415cdf0e10cSrcweir sal_Int32 nPgs = ( nBytes + nPageSize - 1 ) / nPageSize;
416cdf0e10cSrcweir while( nPgs-- )
417cdf0e10cSrcweir {
418cdf0e10cSrcweir if( nTo < 0 )
419cdf0e10cSrcweir {
420cdf0e10cSrcweir rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
421cdf0e10cSrcweir return sal_False;
422cdf0e10cSrcweir }
423cdf0e10cSrcweir rIo.Copy( nTo, nFrom );
424cdf0e10cSrcweir if( nFrom >= 0 )
425cdf0e10cSrcweir {
426cdf0e10cSrcweir nFrom = pFat->GetNextPage( nFrom );
427cdf0e10cSrcweir if( nFrom < 0 )
428cdf0e10cSrcweir {
429cdf0e10cSrcweir rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
430cdf0e10cSrcweir return sal_False;
431cdf0e10cSrcweir }
432cdf0e10cSrcweir }
433cdf0e10cSrcweir nTo = pFat->GetNextPage( nTo );
434cdf0e10cSrcweir }
435cdf0e10cSrcweir return sal_True;
436cdf0e10cSrcweir }
437cdf0e10cSrcweir
SetSize(sal_Int32 nBytes)438cdf0e10cSrcweir sal_Bool StgStrm::SetSize( sal_Int32 nBytes )
439cdf0e10cSrcweir {
440297a844aSArmin Le Grand if ( nBytes < 0 || !pFat )
441297a844aSArmin Le Grand return sal_False;
442297a844aSArmin Le Grand
443cdf0e10cSrcweir // round up to page size
444cdf0e10cSrcweir sal_Int32 nOld = ( ( nSize + nPageSize - 1 ) / nPageSize ) * nPageSize;
445cdf0e10cSrcweir sal_Int32 nNew = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
446cdf0e10cSrcweir if( nNew > nOld )
447cdf0e10cSrcweir {
448cdf0e10cSrcweir if( !Pos2Page( nSize ) )
449cdf0e10cSrcweir return sal_False;
450cdf0e10cSrcweir sal_Int32 nBgn = pFat->AllocPages( nPage, ( nNew - nOld ) / nPageSize );
451cdf0e10cSrcweir if( nBgn == STG_EOF )
452cdf0e10cSrcweir return sal_False;
453cdf0e10cSrcweir if( nStart == STG_EOF )
454cdf0e10cSrcweir nStart = nPage = nBgn;
455cdf0e10cSrcweir }
456cdf0e10cSrcweir else if( nNew < nOld )
457cdf0e10cSrcweir {
458cdf0e10cSrcweir sal_Bool bAll = sal_Bool( nBytes == 0 );
459cdf0e10cSrcweir if( !Pos2Page( nBytes ) || !pFat->FreePages( nPage, bAll ) )
460cdf0e10cSrcweir return sal_False;
461cdf0e10cSrcweir if( bAll )
462cdf0e10cSrcweir nStart = nPage = STG_EOF;
463cdf0e10cSrcweir }
464cdf0e10cSrcweir if( pEntry )
465cdf0e10cSrcweir {
466cdf0e10cSrcweir // change the dir entry?
467cdf0e10cSrcweir if( !nSize || !nBytes )
468cdf0e10cSrcweir pEntry->aEntry.SetLeaf( STG_DATA, nStart );
469cdf0e10cSrcweir pEntry->aEntry.SetSize( nBytes );
470cdf0e10cSrcweir pEntry->SetDirty();
471cdf0e10cSrcweir }
472cdf0e10cSrcweir nSize = nBytes;
473cdf0e10cSrcweir pFat->SetLimit( GetPages() );
474cdf0e10cSrcweir return sal_True;
475cdf0e10cSrcweir }
476cdf0e10cSrcweir
477cdf0e10cSrcweir // Return the # of allocated pages
478cdf0e10cSrcweir
GetPages()479cdf0e10cSrcweir sal_Int32 StgStrm::GetPages()
480cdf0e10cSrcweir {
481cdf0e10cSrcweir return ( nSize + nPageSize - 1 ) / nPageSize;
482cdf0e10cSrcweir }
483cdf0e10cSrcweir
484cdf0e10cSrcweir //////////////////////////// class StgFATStrm //////////////////////////////
485cdf0e10cSrcweir
486cdf0e10cSrcweir // The FAT stream class provides physical access to the master FAT.
487cdf0e10cSrcweir // Since this access is implemented as a StgStrm, we can use the
488cdf0e10cSrcweir // FAT allocator.
489cdf0e10cSrcweir
StgFATStrm(StgIo & r)490cdf0e10cSrcweir StgFATStrm::StgFATStrm( StgIo& r ) : StgStrm( r )
491cdf0e10cSrcweir {
492cdf0e10cSrcweir pFat = new StgFAT( *this, sal_True );
493cdf0e10cSrcweir nSize = rIo.aHdr.GetFATSize() * nPageSize;
494cdf0e10cSrcweir }
495cdf0e10cSrcweir
Pos2Page(sal_Int32 nBytePos)496cdf0e10cSrcweir sal_Bool StgFATStrm::Pos2Page( sal_Int32 nBytePos )
497cdf0e10cSrcweir {
498cdf0e10cSrcweir // Values < 0 seek to the end
499cdf0e10cSrcweir if( nBytePos < 0 || nBytePos >= nSize )
500cdf0e10cSrcweir nBytePos = nSize ? nSize - 1 : 0;
501cdf0e10cSrcweir nPage = nBytePos / nPageSize;
502cdf0e10cSrcweir nOffset = (short) ( nBytePos % nPageSize );
503cdf0e10cSrcweir nPos = nBytePos;
504cdf0e10cSrcweir nPage = GetPage( (short) nPage, sal_False );
505cdf0e10cSrcweir return sal_Bool( nPage >= 0 );
506cdf0e10cSrcweir }
507cdf0e10cSrcweir
508cdf0e10cSrcweir // Retrieve the physical page for a given byte offset.
509cdf0e10cSrcweir // Since Pos2Page() already has computed the physical offset,
510cdf0e10cSrcweir // use the byte offset directly.
511cdf0e10cSrcweir
GetPhysPage(sal_Int32 nBytePos,sal_Bool bForce)512cdf0e10cSrcweir StgPage* StgFATStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
513cdf0e10cSrcweir {
514297a844aSArmin Le Grand OSL_ENSURE( nBytePos >= 0, "The value may not be negative!" );
515cdf0e10cSrcweir return rIo.Get( nBytePos / ( nPageSize >> 2 ), bForce );
516cdf0e10cSrcweir }
517cdf0e10cSrcweir
518cdf0e10cSrcweir // Get the page number entry for the given page offset.
519cdf0e10cSrcweir
GetPage(short nOff,sal_Bool bMake,sal_uInt16 * pnMasterAlloc)520cdf0e10cSrcweir sal_Int32 StgFATStrm::GetPage( short nOff, sal_Bool bMake, sal_uInt16 *pnMasterAlloc )
521cdf0e10cSrcweir {
522297a844aSArmin Le Grand OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
523cdf0e10cSrcweir if( pnMasterAlloc ) *pnMasterAlloc = 0;
524cdf0e10cSrcweir if( nOff < rIo.aHdr.GetFAT1Size() )
525cdf0e10cSrcweir return rIo.aHdr.GetFATPage( nOff );
526cdf0e10cSrcweir sal_Int32 nMaxPage = nSize >> 2;
527cdf0e10cSrcweir nOff = nOff - rIo.aHdr.GetFAT1Size();
528cdf0e10cSrcweir // Anzahl der Masterpages, durch die wir iterieren muessen
529cdf0e10cSrcweir sal_uInt16 nMasterCount = ( nPageSize >> 2 ) - 1;
530cdf0e10cSrcweir sal_uInt16 nBlocks = nOff / nMasterCount;
531cdf0e10cSrcweir // Offset in letzter Masterpage
532cdf0e10cSrcweir nOff = nOff % nMasterCount;
533cdf0e10cSrcweir
534cdf0e10cSrcweir StgPage* pOldPage = 0;
535cdf0e10cSrcweir StgPage* pMaster = 0;
536cdf0e10cSrcweir sal_Int32 nFAT = rIo.aHdr.GetFATChain();
537cdf0e10cSrcweir for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
538cdf0e10cSrcweir {
539cdf0e10cSrcweir if( nFAT == STG_EOF || nFAT == STG_FREE )
540cdf0e10cSrcweir {
541cdf0e10cSrcweir if( bMake )
542cdf0e10cSrcweir {
543cdf0e10cSrcweir // create a new master page
544cdf0e10cSrcweir nFAT = nMaxPage++;
545cdf0e10cSrcweir pMaster = rIo.Copy( nFAT, STG_FREE );
546cdf0e10cSrcweir if ( pMaster )
547cdf0e10cSrcweir {
548cdf0e10cSrcweir for( short k = 0; k < ( nPageSize >> 2 ); k++ )
549cdf0e10cSrcweir pMaster->SetPage( k, STG_FREE );
550cdf0e10cSrcweir // Verkettung herstellen
551cdf0e10cSrcweir if( !pOldPage )
552cdf0e10cSrcweir rIo.aHdr.SetFATChain( nFAT );
553cdf0e10cSrcweir else
554cdf0e10cSrcweir pOldPage->SetPage( nMasterCount, nFAT );
555cdf0e10cSrcweir if( nMaxPage >= rIo.GetPhysPages() )
556cdf0e10cSrcweir if( !rIo.SetSize( nMaxPage ) )
557cdf0e10cSrcweir return STG_EOF;
558cdf0e10cSrcweir // mark the page as used
559cdf0e10cSrcweir // Platz fuer Masterpage schaffen
560cdf0e10cSrcweir if( !pnMasterAlloc ) // Selbst Platz schaffen
561cdf0e10cSrcweir {
562cdf0e10cSrcweir if( !Pos2Page( nFAT << 2 ) )
563cdf0e10cSrcweir return STG_EOF;
564cdf0e10cSrcweir StgPage* pPg = rIo.Get( nPage, sal_True );
565cdf0e10cSrcweir if( !pPg )
566cdf0e10cSrcweir return STG_EOF;
567cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, STG_MASTER );
568cdf0e10cSrcweir }
569cdf0e10cSrcweir else
570cdf0e10cSrcweir (*pnMasterAlloc)++;
571cdf0e10cSrcweir rIo.aHdr.SetMasters( nCount + 1 );
572cdf0e10cSrcweir pOldPage = pMaster;
573cdf0e10cSrcweir }
574cdf0e10cSrcweir }
575cdf0e10cSrcweir }
576cdf0e10cSrcweir else
577cdf0e10cSrcweir {
578cdf0e10cSrcweir pMaster = rIo.Get( nFAT, sal_True );
579cdf0e10cSrcweir if ( pMaster )
580cdf0e10cSrcweir {
581cdf0e10cSrcweir nFAT = pMaster->GetPage( nMasterCount );
582cdf0e10cSrcweir pOldPage = pMaster;
583cdf0e10cSrcweir }
584cdf0e10cSrcweir }
585cdf0e10cSrcweir }
586cdf0e10cSrcweir if( pMaster )
587cdf0e10cSrcweir return pMaster->GetPage( nOff );
588cdf0e10cSrcweir rIo.SetError( SVSTREAM_GENERALERROR );
589cdf0e10cSrcweir return STG_EOF;
590cdf0e10cSrcweir }
591cdf0e10cSrcweir
592cdf0e10cSrcweir
593cdf0e10cSrcweir // Set the page number entry for the given page offset.
594cdf0e10cSrcweir
SetPage(short nOff,sal_Int32 nNewPage)595cdf0e10cSrcweir sal_Bool StgFATStrm::SetPage( short nOff, sal_Int32 nNewPage )
596cdf0e10cSrcweir {
597297a844aSArmin Le Grand OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
598cdf0e10cSrcweir sal_Bool bRes = sal_True;
599cdf0e10cSrcweir if( nOff < rIo.aHdr.GetFAT1Size() )
600cdf0e10cSrcweir rIo.aHdr.SetFATPage( nOff, nNewPage );
601cdf0e10cSrcweir else
602cdf0e10cSrcweir {
603cdf0e10cSrcweir nOff = nOff - rIo.aHdr.GetFAT1Size();
604cdf0e10cSrcweir // Anzahl der Masterpages, durch die wir iterieren muessen
605cdf0e10cSrcweir sal_uInt16 nMasterCount = ( nPageSize >> 2 ) - 1;
606cdf0e10cSrcweir sal_uInt16 nBlocks = nOff / nMasterCount;
607cdf0e10cSrcweir // Offset in letzter Masterpage
608cdf0e10cSrcweir nOff = nOff % nMasterCount;
609cdf0e10cSrcweir
610cdf0e10cSrcweir StgPage* pMaster = 0;
611cdf0e10cSrcweir sal_Int32 nFAT = rIo.aHdr.GetFATChain();
612cdf0e10cSrcweir for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
613cdf0e10cSrcweir {
614cdf0e10cSrcweir if( nFAT == STG_EOF || nFAT == STG_FREE )
615cdf0e10cSrcweir {
616cdf0e10cSrcweir pMaster = 0;
617cdf0e10cSrcweir break;
618cdf0e10cSrcweir }
619cdf0e10cSrcweir pMaster = rIo.Get( nFAT, sal_True );
620cdf0e10cSrcweir if ( pMaster )
621cdf0e10cSrcweir nFAT = pMaster->GetPage( nMasterCount );
622cdf0e10cSrcweir }
623cdf0e10cSrcweir if( pMaster )
624cdf0e10cSrcweir pMaster->SetPage( nOff, nNewPage );
625cdf0e10cSrcweir else
626cdf0e10cSrcweir {
627cdf0e10cSrcweir rIo.SetError( SVSTREAM_GENERALERROR );
628cdf0e10cSrcweir bRes = sal_False;
629cdf0e10cSrcweir }
630cdf0e10cSrcweir }
631cdf0e10cSrcweir
632cdf0e10cSrcweir // lock the page against access
633cdf0e10cSrcweir if( bRes )
634cdf0e10cSrcweir {
635cdf0e10cSrcweir Pos2Page( nNewPage << 2 );
636cdf0e10cSrcweir StgPage* pPg = rIo.Get( nPage, sal_True );
637cdf0e10cSrcweir if( pPg )
638cdf0e10cSrcweir pPg->SetPage( nOffset >> 2, STG_FAT );
639cdf0e10cSrcweir else
640cdf0e10cSrcweir bRes = sal_False;
641cdf0e10cSrcweir }
642cdf0e10cSrcweir return bRes;
643cdf0e10cSrcweir }
644cdf0e10cSrcweir
SetSize(sal_Int32 nBytes)645cdf0e10cSrcweir sal_Bool StgFATStrm::SetSize( sal_Int32 nBytes )
646cdf0e10cSrcweir {
647297a844aSArmin Le Grand if ( nBytes < 0 )
648297a844aSArmin Le Grand return sal_False;
649297a844aSArmin Le Grand
650cdf0e10cSrcweir // Set the number of entries to a multiple of the page size
651cdf0e10cSrcweir short nOld = (short) ( ( nSize + ( nPageSize - 1 ) ) / nPageSize );
652cdf0e10cSrcweir short nNew = (short) (
653cdf0e10cSrcweir ( nBytes + ( nPageSize - 1 ) ) / nPageSize ) ;
654cdf0e10cSrcweir if( nNew < nOld )
655cdf0e10cSrcweir {
656cdf0e10cSrcweir // release master pages
657cdf0e10cSrcweir for( short i = nNew; i < nOld; i++ )
658cdf0e10cSrcweir SetPage( i, STG_FREE );
659cdf0e10cSrcweir }
660cdf0e10cSrcweir else
661cdf0e10cSrcweir {
662cdf0e10cSrcweir while( nOld < nNew )
663cdf0e10cSrcweir {
664cdf0e10cSrcweir // allocate master pages
665cdf0e10cSrcweir // find a free master page slot
666cdf0e10cSrcweir sal_Int32 nPg = 0;
667cdf0e10cSrcweir sal_uInt16 nMasterAlloc = 0;
668cdf0e10cSrcweir nPg = GetPage( nOld, sal_True, &nMasterAlloc );
669cdf0e10cSrcweir if( nPg == STG_EOF )
670cdf0e10cSrcweir return sal_False;
671cdf0e10cSrcweir // 4 Bytes have been used for Allocation of each MegaMasterPage
672cdf0e10cSrcweir nBytes += nMasterAlloc << 2;
673cdf0e10cSrcweir
674cdf0e10cSrcweir // find a free page using the FAT allocator
675cdf0e10cSrcweir sal_Int32 n = 1;
676297a844aSArmin Le Grand OSL_ENSURE( pFat, "The pointer is always initializer here!" );
677cdf0e10cSrcweir sal_Int32 nNewPage = pFat->FindBlock( n );
678cdf0e10cSrcweir if( nNewPage == STG_EOF )
679cdf0e10cSrcweir {
680cdf0e10cSrcweir // no free pages found; create a new page
681cdf0e10cSrcweir // Since all pages are allocated, extend
682cdf0e10cSrcweir // the file size for the next page!
683cdf0e10cSrcweir nNewPage = nSize >> 2;
684cdf0e10cSrcweir // if a MegaMasterPage was created avoid taking
685cdf0e10cSrcweir // the same Page
686cdf0e10cSrcweir nNewPage += nMasterAlloc;
687cdf0e10cSrcweir // adjust the file size if necessary
688cdf0e10cSrcweir if( nNewPage >= rIo.GetPhysPages() )
689cdf0e10cSrcweir if( !rIo.SetSize( nNewPage + 1 ) )
690cdf0e10cSrcweir return sal_False;
691cdf0e10cSrcweir }
692cdf0e10cSrcweir // Set up the page with empty entries
693cdf0e10cSrcweir StgPage* pPg = rIo.Copy( nNewPage, STG_FREE );
694cdf0e10cSrcweir if ( !pPg )
695cdf0e10cSrcweir return sal_False;
696cdf0e10cSrcweir for( short j = 0; j < ( nPageSize >> 2 ); j++ )
697cdf0e10cSrcweir pPg->SetPage( j, STG_FREE );
698cdf0e10cSrcweir
699cdf0e10cSrcweir // store the page number into the master FAT
700cdf0e10cSrcweir // Set the size before so the correct FAT can be found
701cdf0e10cSrcweir nSize = ( nOld + 1 ) * nPageSize;
702cdf0e10cSrcweir SetPage( nOld, nNewPage );
703cdf0e10cSrcweir
704cdf0e10cSrcweir // MegaMasterPages were created, mark it them as used
705cdf0e10cSrcweir
706cdf0e10cSrcweir sal_uInt32 nMax = rIo.aHdr.GetMasters( );
707cdf0e10cSrcweir sal_uInt32 nFAT = rIo.aHdr.GetFATChain();
708cdf0e10cSrcweir if( nMasterAlloc )
709cdf0e10cSrcweir for( sal_uInt16 nCount = 0; nCount < nMax; nCount++ )
710cdf0e10cSrcweir {
711cdf0e10cSrcweir if( !Pos2Page( nFAT << 2 ) )
712cdf0e10cSrcweir return sal_False;
713cdf0e10cSrcweir if( nMax - nCount <= nMasterAlloc )
714cdf0e10cSrcweir {
715cdf0e10cSrcweir StgPage* piPg = rIo.Get( nPage, sal_True );
716cdf0e10cSrcweir if( !piPg )
717cdf0e10cSrcweir return sal_False;
718cdf0e10cSrcweir piPg->SetPage( nOffset >> 2, STG_MASTER );
719cdf0e10cSrcweir }
720cdf0e10cSrcweir StgPage* pPage = rIo.Get( nFAT, sal_True );
721cdf0e10cSrcweir if( !pPage ) return sal_False;
722cdf0e10cSrcweir nFAT = pPage->GetPage( (nPageSize >> 2 ) - 1 );
723cdf0e10cSrcweir }
724cdf0e10cSrcweir
725cdf0e10cSrcweir nOld++;
726cdf0e10cSrcweir // We have used up 4 bytes for the STG_FAT entry
727cdf0e10cSrcweir nBytes += 4;
728cdf0e10cSrcweir nNew = (short) (
729cdf0e10cSrcweir ( nBytes + ( nPageSize - 1 ) ) / nPageSize );
730cdf0e10cSrcweir }
731cdf0e10cSrcweir }
732cdf0e10cSrcweir nSize = nNew * nPageSize;
733cdf0e10cSrcweir rIo.aHdr.SetFATSize( nNew );
734cdf0e10cSrcweir return sal_True;
735cdf0e10cSrcweir }
736cdf0e10cSrcweir
737cdf0e10cSrcweir /////////////////////////// class StgDataStrm //////////////////////////////
738cdf0e10cSrcweir
739cdf0e10cSrcweir // This class is a normal physical stream which can be initialized
740cdf0e10cSrcweir // either with an existing dir entry or an existing FAT chain.
741cdf0e10cSrcweir // The stream has a size increment which normally is 1, but which can be
742cdf0e10cSrcweir // set to any value is you want the size to be incremented by certain values.
743cdf0e10cSrcweir
StgDataStrm(StgIo & r,sal_Int32 nBgn,sal_Int32 nLen)744cdf0e10cSrcweir StgDataStrm::StgDataStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
745cdf0e10cSrcweir {
746cdf0e10cSrcweir Init( nBgn, nLen );
747cdf0e10cSrcweir }
748cdf0e10cSrcweir
StgDataStrm(StgIo & r,StgDirEntry & p)749297a844aSArmin Le Grand StgDataStrm::StgDataStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
750cdf0e10cSrcweir {
751297a844aSArmin Le Grand pEntry = &p;
752297a844aSArmin Le Grand Init( p.aEntry.GetLeaf( STG_DATA ),
753297a844aSArmin Le Grand p.aEntry.GetSize() );
754cdf0e10cSrcweir }
755cdf0e10cSrcweir
Init(sal_Int32 nBgn,sal_Int32 nLen)756cdf0e10cSrcweir void StgDataStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
757cdf0e10cSrcweir {
758297a844aSArmin Le Grand if ( rIo.pFAT )
759297a844aSArmin Le Grand pFat = new StgFAT( *rIo.pFAT, sal_True );
760297a844aSArmin Le Grand
761297a844aSArmin Le Grand OSL_ENSURE( pFat, "The pointer should not be empty!" );
762297a844aSArmin Le Grand
763cdf0e10cSrcweir nStart = nPage = nBgn;
764cdf0e10cSrcweir nSize = nLen;
765cdf0e10cSrcweir nIncr = 1;
766cdf0e10cSrcweir nOffset = 0;
767297a844aSArmin Le Grand if( nLen < 0 && pFat )
768cdf0e10cSrcweir {
769cdf0e10cSrcweir // determine the actual size of the stream by scanning
770cdf0e10cSrcweir // the FAT chain and counting the # of pages allocated
771cdf0e10cSrcweir nSize = 0;
772*92160db5SArmin Le Grand
773*92160db5SArmin Le Grand // there may be files with double page numbers or loops of page
774*92160db5SArmin Le Grand // references. This is not allowed. To be able to track this and
775*92160db5SArmin Le Grand // to exit with an error, track already scanned PageNumbers here
776*92160db5SArmin Le Grand // and use them to see if an already counted page is re-visited
777*92160db5SArmin Le Grand std::set< sal_Int32 > nUsedPageNumbers;
778*92160db5SArmin Le Grand
779*92160db5SArmin Le Grand while(nBgn >= 0)
780cdf0e10cSrcweir {
781*92160db5SArmin Le Grand if(nUsedPageNumbers.find(nBgn) == nUsedPageNumbers.end())
782*92160db5SArmin Le Grand {
783*92160db5SArmin Le Grand nUsedPageNumbers.insert(nBgn);
784*92160db5SArmin Le Grand nSize += nPageSize;
785*92160db5SArmin Le Grand nBgn = pFat->GetNextPage(nBgn);
786*92160db5SArmin Le Grand }
787*92160db5SArmin Le Grand else
788*92160db5SArmin Le Grand {
789*92160db5SArmin Le Grand rIo.SetError(ERRCODE_IO_WRONGFORMAT);
790*92160db5SArmin Le Grand nBgn = -1;
791*92160db5SArmin Le Grand }
792cdf0e10cSrcweir }
793cdf0e10cSrcweir }
794cdf0e10cSrcweir }
795cdf0e10cSrcweir
796cdf0e10cSrcweir // Set the size of a physical stream.
797cdf0e10cSrcweir
SetSize(sal_Int32 nBytes)798cdf0e10cSrcweir sal_Bool StgDataStrm::SetSize( sal_Int32 nBytes )
799cdf0e10cSrcweir {
800297a844aSArmin Le Grand if ( !pFat )
801297a844aSArmin Le Grand return sal_False;
802297a844aSArmin Le Grand
803cdf0e10cSrcweir nBytes = ( ( nBytes + nIncr - 1 ) / nIncr ) * nIncr;
804cdf0e10cSrcweir sal_Int32 nOldSz = nSize;
805cdf0e10cSrcweir if( ( nOldSz != nBytes ) )
806cdf0e10cSrcweir {
807cdf0e10cSrcweir if( !StgStrm::SetSize( nBytes ) )
808cdf0e10cSrcweir return sal_False;
809cdf0e10cSrcweir sal_Int32 nMaxPage = pFat->GetMaxPage();
810cdf0e10cSrcweir if( nMaxPage > rIo.GetPhysPages() )
811cdf0e10cSrcweir if( !rIo.SetSize( nMaxPage ) )
812cdf0e10cSrcweir return sal_False;
813cdf0e10cSrcweir // If we only allocated one page or less, create this
814cdf0e10cSrcweir // page in the cache for faster throughput. The current
815cdf0e10cSrcweir // position is the former EOF point.
816cdf0e10cSrcweir if( ( nSize - 1 ) / nPageSize - ( nOldSz - 1 ) / nPageSize == 1 )
817cdf0e10cSrcweir {
818cdf0e10cSrcweir Pos2Page( nBytes );
819cdf0e10cSrcweir if( nPage >= 0 )
820cdf0e10cSrcweir rIo.Copy( nPage, STG_FREE );
821cdf0e10cSrcweir }
822cdf0e10cSrcweir }
823cdf0e10cSrcweir return sal_True;
824cdf0e10cSrcweir }
825cdf0e10cSrcweir
826cdf0e10cSrcweir // Get the address of the data byte at a specified offset.
827cdf0e10cSrcweir // If bForce = sal_True, a read of non-existent data causes
828cdf0e10cSrcweir // a read fault.
829cdf0e10cSrcweir
GetPtr(sal_Int32 Pos,sal_Bool bForce,sal_Bool bDirty)830cdf0e10cSrcweir void* StgDataStrm::GetPtr( sal_Int32 Pos, sal_Bool bForce, sal_Bool bDirty )
831cdf0e10cSrcweir {
832cdf0e10cSrcweir if( Pos2Page( Pos ) )
833cdf0e10cSrcweir {
834cdf0e10cSrcweir StgPage* pPg = rIo.Get( nPage, bForce );
835cdf0e10cSrcweir if( pPg )
836cdf0e10cSrcweir {
837cdf0e10cSrcweir pPg->SetOwner( pEntry );
838cdf0e10cSrcweir if( bDirty )
839cdf0e10cSrcweir pPg->SetDirty();
840cdf0e10cSrcweir return ((sal_uInt8 *)pPg->GetData()) + nOffset;
841cdf0e10cSrcweir }
842cdf0e10cSrcweir }
843cdf0e10cSrcweir return NULL;
844cdf0e10cSrcweir }
845cdf0e10cSrcweir
846cdf0e10cSrcweir // This could easily be adapted to a better algorithm by determining
847cdf0e10cSrcweir // the amount of consecutable blocks before doing a read. The result
848cdf0e10cSrcweir // is the number of bytes read. No error is generated on EOF.
849cdf0e10cSrcweir
Read(void * pBuf,sal_Int32 n)850cdf0e10cSrcweir sal_Int32 StgDataStrm::Read( void* pBuf, sal_Int32 n )
851cdf0e10cSrcweir {
852cdf0e10cSrcweir if ( n < 0 )
853cdf0e10cSrcweir return 0;
854cdf0e10cSrcweir
855cdf0e10cSrcweir if( ( nPos + n ) > nSize )
856cdf0e10cSrcweir n = nSize - nPos;
857cdf0e10cSrcweir sal_Int32 nDone = 0;
858cdf0e10cSrcweir while( n )
859cdf0e10cSrcweir {
860cdf0e10cSrcweir short nBytes = nPageSize - nOffset;
861cdf0e10cSrcweir short nRes;
862cdf0e10cSrcweir StgPage* pPg;
863cdf0e10cSrcweir if( (sal_Int32) nBytes > n )
864cdf0e10cSrcweir nBytes = (short) n;
865cdf0e10cSrcweir if( nBytes )
866cdf0e10cSrcweir {
867cdf0e10cSrcweir void *p = (sal_uInt8 *) pBuf + nDone;
868cdf0e10cSrcweir if( nBytes == nPageSize )
869cdf0e10cSrcweir {
870cdf0e10cSrcweir pPg = rIo.Find( nPage );
871cdf0e10cSrcweir if( pPg )
872cdf0e10cSrcweir {
873cdf0e10cSrcweir // data is present, so use the cached data
874cdf0e10cSrcweir pPg->SetOwner( pEntry );
875cdf0e10cSrcweir memcpy( p, pPg->GetData(), nBytes );
876cdf0e10cSrcweir nRes = nBytes;
877cdf0e10cSrcweir }
878cdf0e10cSrcweir else
879cdf0e10cSrcweir // do a direct (unbuffered) read
880cdf0e10cSrcweir nRes = (short) rIo.Read( nPage, p, 1 ) * nPageSize;
881cdf0e10cSrcweir }
882cdf0e10cSrcweir else
883cdf0e10cSrcweir {
884cdf0e10cSrcweir // partial block read thru the cache.
885cdf0e10cSrcweir pPg = rIo.Get( nPage, sal_False );
886cdf0e10cSrcweir if( !pPg )
887cdf0e10cSrcweir break;
888cdf0e10cSrcweir pPg->SetOwner( pEntry );
889cdf0e10cSrcweir memcpy( p, (sal_uInt8*)pPg->GetData() + nOffset, nBytes );
890cdf0e10cSrcweir nRes = nBytes;
891cdf0e10cSrcweir }
892cdf0e10cSrcweir nDone += nRes;
893cdf0e10cSrcweir nPos += nRes;
894cdf0e10cSrcweir n -= nRes;
895cdf0e10cSrcweir nOffset = nOffset + nRes;
896cdf0e10cSrcweir if( nRes != nBytes )
897cdf0e10cSrcweir break; // read error or EOF
898cdf0e10cSrcweir }
899cdf0e10cSrcweir // Switch to next page if necessary
900cdf0e10cSrcweir if( nOffset >= nPageSize && !Pos2Page( nPos ) )
901cdf0e10cSrcweir break;
902cdf0e10cSrcweir }
903cdf0e10cSrcweir return nDone;
904cdf0e10cSrcweir }
905cdf0e10cSrcweir
Write(const void * pBuf,sal_Int32 n)906cdf0e10cSrcweir sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n )
907cdf0e10cSrcweir {
908297a844aSArmin Le Grand if ( n < 0 )
909297a844aSArmin Le Grand return 0;
910297a844aSArmin Le Grand
911cdf0e10cSrcweir sal_Int32 nDone = 0;
912cdf0e10cSrcweir if( ( nPos + n ) > nSize )
913cdf0e10cSrcweir {
914cdf0e10cSrcweir sal_Int32 nOld = nPos;
915cdf0e10cSrcweir if( !SetSize( nPos + n ) )
916297a844aSArmin Le Grand return 0;
917cdf0e10cSrcweir Pos2Page( nOld );
918cdf0e10cSrcweir }
919cdf0e10cSrcweir while( n )
920cdf0e10cSrcweir {
921cdf0e10cSrcweir short nBytes = nPageSize - nOffset;
922cdf0e10cSrcweir short nRes;
923cdf0e10cSrcweir StgPage* pPg;
924cdf0e10cSrcweir if( (sal_Int32) nBytes > n )
925cdf0e10cSrcweir nBytes = (short) n;
926cdf0e10cSrcweir if( nBytes )
927cdf0e10cSrcweir {
928cdf0e10cSrcweir const void *p = (const sal_uInt8 *) pBuf + nDone;
929cdf0e10cSrcweir if( nBytes == nPageSize )
930cdf0e10cSrcweir {
931cdf0e10cSrcweir pPg = rIo.Find( nPage );
932cdf0e10cSrcweir if( pPg )
933cdf0e10cSrcweir {
934cdf0e10cSrcweir // data is present, so use the cached data
935cdf0e10cSrcweir pPg->SetOwner( pEntry );
936cdf0e10cSrcweir memcpy( pPg->GetData(), p, nBytes );
937cdf0e10cSrcweir pPg->SetDirty();
938cdf0e10cSrcweir nRes = nBytes;
939cdf0e10cSrcweir }
940cdf0e10cSrcweir else
941cdf0e10cSrcweir // do a direct (unbuffered) write
942cdf0e10cSrcweir nRes = (short) rIo.Write( nPage, (void*) p, 1 ) * nPageSize;
943cdf0e10cSrcweir }
944cdf0e10cSrcweir else
945cdf0e10cSrcweir {
946cdf0e10cSrcweir // partial block read thru the cache.
947cdf0e10cSrcweir pPg = rIo.Get( nPage, sal_False );
948cdf0e10cSrcweir if( !pPg )
949cdf0e10cSrcweir break;
950cdf0e10cSrcweir pPg->SetOwner( pEntry );
951cdf0e10cSrcweir memcpy( (sal_uInt8*)pPg->GetData() + nOffset, p, nBytes );
952cdf0e10cSrcweir pPg->SetDirty();
953cdf0e10cSrcweir nRes = nBytes;
954cdf0e10cSrcweir }
955cdf0e10cSrcweir nDone += nRes;
956cdf0e10cSrcweir nPos += nRes;
957cdf0e10cSrcweir n -= nRes;
958cdf0e10cSrcweir nOffset = nOffset + nRes;
959cdf0e10cSrcweir if( nRes != nBytes )
960cdf0e10cSrcweir break; // read error
961cdf0e10cSrcweir }
962cdf0e10cSrcweir // Switch to next page if necessary
963cdf0e10cSrcweir if( nOffset >= nPageSize && !Pos2Page( nPos ) )
964cdf0e10cSrcweir break;
965cdf0e10cSrcweir }
966cdf0e10cSrcweir return nDone;
967cdf0e10cSrcweir }
968cdf0e10cSrcweir
969cdf0e10cSrcweir //////////////////////////// class StgSmallStream ///////////////////////////
970cdf0e10cSrcweir
971cdf0e10cSrcweir // The small stream class provides access to streams with a size < 4096 bytes.
972cdf0e10cSrcweir // This stream is a StgStream containing small pages. The FAT for this stream
973cdf0e10cSrcweir // is also a StgStream. The start of the FAT is in the header at DataRootPage,
974cdf0e10cSrcweir // the stream itself is pointed to by the root entry (it holds start & size).
975cdf0e10cSrcweir
StgSmallStrm(StgIo & r,sal_Int32 nBgn,sal_Int32 nLen)976cdf0e10cSrcweir StgSmallStrm::StgSmallStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
977cdf0e10cSrcweir {
978cdf0e10cSrcweir Init( nBgn, nLen );
979cdf0e10cSrcweir }
980cdf0e10cSrcweir
StgSmallStrm(StgIo & r,StgDirEntry & p)981297a844aSArmin Le Grand StgSmallStrm::StgSmallStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
982cdf0e10cSrcweir {
983297a844aSArmin Le Grand pEntry = &p;
984297a844aSArmin Le Grand Init( p.aEntry.GetLeaf( STG_DATA ),
985297a844aSArmin Le Grand p.aEntry.GetSize() );
986cdf0e10cSrcweir }
987cdf0e10cSrcweir
Init(sal_Int32 nBgn,sal_Int32 nLen)988cdf0e10cSrcweir void StgSmallStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
989cdf0e10cSrcweir {
990297a844aSArmin Le Grand if ( rIo.pDataFAT )
991297a844aSArmin Le Grand pFat = new StgFAT( *rIo.pDataFAT, sal_False );
992cdf0e10cSrcweir pData = rIo.pDataStrm;
993297a844aSArmin Le Grand OSL_ENSURE( pFat && pData, "The pointers should not be empty!" );
994297a844aSArmin Le Grand
995cdf0e10cSrcweir nPageSize = rIo.GetDataPageSize();
996cdf0e10cSrcweir nStart =
997cdf0e10cSrcweir nPage = nBgn;
998cdf0e10cSrcweir nSize = nLen;
999cdf0e10cSrcweir }
1000cdf0e10cSrcweir
1001cdf0e10cSrcweir // This could easily be adapted to a better algorithm by determining
1002cdf0e10cSrcweir // the amount of consecutable blocks before doing a read. The result
1003cdf0e10cSrcweir // is the number of bytes read. No error is generated on EOF.
1004cdf0e10cSrcweir
Read(void * pBuf,sal_Int32 n)1005cdf0e10cSrcweir sal_Int32 StgSmallStrm::Read( void* pBuf, sal_Int32 n )
1006cdf0e10cSrcweir {
1007cdf0e10cSrcweir // We can safely assume that reads are not huge, since the
1008cdf0e10cSrcweir // small stream is likely to be < 64 KBytes.
1009cdf0e10cSrcweir if( ( nPos + n ) > nSize )
1010cdf0e10cSrcweir n = nSize - nPos;
1011cdf0e10cSrcweir short nDone = 0;
1012cdf0e10cSrcweir while( n )
1013cdf0e10cSrcweir {
1014cdf0e10cSrcweir short nBytes = nPageSize - nOffset;
1015cdf0e10cSrcweir if( (sal_Int32) nBytes > n )
1016cdf0e10cSrcweir nBytes = (short) n;
1017cdf0e10cSrcweir if( nBytes )
1018cdf0e10cSrcweir {
1019297a844aSArmin Le Grand if( !pData || !pData->Pos2Page( nPage * nPageSize + nOffset ) )
1020cdf0e10cSrcweir break;
1021cdf0e10cSrcweir // all reading thru the stream
1022cdf0e10cSrcweir short nRes = (short) pData->Read( (sal_uInt8*)pBuf + nDone, nBytes );
1023cdf0e10cSrcweir nDone = nDone + nRes;
1024cdf0e10cSrcweir nPos += nRes;
1025cdf0e10cSrcweir n -= nRes;
1026cdf0e10cSrcweir nOffset = nOffset + nRes;
1027cdf0e10cSrcweir // read problem?
1028cdf0e10cSrcweir if( nRes != nBytes )
1029cdf0e10cSrcweir break;
1030cdf0e10cSrcweir }
1031cdf0e10cSrcweir // Switch to next page if necessary
1032cdf0e10cSrcweir if( nOffset >= nPageSize && !Pos2Page( nPos ) )
1033cdf0e10cSrcweir break;
1034cdf0e10cSrcweir }
1035cdf0e10cSrcweir return nDone;
1036cdf0e10cSrcweir }
1037cdf0e10cSrcweir
Write(const void * pBuf,sal_Int32 n)1038cdf0e10cSrcweir sal_Int32 StgSmallStrm::Write( const void* pBuf, sal_Int32 n )
1039cdf0e10cSrcweir {
1040cdf0e10cSrcweir // you can safely assume that reads are not huge, since the
1041cdf0e10cSrcweir // small stream is likely to be < 64 KBytes.
1042cdf0e10cSrcweir short nDone = 0;
1043cdf0e10cSrcweir if( ( nPos + n ) > nSize )
1044cdf0e10cSrcweir {
1045cdf0e10cSrcweir sal_Int32 nOld = nPos;
1046cdf0e10cSrcweir if( !SetSize( nPos + n ) )
1047cdf0e10cSrcweir return sal_False;
1048cdf0e10cSrcweir Pos2Page( nOld );
1049cdf0e10cSrcweir }
1050cdf0e10cSrcweir while( n )
1051cdf0e10cSrcweir {
1052cdf0e10cSrcweir short nBytes = nPageSize - nOffset;
1053cdf0e10cSrcweir if( (sal_Int32) nBytes > n )
1054cdf0e10cSrcweir nBytes = (short) n;
1055cdf0e10cSrcweir if( nBytes )
1056cdf0e10cSrcweir {
1057cdf0e10cSrcweir // all writing goes thru the stream
1058cdf0e10cSrcweir sal_Int32 nDataPos = nPage * nPageSize + nOffset;
1059297a844aSArmin Le Grand if ( !pData
1060297a844aSArmin Le Grand || ( pData->GetSize() < ( nDataPos + nBytes )
1061297a844aSArmin Le Grand && !pData->SetSize( nDataPos + nBytes ) ) )
1062297a844aSArmin Le Grand break;
1063cdf0e10cSrcweir if( !pData->Pos2Page( nDataPos ) )
1064cdf0e10cSrcweir break;
1065cdf0e10cSrcweir short nRes = (short) pData->Write( (sal_uInt8*)pBuf + nDone, nBytes );
1066cdf0e10cSrcweir nDone = nDone + nRes;
1067cdf0e10cSrcweir nPos += nRes;
1068cdf0e10cSrcweir n -= nRes;
1069cdf0e10cSrcweir nOffset = nOffset + nRes;
1070cdf0e10cSrcweir // write problem?
1071cdf0e10cSrcweir if( nRes != nBytes )
1072cdf0e10cSrcweir break;
1073cdf0e10cSrcweir }
1074cdf0e10cSrcweir // Switch to next page if necessary
1075cdf0e10cSrcweir if( nOffset >= nPageSize && !Pos2Page( nPos ) )
1076cdf0e10cSrcweir break;
1077cdf0e10cSrcweir }
1078cdf0e10cSrcweir return nDone;
1079cdf0e10cSrcweir }
1080cdf0e10cSrcweir
1081cdf0e10cSrcweir /////////////////////////// class StgTmpStrm /////////////////////////////
1082cdf0e10cSrcweir
1083cdf0e10cSrcweir // The temporary stream uses a memory stream if < 32K, otherwise a
1084cdf0e10cSrcweir // temporary file.
1085cdf0e10cSrcweir
1086cdf0e10cSrcweir #define THRESHOLD 32768L
1087cdf0e10cSrcweir
StgTmpStrm(sal_uLong nInitSize)1088cdf0e10cSrcweir StgTmpStrm::StgTmpStrm( sal_uLong nInitSize )
1089cdf0e10cSrcweir : SvMemoryStream( nInitSize > THRESHOLD
1090cdf0e10cSrcweir ? 16
1091cdf0e10cSrcweir : ( nInitSize ? nInitSize : 16 ), 4096 )
1092cdf0e10cSrcweir {
1093cdf0e10cSrcweir pStrm = NULL;
1094cdf0e10cSrcweir // this calls FlushData, so all members should be set by this time
1095cdf0e10cSrcweir SetBufferSize( 0 );
1096cdf0e10cSrcweir if( nInitSize > THRESHOLD )
1097cdf0e10cSrcweir SetSize( nInitSize );
1098cdf0e10cSrcweir }
1099cdf0e10cSrcweir
Copy(StgTmpStrm & rSrc)1100cdf0e10cSrcweir sal_Bool StgTmpStrm::Copy( StgTmpStrm& rSrc )
1101cdf0e10cSrcweir {
1102cdf0e10cSrcweir sal_uLong n = rSrc.GetSize();
1103cdf0e10cSrcweir sal_uLong nCur = rSrc.Tell();
1104cdf0e10cSrcweir SetSize( n );
1105cdf0e10cSrcweir if( GetError() == SVSTREAM_OK )
1106cdf0e10cSrcweir {
1107cdf0e10cSrcweir sal_uInt8* p = new sal_uInt8[ 4096 ];
1108cdf0e10cSrcweir rSrc.Seek( 0L );
1109cdf0e10cSrcweir Seek( 0L );
1110cdf0e10cSrcweir while( n )
1111cdf0e10cSrcweir {
1112cdf0e10cSrcweir sal_uLong nn = n;
1113cdf0e10cSrcweir if( nn > 4096 )
1114cdf0e10cSrcweir nn = 4096;
1115cdf0e10cSrcweir if( rSrc.Read( p, nn ) != nn )
1116cdf0e10cSrcweir break;
1117cdf0e10cSrcweir if( Write( p, nn ) != nn )
1118cdf0e10cSrcweir break;
1119cdf0e10cSrcweir n -= nn;
1120cdf0e10cSrcweir }
1121cdf0e10cSrcweir delete [] p;
1122cdf0e10cSrcweir rSrc.Seek( nCur );
1123cdf0e10cSrcweir Seek( nCur );
1124cdf0e10cSrcweir return sal_Bool( n == 0 );
1125cdf0e10cSrcweir }
1126cdf0e10cSrcweir else
1127cdf0e10cSrcweir return sal_False;
1128cdf0e10cSrcweir }
1129cdf0e10cSrcweir
~StgTmpStrm()1130cdf0e10cSrcweir StgTmpStrm::~StgTmpStrm()
1131cdf0e10cSrcweir {
1132cdf0e10cSrcweir if( pStrm )
1133cdf0e10cSrcweir {
1134cdf0e10cSrcweir pStrm->Close();
1135cdf0e10cSrcweir osl::File::remove( aName );
1136cdf0e10cSrcweir delete pStrm;
1137cdf0e10cSrcweir }
1138cdf0e10cSrcweir }
1139cdf0e10cSrcweir
GetSize() const1140cdf0e10cSrcweir sal_uLong StgTmpStrm::GetSize() const
1141cdf0e10cSrcweir {
1142cdf0e10cSrcweir sal_uLong n;
1143cdf0e10cSrcweir if( pStrm )
1144cdf0e10cSrcweir {
1145cdf0e10cSrcweir sal_uLong old = pStrm->Tell();
1146cdf0e10cSrcweir n = pStrm->Seek( STREAM_SEEK_TO_END );
1147cdf0e10cSrcweir pStrm->Seek( old );
1148cdf0e10cSrcweir }
1149cdf0e10cSrcweir else
1150cdf0e10cSrcweir n = nEndOfData;
1151cdf0e10cSrcweir return n;
1152cdf0e10cSrcweir }
1153cdf0e10cSrcweir
SetSize(sal_uLong n)1154cdf0e10cSrcweir void StgTmpStrm::SetSize( sal_uLong n )
1155cdf0e10cSrcweir {
1156cdf0e10cSrcweir if( pStrm )
1157cdf0e10cSrcweir pStrm->SetStreamSize( n );
1158cdf0e10cSrcweir else
1159cdf0e10cSrcweir {
1160cdf0e10cSrcweir if( n > THRESHOLD )
1161cdf0e10cSrcweir {
1162cdf0e10cSrcweir aName = TempFile::CreateTempName();
1163cdf0e10cSrcweir SvFileStream* s = new SvFileStream( aName, STREAM_READWRITE );
1164cdf0e10cSrcweir sal_uLong nCur = Tell();
1165cdf0e10cSrcweir sal_uLong i = nEndOfData;
1166cdf0e10cSrcweir if( i )
1167cdf0e10cSrcweir {
1168cdf0e10cSrcweir sal_uInt8* p = new sal_uInt8[ 4096 ];
1169cdf0e10cSrcweir Seek( 0L );
1170cdf0e10cSrcweir while( i )
1171cdf0e10cSrcweir {
1172cdf0e10cSrcweir sal_uLong nb = ( i > 4096 ) ? 4096 : i;
1173cdf0e10cSrcweir if( Read( p, nb ) == nb
1174cdf0e10cSrcweir && s->Write( p, nb ) == nb )
1175cdf0e10cSrcweir i -= nb;
1176cdf0e10cSrcweir else
1177cdf0e10cSrcweir break;
1178cdf0e10cSrcweir }
1179cdf0e10cSrcweir delete [] p;
1180cdf0e10cSrcweir }
1181cdf0e10cSrcweir if( !i && n > nEndOfData )
1182cdf0e10cSrcweir {
1183cdf0e10cSrcweir // We have to write one byte at the end of the file
1184cdf0e10cSrcweir // if the file is bigger than the memstream to see
1185cdf0e10cSrcweir // if it fits on disk
1186cdf0e10cSrcweir s->Seek( n - 1 );
1187cdf0e10cSrcweir s->Write( &i, 1 );
1188cdf0e10cSrcweir s->Flush();
1189cdf0e10cSrcweir if( s->GetError() != SVSTREAM_OK )
1190cdf0e10cSrcweir i = 1;
1191cdf0e10cSrcweir }
1192cdf0e10cSrcweir Seek( nCur );
1193cdf0e10cSrcweir s->Seek( nCur );
1194cdf0e10cSrcweir if( i )
1195cdf0e10cSrcweir {
1196cdf0e10cSrcweir SetError( s->GetError() );
1197cdf0e10cSrcweir delete s;
1198cdf0e10cSrcweir return;
1199cdf0e10cSrcweir }
1200cdf0e10cSrcweir pStrm = s;
1201cdf0e10cSrcweir // Shrink the memory to 16 bytes, which seems to be the minimum
1202cdf0e10cSrcweir ReAllocateMemory( - ( (long) nEndOfData - 16 ) );
1203cdf0e10cSrcweir }
1204cdf0e10cSrcweir else
1205cdf0e10cSrcweir {
1206cdf0e10cSrcweir if( n > nEndOfData )
1207cdf0e10cSrcweir {
1208cdf0e10cSrcweir sal_uLong nCur = Tell();
1209cdf0e10cSrcweir Seek( nEndOfData - 1 );
1210cdf0e10cSrcweir *this << (sal_uInt8) 0;
1211cdf0e10cSrcweir Seek( nCur );
1212cdf0e10cSrcweir }
1213cdf0e10cSrcweir else
1214cdf0e10cSrcweir nEndOfData = n;
1215cdf0e10cSrcweir }
1216cdf0e10cSrcweir }
1217cdf0e10cSrcweir }
1218cdf0e10cSrcweir
GetData(void * pData,sal_uLong n)1219cdf0e10cSrcweir sal_uLong StgTmpStrm::GetData( void* pData, sal_uLong n )
1220cdf0e10cSrcweir {
1221cdf0e10cSrcweir if( pStrm )
1222cdf0e10cSrcweir {
1223cdf0e10cSrcweir n = pStrm->Read( pData, n );
1224cdf0e10cSrcweir SetError( pStrm->GetError() );
1225cdf0e10cSrcweir return n;
1226cdf0e10cSrcweir }
1227cdf0e10cSrcweir else
1228cdf0e10cSrcweir return SvMemoryStream::GetData( (sal_Char *)pData, n );
1229cdf0e10cSrcweir }
1230cdf0e10cSrcweir
PutData(const void * pData,sal_uLong n)1231cdf0e10cSrcweir sal_uLong StgTmpStrm::PutData( const void* pData, sal_uLong n )
1232cdf0e10cSrcweir {
1233cdf0e10cSrcweir sal_uInt32 nCur = Tell();
1234cdf0e10cSrcweir sal_uInt32 nNew = nCur + n;
1235cdf0e10cSrcweir if( nNew > THRESHOLD && !pStrm )
1236cdf0e10cSrcweir {
1237cdf0e10cSrcweir SetSize( nNew );
1238cdf0e10cSrcweir if( GetError() != SVSTREAM_OK )
1239cdf0e10cSrcweir return 0;
1240cdf0e10cSrcweir }
1241cdf0e10cSrcweir if( pStrm )
1242cdf0e10cSrcweir {
1243cdf0e10cSrcweir nNew = pStrm->Write( pData, n );
1244cdf0e10cSrcweir SetError( pStrm->GetError() );
1245cdf0e10cSrcweir }
1246cdf0e10cSrcweir else
1247cdf0e10cSrcweir nNew = SvMemoryStream::PutData( (sal_Char*)pData, n );
1248cdf0e10cSrcweir return nNew;
1249cdf0e10cSrcweir }
1250cdf0e10cSrcweir
SeekPos(sal_uLong n)1251cdf0e10cSrcweir sal_uLong StgTmpStrm::SeekPos( sal_uLong n )
1252cdf0e10cSrcweir {
1253cdf0e10cSrcweir if( n == STREAM_SEEK_TO_END )
1254cdf0e10cSrcweir n = GetSize();
1255cdf0e10cSrcweir if( n && n > THRESHOLD && !pStrm )
1256cdf0e10cSrcweir {
1257cdf0e10cSrcweir SetSize( n );
1258cdf0e10cSrcweir if( GetError() != SVSTREAM_OK )
1259cdf0e10cSrcweir return Tell();
1260cdf0e10cSrcweir else
1261cdf0e10cSrcweir return n;
1262cdf0e10cSrcweir }
1263cdf0e10cSrcweir else if( pStrm )
1264cdf0e10cSrcweir {
1265cdf0e10cSrcweir n = pStrm->Seek( n );
1266cdf0e10cSrcweir SetError( pStrm->GetError() );
1267cdf0e10cSrcweir return n;
1268cdf0e10cSrcweir }
1269cdf0e10cSrcweir else
1270cdf0e10cSrcweir return SvMemoryStream::SeekPos( n );
1271cdf0e10cSrcweir }
1272cdf0e10cSrcweir
FlushData()1273cdf0e10cSrcweir void StgTmpStrm::FlushData()
1274cdf0e10cSrcweir {
1275cdf0e10cSrcweir if( pStrm )
1276cdf0e10cSrcweir {
1277cdf0e10cSrcweir pStrm->Flush();
1278cdf0e10cSrcweir SetError( pStrm->GetError() );
1279cdf0e10cSrcweir }
1280cdf0e10cSrcweir else
1281cdf0e10cSrcweir SvMemoryStream::FlushData();
1282cdf0e10cSrcweir }
1283cdf0e10cSrcweir
1284