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 #if defined(_MSC_VER) && (_MSC_VER<1200)
28cdf0e10cSrcweir #include <tools/presys.h>
29cdf0e10cSrcweir #endif
30cdf0e10cSrcweir #include <hash_map>
31cdf0e10cSrcweir #if defined(_MSC_VER) && (_MSC_VER<1200)
32cdf0e10cSrcweir #include <tools/postsys.h>
33cdf0e10cSrcweir #endif
34cdf0e10cSrcweir #include <vos/macros.hxx>
35cdf0e10cSrcweir
36cdf0e10cSrcweir #include <string.h>
37cdf0e10cSrcweir #include <osl/endian.h>
38cdf0e10cSrcweir #include <tools/string.hxx>
39cdf0e10cSrcweir
40cdf0e10cSrcweir #include "sot/stg.hxx"
41cdf0e10cSrcweir #include "stgelem.hxx"
42cdf0e10cSrcweir #include "stgcache.hxx"
43cdf0e10cSrcweir #include "stgstrms.hxx"
44cdf0e10cSrcweir #include "stgdir.hxx"
45cdf0e10cSrcweir #include "stgio.hxx"
46cdf0e10cSrcweir
47cdf0e10cSrcweir /*************************************************************************/
48cdf0e10cSrcweir //-----------------------------------------------------------------------------
49cdf0e10cSrcweir typedef std::hash_map
50cdf0e10cSrcweir <
51cdf0e10cSrcweir sal_Int32,
52cdf0e10cSrcweir StgPage *,
53cdf0e10cSrcweir std::hash< sal_Int32 >,
54cdf0e10cSrcweir NAMESPACE_STD(equal_to)< sal_Int32 >
55cdf0e10cSrcweir > UsrStgPagePtr_Impl;
56cdf0e10cSrcweir #ifdef _MSC_VER
57cdf0e10cSrcweir #pragma warning( disable: 4786 )
58cdf0e10cSrcweir #endif
59cdf0e10cSrcweir
60cdf0e10cSrcweir //#define CHECK_DIRTY 1
61cdf0e10cSrcweir //#define READ_AFTER_WRITE 1
62cdf0e10cSrcweir
63cdf0e10cSrcweir ////////////////////////////// class StgPage /////////////////////////////
64cdf0e10cSrcweir // This class implements buffer functionality. The cache will always return
65cdf0e10cSrcweir // a page buffer, even if a read fails. It is up to the caller to determine
66cdf0e10cSrcweir // the correctness of the I/O.
67cdf0e10cSrcweir
StgPage(StgCache * p,short n)68cdf0e10cSrcweir StgPage::StgPage( StgCache* p, short n )
69cdf0e10cSrcweir {
70*297a844aSArmin Le Grand OSL_ENSURE( n >= 512, "Unexpected page size is provided!" );
71cdf0e10cSrcweir pCache = p;
72cdf0e10cSrcweir nData = n;
73cdf0e10cSrcweir bDirty = sal_False;
74cdf0e10cSrcweir nPage = 0;
75cdf0e10cSrcweir pData = new sal_uInt8[ nData ];
76cdf0e10cSrcweir pNext1 =
77cdf0e10cSrcweir pNext2 =
78cdf0e10cSrcweir pLast1 =
79cdf0e10cSrcweir pLast2 = NULL;
80cdf0e10cSrcweir pOwner = NULL;
81cdf0e10cSrcweir }
82cdf0e10cSrcweir
~StgPage()83cdf0e10cSrcweir StgPage::~StgPage()
84cdf0e10cSrcweir {
85cdf0e10cSrcweir delete [] pData;
86cdf0e10cSrcweir }
87cdf0e10cSrcweir
SetPage(short nOff,sal_Int32 nVal)88cdf0e10cSrcweir void StgPage::SetPage( short nOff, sal_Int32 nVal )
89cdf0e10cSrcweir {
90cdf0e10cSrcweir if( ( nOff < (short) ( nData / sizeof( sal_Int32 ) ) ) && nOff >= 0 )
91cdf0e10cSrcweir {
92cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
93cdf0e10cSrcweir nVal = SWAPLONG(nVal);
94cdf0e10cSrcweir #endif
95cdf0e10cSrcweir ((sal_Int32*) pData )[ nOff ] = nVal;
96cdf0e10cSrcweir bDirty = sal_True;
97cdf0e10cSrcweir }
98cdf0e10cSrcweir }
99cdf0e10cSrcweir
100cdf0e10cSrcweir //////////////////////////////// class StgCache ////////////////////////////
101cdf0e10cSrcweir
102cdf0e10cSrcweir // The disk cache holds the cached sectors. The sector type differ according
103cdf0e10cSrcweir // to their purpose.
104cdf0e10cSrcweir
lcl_GetPageCount(sal_uLong nFileSize,short nPageSize)105cdf0e10cSrcweir sal_Int32 lcl_GetPageCount( sal_uLong nFileSize, short nPageSize )
106cdf0e10cSrcweir {
107cdf0e10cSrcweir // return (nFileSize >= 512) ? (nFileSize - 512) / nPageSize : 0;
108cdf0e10cSrcweir // #i61980# reallife: last page may be incomplete, return number of *started* pages
109cdf0e10cSrcweir return (nFileSize >= 512) ? (nFileSize - 512 + nPageSize - 1) / nPageSize : 0;
110cdf0e10cSrcweir }
111cdf0e10cSrcweir
StgCache()112cdf0e10cSrcweir StgCache::StgCache()
113cdf0e10cSrcweir {
114cdf0e10cSrcweir nRef = 0;
115cdf0e10cSrcweir pStrm = NULL;
116cdf0e10cSrcweir pCur = pElem1 = NULL;
117cdf0e10cSrcweir nPageSize = 512;
118cdf0e10cSrcweir nError = SVSTREAM_OK;
119cdf0e10cSrcweir bMyStream = sal_False;
120cdf0e10cSrcweir bFile = sal_False;
121cdf0e10cSrcweir pLRUCache = NULL;
122cdf0e10cSrcweir pStorageStream = NULL;
123cdf0e10cSrcweir }
124cdf0e10cSrcweir
~StgCache()125cdf0e10cSrcweir StgCache::~StgCache()
126cdf0e10cSrcweir {
127cdf0e10cSrcweir Clear();
128cdf0e10cSrcweir SetStrm( NULL, sal_False );
129cdf0e10cSrcweir delete (UsrStgPagePtr_Impl*)pLRUCache;
130cdf0e10cSrcweir }
131cdf0e10cSrcweir
SetPhysPageSize(short n)132cdf0e10cSrcweir void StgCache::SetPhysPageSize( short n )
133cdf0e10cSrcweir {
134*297a844aSArmin Le Grand OSL_ENSURE( n >= 512, "Unexpecte page size is provided!" );
135*297a844aSArmin Le Grand if ( n >= 512 )
136*297a844aSArmin Le Grand {
137*297a844aSArmin Le Grand nPageSize = n;
138*297a844aSArmin Le Grand sal_uLong nPos = pStrm->Tell();
139*297a844aSArmin Le Grand sal_uLong nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
140*297a844aSArmin Le Grand nPages = lcl_GetPageCount( nFileSize, nPageSize );
141*297a844aSArmin Le Grand pStrm->Seek( nPos );
142*297a844aSArmin Le Grand }
143cdf0e10cSrcweir }
144cdf0e10cSrcweir
145cdf0e10cSrcweir // Create a new cache element
146cdf0e10cSrcweir // pCur points to this element
147cdf0e10cSrcweir
Create(sal_Int32 nPg)148cdf0e10cSrcweir StgPage* StgCache::Create( sal_Int32 nPg )
149cdf0e10cSrcweir {
150cdf0e10cSrcweir StgPage* pElem = new StgPage( this, nPageSize );
151cdf0e10cSrcweir pElem->nPage = nPg;
152cdf0e10cSrcweir // For data security, clear the buffer contents
153cdf0e10cSrcweir memset( pElem->pData, 0, pElem->nData );
154cdf0e10cSrcweir
155cdf0e10cSrcweir // insert to LRU
156cdf0e10cSrcweir if( pCur )
157cdf0e10cSrcweir {
158cdf0e10cSrcweir pElem->pNext1 = pCur;
159cdf0e10cSrcweir pElem->pLast1 = pCur->pLast1;
160cdf0e10cSrcweir pElem->pNext1->pLast1 =
161cdf0e10cSrcweir pElem->pLast1->pNext1 = pElem;
162cdf0e10cSrcweir }
163cdf0e10cSrcweir else
164cdf0e10cSrcweir pElem->pNext1 = pElem->pLast1 = pElem;
165cdf0e10cSrcweir if( !pLRUCache )
166cdf0e10cSrcweir pLRUCache = new UsrStgPagePtr_Impl();
167cdf0e10cSrcweir (*(UsrStgPagePtr_Impl*)pLRUCache)[pElem->nPage] = pElem;
168cdf0e10cSrcweir pCur = pElem;
169cdf0e10cSrcweir
170cdf0e10cSrcweir // insert to Sorted
171cdf0e10cSrcweir if( !pElem1 )
172cdf0e10cSrcweir pElem1 = pElem->pNext2 = pElem->pLast2 = pElem;
173cdf0e10cSrcweir else
174cdf0e10cSrcweir {
175cdf0e10cSrcweir StgPage* p = pElem1;
176cdf0e10cSrcweir do
177cdf0e10cSrcweir {
178cdf0e10cSrcweir if( pElem->nPage < p->nPage )
179cdf0e10cSrcweir break;
180cdf0e10cSrcweir p = p->pNext2;
181cdf0e10cSrcweir } while( p != pElem1 );
182cdf0e10cSrcweir pElem->pNext2 = p;
183cdf0e10cSrcweir pElem->pLast2 = p->pLast2;
184cdf0e10cSrcweir pElem->pNext2->pLast2 =
185cdf0e10cSrcweir pElem->pLast2->pNext2 = pElem;
186cdf0e10cSrcweir if( p->nPage < pElem1->nPage )
187cdf0e10cSrcweir pElem1 = pElem;
188cdf0e10cSrcweir }
189cdf0e10cSrcweir return pElem;
190cdf0e10cSrcweir }
191cdf0e10cSrcweir
192cdf0e10cSrcweir // Delete the given element
193cdf0e10cSrcweir
Erase(StgPage * pElem)194cdf0e10cSrcweir void StgCache::Erase( StgPage* pElem )
195cdf0e10cSrcweir {
196*297a844aSArmin Le Grand OSL_ENSURE( pElem, "The pointer should not be NULL!" );
197*297a844aSArmin Le Grand if ( pElem )
198*297a844aSArmin Le Grand {
199*297a844aSArmin Le Grand OSL_ENSURE( pElem->pNext1 && pElem->pLast1, "The pointers may not be NULL!" );
200*297a844aSArmin Le Grand //remove from LRU
201*297a844aSArmin Le Grand pElem->pNext1->pLast1 = pElem->pLast1;
202*297a844aSArmin Le Grand pElem->pLast1->pNext1 = pElem->pNext1;
203*297a844aSArmin Le Grand if( pCur == pElem )
204*297a844aSArmin Le Grand pCur = ( pElem->pNext1 == pElem ) ? NULL : pElem->pNext1;
205*297a844aSArmin Le Grand if( pLRUCache )
206*297a844aSArmin Le Grand ((UsrStgPagePtr_Impl*)pLRUCache)->erase( pElem->nPage );
207*297a844aSArmin Le Grand // remove from Sorted
208*297a844aSArmin Le Grand pElem->pNext2->pLast2 = pElem->pLast2;
209*297a844aSArmin Le Grand pElem->pLast2->pNext2 = pElem->pNext2;
210*297a844aSArmin Le Grand if( pElem1 == pElem )
211*297a844aSArmin Le Grand pElem1 = ( pElem->pNext2 == pElem ) ? NULL : pElem->pNext2;
212*297a844aSArmin Le Grand delete pElem;
213*297a844aSArmin Le Grand }
214cdf0e10cSrcweir }
215cdf0e10cSrcweir
216cdf0e10cSrcweir // remove all cache elements without flushing them
217cdf0e10cSrcweir
Clear()218cdf0e10cSrcweir void StgCache::Clear()
219cdf0e10cSrcweir {
220cdf0e10cSrcweir StgPage* pElem = pCur;
221cdf0e10cSrcweir if( pCur ) do
222cdf0e10cSrcweir {
223cdf0e10cSrcweir StgPage* pDelete = pElem;
224cdf0e10cSrcweir pElem = pElem->pNext1;
225cdf0e10cSrcweir delete pDelete;
226cdf0e10cSrcweir }
227cdf0e10cSrcweir while( pCur != pElem );
228cdf0e10cSrcweir pCur = NULL;
229cdf0e10cSrcweir pElem1 = NULL;
230cdf0e10cSrcweir delete (UsrStgPagePtr_Impl*)pLRUCache;
231cdf0e10cSrcweir pLRUCache = NULL;
232cdf0e10cSrcweir }
233cdf0e10cSrcweir
234cdf0e10cSrcweir // Look for a cached page
235cdf0e10cSrcweir
Find(sal_Int32 nPage)236cdf0e10cSrcweir StgPage* StgCache::Find( sal_Int32 nPage )
237cdf0e10cSrcweir {
238cdf0e10cSrcweir if( !pLRUCache )
239cdf0e10cSrcweir return NULL;
240cdf0e10cSrcweir UsrStgPagePtr_Impl::iterator aIt = ((UsrStgPagePtr_Impl*)pLRUCache)->find( nPage );
241cdf0e10cSrcweir if( aIt != ((UsrStgPagePtr_Impl*)pLRUCache)->end() )
242cdf0e10cSrcweir {
243cdf0e10cSrcweir // page found
244cdf0e10cSrcweir StgPage* pFound = (*aIt).second;
245*297a844aSArmin Le Grand OSL_ENSURE( pFound, "The pointer may not be NULL!" );
246cdf0e10cSrcweir
247cdf0e10cSrcweir if( pFound != pCur )
248cdf0e10cSrcweir {
249*297a844aSArmin Le Grand OSL_ENSURE( pFound->pNext1 && pFound->pLast1, "The pointers may not be NULL!" );
250cdf0e10cSrcweir // remove from LRU
251cdf0e10cSrcweir pFound->pNext1->pLast1 = pFound->pLast1;
252cdf0e10cSrcweir pFound->pLast1->pNext1 = pFound->pNext1;
253cdf0e10cSrcweir // insert to LRU
254cdf0e10cSrcweir pFound->pNext1 = pCur;
255cdf0e10cSrcweir pFound->pLast1 = pCur->pLast1;
256cdf0e10cSrcweir pFound->pNext1->pLast1 =
257cdf0e10cSrcweir pFound->pLast1->pNext1 = pFound;
258cdf0e10cSrcweir }
259cdf0e10cSrcweir return pFound;
260cdf0e10cSrcweir }
261cdf0e10cSrcweir return NULL;
262cdf0e10cSrcweir }
263cdf0e10cSrcweir
264cdf0e10cSrcweir // Load a page into the cache
265cdf0e10cSrcweir
Get(sal_Int32 nPage,sal_Bool bForce)266cdf0e10cSrcweir StgPage* StgCache::Get( sal_Int32 nPage, sal_Bool bForce )
267cdf0e10cSrcweir {
268cdf0e10cSrcweir StgPage* p = Find( nPage );
269cdf0e10cSrcweir if( !p )
270cdf0e10cSrcweir {
271cdf0e10cSrcweir p = Create( nPage );
272cdf0e10cSrcweir if( !Read( nPage, p->pData, 1 ) && bForce )
273cdf0e10cSrcweir {
274cdf0e10cSrcweir Erase( p );
275cdf0e10cSrcweir p = NULL;
276cdf0e10cSrcweir SetError( SVSTREAM_READ_ERROR );
277cdf0e10cSrcweir }
278cdf0e10cSrcweir }
279cdf0e10cSrcweir return p;
280cdf0e10cSrcweir }
281cdf0e10cSrcweir
282cdf0e10cSrcweir // Copy an existing page into a new page. Use this routine
283cdf0e10cSrcweir // to duplicate an existing stream or to create new entries.
284cdf0e10cSrcweir // The new page is initially marked dirty. No owner is copied.
285cdf0e10cSrcweir
Copy(sal_Int32 nNew,sal_Int32 nOld)286cdf0e10cSrcweir StgPage* StgCache::Copy( sal_Int32 nNew, sal_Int32 nOld )
287cdf0e10cSrcweir {
288cdf0e10cSrcweir StgPage* p = Find( nNew );
289cdf0e10cSrcweir if( !p )
290cdf0e10cSrcweir p = Create( nNew );
291cdf0e10cSrcweir if( nOld >= 0 )
292cdf0e10cSrcweir {
293cdf0e10cSrcweir // old page: we must have this data!
294cdf0e10cSrcweir StgPage* q = Get( nOld, sal_True );
295cdf0e10cSrcweir if( q )
296*297a844aSArmin Le Grand {
297*297a844aSArmin Le Grand OSL_ENSURE( p->nData == q->nData, "Unexpected page size!" );
298cdf0e10cSrcweir memcpy( p->pData, q->pData, p->nData );
299*297a844aSArmin Le Grand }
300cdf0e10cSrcweir }
301cdf0e10cSrcweir p->SetDirty();
302cdf0e10cSrcweir return p;
303cdf0e10cSrcweir }
304cdf0e10cSrcweir
305cdf0e10cSrcweir // Flush the cache whose owner is given. NULL flushes all.
306cdf0e10cSrcweir
Commit(StgDirEntry *)307cdf0e10cSrcweir sal_Bool StgCache::Commit( StgDirEntry* )
308cdf0e10cSrcweir {
309cdf0e10cSrcweir StgPage* p = pElem1;
310cdf0e10cSrcweir if( p ) do
311cdf0e10cSrcweir {
312cdf0e10cSrcweir if( p->bDirty )
313cdf0e10cSrcweir {
314cdf0e10cSrcweir sal_Bool b = Write( p->nPage, p->pData, 1 );
315cdf0e10cSrcweir if( !b )
316cdf0e10cSrcweir return sal_False;
317cdf0e10cSrcweir p->bDirty = sal_False;
318cdf0e10cSrcweir }
319cdf0e10cSrcweir p = p->pNext2;
320cdf0e10cSrcweir } while( p != pElem1 );
321cdf0e10cSrcweir pStrm->Flush();
322cdf0e10cSrcweir SetError( pStrm->GetError() );
323cdf0e10cSrcweir #ifdef CHECK_DIRTY
324cdf0e10cSrcweir p = pElem1;
325cdf0e10cSrcweir if( p ) do
326cdf0e10cSrcweir {
327cdf0e10cSrcweir if( p->bDirty )
328cdf0e10cSrcweir {
329cdf0e10cSrcweir ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in Ordered List") ).Execute();
330cdf0e10cSrcweir sal_Bool b = Write( p->nPage, p->pData, 1 );
331cdf0e10cSrcweir if( !b )
332cdf0e10cSrcweir return sal_False;
333cdf0e10cSrcweir p->bDirty = sal_False;
334cdf0e10cSrcweir }
335cdf0e10cSrcweir p = p->pNext2;
336cdf0e10cSrcweir } while( p != pElem1 );
337cdf0e10cSrcweir p = pElem1;
338cdf0e10cSrcweir if( p ) do
339cdf0e10cSrcweir {
340cdf0e10cSrcweir if( p->bDirty )
341cdf0e10cSrcweir {
342cdf0e10cSrcweir ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in LRU List") ).Execute();
343cdf0e10cSrcweir sal_Bool b = Write( p->nPage, p->pData, 1 );
344cdf0e10cSrcweir if( !b )
345cdf0e10cSrcweir return sal_False;
346cdf0e10cSrcweir p->bDirty = sal_False;
347cdf0e10cSrcweir }
348cdf0e10cSrcweir p = p->pNext1;
349cdf0e10cSrcweir } while( p != pElem1 );
350cdf0e10cSrcweir #endif
351cdf0e10cSrcweir return sal_True;
352cdf0e10cSrcweir }
353cdf0e10cSrcweir
Revert(StgDirEntry *)354cdf0e10cSrcweir void StgCache::Revert( StgDirEntry* )
355cdf0e10cSrcweir {}
356cdf0e10cSrcweir
357cdf0e10cSrcweir // Set a stream
358cdf0e10cSrcweir
SetStrm(SvStream * p,sal_Bool bMy)359cdf0e10cSrcweir void StgCache::SetStrm( SvStream* p, sal_Bool bMy )
360cdf0e10cSrcweir {
361cdf0e10cSrcweir if( pStorageStream )
362cdf0e10cSrcweir {
363cdf0e10cSrcweir pStorageStream->ReleaseRef();
364cdf0e10cSrcweir pStorageStream = NULL;
365cdf0e10cSrcweir }
366cdf0e10cSrcweir
367cdf0e10cSrcweir if( bMyStream )
368cdf0e10cSrcweir delete pStrm;
369cdf0e10cSrcweir pStrm = p;
370cdf0e10cSrcweir bMyStream = bMy;
371cdf0e10cSrcweir }
372cdf0e10cSrcweir
SetStrm(UCBStorageStream * pStgStream)373cdf0e10cSrcweir void StgCache::SetStrm( UCBStorageStream* pStgStream )
374cdf0e10cSrcweir {
375cdf0e10cSrcweir if( pStorageStream )
376cdf0e10cSrcweir pStorageStream->ReleaseRef();
377cdf0e10cSrcweir pStorageStream = pStgStream;
378cdf0e10cSrcweir
379cdf0e10cSrcweir if( bMyStream )
380cdf0e10cSrcweir delete pStrm;
381cdf0e10cSrcweir
382cdf0e10cSrcweir pStrm = NULL;
383cdf0e10cSrcweir
384cdf0e10cSrcweir if ( pStorageStream )
385cdf0e10cSrcweir {
386cdf0e10cSrcweir pStorageStream->AddRef();
387cdf0e10cSrcweir pStrm = pStorageStream->GetModifySvStream();
388cdf0e10cSrcweir }
389cdf0e10cSrcweir
390cdf0e10cSrcweir bMyStream = sal_False;
391cdf0e10cSrcweir }
392cdf0e10cSrcweir
393cdf0e10cSrcweir // Open/close the disk file
394cdf0e10cSrcweir
Open(const String & rName,StreamMode nMode)395cdf0e10cSrcweir sal_Bool StgCache::Open( const String& rName, StreamMode nMode )
396cdf0e10cSrcweir {
397cdf0e10cSrcweir // do not open in exclusive mode!
398cdf0e10cSrcweir if( nMode & STREAM_SHARE_DENYALL )
399cdf0e10cSrcweir nMode = ( ( nMode & ~STREAM_SHARE_DENYALL ) | STREAM_SHARE_DENYWRITE );
400cdf0e10cSrcweir SvFileStream* pFileStrm = new SvFileStream( rName, nMode );
401cdf0e10cSrcweir // SvStream "Feature" Write Open auch erfolgreich, wenns nicht klappt
402cdf0e10cSrcweir sal_Bool bAccessDenied = sal_False;
403cdf0e10cSrcweir if( ( nMode & STREAM_WRITE ) && !pFileStrm->IsWritable() )
404cdf0e10cSrcweir {
405cdf0e10cSrcweir pFileStrm->Close();
406cdf0e10cSrcweir bAccessDenied = sal_True;
407cdf0e10cSrcweir }
408cdf0e10cSrcweir SetStrm( pFileStrm, sal_True );
409cdf0e10cSrcweir if( pFileStrm->IsOpen() )
410cdf0e10cSrcweir {
411cdf0e10cSrcweir sal_uLong nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
412cdf0e10cSrcweir nPages = lcl_GetPageCount( nFileSize, nPageSize );
413cdf0e10cSrcweir pStrm->Seek( 0L );
414cdf0e10cSrcweir }
415cdf0e10cSrcweir else
416cdf0e10cSrcweir nPages = 0;
417cdf0e10cSrcweir bFile = sal_True;
418cdf0e10cSrcweir SetError( bAccessDenied ? ERRCODE_IO_ACCESSDENIED : pStrm->GetError() );
419cdf0e10cSrcweir return Good();
420cdf0e10cSrcweir }
421cdf0e10cSrcweir
Close()422cdf0e10cSrcweir void StgCache::Close()
423cdf0e10cSrcweir {
424cdf0e10cSrcweir if( bFile )
425cdf0e10cSrcweir {
426cdf0e10cSrcweir ((SvFileStream*) pStrm)->Close();
427cdf0e10cSrcweir SetError( pStrm->GetError() );
428cdf0e10cSrcweir }
429cdf0e10cSrcweir }
430cdf0e10cSrcweir
431cdf0e10cSrcweir // low level I/O
432cdf0e10cSrcweir
Read(sal_Int32 nPage,void * pBuf,sal_Int32 nPg)433cdf0e10cSrcweir sal_Bool StgCache::Read( sal_Int32 nPage, void* pBuf, sal_Int32 nPg )
434cdf0e10cSrcweir {
435cdf0e10cSrcweir if( Good() )
436cdf0e10cSrcweir {
437cdf0e10cSrcweir /* #i73846# real life: a storage may refer to a page one-behind the
438cdf0e10cSrcweir last valid page (see document attached to the issue). In that case
439cdf0e10cSrcweir (if nPage==nPages), just do nothing here and let the caller work on
440cdf0e10cSrcweir the empty zero-filled buffer. */
441cdf0e10cSrcweir if ( nPage > nPages )
442cdf0e10cSrcweir SetError( SVSTREAM_READ_ERROR );
443cdf0e10cSrcweir else if ( nPage < nPages )
444cdf0e10cSrcweir {
445cdf0e10cSrcweir sal_uLong nPos = Page2Pos( nPage );
446cdf0e10cSrcweir sal_Int32 nPg2 = ( ( nPage + nPg ) > nPages ) ? nPages - nPage : nPg;
447cdf0e10cSrcweir sal_uLong nBytes = nPg2 * nPageSize;
448cdf0e10cSrcweir // fixed address and size for the header
449cdf0e10cSrcweir if( nPage == -1 )
450cdf0e10cSrcweir {
451cdf0e10cSrcweir nPos = 0L, nBytes = 512;
452cdf0e10cSrcweir nPg2 = nPg;
453cdf0e10cSrcweir }
454cdf0e10cSrcweir if( pStrm->Tell() != nPos )
455cdf0e10cSrcweir {
456cdf0e10cSrcweir if( pStrm->Seek( nPos ) != nPos ) {
457cdf0e10cSrcweir #ifdef CHECK_DIRTY
458cdf0e10cSrcweir ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
459cdf0e10cSrcweir #endif
460cdf0e10cSrcweir }
461cdf0e10cSrcweir }
462cdf0e10cSrcweir pStrm->Read( pBuf, nBytes );
463cdf0e10cSrcweir if ( nPg != nPg2 )
464cdf0e10cSrcweir SetError( SVSTREAM_READ_ERROR );
465cdf0e10cSrcweir else
466cdf0e10cSrcweir SetError( pStrm->GetError() );
467cdf0e10cSrcweir }
468cdf0e10cSrcweir }
469cdf0e10cSrcweir return Good();
470cdf0e10cSrcweir }
471cdf0e10cSrcweir
Write(sal_Int32 nPage,void * pBuf,sal_Int32 nPg)472cdf0e10cSrcweir sal_Bool StgCache::Write( sal_Int32 nPage, void* pBuf, sal_Int32 nPg )
473cdf0e10cSrcweir {
474*297a844aSArmin Le Grand if( Good() )
475cdf0e10cSrcweir {
476cdf0e10cSrcweir sal_uLong nPos = Page2Pos( nPage );
477*297a844aSArmin Le Grand sal_uLong nBytes = 0;
478*297a844aSArmin Le Grand if ( SAL_MAX_INT32 / nPg > nPageSize )
479*297a844aSArmin Le Grand nBytes = nPg * nPageSize;
480*297a844aSArmin Le Grand
481cdf0e10cSrcweir // fixed address and size for the header
482*297a844aSArmin Le Grand // nPageSize must be >= 512, otherwise the header can not be written here, we check it on import
483cdf0e10cSrcweir if( nPage == -1 )
484cdf0e10cSrcweir nPos = 0L, nBytes = 512;
485cdf0e10cSrcweir if( pStrm->Tell() != nPos )
486cdf0e10cSrcweir {
487cdf0e10cSrcweir if( pStrm->Seek( nPos ) != nPos ) {
488cdf0e10cSrcweir #ifdef CHECK_DIRTY
489cdf0e10cSrcweir ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
490cdf0e10cSrcweir #endif
491cdf0e10cSrcweir }
492cdf0e10cSrcweir }
493cdf0e10cSrcweir sal_uLong nRes = pStrm->Write( pBuf, nBytes );
494cdf0e10cSrcweir if( nRes != nBytes )
495cdf0e10cSrcweir SetError( SVSTREAM_WRITE_ERROR );
496cdf0e10cSrcweir else
497cdf0e10cSrcweir SetError( pStrm->GetError() );
498cdf0e10cSrcweir #ifdef READ_AFTER_WRITE
499cdf0e10cSrcweir sal_uInt8 cBuf[ 512 ];
500cdf0e10cSrcweir pStrm->Flush();
501cdf0e10cSrcweir pStrm->Seek( nPos );
502cdf0e10cSrcweir sal_Bool bRes = ( pStrm->Read( cBuf, 512 ) == 512 );
503cdf0e10cSrcweir if( bRes )
504cdf0e10cSrcweir bRes = !memcmp( cBuf, pBuf, 512 );
505cdf0e10cSrcweir if( !bRes )
506cdf0e10cSrcweir {
507cdf0e10cSrcweir ErrorBox( NULL, WB_OK, String("SO2: Read after Write failed") ).Execute();
508cdf0e10cSrcweir pStrm->SetError( SVSTREAM_WRITE_ERROR );
509cdf0e10cSrcweir }
510cdf0e10cSrcweir #endif
511cdf0e10cSrcweir }
512cdf0e10cSrcweir return Good();
513cdf0e10cSrcweir }
514cdf0e10cSrcweir
515cdf0e10cSrcweir // set the file size in pages
516cdf0e10cSrcweir
SetSize(sal_Int32 n)517cdf0e10cSrcweir sal_Bool StgCache::SetSize( sal_Int32 n )
518cdf0e10cSrcweir {
519cdf0e10cSrcweir // Add the file header
520cdf0e10cSrcweir sal_Int32 nSize = n * nPageSize + 512;
521cdf0e10cSrcweir pStrm->SetStreamSize( nSize );
522cdf0e10cSrcweir SetError( pStrm->GetError() );
523cdf0e10cSrcweir if( !nError )
524cdf0e10cSrcweir nPages = n;
525cdf0e10cSrcweir return Good();
526cdf0e10cSrcweir }
527cdf0e10cSrcweir
SetError(sal_uLong n)528cdf0e10cSrcweir void StgCache::SetError( sal_uLong n )
529cdf0e10cSrcweir {
530cdf0e10cSrcweir if( n && !nError )
531cdf0e10cSrcweir nError = n;
532cdf0e10cSrcweir }
533cdf0e10cSrcweir
ResetError()534cdf0e10cSrcweir void StgCache::ResetError()
535cdf0e10cSrcweir {
536cdf0e10cSrcweir nError = SVSTREAM_OK;
537cdf0e10cSrcweir pStrm->ResetError();
538cdf0e10cSrcweir }
539cdf0e10cSrcweir
MoveError(StorageBase & r)540cdf0e10cSrcweir void StgCache::MoveError( StorageBase& r )
541cdf0e10cSrcweir {
542cdf0e10cSrcweir if( nError != SVSTREAM_OK )
543cdf0e10cSrcweir {
544cdf0e10cSrcweir r.SetError( nError );
545cdf0e10cSrcweir ResetError();
546cdf0e10cSrcweir }
547cdf0e10cSrcweir }
548cdf0e10cSrcweir
549cdf0e10cSrcweir // Utility functions
550cdf0e10cSrcweir
Page2Pos(sal_Int32 nPage)551cdf0e10cSrcweir sal_Int32 StgCache::Page2Pos( sal_Int32 nPage )
552cdf0e10cSrcweir {
553cdf0e10cSrcweir if( nPage < 0 ) nPage = 0;
554cdf0e10cSrcweir return( nPage * nPageSize ) + nPageSize;
555cdf0e10cSrcweir }
556cdf0e10cSrcweir
Pos2Page(sal_Int32 nPos)557cdf0e10cSrcweir sal_Int32 StgCache::Pos2Page( sal_Int32 nPos )
558cdf0e10cSrcweir {
559cdf0e10cSrcweir return ( ( nPos + nPageSize - 1 ) / nPageSize ) * nPageSize - 1;
560cdf0e10cSrcweir }
561cdf0e10cSrcweir
562