bump product version to 4.2.0.1
[LibreOffice.git] / sot / source / sdstor / stgio.cxx
blob84da972da50cf86af1058e70691e529978c005e1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "sot/stg.hxx"
22 #include "stgelem.hxx"
23 #include "stgcache.hxx"
24 #include "stgstrms.hxx"
25 #include "stgdir.hxx"
26 #include "stgio.hxx"
27 #include <rtl/instance.hxx>
29 ///////////////////////////// class StgIo //////////////////////////////
31 // This class holds the storage header and all internal streams.
33 StgIo::StgIo() : StgCache()
35 pTOC = NULL;
36 pDataFAT = NULL;
37 pDataStrm = NULL;
38 pFAT = NULL;
39 bCopied = false;
42 StgIo::~StgIo()
44 delete pTOC;
45 delete pDataFAT;
46 delete pDataStrm;
47 delete pFAT;
50 // Load the header. Do not set an error code if the header is invalid.
52 bool StgIo::Load()
54 if( pStrm )
56 if( aHdr.Load( *this ) )
58 if( aHdr.Check() )
59 SetupStreams();
60 else
61 return false;
63 else
64 return false;
66 return Good();
69 // Set up an initial, empty storage
71 bool StgIo::Init()
73 aHdr.Init();
74 SetupStreams();
75 return CommitAll();
78 void StgIo::SetupStreams()
80 delete pTOC;
81 delete pDataFAT;
82 delete pDataStrm;
83 delete pFAT;
84 pTOC = NULL;
85 pDataFAT = NULL;
86 pDataStrm = NULL;
87 pFAT = NULL;
88 ResetError();
89 SetPhysPageSize( 1 << aHdr.GetPageSize() );
90 pFAT = new StgFATStrm( *this );
91 pTOC = new StgDirStrm( *this );
92 if( !GetError() )
94 StgDirEntry* pRoot = pTOC->GetRoot();
95 if( pRoot )
97 pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
98 pDataStrm = new StgDataStrm( *this, *pRoot );
99 pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
100 pDataStrm->SetIncrement( GetDataPageSize() );
101 pDataStrm->SetEntry( *pRoot );
103 else
104 SetError( SVSTREAM_FILEFORMAT_ERROR );
108 // get the logical data page size
110 short StgIo::GetDataPageSize()
112 return 1 << aHdr.GetDataPageSize();
115 // Commit everything
117 bool StgIo::CommitAll()
119 // Store the data (all streams and the TOC)
120 if( pTOC && pTOC->Store() && pDataFAT )
122 if( Commit() )
124 aHdr.SetDataFATStart( pDataFAT->GetStart() );
125 aHdr.SetDataFATSize( pDataFAT->GetPages() );
126 aHdr.SetTOCStart( pTOC->GetStart() );
127 if( aHdr.Store( *this ) )
129 pStrm->Flush();
130 sal_uLong n = pStrm->GetError();
131 SetError( n );
132 #ifdef DBG_UTIL
133 if( n==0 ) ValidateFATs();
134 #endif
135 return n == 0;
139 SetError( SVSTREAM_WRITE_ERROR );
140 return false;
144 class EasyFat
146 sal_Int32 *pFat;
147 bool *pFree;
148 sal_Int32 nPages;
149 sal_Int32 nPageSize;
151 public:
152 EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
153 ~EasyFat() { delete[] pFat; delete[] pFree; }
155 sal_Int32 GetPageSize() { return nPageSize; }
156 sal_Int32 Count() { return nPages; }
157 sal_Int32 operator[]( sal_Int32 nOffset )
159 OSL_ENSURE( nOffset >= 0 && nOffset < nPages, "Unexpected offset!" );
160 return nOffset >= 0 && nOffset < nPages ? pFat[ nOffset ] : -2;
163 sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
164 bool HasUnrefChains();
167 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
169 nPages = pFatStream->GetSize() >> 2;
170 nPageSize = nPSize;
171 pFat = new sal_Int32[ nPages ];
172 pFree = new bool[ nPages ];
174 rtl::Reference< StgPage > pPage;
175 sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
177 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
179 if( ! (nPage % nFatPageSize) )
181 pFatStream->Pos2Page( nPage << 2 );
182 sal_Int32 nPhysPage = pFatStream->GetPage();
183 pPage = rIo.Get( nPhysPage, true );
186 pFat[ nPage ] = rIo.GetFromPage( pPage, short( nPage % nFatPageSize ) );
187 pFree[ nPage ] = true;
191 bool EasyFat::HasUnrefChains()
193 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
195 if( pFree[ nPage ] && pFat[ nPage ] != -1 )
196 return true;
198 return false;
201 sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
203 if( nCount > 0 )
204 --nCount /= GetPageSize(), nCount++;
206 sal_Int32 nCurPage = nPage;
207 while( nCount != 0 )
209 if( nCurPage < 0 || nCurPage >= nPages )
210 return FAT_OUTOFBOUNDS;
211 pFree[ nCurPage ] = false;
212 nCurPage = pFat[ nCurPage ];
213 //Stream zu lang
214 if( nCurPage != nExpect && nCount == 1 )
215 return FAT_WRONGLENGTH;
216 //Stream zu kurz
217 if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
218 return FAT_WRONGLENGTH;
219 // letzter Block bei Stream ohne Laenge
220 if( nCurPage == nExpect && nCount == -1 )
221 nCount = 1;
222 if( nCount != -1 )
223 nCount--;
225 return FAT_OK;
228 class Validator
230 sal_uLong nError;
232 EasyFat aSmallFat;
233 EasyFat aFat;
235 StgIo &rIo;
237 sal_uLong ValidateMasterFATs();
238 sal_uLong ValidateDirectoryEntries();
239 sal_uLong FindUnrefedChains();
240 sal_uLong MarkAll( StgDirEntry *pEntry );
242 public:
244 Validator( StgIo &rIo );
245 bool IsError() { return nError != 0; }
248 Validator::Validator( StgIo &rIoP )
249 : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
250 aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
251 rIo( rIoP )
253 sal_uLong nErr = nError = FAT_OK;
255 if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
256 nError = nErr;
257 else if( ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
258 nError = nErr;
259 else if( ( nErr = FindUnrefedChains()) != FAT_OK )
260 nError = nErr;
263 sal_uLong Validator::ValidateMasterFATs()
265 sal_Int32 nCount = rIo.aHdr.GetFATSize();
266 sal_uLong nErr;
267 if ( !rIo.pFAT )
268 return FAT_INMEMORYERROR;
270 for( sal_Int32 i = 0; i < nCount; i++ )
272 if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), false ), aFat.GetPageSize(), -3 )) != FAT_OK )
273 return nErr;
275 if( rIo.aHdr.GetMasters() )
276 if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
277 return nErr;
279 return FAT_OK;
282 sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
284 if ( !pEntry )
285 return FAT_INMEMORYERROR;
287 StgIterator aIter( *pEntry );
288 sal_uLong nErr = FAT_OK;
289 for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
291 if( p->aEntry.GetType() == STG_STORAGE )
293 nErr = MarkAll( p );
294 if( nErr != FAT_OK )
295 return nErr;
297 else
299 sal_Int32 nSize = p->aEntry.GetSize();
300 if( nSize < rIo.aHdr.GetThreshold() )
301 nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
302 else
303 nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
304 if( nErr != FAT_OK )
305 return nErr;
308 return FAT_OK;
311 sal_uLong Validator::ValidateDirectoryEntries()
313 if ( !rIo.pTOC )
314 return FAT_INMEMORYERROR;
316 // Normale DirEntries
317 sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
318 if( nErr != FAT_OK )
319 return nErr;
320 // Small Data
321 nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
322 rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
323 if( nErr != FAT_OK )
324 return nErr;
325 // Small Data FAT
326 nErr = aFat.Mark(
327 rIo.aHdr.GetDataFATStart(),
328 rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
329 if( nErr != FAT_OK )
330 return nErr;
331 // TOC
332 nErr = aFat.Mark(
333 rIo.aHdr.GetTOCStart(), -1, -2 );
334 return nErr;
337 sal_uLong Validator::FindUnrefedChains()
339 if( aSmallFat.HasUnrefChains() ||
340 aFat.HasUnrefChains() )
341 return FAT_UNREFCHAIN;
342 else
343 return FAT_OK;
346 namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
348 void StgIo::SetErrorLink( const Link& rLink )
350 ErrorLink::get() = rLink;
353 const Link& StgIo::GetErrorLink()
355 return ErrorLink::get();
358 sal_uLong StgIo::ValidateFATs()
360 if( bFile )
362 Validator *pV = new Validator( *this );
363 bool bRet1 = !pV->IsError(), bRet2 = true ;
364 delete pV;
366 SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
367 if ( !pFileStrm )
368 return FAT_INMEMORYERROR;
370 StgIo aIo;
371 if( aIo.Open( pFileStrm->GetFileName(),
372 STREAM_READ | STREAM_SHARE_DENYNONE) &&
373 aIo.Load() )
375 pV = new Validator( aIo );
376 bRet2 = !pV->IsError();
377 delete pV;
380 sal_uLong nErr;
381 if( bRet1 != bRet2 )
382 nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
383 else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
384 if( nErr != FAT_OK && !bCopied )
386 StgLinkArg aArg;
387 aArg.aFile = pFileStrm->GetFileName();
388 aArg.nErr = nErr;
389 ErrorLink::get().Call( &aArg );
390 bCopied = true;
392 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
393 return nErr;
395 // OSL_FAIL("Validiere nicht (kein FileStorage)");
396 return FAT_OK;
399 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */