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