bump product version to 5.0.4.1
[LibreOffice.git] / sot / source / sdstor / stgio.cxx
blob11f391efe0fb250f0a03f4bddd34d9be7a77d4d1
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; }
157 sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
158 bool HasUnrefChains();
161 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
163 nPages = pFatStream->GetSize() >> 2;
164 nPageSize = nPSize;
165 pFat = new sal_Int32[ nPages ];
166 pFree = new bool[ nPages ];
168 rtl::Reference< StgPage > pPage;
169 sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
171 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
173 if( ! (nPage % nFatPageSize) )
175 pFatStream->Pos2Page( nPage << 2 );
176 sal_Int32 nPhysPage = pFatStream->GetPage();
177 pPage = rIo.Get( nPhysPage, true );
180 pFat[ nPage ] = StgCache::GetFromPage( pPage, short( nPage % nFatPageSize ) );
181 pFree[ nPage ] = true;
185 bool EasyFat::HasUnrefChains()
187 for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
189 if( pFree[ nPage ] && pFat[ nPage ] != -1 )
190 return true;
192 return false;
195 sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
197 if( nCount > 0 )
198 --nCount /= GetPageSize(), nCount++;
200 sal_Int32 nCurPage = nPage;
201 while( nCount != 0 )
203 if( nCurPage < 0 || nCurPage >= nPages )
204 return FAT_OUTOFBOUNDS;
205 pFree[ nCurPage ] = false;
206 nCurPage = pFat[ nCurPage ];
207 //Stream zu lang
208 if( nCurPage != nExpect && nCount == 1 )
209 return FAT_WRONGLENGTH;
210 //Stream zu kurz
211 if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
212 return FAT_WRONGLENGTH;
213 // letzter Block bei Stream ohne Laenge
214 if( nCurPage == nExpect && nCount == -1 )
215 nCount = 1;
216 if( nCount != -1 )
217 nCount--;
219 return FAT_OK;
222 class Validator
224 sal_uLong nError;
226 EasyFat aSmallFat;
227 EasyFat aFat;
229 StgIo &rIo;
231 sal_uLong ValidateMasterFATs();
232 sal_uLong ValidateDirectoryEntries();
233 sal_uLong FindUnrefedChains();
234 sal_uLong MarkAll( StgDirEntry *pEntry );
236 public:
238 Validator( StgIo &rIo );
239 bool IsError() { return nError != 0; }
242 Validator::Validator( StgIo &rIoP )
243 : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
244 aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
245 rIo( rIoP )
247 sal_uLong nErr = nError = FAT_OK;
249 if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
250 nError = nErr;
251 else if( ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
252 nError = nErr;
253 else if( ( nErr = FindUnrefedChains()) != FAT_OK )
254 nError = nErr;
257 sal_uLong Validator::ValidateMasterFATs()
259 sal_Int32 nCount = rIo.aHdr.GetFATSize();
260 sal_uLong nErr;
261 if ( !rIo.pFAT )
262 return FAT_INMEMORYERROR;
264 for( sal_Int32 i = 0; i < nCount; i++ )
266 if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), false ), aFat.GetPageSize(), -3 )) != FAT_OK )
267 return nErr;
269 if( rIo.aHdr.GetMasters() )
270 if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
271 return nErr;
273 return FAT_OK;
276 sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
278 if ( !pEntry )
279 return FAT_INMEMORYERROR;
281 StgIterator aIter( *pEntry );
282 sal_uLong nErr = FAT_OK;
283 for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
285 if( p->aEntry.GetType() == STG_STORAGE )
287 nErr = MarkAll( p );
288 if( nErr != FAT_OK )
289 return nErr;
291 else
293 sal_Int32 nSize = p->aEntry.GetSize();
294 if( nSize < rIo.aHdr.GetThreshold() )
295 nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
296 else
297 nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
298 if( nErr != FAT_OK )
299 return nErr;
302 return FAT_OK;
305 sal_uLong Validator::ValidateDirectoryEntries()
307 if ( !rIo.pTOC )
308 return FAT_INMEMORYERROR;
310 // Normale DirEntries
311 sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
312 if( nErr != FAT_OK )
313 return nErr;
314 // Small Data
315 nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
316 rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
317 if( nErr != FAT_OK )
318 return nErr;
319 // Small Data FAT
320 nErr = aFat.Mark(
321 rIo.aHdr.GetDataFATStart(),
322 rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
323 if( nErr != FAT_OK )
324 return nErr;
325 // TOC
326 nErr = aFat.Mark(
327 rIo.aHdr.GetTOCStart(), -1, -2 );
328 return nErr;
331 sal_uLong Validator::FindUnrefedChains()
333 if( aSmallFat.HasUnrefChains() ||
334 aFat.HasUnrefChains() )
335 return FAT_UNREFCHAIN;
336 else
337 return FAT_OK;
340 namespace { struct ErrorLink : public rtl::Static<Link<>, ErrorLink > {}; }
342 void StgIo::SetErrorLink( const Link<>& rLink )
344 ErrorLink::get() = rLink;
347 const Link<>& StgIo::GetErrorLink()
349 return ErrorLink::get();
352 sal_uLong StgIo::ValidateFATs()
354 if( bFile )
356 Validator *pV = new Validator( *this );
357 bool bRet1 = !pV->IsError(), bRet2 = true ;
358 delete pV;
360 SvFileStream *pFileStrm = static_cast<SvFileStream *>( GetStrm() );
361 if ( !pFileStrm )
362 return FAT_INMEMORYERROR;
364 StgIo aIo;
365 if( aIo.Open( pFileStrm->GetFileName(),
366 StreamMode::READ | StreamMode::SHARE_DENYNONE) &&
367 aIo.Load() )
369 pV = new Validator( aIo );
370 bRet2 = !pV->IsError();
371 delete pV;
374 sal_uLong nErr;
375 if( bRet1 != bRet2 )
376 nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
377 else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
378 if( nErr != FAT_OK && !bCopied )
380 StgLinkArg aArg;
381 aArg.aFile = pFileStrm->GetFileName();
382 aArg.nErr = nErr;
383 ErrorLink::get().Call( &aArg );
384 bCopied = true;
386 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
387 return nErr;
389 // OSL_FAIL("Validiere nicht (kein FileStorage)");
390 return FAT_OK;
393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */