xref: /aoo42x/main/sot/source/sdstor/stgcache.cxx (revision 046d9d1f)
1*046d9d1fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*046d9d1fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*046d9d1fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*046d9d1fSAndrew Rist  * distributed with this work for additional information
6*046d9d1fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*046d9d1fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*046d9d1fSAndrew Rist  * "License"); you may not use this file except in compliance
9*046d9d1fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*046d9d1fSAndrew Rist  *
11*046d9d1fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*046d9d1fSAndrew Rist  *
13*046d9d1fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*046d9d1fSAndrew Rist  * software distributed under the License is distributed on an
15*046d9d1fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*046d9d1fSAndrew Rist  * KIND, either express or implied.  See the License for the
17*046d9d1fSAndrew Rist  * specific language governing permissions and limitations
18*046d9d1fSAndrew Rist  * under the License.
19*046d9d1fSAndrew Rist  *
20*046d9d1fSAndrew Rist  *************************************************************/
21*046d9d1fSAndrew Rist 
22*046d9d1fSAndrew 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 
68cdf0e10cSrcweir StgPage::StgPage( StgCache* p, short n )
69cdf0e10cSrcweir {
70cdf0e10cSrcweir     pCache = p;
71cdf0e10cSrcweir     nData  = n;
72cdf0e10cSrcweir     bDirty = sal_False;
73cdf0e10cSrcweir     nPage  = 0;
74cdf0e10cSrcweir     pData  = new sal_uInt8[ nData ];
75cdf0e10cSrcweir     pNext1 =
76cdf0e10cSrcweir     pNext2 =
77cdf0e10cSrcweir     pLast1 =
78cdf0e10cSrcweir     pLast2 = NULL;
79cdf0e10cSrcweir 	pOwner = NULL;
80cdf0e10cSrcweir }
81cdf0e10cSrcweir 
82cdf0e10cSrcweir StgPage::~StgPage()
83cdf0e10cSrcweir {
84cdf0e10cSrcweir     delete [] pData;
85cdf0e10cSrcweir }
86cdf0e10cSrcweir 
87cdf0e10cSrcweir void StgPage::SetPage( short nOff, sal_Int32 nVal )
88cdf0e10cSrcweir {
89cdf0e10cSrcweir     if( ( nOff < (short) ( nData / sizeof( sal_Int32 ) ) ) && nOff >= 0 )
90cdf0e10cSrcweir     {
91cdf0e10cSrcweir #ifdef OSL_BIGENDIAN
92cdf0e10cSrcweir 	  nVal = SWAPLONG(nVal);
93cdf0e10cSrcweir #endif
94cdf0e10cSrcweir         ((sal_Int32*) pData )[ nOff ] = nVal;
95cdf0e10cSrcweir         bDirty = sal_True;
96cdf0e10cSrcweir     }
97cdf0e10cSrcweir }
98cdf0e10cSrcweir 
99cdf0e10cSrcweir //////////////////////////////// class StgCache ////////////////////////////
100cdf0e10cSrcweir 
101cdf0e10cSrcweir // The disk cache holds the cached sectors. The sector type differ according
102cdf0e10cSrcweir // to their purpose.
103cdf0e10cSrcweir 
104cdf0e10cSrcweir sal_Int32 lcl_GetPageCount( sal_uLong nFileSize, short nPageSize )
105cdf0e10cSrcweir {
106cdf0e10cSrcweir //    return (nFileSize >= 512) ? (nFileSize - 512) / nPageSize : 0;
107cdf0e10cSrcweir     // #i61980# reallife: last page may be incomplete, return number of *started* pages
108cdf0e10cSrcweir     return (nFileSize >= 512) ? (nFileSize - 512 + nPageSize - 1) / nPageSize : 0;
109cdf0e10cSrcweir }
110cdf0e10cSrcweir 
111cdf0e10cSrcweir StgCache::StgCache()
112cdf0e10cSrcweir {
113cdf0e10cSrcweir 	nRef = 0;
114cdf0e10cSrcweir 	pStrm = NULL;
115cdf0e10cSrcweir 	pCur = pElem1 = NULL;
116cdf0e10cSrcweir     nPageSize = 512;
117cdf0e10cSrcweir     nError = SVSTREAM_OK;
118cdf0e10cSrcweir 	bMyStream = sal_False;
119cdf0e10cSrcweir 	bFile = sal_False;
120cdf0e10cSrcweir 	pLRUCache = NULL;
121cdf0e10cSrcweir 	pStorageStream = NULL;
122cdf0e10cSrcweir }
123cdf0e10cSrcweir 
124cdf0e10cSrcweir StgCache::~StgCache()
125cdf0e10cSrcweir {
126cdf0e10cSrcweir     Clear();
127cdf0e10cSrcweir 	SetStrm( NULL, sal_False );
128cdf0e10cSrcweir 	delete (UsrStgPagePtr_Impl*)pLRUCache;
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
131cdf0e10cSrcweir void StgCache::SetPhysPageSize( short n )
132cdf0e10cSrcweir {
133cdf0e10cSrcweir     nPageSize = n;
134cdf0e10cSrcweir     sal_uLong nPos = pStrm->Tell();
135cdf0e10cSrcweir     sal_uLong nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
136cdf0e10cSrcweir     nPages = lcl_GetPageCount( nFileSize, nPageSize );
137cdf0e10cSrcweir     pStrm->Seek( nPos );
138cdf0e10cSrcweir }
139cdf0e10cSrcweir 
140cdf0e10cSrcweir // Create a new cache element
141cdf0e10cSrcweir // pCur points to this element
142cdf0e10cSrcweir 
143cdf0e10cSrcweir StgPage* StgCache::Create( sal_Int32 nPg )
144cdf0e10cSrcweir {
145cdf0e10cSrcweir     StgPage* pElem = new StgPage( this, nPageSize );
146cdf0e10cSrcweir     pElem->nPage = nPg;
147cdf0e10cSrcweir     // For data security, clear the buffer contents
148cdf0e10cSrcweir     memset( pElem->pData, 0, pElem->nData );
149cdf0e10cSrcweir 
150cdf0e10cSrcweir 	// insert to LRU
151cdf0e10cSrcweir     if( pCur )
152cdf0e10cSrcweir     {
153cdf0e10cSrcweir         pElem->pNext1 = pCur;
154cdf0e10cSrcweir         pElem->pLast1 = pCur->pLast1;
155cdf0e10cSrcweir         pElem->pNext1->pLast1 =
156cdf0e10cSrcweir         pElem->pLast1->pNext1 = pElem;
157cdf0e10cSrcweir     }
158cdf0e10cSrcweir     else
159cdf0e10cSrcweir         pElem->pNext1 = pElem->pLast1 = pElem;
160cdf0e10cSrcweir 	if( !pLRUCache )
161cdf0e10cSrcweir 		pLRUCache = new UsrStgPagePtr_Impl();
162cdf0e10cSrcweir 	(*(UsrStgPagePtr_Impl*)pLRUCache)[pElem->nPage] = pElem;
163cdf0e10cSrcweir     pCur = pElem;
164cdf0e10cSrcweir 
165cdf0e10cSrcweir 	// insert to Sorted
166cdf0e10cSrcweir     if( !pElem1 )
167cdf0e10cSrcweir         pElem1 = pElem->pNext2 = pElem->pLast2 = pElem;
168cdf0e10cSrcweir     else
169cdf0e10cSrcweir     {
170cdf0e10cSrcweir         StgPage* p = pElem1;
171cdf0e10cSrcweir         do
172cdf0e10cSrcweir         {
173cdf0e10cSrcweir             if( pElem->nPage < p->nPage )
174cdf0e10cSrcweir                 break;
175cdf0e10cSrcweir             p = p->pNext2;
176cdf0e10cSrcweir         } while( p != pElem1 );
177cdf0e10cSrcweir         pElem->pNext2 = p;
178cdf0e10cSrcweir         pElem->pLast2 = p->pLast2;
179cdf0e10cSrcweir         pElem->pNext2->pLast2 =
180cdf0e10cSrcweir         pElem->pLast2->pNext2 = pElem;
181cdf0e10cSrcweir         if( p->nPage < pElem1->nPage )
182cdf0e10cSrcweir             pElem1 = pElem;
183cdf0e10cSrcweir     }
184cdf0e10cSrcweir     return pElem;
185cdf0e10cSrcweir }
186cdf0e10cSrcweir 
187cdf0e10cSrcweir // Delete the given element
188cdf0e10cSrcweir 
189cdf0e10cSrcweir void StgCache::Erase( StgPage* pElem )
190cdf0e10cSrcweir {
191cdf0e10cSrcweir 	//remove from LRU
192cdf0e10cSrcweir     pElem->pNext1->pLast1 = pElem->pLast1;
193cdf0e10cSrcweir     pElem->pLast1->pNext1 = pElem->pNext1;
194cdf0e10cSrcweir     if( pCur == pElem )
195cdf0e10cSrcweir         pCur = ( pElem->pNext1 == pElem ) ? NULL : pElem->pNext1;
196cdf0e10cSrcweir 	if( pLRUCache )
197cdf0e10cSrcweir 		((UsrStgPagePtr_Impl*)pLRUCache)->erase( pElem->nPage );
198cdf0e10cSrcweir 	// remove from Sorted
199cdf0e10cSrcweir     pElem->pNext2->pLast2 = pElem->pLast2;
200cdf0e10cSrcweir     pElem->pLast2->pNext2 = pElem->pNext2;
201cdf0e10cSrcweir     if( pElem1 == pElem )
202cdf0e10cSrcweir         pElem1 = ( pElem->pNext2 == pElem ) ? NULL : pElem->pNext2;
203cdf0e10cSrcweir     delete pElem;
204cdf0e10cSrcweir }
205cdf0e10cSrcweir 
206cdf0e10cSrcweir // remove all cache elements without flushing them
207cdf0e10cSrcweir 
208cdf0e10cSrcweir void StgCache::Clear()
209cdf0e10cSrcweir {
210cdf0e10cSrcweir 	StgPage* pElem = pCur;
211cdf0e10cSrcweir 	if( pCur ) do
212cdf0e10cSrcweir 	{
213cdf0e10cSrcweir 		StgPage* pDelete = pElem;
214cdf0e10cSrcweir 		pElem = pElem->pNext1;
215cdf0e10cSrcweir 		delete pDelete;
216cdf0e10cSrcweir 	}
217cdf0e10cSrcweir     while( pCur != pElem );
218cdf0e10cSrcweir     pCur = NULL;
219cdf0e10cSrcweir 	pElem1 = NULL;
220cdf0e10cSrcweir 	delete (UsrStgPagePtr_Impl*)pLRUCache;
221cdf0e10cSrcweir 	pLRUCache = NULL;
222cdf0e10cSrcweir }
223cdf0e10cSrcweir 
224cdf0e10cSrcweir // Look for a cached page
225cdf0e10cSrcweir 
226cdf0e10cSrcweir StgPage* StgCache::Find( sal_Int32 nPage )
227cdf0e10cSrcweir {
228cdf0e10cSrcweir 	if( !pLRUCache )
229cdf0e10cSrcweir 		return NULL;
230cdf0e10cSrcweir 	UsrStgPagePtr_Impl::iterator aIt = ((UsrStgPagePtr_Impl*)pLRUCache)->find( nPage );
231cdf0e10cSrcweir 	if( aIt != ((UsrStgPagePtr_Impl*)pLRUCache)->end() )
232cdf0e10cSrcweir 	{
233cdf0e10cSrcweir 		// page found
234cdf0e10cSrcweir 	    StgPage* pFound = (*aIt).second;
235cdf0e10cSrcweir 
236cdf0e10cSrcweir 		if( pFound != pCur )
237cdf0e10cSrcweir 		{
238cdf0e10cSrcweir 			// remove from LRU
239cdf0e10cSrcweir 			pFound->pNext1->pLast1 = pFound->pLast1;
240cdf0e10cSrcweir 			pFound->pLast1->pNext1 = pFound->pNext1;
241cdf0e10cSrcweir 			// insert to LRU
242cdf0e10cSrcweir 			pFound->pNext1 = pCur;
243cdf0e10cSrcweir 			pFound->pLast1 = pCur->pLast1;
244cdf0e10cSrcweir 			pFound->pNext1->pLast1 =
245cdf0e10cSrcweir 			pFound->pLast1->pNext1 = pFound;
246cdf0e10cSrcweir 		}
247cdf0e10cSrcweir 		return pFound;
248cdf0e10cSrcweir 	}
249cdf0e10cSrcweir     return NULL;
250cdf0e10cSrcweir }
251cdf0e10cSrcweir 
252cdf0e10cSrcweir // Load a page into the cache
253cdf0e10cSrcweir 
254cdf0e10cSrcweir StgPage* StgCache::Get( sal_Int32 nPage, sal_Bool bForce )
255cdf0e10cSrcweir {
256cdf0e10cSrcweir     StgPage* p = Find( nPage );
257cdf0e10cSrcweir     if( !p )
258cdf0e10cSrcweir     {
259cdf0e10cSrcweir         p = Create( nPage );
260cdf0e10cSrcweir         if( !Read( nPage, p->pData, 1 ) && bForce )
261cdf0e10cSrcweir 		{
262cdf0e10cSrcweir 			Erase( p );
263cdf0e10cSrcweir 			p = NULL;
264cdf0e10cSrcweir             SetError( SVSTREAM_READ_ERROR );
265cdf0e10cSrcweir 		}
266cdf0e10cSrcweir 	}
267cdf0e10cSrcweir     return p;
268cdf0e10cSrcweir }
269cdf0e10cSrcweir 
270cdf0e10cSrcweir // Copy an existing page into a new page. Use this routine
271cdf0e10cSrcweir // to duplicate an existing stream or to create new entries.
272cdf0e10cSrcweir // The new page is initially marked dirty. No owner is copied.
273cdf0e10cSrcweir 
274cdf0e10cSrcweir StgPage* StgCache::Copy( sal_Int32 nNew, sal_Int32 nOld )
275cdf0e10cSrcweir {
276cdf0e10cSrcweir     StgPage* p = Find( nNew );
277cdf0e10cSrcweir     if( !p )
278cdf0e10cSrcweir         p = Create( nNew );
279cdf0e10cSrcweir     if( nOld >= 0 )
280cdf0e10cSrcweir     {
281cdf0e10cSrcweir         // old page: we must have this data!
282cdf0e10cSrcweir         StgPage* q = Get( nOld, sal_True );
283cdf0e10cSrcweir         if( q )
284cdf0e10cSrcweir             memcpy( p->pData, q->pData, p->nData );
285cdf0e10cSrcweir     }
286cdf0e10cSrcweir     p->SetDirty();
287cdf0e10cSrcweir     return p;
288cdf0e10cSrcweir }
289cdf0e10cSrcweir 
290cdf0e10cSrcweir // Flush the cache whose owner is given. NULL flushes all.
291cdf0e10cSrcweir 
292cdf0e10cSrcweir sal_Bool StgCache::Commit( StgDirEntry* )
293cdf0e10cSrcweir {
294cdf0e10cSrcweir     StgPage* p = pElem1;
295cdf0e10cSrcweir     if( p ) do
296cdf0e10cSrcweir     {
297cdf0e10cSrcweir         if( p->bDirty )
298cdf0e10cSrcweir         {
299cdf0e10cSrcweir             sal_Bool b = Write( p->nPage, p->pData, 1 );
300cdf0e10cSrcweir             if( !b )
301cdf0e10cSrcweir 				return sal_False;
302cdf0e10cSrcweir             p->bDirty = sal_False;
303cdf0e10cSrcweir         }
304cdf0e10cSrcweir         p = p->pNext2;
305cdf0e10cSrcweir     } while( p != pElem1 );
306cdf0e10cSrcweir 	pStrm->Flush();
307cdf0e10cSrcweir 	SetError( pStrm->GetError() );
308cdf0e10cSrcweir #ifdef CHECK_DIRTY
309cdf0e10cSrcweir 	p = pElem1;
310cdf0e10cSrcweir 	if( p ) do
311cdf0e10cSrcweir 	{
312cdf0e10cSrcweir 	    if( p->bDirty )
313cdf0e10cSrcweir 	    {
314cdf0e10cSrcweir 			ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in Ordered List") ).Execute();
315cdf0e10cSrcweir 	        sal_Bool b = Write( p->nPage, p->pData, 1 );
316cdf0e10cSrcweir 	        if( !b )
317cdf0e10cSrcweir 				return sal_False;
318cdf0e10cSrcweir 	        p->bDirty = sal_False;
319cdf0e10cSrcweir 	    }
320cdf0e10cSrcweir 	    p = p->pNext2;
321cdf0e10cSrcweir 	} while( p != pElem1 );
322cdf0e10cSrcweir 	p = pElem1;
323cdf0e10cSrcweir 	if( p ) do
324cdf0e10cSrcweir 	{
325cdf0e10cSrcweir 	    if( p->bDirty )
326cdf0e10cSrcweir 	    {
327cdf0e10cSrcweir 			ErrorBox( NULL, WB_OK, String("SO2: Dirty Block in LRU List") ).Execute();
328cdf0e10cSrcweir 	        sal_Bool b = Write( p->nPage, p->pData, 1 );
329cdf0e10cSrcweir 	        if( !b )
330cdf0e10cSrcweir 				return sal_False;
331cdf0e10cSrcweir 	        p->bDirty = sal_False;
332cdf0e10cSrcweir 	    }
333cdf0e10cSrcweir 	    p = p->pNext1;
334cdf0e10cSrcweir 	} while( p != pElem1 );
335cdf0e10cSrcweir #endif
336cdf0e10cSrcweir 	return sal_True;
337cdf0e10cSrcweir }
338cdf0e10cSrcweir 
339cdf0e10cSrcweir void StgCache::Revert( StgDirEntry* )
340cdf0e10cSrcweir {}
341cdf0e10cSrcweir 
342cdf0e10cSrcweir // Set a stream
343cdf0e10cSrcweir 
344cdf0e10cSrcweir void StgCache::SetStrm( SvStream* p, sal_Bool bMy )
345cdf0e10cSrcweir {
346cdf0e10cSrcweir 	if( pStorageStream )
347cdf0e10cSrcweir 	{
348cdf0e10cSrcweir 		pStorageStream->ReleaseRef();
349cdf0e10cSrcweir 		pStorageStream = NULL;
350cdf0e10cSrcweir 	}
351cdf0e10cSrcweir 
352cdf0e10cSrcweir 	if( bMyStream )
353cdf0e10cSrcweir 		delete pStrm;
354cdf0e10cSrcweir 	pStrm = p;
355cdf0e10cSrcweir 	bMyStream = bMy;
356cdf0e10cSrcweir }
357cdf0e10cSrcweir 
358cdf0e10cSrcweir void StgCache::SetStrm( UCBStorageStream* pStgStream )
359cdf0e10cSrcweir {
360cdf0e10cSrcweir 	if( pStorageStream )
361cdf0e10cSrcweir 		pStorageStream->ReleaseRef();
362cdf0e10cSrcweir 	pStorageStream = pStgStream;
363cdf0e10cSrcweir 
364cdf0e10cSrcweir 	if( bMyStream )
365cdf0e10cSrcweir 		delete pStrm;
366cdf0e10cSrcweir 
367cdf0e10cSrcweir 	pStrm = NULL;
368cdf0e10cSrcweir 
369cdf0e10cSrcweir 	if ( pStorageStream )
370cdf0e10cSrcweir 	{
371cdf0e10cSrcweir 		pStorageStream->AddRef();
372cdf0e10cSrcweir 		pStrm = pStorageStream->GetModifySvStream();
373cdf0e10cSrcweir 	}
374cdf0e10cSrcweir 
375cdf0e10cSrcweir 	bMyStream = sal_False;
376cdf0e10cSrcweir }
377cdf0e10cSrcweir 
378cdf0e10cSrcweir // Open/close the disk file
379cdf0e10cSrcweir 
380cdf0e10cSrcweir sal_Bool StgCache::Open( const String& rName, StreamMode nMode )
381cdf0e10cSrcweir {
382cdf0e10cSrcweir 	// do not open in exclusive mode!
383cdf0e10cSrcweir 	if( nMode & STREAM_SHARE_DENYALL )
384cdf0e10cSrcweir 		nMode = ( ( nMode & ~STREAM_SHARE_DENYALL ) | STREAM_SHARE_DENYWRITE );
385cdf0e10cSrcweir 	SvFileStream* pFileStrm = new SvFileStream( rName, nMode );
386cdf0e10cSrcweir 	// SvStream "Feature" Write Open auch erfolgreich, wenns nicht klappt
387cdf0e10cSrcweir 	sal_Bool bAccessDenied = sal_False;
388cdf0e10cSrcweir 	if( ( nMode & STREAM_WRITE ) && !pFileStrm->IsWritable() )
389cdf0e10cSrcweir 	{
390cdf0e10cSrcweir 		pFileStrm->Close();
391cdf0e10cSrcweir 		bAccessDenied = sal_True;
392cdf0e10cSrcweir 	}
393cdf0e10cSrcweir 	SetStrm( pFileStrm, sal_True );
394cdf0e10cSrcweir 	if( pFileStrm->IsOpen() )
395cdf0e10cSrcweir 	{
396cdf0e10cSrcweir 	    sal_uLong nFileSize = pStrm->Seek( STREAM_SEEK_TO_END );
397cdf0e10cSrcweir         nPages = lcl_GetPageCount( nFileSize, nPageSize );
398cdf0e10cSrcweir 	    pStrm->Seek( 0L );
399cdf0e10cSrcweir 	}
400cdf0e10cSrcweir 	else
401cdf0e10cSrcweir 		nPages = 0;
402cdf0e10cSrcweir 	bFile = sal_True;
403cdf0e10cSrcweir     SetError( bAccessDenied ? ERRCODE_IO_ACCESSDENIED : pStrm->GetError() );
404cdf0e10cSrcweir     return Good();
405cdf0e10cSrcweir }
406cdf0e10cSrcweir 
407cdf0e10cSrcweir void StgCache::Close()
408cdf0e10cSrcweir {
409cdf0e10cSrcweir 	if( bFile )
410cdf0e10cSrcweir 	{
411cdf0e10cSrcweir 		((SvFileStream*) pStrm)->Close();
412cdf0e10cSrcweir 	    SetError( pStrm->GetError() );
413cdf0e10cSrcweir 	}
414cdf0e10cSrcweir }
415cdf0e10cSrcweir 
416cdf0e10cSrcweir // low level I/O
417cdf0e10cSrcweir 
418cdf0e10cSrcweir sal_Bool StgCache::Read( sal_Int32 nPage, void* pBuf, sal_Int32 nPg )
419cdf0e10cSrcweir {
420cdf0e10cSrcweir     if( Good() )
421cdf0e10cSrcweir     {
422cdf0e10cSrcweir         /*  #i73846# real life: a storage may refer to a page one-behind the
423cdf0e10cSrcweir             last valid page (see document attached to the issue). In that case
424cdf0e10cSrcweir             (if nPage==nPages), just do nothing here and let the caller work on
425cdf0e10cSrcweir             the empty zero-filled buffer. */
426cdf0e10cSrcweir         if ( nPage > nPages )
427cdf0e10cSrcweir 			SetError( SVSTREAM_READ_ERROR );
428cdf0e10cSrcweir         else if ( nPage < nPages )
429cdf0e10cSrcweir 		{
430cdf0e10cSrcweir 			sal_uLong nPos = Page2Pos( nPage );
431cdf0e10cSrcweir 			sal_Int32 nPg2 = ( ( nPage + nPg ) > nPages ) ? nPages - nPage : nPg;
432cdf0e10cSrcweir 			sal_uLong nBytes = nPg2 * nPageSize;
433cdf0e10cSrcweir 			// fixed address and size for the header
434cdf0e10cSrcweir 			if( nPage == -1 )
435cdf0e10cSrcweir 			{
436cdf0e10cSrcweir 				nPos = 0L, nBytes = 512;
437cdf0e10cSrcweir 				nPg2 = nPg;
438cdf0e10cSrcweir 			}
439cdf0e10cSrcweir 			if( pStrm->Tell() != nPos )
440cdf0e10cSrcweir 			{
441cdf0e10cSrcweir 				if( pStrm->Seek( nPos ) != nPos ) {
442cdf0e10cSrcweir 	#ifdef CHECK_DIRTY
443cdf0e10cSrcweir 					ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
444cdf0e10cSrcweir 	#endif
445cdf0e10cSrcweir                 }
446cdf0e10cSrcweir 			}
447cdf0e10cSrcweir 			pStrm->Read( pBuf, nBytes );
448cdf0e10cSrcweir 			if ( nPg != nPg2 )
449cdf0e10cSrcweir 				SetError( SVSTREAM_READ_ERROR );
450cdf0e10cSrcweir 			else
451cdf0e10cSrcweir 				SetError( pStrm->GetError() );
452cdf0e10cSrcweir 		}
453cdf0e10cSrcweir     }
454cdf0e10cSrcweir     return Good();
455cdf0e10cSrcweir }
456cdf0e10cSrcweir 
457cdf0e10cSrcweir sal_Bool StgCache::Write( sal_Int32 nPage, void* pBuf, sal_Int32 nPg )
458cdf0e10cSrcweir {
459cdf0e10cSrcweir     if( Good() )
460cdf0e10cSrcweir     {
461cdf0e10cSrcweir         sal_uLong nPos = Page2Pos( nPage );
462cdf0e10cSrcweir         sal_uLong nBytes = nPg * nPageSize;
463cdf0e10cSrcweir         // fixed address and size for the header
464cdf0e10cSrcweir         if( nPage == -1 )
465cdf0e10cSrcweir             nPos = 0L, nBytes = 512;
466cdf0e10cSrcweir         if( pStrm->Tell() != nPos )
467cdf0e10cSrcweir 		{
468cdf0e10cSrcweir 			if( pStrm->Seek( nPos ) != nPos ) {
469cdf0e10cSrcweir #ifdef CHECK_DIRTY
470cdf0e10cSrcweir 				ErrorBox( NULL, WB_OK, String("SO2: Seek failed") ).Execute();
471cdf0e10cSrcweir #endif
472cdf0e10cSrcweir             }
473cdf0e10cSrcweir 		}
474cdf0e10cSrcweir 		sal_uLong nRes = pStrm->Write( pBuf, nBytes );
475cdf0e10cSrcweir         if( nRes != nBytes )
476cdf0e10cSrcweir             SetError( SVSTREAM_WRITE_ERROR );
477cdf0e10cSrcweir         else
478cdf0e10cSrcweir             SetError( pStrm->GetError() );
479cdf0e10cSrcweir #ifdef READ_AFTER_WRITE
480cdf0e10cSrcweir 		sal_uInt8 cBuf[ 512 ];
481cdf0e10cSrcweir 		pStrm->Flush();
482cdf0e10cSrcweir 		pStrm->Seek( nPos );
483cdf0e10cSrcweir 		sal_Bool bRes = ( pStrm->Read( cBuf, 512 ) == 512 );
484cdf0e10cSrcweir 		if( bRes )
485cdf0e10cSrcweir 			bRes = !memcmp( cBuf, pBuf, 512 );
486cdf0e10cSrcweir 		if( !bRes )
487cdf0e10cSrcweir 		{
488cdf0e10cSrcweir 			ErrorBox( NULL, WB_OK, String("SO2: Read after Write failed") ).Execute();
489cdf0e10cSrcweir 			pStrm->SetError( SVSTREAM_WRITE_ERROR );
490cdf0e10cSrcweir 		}
491cdf0e10cSrcweir #endif
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir     return Good();
494cdf0e10cSrcweir }
495cdf0e10cSrcweir 
496cdf0e10cSrcweir // set the file size in pages
497cdf0e10cSrcweir 
498cdf0e10cSrcweir sal_Bool StgCache::SetSize( sal_Int32 n )
499cdf0e10cSrcweir {
500cdf0e10cSrcweir     // Add the file header
501cdf0e10cSrcweir     sal_Int32 nSize = n * nPageSize + 512;
502cdf0e10cSrcweir     pStrm->SetStreamSize( nSize );
503cdf0e10cSrcweir     SetError( pStrm->GetError() );
504cdf0e10cSrcweir 	if( !nError )
505cdf0e10cSrcweir 	    nPages = n;
506cdf0e10cSrcweir     return Good();
507cdf0e10cSrcweir }
508cdf0e10cSrcweir 
509cdf0e10cSrcweir void StgCache::SetError( sal_uLong n )
510cdf0e10cSrcweir {
511cdf0e10cSrcweir     if( n && !nError )
512cdf0e10cSrcweir         nError = n;
513cdf0e10cSrcweir }
514cdf0e10cSrcweir 
515cdf0e10cSrcweir void StgCache::ResetError()
516cdf0e10cSrcweir {
517cdf0e10cSrcweir     nError = SVSTREAM_OK;
518cdf0e10cSrcweir     pStrm->ResetError();
519cdf0e10cSrcweir }
520cdf0e10cSrcweir 
521cdf0e10cSrcweir void StgCache::MoveError( StorageBase& r )
522cdf0e10cSrcweir {
523cdf0e10cSrcweir 	if( nError != SVSTREAM_OK )
524cdf0e10cSrcweir 	{
525cdf0e10cSrcweir 		r.SetError( nError );
526cdf0e10cSrcweir 		ResetError();
527cdf0e10cSrcweir 	}
528cdf0e10cSrcweir }
529cdf0e10cSrcweir 
530cdf0e10cSrcweir // Utility functions
531cdf0e10cSrcweir 
532cdf0e10cSrcweir sal_Int32 StgCache::Page2Pos( sal_Int32 nPage )
533cdf0e10cSrcweir {
534cdf0e10cSrcweir     if( nPage < 0 ) nPage = 0;
535cdf0e10cSrcweir     return( nPage * nPageSize ) + nPageSize;
536cdf0e10cSrcweir }
537cdf0e10cSrcweir 
538cdf0e10cSrcweir sal_Int32 StgCache::Pos2Page( sal_Int32 nPos )
539cdf0e10cSrcweir {
540cdf0e10cSrcweir     return ( ( nPos + nPageSize - 1 ) / nPageSize ) * nPageSize - 1;
541cdf0e10cSrcweir }
542cdf0e10cSrcweir 
543