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