xref: /aoo42x/main/sot/source/sdstor/stgcache.cxx (revision 297a844a)
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