File: | home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx |
Warning: | line 721, column 28 The result of the left shift is undefined because the left operand is negative |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <algorithm> | |||
21 | ||||
22 | #include <string.h> | |||
23 | #include <sal/log.hxx> | |||
24 | #include <o3tl/safeint.hxx> | |||
25 | #include <osl/file.hxx> | |||
26 | #include <unotools/tempfile.hxx> | |||
27 | ||||
28 | #include "stgelem.hxx" | |||
29 | #include "stgcache.hxx" | |||
30 | #include "stgstrms.hxx" | |||
31 | #include "stgdir.hxx" | |||
32 | #include "stgio.hxx" | |||
33 | #include <memory> | |||
34 | ||||
35 | ///////////////////////////// class StgFAT | |||
36 | ||||
37 | // The FAT class performs FAT operations on an underlying storage stream. | |||
38 | // This stream is either the master FAT stream (m == true ) or a normal | |||
39 | // storage stream, which then holds the FAT for small data allocations. | |||
40 | ||||
41 | StgFAT::StgFAT( StgStrm& r, bool m ) : m_rStrm( r ) | |||
42 | { | |||
43 | m_bPhys = m; | |||
44 | m_nPageSize = m_rStrm.GetIo().GetPhysPageSize(); | |||
45 | m_nEntries = m_nPageSize >> 2; | |||
46 | m_nOffset = 0; | |||
47 | m_nMaxPage = 0; | |||
48 | m_nLimit = 0; | |||
49 | } | |||
50 | ||||
51 | // Retrieve the physical page for a given byte offset. | |||
52 | ||||
53 | rtl::Reference< StgPage > StgFAT::GetPhysPage( sal_Int32 nByteOff ) | |||
54 | { | |||
55 | rtl::Reference< StgPage > pPg; | |||
56 | // Position within the underlying stream | |||
57 | // use the Pos2Page() method of the stream | |||
58 | if( m_rStrm.Pos2Page( nByteOff ) ) | |||
59 | { | |||
60 | m_nOffset = m_rStrm.GetOffset(); | |||
61 | sal_Int32 nPhysPage = m_rStrm.GetPage(); | |||
62 | // get the physical page (must be present) | |||
63 | pPg = m_rStrm.GetIo().Get( nPhysPage, true ); | |||
64 | } | |||
65 | return pPg; | |||
66 | } | |||
67 | ||||
68 | // Get the follow page for a certain FAT page. | |||
69 | ||||
70 | sal_Int32 StgFAT::GetNextPage( sal_Int32 nPg ) | |||
71 | { | |||
72 | if (nPg >= 0) | |||
73 | { | |||
74 | if (nPg > (SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF) >> 2)) | |||
75 | return STG_EOF-2L; | |||
76 | rtl::Reference< StgPage > pPg = GetPhysPage( nPg << 2 ); | |||
77 | nPg = pPg.is() ? StgCache::GetFromPage( pPg, m_nOffset >> 2 ) : STG_EOF-2L; | |||
78 | } | |||
79 | return nPg; | |||
80 | } | |||
81 | ||||
82 | // Find the best fit block for the given size. Return | |||
83 | // the starting block and its size or STG_EOF and 0. | |||
84 | // nLastPage is a stopper which tells the current | |||
85 | // underlying stream size. It is treated as a recommendation | |||
86 | // to abort the search to inhibit excessive file growth. | |||
87 | ||||
88 | sal_Int32 StgFAT::FindBlock( sal_Int32& nPgs ) | |||
89 | { | |||
90 | sal_Int32 nMinStart = STG_EOF-2L, nMinLen = 0; | |||
91 | sal_Int32 nMaxStart = STG_EOF-2L, nMaxLen = 0x7FFFFFFFL; | |||
92 | sal_Int32 nTmpStart = STG_EOF-2L, nTmpLen = 0; | |||
93 | sal_Int32 nPages = m_rStrm.GetSize() >> 2; | |||
94 | bool bFound = false; | |||
95 | rtl::Reference< StgPage > pPg; | |||
96 | short nEntry = 0; | |||
97 | for( sal_Int32 i = 0; i < nPages; i++, nEntry++ ) | |||
98 | { | |||
99 | if( !( nEntry % m_nEntries ) ) | |||
100 | { | |||
101 | // load the next page for that stream | |||
102 | nEntry = 0; | |||
103 | pPg = GetPhysPage( i << 2 ); | |||
104 | if( !pPg.is() ) | |||
105 | return STG_EOF-2L; | |||
106 | } | |||
107 | sal_Int32 nCur = StgCache::GetFromPage( pPg, nEntry ); | |||
108 | if( nCur == STG_FREE-1L ) | |||
109 | { | |||
110 | // count the size of this area | |||
111 | if( nTmpLen ) | |||
112 | nTmpLen++; | |||
113 | else | |||
114 | { | |||
115 | nTmpStart = i; | |||
116 | nTmpLen = 1; | |||
117 | } | |||
118 | if( nTmpLen == nPgs | |||
119 | // If we already did find a block, stop when reaching the limit | |||
120 | || ( bFound && ( nEntry >= m_nLimit ) ) ) | |||
121 | break; | |||
122 | } | |||
123 | else if( nTmpLen ) | |||
124 | { | |||
125 | if( nTmpLen > nPgs && nTmpLen < nMaxLen ) | |||
126 | { | |||
127 | // block > requested size | |||
128 | nMaxLen = nTmpLen; | |||
129 | nMaxStart = nTmpStart; | |||
130 | bFound = true; | |||
131 | } | |||
132 | else if( nTmpLen >= nMinLen ) | |||
133 | { | |||
134 | // block < requested size | |||
135 | nMinLen = nTmpLen; | |||
136 | nMinStart = nTmpStart; | |||
137 | bFound = true; | |||
138 | if( nTmpLen == nPgs ) | |||
139 | break; | |||
140 | } | |||
141 | nTmpStart = STG_EOF-2L; | |||
142 | nTmpLen = 0; | |||
143 | } | |||
144 | } | |||
145 | // Determine which block to use. | |||
146 | if( nTmpLen ) | |||
147 | { | |||
148 | if( nTmpLen > nPgs && nTmpLen < nMaxLen ) | |||
149 | { | |||
150 | // block > requested size | |||
151 | nMaxLen = nTmpLen; | |||
152 | nMaxStart = nTmpStart; | |||
153 | } | |||
154 | else if( nTmpLen >= nMinLen ) | |||
155 | { | |||
156 | // block < requested size | |||
157 | nMinLen = nTmpLen; | |||
158 | nMinStart = nTmpStart; | |||
159 | } | |||
160 | } | |||
161 | if( nMinStart != STG_EOF-2L && nMaxStart != STG_EOF-2L ) | |||
162 | { | |||
163 | // two areas found; return the best fit area | |||
164 | sal_Int32 nMinDiff = nPgs - nMinLen; | |||
165 | sal_Int32 nMaxDiff = nMaxLen - nPgs; | |||
166 | if( nMinDiff > nMaxDiff ) | |||
167 | nMinStart = STG_EOF-2L; | |||
168 | } | |||
169 | if( nMinStart != STG_EOF-2L ) | |||
170 | { | |||
171 | nPgs = nMinLen; return nMinStart; | |||
172 | } | |||
173 | else | |||
174 | { | |||
175 | return nMaxStart; | |||
176 | } | |||
177 | } | |||
178 | ||||
179 | // Set up the consecutive chain for a given block. | |||
180 | ||||
181 | bool StgFAT::MakeChain( sal_Int32 nStart, sal_Int32 nPgs ) | |||
182 | { | |||
183 | sal_Int32 nPos = nStart << 2; | |||
184 | rtl::Reference< StgPage > pPg = GetPhysPage( nPos ); | |||
185 | if( !pPg.is() || !nPgs ) | |||
186 | return false; | |||
187 | while( --nPgs ) | |||
188 | { | |||
189 | if( m_nOffset >= m_nPageSize ) | |||
190 | { | |||
191 | pPg = GetPhysPage( nPos ); | |||
192 | if( !pPg.is() ) | |||
193 | return false; | |||
194 | } | |||
195 | m_rStrm.GetIo().SetToPage( pPg, m_nOffset >> 2, ++nStart ); | |||
196 | m_nOffset += 4; | |||
197 | nPos += 4; | |||
198 | } | |||
199 | if( m_nOffset >= m_nPageSize ) | |||
200 | { | |||
201 | pPg = GetPhysPage( nPos ); | |||
202 | if( !pPg.is() ) | |||
203 | return false; | |||
204 | } | |||
205 | m_rStrm.GetIo().SetToPage( pPg, m_nOffset >> 2, STG_EOF-2L ); | |||
206 | return true; | |||
207 | } | |||
208 | ||||
209 | // Allocate a block of data from the given page number on. | |||
210 | // It the page number is != STG_EOF, chain the block. | |||
211 | ||||
212 | sal_Int32 StgFAT::AllocPages( sal_Int32 nBgn, sal_Int32 nPgs ) | |||
213 | { | |||
214 | sal_Int32 nOrig = nBgn; | |||
215 | sal_Int32 nLast = nBgn; | |||
216 | sal_Int32 nBegin = STG_EOF-2L; | |||
217 | sal_Int32 nAlloc; | |||
218 | sal_Int32 nPages = m_rStrm.GetSize() >> 2; | |||
219 | short nPasses = 0; | |||
220 | // allow for two passes | |||
221 | while( nPasses < 2 ) | |||
222 | { | |||
223 | // try to satisfy the request from the pool of free pages | |||
224 | while( nPgs ) | |||
225 | { | |||
226 | nAlloc = nPgs; | |||
227 | nBegin = FindBlock( nAlloc ); | |||
228 | // no more blocks left in present alloc chain | |||
229 | if( nBegin == STG_EOF-2L ) | |||
230 | break; | |||
231 | if( ( nBegin + nAlloc ) > m_nMaxPage ) | |||
232 | m_nMaxPage = nBegin + nAlloc; | |||
233 | if( !MakeChain( nBegin, nAlloc ) ) | |||
234 | return STG_EOF-2L; | |||
235 | if( nOrig == STG_EOF-2L ) | |||
236 | nOrig = nBegin; | |||
237 | else | |||
238 | { | |||
239 | // Patch the chain | |||
240 | rtl::Reference< StgPage > pPg = GetPhysPage( nLast << 2 ); | |||
241 | if( !pPg.is() ) | |||
242 | return STG_EOF-2L; | |||
243 | m_rStrm.GetIo().SetToPage( pPg, m_nOffset >> 2, nBegin ); | |||
244 | } | |||
245 | nLast = nBegin + nAlloc - 1; | |||
246 | nPgs -= nAlloc; | |||
247 | } | |||
248 | if( nPgs && !nPasses ) | |||
249 | { | |||
250 | // we need new, fresh space, so allocate and retry | |||
251 | if( !m_rStrm.SetSize( ( nPages + nPgs ) << 2 ) ) | |||
252 | return STG_EOF-2L; | |||
253 | if( !m_bPhys && !InitNew( nPages ) ) | |||
254 | return 0; | |||
255 | // FIXME: this was originally "FALSE", whether or not that | |||
256 | // makes sense (or should be STG_EOF instead, say?) | |||
257 | nPages = m_rStrm.GetSize() >> 2; | |||
258 | nPasses++; | |||
259 | } | |||
260 | else | |||
261 | break; | |||
262 | } | |||
263 | // now we should have a chain for the complete block | |||
264 | if( nBegin == STG_EOF-2L || nPgs ) | |||
265 | { | |||
266 | m_rStrm.GetIo().SetError( SVSTREAM_FILEFORMAT_ERRORErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) ); | |||
267 | return STG_EOF-2L; // bad structure | |||
268 | } | |||
269 | return nOrig; | |||
270 | } | |||
271 | ||||
272 | // Initialize newly allocated pages for a standard FAT stream | |||
273 | // It can be assumed that the stream size is always on | |||
274 | // a page boundary | |||
275 | ||||
276 | bool StgFAT::InitNew( sal_Int32 nPage1 ) | |||
277 | { | |||
278 | sal_Int32 n = ( ( m_rStrm.GetSize() >> 2 ) - nPage1 ) / m_nEntries; | |||
279 | if ( n > 0 ) | |||
280 | { | |||
281 | while( n-- ) | |||
282 | { | |||
283 | rtl::Reference< StgPage > pPg; | |||
284 | // Position within the underlying stream | |||
285 | // use the Pos2Page() method of the stream | |||
286 | m_rStrm.Pos2Page( nPage1 << 2 ); | |||
287 | // Initialize the page | |||
288 | pPg = m_rStrm.GetIo().Copy( m_rStrm.GetPage() ); | |||
289 | if ( !pPg.is() ) | |||
290 | return false; | |||
291 | for( short i = 0; i < m_nEntries; i++ ) | |||
292 | m_rStrm.GetIo().SetToPage( pPg, i, STG_FREE-1L ); | |||
293 | nPage1++; | |||
294 | } | |||
295 | } | |||
296 | return true; | |||
297 | } | |||
298 | ||||
299 | // Release a chain | |||
300 | ||||
301 | bool StgFAT::FreePages( sal_Int32 nStart, bool bAll ) | |||
302 | { | |||
303 | while( nStart >= 0 ) | |||
304 | { | |||
305 | rtl::Reference< StgPage > pPg = GetPhysPage( nStart << 2 ); | |||
306 | if( !pPg.is() ) | |||
307 | return false; | |||
308 | nStart = StgCache::GetFromPage( pPg, m_nOffset >> 2 ); | |||
309 | // The first released page is either set to EOF or FREE | |||
310 | m_rStrm.GetIo().SetToPage( pPg, m_nOffset >> 2, bAll ? STG_FREE-1L : STG_EOF-2L ); | |||
311 | bAll = true; | |||
312 | } | |||
313 | return true; | |||
314 | } | |||
315 | ||||
316 | ///////////////////////////// class StgStrm | |||
317 | ||||
318 | // The base stream class provides basic functionality for seeking | |||
319 | // and accessing the data on a physical basis. It uses the built-in | |||
320 | // FAT class for the page allocations. | |||
321 | ||||
322 | StgStrm::StgStrm( StgIo& r ) | |||
323 | : m_nPos(0), | |||
324 | m_bBytePosValid(true), | |||
325 | m_rIo(r), | |||
326 | m_pEntry(nullptr), | |||
327 | m_nStart(STG_EOF-2L), | |||
328 | m_nSize(0), | |||
329 | m_nPage(STG_EOF-2L), | |||
330 | m_nOffset(0), | |||
331 | m_nPageSize(m_rIo.GetPhysPageSize()) | |||
332 | { | |||
333 | } | |||
334 | ||||
335 | StgStrm::~StgStrm() | |||
336 | { | |||
337 | } | |||
338 | ||||
339 | // Attach the stream to the given entry. | |||
340 | ||||
341 | void StgStrm::SetEntry( StgDirEntry& r ) | |||
342 | { | |||
343 | r.m_aEntry.SetLeaf( STG_DATA, m_nStart ); | |||
344 | r.m_aEntry.SetSize( m_nSize ); | |||
345 | m_pEntry = &r; | |||
346 | r.SetDirty(); | |||
347 | } | |||
348 | ||||
349 | /* | |||
350 | * The page chain, is basically a singly linked list of slots each | |||
351 | * point to the next page. Instead of traversing the file structure | |||
352 | * for this each time build a simple flat in-memory vector list | |||
353 | * of pages. | |||
354 | */ | |||
355 | sal_Int32 StgStrm::scanBuildPageChainCache() | |||
356 | { | |||
357 | if (m_nSize > 0) | |||
358 | { | |||
359 | m_aPagesCache.reserve(m_nSize/m_nPageSize); | |||
360 | m_aUsedPageNumbers.reserve(m_nSize/m_nPageSize); | |||
361 | } | |||
362 | ||||
363 | bool bError = false; | |||
364 | sal_Int32 nBgn = m_nStart; | |||
365 | sal_Int32 nOptSize = 0; | |||
366 | ||||
367 | // Track already scanned PageNumbers here and use them to | |||
368 | // see if an already counted page is re-visited | |||
369 | while( nBgn >= 0 && !bError ) | |||
370 | { | |||
371 | m_aPagesCache.push_back(nBgn); | |||
372 | nBgn = m_pFat->GetNextPage( nBgn ); | |||
373 | ||||
374 | //returned second is false if it already exists | |||
375 | if (!m_aUsedPageNumbers.insert(nBgn).second) | |||
376 | { | |||
377 | SAL_WARN ("sot", "Error: page number " << nBgn << " already in chain for stream")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Error: page number " << nBgn << " already in chain for stream" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot" ), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "377" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error: page number " << nBgn << " already in chain for stream"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error: page number " << nBgn << " already in chain for stream"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "377" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Error: page number " << nBgn << " already in chain for stream" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot" ), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "377" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error: page number " << nBgn << " already in chain for stream"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error: page number " << nBgn << " already in chain for stream"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "377" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
378 | bError = true; | |||
379 | } | |||
380 | ||||
381 | nOptSize += m_nPageSize; | |||
382 | } | |||
383 | if (bError) | |||
384 | { | |||
385 | SAL_WARN("sot", "returning wrong format error")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "returning wrong format error") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "385" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "returning wrong format error"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "returning wrong format error"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "385" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "returning wrong format error") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "385" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "returning wrong format error"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "returning wrong format error"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "385" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
386 | m_rIo.SetError( ERRCODE_IO_WRONGFORMATErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) ); | |||
387 | m_aPagesCache.clear(); | |||
388 | m_aUsedPageNumbers.clear(); | |||
389 | } | |||
390 | return nOptSize; | |||
391 | } | |||
392 | ||||
393 | // Compute page number and offset for the given byte position. | |||
394 | // If the position is behind the size, set the stream right | |||
395 | // behind the EOF. | |||
396 | bool StgStrm::Pos2Page( sal_Int32 nBytePos ) | |||
397 | { | |||
398 | if ( !m_pFat ) | |||
399 | return false; | |||
400 | ||||
401 | // Values < 0 seek to the end | |||
402 | if( nBytePos < 0 || nBytePos >= m_nSize ) | |||
403 | nBytePos = m_nSize; | |||
404 | // Adjust the position back to offset 0 | |||
405 | m_nPos -= m_nOffset; | |||
406 | sal_Int32 nMask = ~( m_nPageSize - 1 ); | |||
407 | sal_Int32 nOld = m_nPos & nMask; | |||
408 | sal_Int32 nNew = nBytePos & nMask; | |||
409 | m_nOffset = static_cast<short>( nBytePos & ~nMask ); | |||
410 | m_nPos = nBytePos; | |||
411 | if (nOld == nNew) | |||
412 | return m_bBytePosValid; | |||
413 | ||||
414 | // See fdo#47644 for a .doc with a vast amount of pages where seeking around the | |||
415 | // document takes a colossal amount of time | |||
416 | ||||
417 | // Please Note: we build the pagescache incrementally as we go if necessary, | |||
418 | // so that a corrupted FAT doesn't poison the stream state for earlier reads | |||
419 | size_t nIdx = nNew / m_nPageSize; | |||
420 | if( nIdx >= m_aPagesCache.size() ) | |||
421 | { | |||
422 | // Extend the FAT cache ! ... | |||
423 | size_t nToAdd = nIdx + 1; | |||
424 | ||||
425 | if (m_aPagesCache.empty()) | |||
426 | { | |||
427 | m_aPagesCache.push_back( m_nStart ); | |||
428 | assert(m_aUsedPageNumbers.empty())(static_cast <bool> (m_aUsedPageNumbers.empty()) ? void (0) : __assert_fail ("m_aUsedPageNumbers.empty()", "/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" , 428, __extension__ __PRETTY_FUNCTION__)); | |||
429 | m_aUsedPageNumbers.insert(m_nStart); | |||
430 | } | |||
431 | ||||
432 | nToAdd -= m_aPagesCache.size(); | |||
433 | ||||
434 | sal_Int32 nBgn = m_aPagesCache.back(); | |||
435 | ||||
436 | // Start adding pages while we can | |||
437 | while (nToAdd > 0 && nBgn >= 0) | |||
438 | { | |||
439 | sal_Int32 nOldBgn = nBgn; | |||
440 | nBgn = m_pFat->GetNextPage(nOldBgn); | |||
441 | if( nBgn >= 0 ) | |||
442 | { | |||
443 | //returned second is false if it already exists | |||
444 | if (!m_aUsedPageNumbers.insert(nBgn).second) | |||
445 | { | |||
446 | SAL_WARN ("sot", "Error: page number " << nBgn << " already in chain for stream")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Error: page number " << nBgn << " already in chain for stream" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot" ), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "446" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error: page number " << nBgn << " already in chain for stream"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error: page number " << nBgn << " already in chain for stream"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "446" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Error: page number " << nBgn << " already in chain for stream" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot" ), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "446" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Error: page number " << nBgn << " already in chain for stream"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Error: page number " << nBgn << " already in chain for stream"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "446" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
447 | break; | |||
448 | } | |||
449 | ||||
450 | //very much the normal case | |||
451 | m_aPagesCache.push_back(nBgn); | |||
452 | --nToAdd; | |||
453 | } | |||
454 | } | |||
455 | } | |||
456 | ||||
457 | if ( nIdx > m_aPagesCache.size() ) | |||
458 | { | |||
459 | SAL_WARN("sot", "seek to index " << nIdx <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()) == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()) == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
460 | " beyond page cache size " << m_aPagesCache.size())do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "sot")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()) == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()) == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size()), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "seek to index " << nIdx << " beyond page cache size " << m_aPagesCache.size(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sot"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "460" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
461 | // fdo#84229 - handle seek to end and back as eg. XclImpStream expects | |||
462 | m_nPage = STG_EOF-2L; | |||
463 | m_nOffset = 0; | |||
464 | // Intriguingly in the past we didn't reset nPos to match the real | |||
465 | // length of the stream thus: | |||
466 | // nIdx = m_aPagesCache.size(); | |||
467 | // nPos = nPageSize * nIdx; | |||
468 | // so retain this behavior for now. | |||
469 | m_bBytePosValid = false; | |||
470 | return false; | |||
471 | } | |||
472 | ||||
473 | // special case: seek to 1st byte of new, unallocated page | |||
474 | // (in case the file size is a multiple of the page size) | |||
475 | if( nBytePos == m_nSize && !m_nOffset && nIdx > 0 && nIdx == m_aPagesCache.size() ) | |||
476 | { | |||
477 | nIdx--; | |||
478 | m_nOffset = m_nPageSize; | |||
479 | } | |||
480 | else if ( nIdx == m_aPagesCache.size() ) | |||
481 | { | |||
482 | m_nPage = STG_EOF-2L; | |||
483 | m_bBytePosValid = false; | |||
484 | return false; | |||
485 | } | |||
486 | ||||
487 | m_nPage = m_aPagesCache[ nIdx ]; | |||
488 | ||||
489 | m_bBytePosValid = m_nPage >= 0; | |||
490 | return m_bBytePosValid; | |||
491 | } | |||
492 | ||||
493 | // Copy an entire stream. Both streams are allocated in the FAT. | |||
494 | // The target stream is this stream. | |||
495 | ||||
496 | bool StgStrm::Copy( sal_Int32 nFrom, sal_Int32 nBytes ) | |||
497 | { | |||
498 | if ( !m_pFat ) | |||
499 | return false; | |||
500 | ||||
501 | m_aPagesCache.clear(); | |||
502 | m_aUsedPageNumbers.clear(); | |||
503 | ||||
504 | sal_Int32 nTo = m_nStart; | |||
505 | sal_Int32 nPgs = ( nBytes + m_nPageSize - 1 ) / m_nPageSize; | |||
506 | while( nPgs-- ) | |||
507 | { | |||
508 | if( nTo < 0 ) | |||
509 | { | |||
510 | m_rIo.SetError( SVSTREAM_FILEFORMAT_ERRORErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) ); | |||
511 | return false; | |||
512 | } | |||
513 | m_rIo.Copy( nTo, nFrom ); | |||
514 | if( nFrom >= 0 ) | |||
515 | { | |||
516 | nFrom = m_pFat->GetNextPage( nFrom ); | |||
517 | if( nFrom < 0 ) | |||
518 | { | |||
519 | m_rIo.SetError( SVSTREAM_FILEFORMAT_ERRORErrCode( ErrCodeArea::Io, ErrCodeClass::Format, 21 ) ); | |||
520 | return false; | |||
521 | } | |||
522 | } | |||
523 | nTo = m_pFat->GetNextPage( nTo ); | |||
524 | } | |||
525 | return true; | |||
526 | } | |||
527 | ||||
528 | bool StgStrm::SetSize( sal_Int32 nBytes ) | |||
529 | { | |||
530 | if ( nBytes < 0 || !m_pFat ) | |||
531 | return false; | |||
532 | ||||
533 | m_aPagesCache.clear(); | |||
534 | m_aUsedPageNumbers.clear(); | |||
535 | ||||
536 | // round up to page size | |||
537 | sal_Int32 nOld = ( ( m_nSize + m_nPageSize - 1 ) / m_nPageSize ) * m_nPageSize; | |||
538 | sal_Int32 nNew = ( ( nBytes + m_nPageSize - 1 ) / m_nPageSize ) * m_nPageSize; | |||
539 | if( nNew > nOld ) | |||
540 | { | |||
541 | if( !Pos2Page( m_nSize ) ) | |||
542 | return false; | |||
543 | sal_Int32 nBgn = m_pFat->AllocPages( m_nPage, ( nNew - nOld ) / m_nPageSize ); | |||
544 | if( nBgn == STG_EOF-2L ) | |||
545 | return false; | |||
546 | if( m_nStart == STG_EOF-2L ) | |||
547 | m_nStart = m_nPage = nBgn; | |||
548 | } | |||
549 | else if( nNew < nOld ) | |||
550 | { | |||
551 | bool bAll = ( nBytes == 0 ); | |||
552 | if( !Pos2Page( nBytes ) || !m_pFat->FreePages( m_nPage, bAll ) ) | |||
553 | return false; | |||
554 | if( bAll ) | |||
555 | m_nStart = m_nPage = STG_EOF-2L; | |||
556 | } | |||
557 | if( m_pEntry ) | |||
558 | { | |||
559 | // change the dir entry? | |||
560 | if( !m_nSize || !nBytes ) | |||
561 | m_pEntry->m_aEntry.SetLeaf( STG_DATA, m_nStart ); | |||
562 | m_pEntry->m_aEntry.SetSize( nBytes ); | |||
563 | m_pEntry->SetDirty(); | |||
564 | } | |||
565 | m_nSize = nBytes; | |||
566 | m_pFat->SetLimit( GetPages() ); | |||
567 | return true; | |||
568 | } | |||
569 | ||||
570 | // Return the # of allocated pages | |||
571 | ||||
572 | ||||
573 | //////////////////////////// class StgFATStrm | |||
574 | ||||
575 | // The FAT stream class provides physical access to the master FAT. | |||
576 | // Since this access is implemented as a StgStrm, we can use the | |||
577 | // FAT allocator. | |||
578 | ||||
579 | StgFATStrm::StgFATStrm(StgIo& r, sal_Int32 nFatStrmSize) : StgStrm( r ) | |||
580 | { | |||
581 | m_pFat.reset( new StgFAT( *this, true ) ); | |||
582 | m_nSize = nFatStrmSize; | |||
583 | } | |||
584 | ||||
585 | bool StgFATStrm::Pos2Page( sal_Int32 nBytePos ) | |||
586 | { | |||
587 | // Values < 0 seek to the end | |||
588 | if( nBytePos < 0 || nBytePos >= m_nSize ) | |||
589 | nBytePos = m_nSize ? m_nSize - 1 : 0; | |||
590 | m_nPage = nBytePos / m_nPageSize; | |||
591 | m_nOffset = static_cast<short>( nBytePos % m_nPageSize ); | |||
592 | m_nPage = GetPage(m_nPage, false); | |||
593 | bool bValid = m_nPage >= 0; | |||
594 | SetPos(nBytePos, bValid); | |||
595 | return bValid; | |||
596 | } | |||
597 | ||||
598 | // Get the page number entry for the given page offset. | |||
599 | ||||
600 | sal_Int32 StgFATStrm::GetPage(sal_Int32 nOff, bool bMake, sal_uInt16 *pnMasterAlloc) | |||
601 | { | |||
602 | OSL_ENSURE( nOff >= 0, "The offset may not be negative!" )do { if (true && (!(nOff >= 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "602" ": "), "%s", "The offset may not be negative!"); } } while (false); | |||
603 | if( pnMasterAlloc ) *pnMasterAlloc = 0; | |||
604 | if( nOff < StgHeader::GetFAT1Size() ) | |||
605 | return m_rIo.m_aHdr.GetFATPage( nOff ); | |||
606 | sal_Int32 nMaxPage = m_nSize >> 2; | |||
607 | nOff = nOff - StgHeader::GetFAT1Size(); | |||
608 | // number of master pages that we need to iterate through | |||
609 | sal_uInt16 nMasterCount = ( m_nPageSize >> 2 ) - 1; | |||
610 | sal_uInt16 nBlocks = nOff / nMasterCount; | |||
611 | // offset in the last master page | |||
612 | nOff = nOff % nMasterCount; | |||
613 | ||||
614 | rtl::Reference< StgPage > pOldPage; | |||
615 | rtl::Reference< StgPage > pMaster; | |||
616 | sal_Int32 nFAT = m_rIo.m_aHdr.GetFATChain(); | |||
617 | for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ ) | |||
618 | { | |||
619 | if( nFAT == STG_EOF-2L || nFAT == STG_FREE-1L ) | |||
620 | { | |||
621 | if( bMake ) | |||
622 | { | |||
623 | m_aPagesCache.clear(); | |||
624 | m_aUsedPageNumbers.clear(); | |||
625 | ||||
626 | // create a new master page | |||
627 | nFAT = nMaxPage++; | |||
628 | pMaster = m_rIo.Copy( nFAT ); | |||
629 | if ( pMaster.is() ) | |||
630 | { | |||
631 | for( short k = 0; k < static_cast<short>( m_nPageSize >> 2 ); k++ ) | |||
632 | m_rIo.SetToPage( pMaster, k, STG_FREE-1L ); | |||
633 | // chaining | |||
634 | if( !pOldPage.is() ) | |||
635 | m_rIo.m_aHdr.SetFATChain( nFAT ); | |||
636 | else | |||
637 | m_rIo.SetToPage( pOldPage, nMasterCount, nFAT ); | |||
638 | if( nMaxPage >= m_rIo.GetPhysPages() ) | |||
639 | if( !m_rIo.SetSize( nMaxPage ) ) | |||
640 | return STG_EOF-2L; | |||
641 | // mark the page as used | |||
642 | // make space for Masterpage | |||
643 | if( !pnMasterAlloc ) // create space oneself | |||
644 | { | |||
645 | if( !Pos2Page( nFAT << 2 ) ) | |||
646 | return STG_EOF-2L; | |||
647 | rtl::Reference< StgPage > pPg = m_rIo.Get( m_nPage, true ); | |||
648 | if( !pPg.is() ) | |||
649 | return STG_EOF-2L; | |||
650 | m_rIo.SetToPage( pPg, m_nOffset >> 2, STG_MASTER-4L ); | |||
651 | } | |||
652 | else | |||
653 | (*pnMasterAlloc)++; | |||
654 | m_rIo.m_aHdr.SetMasters( nCount + 1 ); | |||
655 | pOldPage = pMaster; | |||
656 | } | |||
657 | } | |||
658 | } | |||
659 | else | |||
660 | { | |||
661 | pMaster = m_rIo.Get( nFAT, true ); | |||
662 | if ( pMaster.is() ) | |||
663 | { | |||
664 | nFAT = StgCache::GetFromPage( pMaster, nMasterCount ); | |||
665 | pOldPage = pMaster; | |||
666 | } | |||
667 | } | |||
668 | } | |||
669 | if( pMaster.is() ) | |||
670 | return StgCache::GetFromPage( pMaster, nOff ); | |||
671 | m_rIo.SetError( SVSTREAM_GENERALERRORErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) ); | |||
672 | return STG_EOF-2L; | |||
673 | } | |||
674 | ||||
675 | ||||
676 | // Set the page number entry for the given page offset. | |||
677 | ||||
678 | bool StgFATStrm::SetPage( short nOff, sal_Int32 nNewPage ) | |||
679 | { | |||
680 | OSL_ENSURE( nOff >= 0, "The offset may not be negative!" )do { if (true && (!(nOff >= 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "680" ": "), "%s", "The offset may not be negative!"); } } while (false); | |||
681 | m_aPagesCache.clear(); | |||
682 | m_aUsedPageNumbers.clear(); | |||
683 | ||||
684 | bool bRes = true; | |||
685 | if( nOff < StgHeader::GetFAT1Size() ) | |||
686 | m_rIo.m_aHdr.SetFATPage( nOff, nNewPage ); | |||
687 | else | |||
688 | { | |||
689 | nOff = nOff - StgHeader::GetFAT1Size(); | |||
690 | // number of master pages that we need to iterate through | |||
691 | sal_uInt16 nMasterCount = ( m_nPageSize >> 2 ) - 1; | |||
692 | sal_uInt16 nBlocks = nOff / nMasterCount; | |||
693 | // offset in the last master page | |||
694 | nOff = nOff % nMasterCount; | |||
695 | ||||
696 | rtl::Reference< StgPage > pMaster; | |||
697 | sal_Int32 nFAT = m_rIo.m_aHdr.GetFATChain(); | |||
698 | for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ ) | |||
699 | { | |||
700 | if( nFAT == STG_EOF-2L || nFAT == STG_FREE-1L ) | |||
701 | { | |||
702 | pMaster = nullptr; | |||
703 | break; | |||
704 | } | |||
705 | pMaster = m_rIo.Get( nFAT, true ); | |||
706 | if ( pMaster.is() ) | |||
707 | nFAT = StgCache::GetFromPage( pMaster, nMasterCount ); | |||
708 | } | |||
709 | if( pMaster.is() ) | |||
710 | m_rIo.SetToPage( pMaster, nOff, nNewPage ); | |||
711 | else | |||
712 | { | |||
713 | m_rIo.SetError( SVSTREAM_GENERALERRORErrCode( ErrCodeArea::Io, ErrCodeClass::General, 13 ) ); | |||
714 | bRes = false; | |||
715 | } | |||
716 | } | |||
717 | ||||
718 | // lock the page against access | |||
719 | if( bRes
| |||
720 | { | |||
721 | Pos2Page( nNewPage << 2 ); | |||
| ||||
722 | rtl::Reference< StgPage > pPg = m_rIo.Get( m_nPage, true ); | |||
723 | if( pPg.is() ) | |||
724 | m_rIo.SetToPage( pPg, m_nOffset >> 2, STG_FAT-3L ); | |||
725 | else | |||
726 | bRes = false; | |||
727 | } | |||
728 | return bRes; | |||
729 | } | |||
730 | ||||
731 | bool StgFATStrm::SetSize( sal_Int32 nBytes ) | |||
732 | { | |||
733 | if ( nBytes < 0 ) | |||
| ||||
734 | return false; | |||
735 | ||||
736 | m_aPagesCache.clear(); | |||
737 | m_aUsedPageNumbers.clear(); | |||
738 | ||||
739 | // Set the number of entries to a multiple of the page size | |||
740 | short nOld = static_cast<short>( ( m_nSize + ( m_nPageSize - 1 ) ) / m_nPageSize ); | |||
741 | short nNew = static_cast<short>( | |||
742 | ( nBytes + ( m_nPageSize - 1 ) ) / m_nPageSize ) ; | |||
743 | if( nNew < nOld ) | |||
744 | { | |||
745 | // release master pages | |||
746 | for( short i = nNew; i
| |||
747 | SetPage( i, STG_FREE-1L ); | |||
748 | } | |||
749 | else | |||
750 | { | |||
751 | while( nOld < nNew ) | |||
752 | { | |||
753 | // allocate master pages | |||
754 | // find a free master page slot | |||
755 | sal_Int32 nPg = 0; | |||
756 | sal_uInt16 nMasterAlloc = 0; | |||
757 | nPg = GetPage( nOld, true, &nMasterAlloc ); | |||
758 | if( nPg == STG_EOF-2L ) | |||
759 | return false; | |||
760 | // 4 Bytes have been used for Allocation of each MegaMasterPage | |||
761 | nBytes += nMasterAlloc << 2; | |||
762 | ||||
763 | // find a free page using the FAT allocator | |||
764 | sal_Int32 n = 1; | |||
765 | OSL_ENSURE( m_pFat, "The pointer is always initializer here!" )do { if (true && (!(m_pFat))) { sal_detail_logFormat( (SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "765" ": "), "%s", "The pointer is always initializer here!" ); } } while (false); | |||
766 | sal_Int32 nNewPage = m_pFat->FindBlock( n ); | |||
767 | if( nNewPage == STG_EOF-2L ) | |||
768 | { | |||
769 | // no free pages found; create a new page | |||
770 | // Since all pages are allocated, extend | |||
771 | // the file size for the next page! | |||
772 | nNewPage = m_nSize >> 2; | |||
773 | // if a MegaMasterPage was created avoid taking | |||
774 | // the same Page | |||
775 | nNewPage += nMasterAlloc; | |||
776 | // adjust the file size if necessary | |||
777 | if( nNewPage >= m_rIo.GetPhysPages() ) | |||
778 | if( !m_rIo.SetSize( nNewPage + 1 ) ) | |||
779 | return false; | |||
780 | } | |||
781 | // Set up the page with empty entries | |||
782 | rtl::Reference< StgPage > pPg = m_rIo.Copy( nNewPage ); | |||
783 | if ( !pPg.is() ) | |||
784 | return false; | |||
785 | for( short j = 0; j < static_cast<short>( m_nPageSize >> 2 ); j++ ) | |||
786 | m_rIo.SetToPage( pPg, j, STG_FREE-1L ); | |||
787 | ||||
788 | // store the page number into the master FAT | |||
789 | // Set the size before so the correct FAT can be found | |||
790 | m_nSize = ( nOld + 1 ) * m_nPageSize; | |||
791 | SetPage( nOld, nNewPage ); | |||
792 | ||||
793 | // MegaMasterPages were created, mark it them as used | |||
794 | ||||
795 | sal_uInt32 nMax = m_rIo.m_aHdr.GetMasters( ); | |||
796 | sal_uInt32 nFAT = m_rIo.m_aHdr.GetFATChain(); | |||
797 | if( nMasterAlloc ) | |||
798 | for( sal_uInt32 nCount = 0; nCount < nMax; nCount++ ) | |||
799 | { | |||
800 | if( !Pos2Page( nFAT << 2 ) ) | |||
801 | return false; | |||
802 | if( nMax - nCount <= nMasterAlloc ) | |||
803 | { | |||
804 | rtl::Reference< StgPage > piPg = m_rIo.Get( m_nPage, true ); | |||
805 | if( !piPg.is() ) | |||
806 | return false; | |||
807 | m_rIo.SetToPage( piPg, m_nOffset >> 2, STG_MASTER-4L ); | |||
808 | } | |||
809 | rtl::Reference< StgPage > pPage = m_rIo.Get( nFAT, true ); | |||
810 | if( !pPage.is() ) return false; | |||
811 | nFAT = StgCache::GetFromPage( pPage, (m_nPageSize >> 2 ) - 1 ); | |||
812 | } | |||
813 | ||||
814 | nOld++; | |||
815 | // We have used up 4 bytes for the STG_FAT entry | |||
816 | nBytes += 4; | |||
817 | nNew = static_cast<short>( | |||
818 | ( nBytes + ( m_nPageSize - 1 ) ) / m_nPageSize ); | |||
819 | } | |||
820 | } | |||
821 | m_nSize = nNew * m_nPageSize; | |||
822 | m_rIo.m_aHdr.SetFATSize( nNew ); | |||
823 | return true; | |||
824 | } | |||
825 | ||||
826 | /////////////////////////// class StgDataStrm | |||
827 | ||||
828 | // This class is a normal physical stream which can be initialized | |||
829 | // either with an existing dir entry or an existing FAT chain. | |||
830 | // The stream has a size increment which normally is 1, but which can be | |||
831 | // set to any value is you want the size to be incremented by certain values. | |||
832 | ||||
833 | StgDataStrm::StgDataStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r ) | |||
834 | { | |||
835 | Init( nBgn, nLen ); | |||
836 | } | |||
837 | ||||
838 | StgDataStrm::StgDataStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r ) | |||
839 | { | |||
840 | m_pEntry = &p; | |||
841 | Init( p.m_aEntry.GetLeaf( STG_DATA ), | |||
842 | p.m_aEntry.GetSize() ); | |||
843 | } | |||
844 | ||||
845 | void StgDataStrm::Init( sal_Int32 nBgn, sal_Int32 nLen ) | |||
846 | { | |||
847 | if ( m_rIo.m_pFAT ) | |||
848 | m_pFat.reset( new StgFAT( *m_rIo.m_pFAT, true ) ); | |||
849 | ||||
850 | OSL_ENSURE( m_pFat, "The pointer should not be empty!" )do { if (true && (!(m_pFat))) { sal_detail_logFormat( (SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "850" ": "), "%s", "The pointer should not be empty!"); } } while (false); | |||
851 | ||||
852 | m_nStart = m_nPage = nBgn; | |||
853 | m_nSize = nLen; | |||
854 | m_nIncr = 1; | |||
855 | m_nOffset = 0; | |||
856 | if( nLen < 0 && m_pFat ) | |||
857 | { | |||
858 | // determine the actual size of the stream by scanning | |||
859 | // the FAT chain and counting the # of pages allocated | |||
860 | m_nSize = scanBuildPageChainCache(); | |||
861 | } | |||
862 | } | |||
863 | ||||
864 | // Set the size of a physical stream. | |||
865 | ||||
866 | bool StgDataStrm::SetSize( sal_Int32 nBytes ) | |||
867 | { | |||
868 | if ( !m_pFat ) | |||
869 | return false; | |||
870 | ||||
871 | nBytes = ( ( nBytes + m_nIncr - 1 ) / m_nIncr ) * m_nIncr; | |||
872 | sal_Int32 nOldSz = m_nSize; | |||
873 | if( nOldSz != nBytes ) | |||
874 | { | |||
875 | if( !StgStrm::SetSize( nBytes ) ) | |||
876 | return false; | |||
877 | sal_Int32 nMaxPage = m_pFat->GetMaxPage(); | |||
878 | if( nMaxPage > m_rIo.GetPhysPages() ) | |||
879 | if( !m_rIo.SetSize( nMaxPage ) ) | |||
880 | return false; | |||
881 | // If we only allocated one page or less, create this | |||
882 | // page in the cache for faster throughput. The current | |||
883 | // position is the former EOF point. | |||
884 | if( ( m_nSize - 1 ) / m_nPageSize - ( nOldSz - 1 ) / m_nPageSize == 1 ) | |||
885 | { | |||
886 | Pos2Page( nBytes ); | |||
887 | if( m_nPage >= 0 ) | |||
888 | m_rIo.Copy( m_nPage ); | |||
889 | } | |||
890 | } | |||
891 | return true; | |||
892 | } | |||
893 | ||||
894 | // Get the address of the data byte at a specified offset. | |||
895 | // If bForce = true, a read of non-existent data causes | |||
896 | // a read fault. | |||
897 | ||||
898 | void* StgDataStrm::GetPtr( sal_Int32 Pos, bool bDirty ) | |||
899 | { | |||
900 | if( Pos2Page( Pos ) ) | |||
901 | { | |||
902 | rtl::Reference< StgPage > pPg = m_rIo.Get( m_nPage, true/*bForce*/ ); | |||
903 | if (pPg.is() && m_nOffset < pPg->GetSize()) | |||
904 | { | |||
905 | if( bDirty ) | |||
906 | m_rIo.SetDirty( pPg ); | |||
907 | return static_cast<sal_uInt8 *>(pPg->GetData()) + m_nOffset; | |||
908 | } | |||
909 | } | |||
910 | return nullptr; | |||
911 | } | |||
912 | ||||
913 | // This could easily be adapted to a better algorithm by determining | |||
914 | // the amount of consecutable blocks before doing a read. The result | |||
915 | // is the number of bytes read. No error is generated on EOF. | |||
916 | ||||
917 | sal_Int32 StgDataStrm::Read( void* pBuf, sal_Int32 n ) | |||
918 | { | |||
919 | if ( n < 0 ) | |||
920 | return 0; | |||
921 | ||||
922 | const auto nAvailable = m_nSize - GetPos(); | |||
923 | if (n > nAvailable) | |||
924 | n = nAvailable; | |||
925 | sal_Int32 nDone = 0; | |||
926 | while( n ) | |||
927 | { | |||
928 | short nBytes = m_nPageSize - m_nOffset; | |||
929 | rtl::Reference< StgPage > pPg; | |||
930 | if( static_cast<sal_Int32>(nBytes) > n ) | |||
931 | nBytes = static_cast<short>(n); | |||
932 | if( nBytes ) | |||
933 | { | |||
934 | short nRes; | |||
935 | void *p = static_cast<sal_uInt8 *>(pBuf) + nDone; | |||
936 | if( nBytes == m_nPageSize ) | |||
937 | { | |||
938 | pPg = m_rIo.Find( m_nPage ); | |||
939 | if( pPg.is() ) | |||
940 | { | |||
941 | // data is present, so use the cached data | |||
942 | memcpy( p, pPg->GetData(), nBytes ); | |||
943 | nRes = nBytes; | |||
944 | } | |||
945 | else | |||
946 | // do a direct (unbuffered) read | |||
947 | nRes = static_cast<short>(m_rIo.Read( m_nPage, p )) * m_nPageSize; | |||
948 | } | |||
949 | else | |||
950 | { | |||
951 | // partial block read through the cache. | |||
952 | pPg = m_rIo.Get( m_nPage, false ); | |||
953 | if( !pPg.is() ) | |||
954 | break; | |||
955 | memcpy( p, static_cast<sal_uInt8*>(pPg->GetData()) + m_nOffset, nBytes ); | |||
956 | nRes = nBytes; | |||
957 | } | |||
958 | nDone += nRes; | |||
959 | SetPos(GetPos() + nRes, true); | |||
960 | n -= nRes; | |||
961 | m_nOffset = m_nOffset + nRes; | |||
962 | if( nRes != nBytes ) | |||
963 | break; // read error or EOF | |||
964 | } | |||
965 | // Switch to next page if necessary | |||
966 | if (m_nOffset >= m_nPageSize && !Pos2Page(GetPos())) | |||
967 | break; | |||
968 | } | |||
969 | return nDone; | |||
970 | } | |||
971 | ||||
972 | sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n ) | |||
973 | { | |||
974 | if ( n < 0 ) | |||
975 | return 0; | |||
976 | ||||
977 | sal_Int32 nDone = 0; | |||
978 | if( ( GetPos() + n ) > m_nSize ) | |||
979 | { | |||
980 | sal_Int32 nOld = GetPos(); | |||
981 | if( !SetSize( nOld + n ) ) | |||
982 | return 0; | |||
983 | Pos2Page( nOld ); | |||
984 | } | |||
985 | while( n ) | |||
986 | { | |||
987 | short nBytes = m_nPageSize - m_nOffset; | |||
988 | rtl::Reference< StgPage > pPg; | |||
989 | if( static_cast<sal_Int32>(nBytes) > n ) | |||
990 | nBytes = static_cast<short>(n); | |||
991 | if( nBytes ) | |||
992 | { | |||
993 | short nRes; | |||
994 | const void *p = static_cast<const sal_uInt8 *>(pBuf) + nDone; | |||
995 | if( nBytes == m_nPageSize ) | |||
996 | { | |||
997 | pPg = m_rIo.Find( m_nPage ); | |||
998 | if( pPg.is() ) | |||
999 | { | |||
1000 | // data is present, so use the cached data | |||
1001 | memcpy( pPg->GetData(), p, nBytes ); | |||
1002 | m_rIo.SetDirty( pPg ); | |||
1003 | nRes = nBytes; | |||
1004 | } | |||
1005 | else | |||
1006 | // do a direct (unbuffered) write | |||
1007 | nRes = static_cast<short>(m_rIo.Write( m_nPage, p )) * m_nPageSize; | |||
1008 | } | |||
1009 | else | |||
1010 | { | |||
1011 | // partial block read through the cache. | |||
1012 | pPg = m_rIo.Get( m_nPage, false ); | |||
1013 | if( !pPg.is() ) | |||
1014 | break; | |||
1015 | memcpy( static_cast<sal_uInt8*>(pPg->GetData()) + m_nOffset, p, nBytes ); | |||
1016 | m_rIo.SetDirty( pPg ); | |||
1017 | nRes = nBytes; | |||
1018 | } | |||
1019 | nDone += nRes; | |||
1020 | SetPos(GetPos() + nRes, true); | |||
1021 | n -= nRes; | |||
1022 | m_nOffset = m_nOffset + nRes; | |||
1023 | if( nRes != nBytes ) | |||
1024 | break; // read error | |||
1025 | } | |||
1026 | // Switch to next page if necessary | |||
1027 | if( m_nOffset >= m_nPageSize && !Pos2Page(GetPos()) ) | |||
1028 | break; | |||
1029 | } | |||
1030 | return nDone; | |||
1031 | } | |||
1032 | ||||
1033 | //////////////////////////// class StgSmallStream | |||
1034 | ||||
1035 | // The small stream class provides access to streams with a size < 4096 bytes. | |||
1036 | // This stream is a StgStream containing small pages. The FAT for this stream | |||
1037 | // is also a StgStream. The start of the FAT is in the header at DataRootPage, | |||
1038 | // the stream itself is pointed to by the root entry (it holds start & size). | |||
1039 | ||||
1040 | StgSmallStrm::StgSmallStrm( StgIo& r, sal_Int32 nBgn ) : StgStrm( r ) | |||
1041 | { | |||
1042 | Init( nBgn, 0 ); | |||
1043 | } | |||
1044 | ||||
1045 | StgSmallStrm::StgSmallStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r ) | |||
1046 | { | |||
1047 | m_pEntry = &p; | |||
1048 | Init( p.m_aEntry.GetLeaf( STG_DATA ), | |||
1049 | p.m_aEntry.GetSize() ); | |||
1050 | } | |||
1051 | ||||
1052 | void StgSmallStrm::Init( sal_Int32 nBgn, sal_Int32 nLen ) | |||
1053 | { | |||
1054 | if ( m_rIo.m_pDataFAT ) | |||
1055 | m_pFat.reset( new StgFAT( *m_rIo.m_pDataFAT, false ) ); | |||
1056 | m_pData = m_rIo.m_pDataStrm; | |||
1057 | OSL_ENSURE( m_pFat && m_pData, "The pointers should not be empty!" )do { if (true && (!(m_pFat && m_pData))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" ":" "1057" ": "), "%s", "The pointers should not be empty!") ; } } while (false); | |||
1058 | ||||
1059 | m_nPageSize = m_rIo.GetDataPageSize(); | |||
1060 | m_nStart = | |||
1061 | m_nPage = nBgn; | |||
1062 | m_nSize = nLen; | |||
1063 | } | |||
1064 | ||||
1065 | // This could easily be adapted to a better algorithm by determining | |||
1066 | // the amount of consecutable blocks before doing a read. The result | |||
1067 | // is the number of bytes read. No error is generated on EOF. | |||
1068 | ||||
1069 | sal_Int32 StgSmallStrm::Read( void* pBuf, sal_Int32 n ) | |||
1070 | { | |||
1071 | // We can safely assume that reads are not huge, since the | |||
1072 | // small stream is likely to be < 64 KBytes. | |||
1073 | sal_Int32 nBytePos = GetPos(); | |||
1074 | if( ( nBytePos + n ) > m_nSize ) | |||
1075 | n = m_nSize - nBytePos; | |||
1076 | sal_Int32 nDone = 0; | |||
1077 | while( n ) | |||
1078 | { | |||
1079 | short nBytes = m_nPageSize - m_nOffset; | |||
1080 | if( static_cast<sal_Int32>(nBytes) > n ) | |||
1081 | nBytes = static_cast<short>(n); | |||
1082 | if( nBytes ) | |||
1083 | { | |||
1084 | if (!m_pData) | |||
1085 | break; | |||
1086 | sal_Int32 nPos; | |||
1087 | if (o3tl::checked_multiply<sal_Int32>(m_nPage, m_nPageSize, nPos)) | |||
1088 | break; | |||
1089 | if (!m_pData->Pos2Page(nPos + m_nOffset)) | |||
1090 | break; | |||
1091 | // all reading through the stream | |||
1092 | short nRes = static_cast<short>(m_pData->Read( static_cast<sal_uInt8*>(pBuf) + nDone, nBytes )); | |||
1093 | nDone += nRes; | |||
1094 | SetPos(GetPos() + nRes, true); | |||
1095 | n -= nRes; | |||
1096 | m_nOffset = m_nOffset + nRes; | |||
1097 | // read problem? | |||
1098 | if( nRes != nBytes ) | |||
1099 | break; | |||
1100 | } | |||
1101 | // Switch to next page if necessary | |||
1102 | if (m_nOffset >= m_nPageSize && !Pos2Page(GetPos())) | |||
1103 | break; | |||
1104 | } | |||
1105 | return nDone; | |||
1106 | } | |||
1107 | ||||
1108 | sal_Int32 StgSmallStrm::Write( const void* pBuf, sal_Int32 n ) | |||
1109 | { | |||
1110 | // you can safely assume that reads are not huge, since the | |||
1111 | // small stream is likely to be < 64 KBytes. | |||
1112 | sal_Int32 nDone = 0; | |||
1113 | sal_Int32 nOldPos = GetPos(); | |||
1114 | if( ( nOldPos + n ) > m_nSize ) | |||
1115 | { | |||
1116 | if (!SetSize(nOldPos + n)) | |||
1117 | return 0; | |||
1118 | Pos2Page(nOldPos); | |||
1119 | } | |||
1120 | while( n ) | |||
1121 | { | |||
1122 | short nBytes = m_nPageSize - m_nOffset; | |||
1123 | if( static_cast<sal_Int32>(nBytes) > n ) | |||
1124 | nBytes = static_cast<short>(n); | |||
1125 | if( nBytes ) | |||
1126 | { | |||
1127 | // all writing goes through the stream | |||
1128 | sal_Int32 nDataPos = m_nPage * m_nPageSize + m_nOffset; | |||
1129 | if ( !m_pData | |||
1130 | || ( m_pData->GetSize() < ( nDataPos + nBytes ) | |||
1131 | && !m_pData->SetSize( nDataPos + nBytes ) ) ) | |||
1132 | break; | |||
1133 | if( !m_pData->Pos2Page( nDataPos ) ) | |||
1134 | break; | |||
1135 | short nRes = static_cast<short>(m_pData->Write( static_cast<sal_uInt8 const *>(pBuf) + nDone, nBytes )); | |||
1136 | nDone += nRes; | |||
1137 | SetPos(GetPos() + nRes, true); | |||
1138 | n -= nRes; | |||
1139 | m_nOffset = m_nOffset + nRes; | |||
1140 | // write problem? | |||
1141 | if( nRes != nBytes ) | |||
1142 | break; | |||
1143 | } | |||
1144 | // Switch to next page if necessary | |||
1145 | if( m_nOffset >= m_nPageSize && !Pos2Page(GetPos()) ) | |||
1146 | break; | |||
1147 | } | |||
1148 | return nDone; | |||
1149 | } | |||
1150 | ||||
1151 | /////////////////////////// class StgTmpStrm | |||
1152 | ||||
1153 | // The temporary stream uses a memory stream if < 32K, otherwise a | |||
1154 | // temporary file. | |||
1155 | ||||
1156 | #define THRESHOLD32768L 32768L | |||
1157 | ||||
1158 | StgTmpStrm::StgTmpStrm( sal_uInt64 nInitSize ) | |||
1159 | : SvMemoryStream( nInitSize > THRESHOLD32768L | |||
1160 | ? 16 | |||
1161 | : ( nInitSize ? nInitSize : 16 ), 4096 ) | |||
1162 | { | |||
1163 | m_pStrm = nullptr; | |||
1164 | // this calls FlushData, so all members should be set by this time | |||
1165 | SetBufferSize( 0 ); | |||
1166 | if( nInitSize > THRESHOLD32768L ) | |||
1167 | SetSize( nInitSize ); | |||
1168 | } | |||
1169 | ||||
1170 | bool StgTmpStrm::Copy( StgTmpStrm& rSrc ) | |||
1171 | { | |||
1172 | sal_uInt64 n = rSrc.GetSize(); | |||
1173 | const sal_uInt64 nCur = rSrc.Tell(); | |||
1174 | SetSize( n ); | |||
1175 | if( GetError() == ERRCODE_NONEErrCode(0) ) | |||
1176 | { | |||
1177 | std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]); | |||
1178 | rSrc.Seek( 0 ); | |||
1179 | Seek( 0 ); | |||
1180 | while( n ) | |||
1181 | { | |||
1182 | const sal_uInt64 nn = std::min<sal_uInt64>(n, 4096); | |||
1183 | if (rSrc.ReadBytes( p.get(), nn ) != nn) | |||
1184 | break; | |||
1185 | if (WriteBytes( p.get(), nn ) != nn) | |||
1186 | break; | |||
1187 | n -= nn; | |||
1188 | } | |||
1189 | p.reset(); | |||
1190 | rSrc.Seek( nCur ); | |||
1191 | Seek( nCur ); | |||
1192 | return n == 0; | |||
1193 | } | |||
1194 | else | |||
1195 | return false; | |||
1196 | } | |||
1197 | ||||
1198 | StgTmpStrm::~StgTmpStrm() | |||
1199 | { | |||
1200 | if( m_pStrm ) | |||
1201 | { | |||
1202 | m_pStrm->Close(); | |||
1203 | osl::File::remove( m_aName ); | |||
1204 | delete m_pStrm; | |||
1205 | } | |||
1206 | } | |||
1207 | ||||
1208 | sal_uInt64 StgTmpStrm::GetSize() const | |||
1209 | { | |||
1210 | sal_uInt64 n; | |||
1211 | if( m_pStrm ) | |||
1212 | { | |||
1213 | n = m_pStrm->TellEnd(); | |||
1214 | } | |||
1215 | else | |||
1216 | n = nEndOfData; | |||
1217 | return n; | |||
1218 | } | |||
1219 | ||||
1220 | void StgTmpStrm::SetSize(sal_uInt64 n) | |||
1221 | { | |||
1222 | if( m_pStrm ) | |||
1223 | m_pStrm->SetStreamSize( n ); | |||
1224 | else | |||
1225 | { | |||
1226 | if( n > THRESHOLD32768L ) | |||
1227 | { | |||
1228 | m_aName = utl::TempFile(nullptr, false).GetURL(); | |||
1229 | std::unique_ptr<SvFileStream> s(new SvFileStream( m_aName, StreamMode::READWRITE )); | |||
1230 | const sal_uInt64 nCur = Tell(); | |||
1231 | sal_uInt64 i = nEndOfData; | |||
1232 | std::unique_ptr<sal_uInt8[]> p(new sal_uInt8[ 4096 ]); | |||
1233 | if( i ) | |||
1234 | { | |||
1235 | Seek( 0 ); | |||
1236 | while( i ) | |||
1237 | { | |||
1238 | const sal_uInt64 nb = std::min<sal_uInt64>(i, 4096); | |||
1239 | if (ReadBytes(p.get(), nb) == nb | |||
1240 | && s->WriteBytes(p.get(), nb) == nb) | |||
1241 | i -= nb; | |||
1242 | else | |||
1243 | break; | |||
1244 | } | |||
1245 | } | |||
1246 | if( !i && n > nEndOfData ) | |||
1247 | { | |||
1248 | // We have to write one byte at the end of the file | |||
1249 | // if the file is bigger than the memstream to see | |||
1250 | // if it fits on disk | |||
1251 | s->Seek(nEndOfData); | |||
1252 | memset(p.get(), 0x00, 4096); | |||
1253 | i = n - nEndOfData; | |||
1254 | while (i) | |||
1255 | { | |||
1256 | const sal_uInt64 nb = std::min<sal_uInt64>(i, 4096); | |||
1257 | if (s->WriteBytes(p.get(), nb) == nb) | |||
1258 | i -= nb; | |||
1259 | else | |||
1260 | break; // error | |||
1261 | } | |||
1262 | s->Flush(); | |||
1263 | if( s->GetError() != ERRCODE_NONEErrCode(0) ) | |||
1264 | i = 1; | |||
1265 | } | |||
1266 | Seek( nCur ); | |||
1267 | s->Seek( nCur ); | |||
1268 | if( i ) | |||
1269 | { | |||
1270 | SetError( s->GetError() ); | |||
1271 | return; | |||
1272 | } | |||
1273 | m_pStrm = s.release(); | |||
1274 | // Shrink the memory to 16 bytes, which seems to be the minimum | |||
1275 | ReAllocateMemory( - ( static_cast<long>(nEndOfData) - 16 ) ); | |||
1276 | } | |||
1277 | else | |||
1278 | { | |||
1279 | if( n > nEndOfData ) | |||
1280 | { | |||
1281 | SvMemoryStream::SetSize(n); | |||
1282 | } | |||
1283 | else | |||
1284 | nEndOfData = n; | |||
1285 | } | |||
1286 | } | |||
1287 | } | |||
1288 | ||||
1289 | std::size_t StgTmpStrm::GetData( void* pData, std::size_t n ) | |||
1290 | { | |||
1291 | if( m_pStrm ) | |||
1292 | { | |||
1293 | n = m_pStrm->ReadBytes( pData, n ); | |||
1294 | SetError( m_pStrm->GetError() ); | |||
1295 | return n; | |||
1296 | } | |||
1297 | else | |||
1298 | return SvMemoryStream::GetData( pData, n ); | |||
1299 | } | |||
1300 | ||||
1301 | std::size_t StgTmpStrm::PutData( const void* pData, std::size_t n ) | |||
1302 | { | |||
1303 | sal_uInt32 nCur = Tell(); | |||
1304 | sal_uInt32 nNew = nCur + n; | |||
1305 | if( nNew > THRESHOLD32768L && !m_pStrm ) | |||
1306 | { | |||
1307 | SetSize( nNew ); | |||
1308 | if( GetError() != ERRCODE_NONEErrCode(0) ) | |||
1309 | return 0; | |||
1310 | } | |||
1311 | if( m_pStrm ) | |||
1312 | { | |||
1313 | nNew = m_pStrm->WriteBytes( pData, n ); | |||
1314 | SetError( m_pStrm->GetError() ); | |||
1315 | } | |||
1316 | else | |||
1317 | nNew = SvMemoryStream::PutData( pData, n ); | |||
1318 | return nNew; | |||
1319 | } | |||
1320 | ||||
1321 | sal_uInt64 StgTmpStrm::SeekPos(sal_uInt64 n) | |||
1322 | { | |||
1323 | // check if a truncated STREAM_SEEK_TO_END was passed | |||
1324 | assert(n != SAL_MAX_UINT32)(static_cast <bool> (n != ((sal_uInt32) 0xFFFFFFFF)) ? void (0) : __assert_fail ("n != SAL_MAX_UINT32", "/home/maarten/src/libreoffice/core/sot/source/sdstor/stgstrms.cxx" , 1324, __extension__ __PRETTY_FUNCTION__)); | |||
1325 | if( n == STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) ) | |||
1326 | n = GetSize(); | |||
1327 | if( n > THRESHOLD32768L && !m_pStrm ) | |||
1328 | { | |||
1329 | SetSize( n ); | |||
1330 | if( GetError() != ERRCODE_NONEErrCode(0) ) | |||
1331 | return Tell(); | |||
1332 | else | |||
1333 | return n; | |||
1334 | } | |||
1335 | else if( m_pStrm ) | |||
1336 | { | |||
1337 | n = m_pStrm->Seek( n ); | |||
1338 | SetError( m_pStrm->GetError() ); | |||
1339 | return n; | |||
1340 | } | |||
1341 | else | |||
1342 | return SvMemoryStream::SeekPos( n ); | |||
1343 | } | |||
1344 | ||||
1345 | void StgTmpStrm::FlushData() | |||
1346 | { | |||
1347 | if( m_pStrm ) | |||
1348 | { | |||
1349 | m_pStrm->Flush(); | |||
1350 | SetError( m_pStrm->GetError() ); | |||
1351 | } | |||
1352 | else | |||
1353 | SvMemoryStream::FlushData(); | |||
1354 | } | |||
1355 | ||||
1356 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |