merge the formfield patch from ooo-build
[ooovba.git] / sot / source / sdstor / stgio.cxx
blob0d279235064de7f0d67942653b830bdad31feaae
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stgio.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sot.hxx"
34 #include "stg.hxx"
35 #include "stgelem.hxx"
36 #include "stgcache.hxx"
37 #include "stgstrms.hxx"
38 #include "stgdir.hxx"
39 #include "stgio.hxx"
40 #include <rtl/instance.hxx>
42 ///////////////////////////// class StgIo //////////////////////////////
44 // This class holds the storage header and all internal streams.
46 StgIo::StgIo() : StgCache()
48 pTOC = NULL;
49 pDataFAT = NULL;
50 pDataStrm = NULL;
51 pFAT = NULL;
52 bCopied = FALSE;
55 StgIo::~StgIo()
57 delete pTOC;
58 delete pDataFAT;
59 delete pDataStrm;
60 delete pFAT;
63 // Load the header. Do not set an error code if the header is invalid.
65 BOOL StgIo::Load()
67 if( pStrm )
69 if( aHdr.Load( *this ) )
71 if( aHdr.Check() )
72 SetupStreams();
73 else
74 return FALSE;
77 return Good();
80 // Set up an initial, empty storage
82 BOOL StgIo::Init()
84 aHdr.Init();
85 SetupStreams();
86 return CommitAll();
89 void StgIo::SetupStreams()
91 delete pTOC;
92 delete pDataFAT;
93 delete pDataStrm;
94 delete pFAT;
95 pTOC = NULL;
96 pDataFAT = NULL;
97 pDataStrm = NULL;
98 pFAT = NULL;
99 ResetError();
100 SetPhysPageSize( 1 << aHdr.GetPageSize() );
101 pFAT = new StgFATStrm( *this );
102 pTOC = new StgDirStrm( *this );
103 if( !GetError() )
105 StgDirEntry* pRoot = pTOC->GetRoot();
106 if( pRoot )
108 pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
109 pDataStrm = new StgDataStrm( *this, pRoot );
110 pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
111 pDataStrm->SetIncrement( GetDataPageSize() );
112 pDataStrm->SetEntry( *pRoot );
114 else
115 SetError( SVSTREAM_FILEFORMAT_ERROR );
119 // get the logical data page size
121 short StgIo::GetDataPageSize()
123 return 1 << aHdr.GetDataPageSize();
126 // Commit everything
128 BOOL StgIo::CommitAll()
130 // Store the data (all streams and the TOC)
131 if( pTOC->Store() )
133 if( Commit( NULL ) )
135 aHdr.SetDataFATStart( pDataFAT->GetStart() );
136 aHdr.SetDataFATSize( pDataFAT->GetPages() );
137 aHdr.SetTOCStart( pTOC->GetStart() );
138 if( aHdr.Store( *this ) )
140 pStrm->Flush();
141 ULONG n = pStrm->GetError();
142 SetError( n );
143 #ifdef DBG_UTIL
144 if( n==0 ) ValidateFATs();
145 #endif
146 return BOOL( n == 0 );
150 SetError( SVSTREAM_WRITE_ERROR );
151 return FALSE;
155 class EasyFat
157 INT32 *pFat;
158 BOOL *pFree;
159 INT32 nPages;
160 INT32 nPageSize;
162 public:
163 EasyFat( StgIo & rIo, StgStrm *pFatStream, INT32 nPSize );
164 ~EasyFat() { delete pFat; delete pFree; }
165 INT32 GetPageSize() { return nPageSize; }
166 INT32 Count() { return nPages; }
167 INT32 operator[]( INT32 nOffset ) { return pFat[ nOffset ]; }
169 ULONG Mark( INT32 nPage, INT32 nCount, INT32 nExpect );
170 BOOL HasUnrefChains();
173 EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, INT32 nPSize )
175 nPages = pFatStream->GetSize() >> 2;
176 nPageSize = nPSize;
177 pFat = new INT32[ nPages ];
178 pFree = new BOOL[ nPages ];
180 StgPage *pPage = NULL;
181 INT32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
183 for( INT32 nPage = 0; nPage < nPages; nPage++ )
185 if( ! (nPage % nFatPageSize) )
187 pFatStream->Pos2Page( nPage << 2 );
188 INT32 nPhysPage = pFatStream->GetPage();
189 pPage = rIo.Get( nPhysPage, TRUE );
192 pFat[ nPage ] = pPage->GetPage( short( nPage % nFatPageSize ) );
193 pFree[ nPage ] = TRUE;
197 BOOL EasyFat::HasUnrefChains()
199 for( INT32 nPage = 0; nPage < nPages; nPage++ )
201 if( pFree[ nPage ] && pFat[ nPage ] != -1 )
202 return TRUE;
204 return FALSE;
207 ULONG EasyFat::Mark( INT32 nPage, INT32 nCount, INT32 nExpect )
209 if( nCount > 0 )
210 --nCount /= GetPageSize(), nCount++;
212 INT32 nCurPage = nPage;
213 while( nCount != 0 )
215 pFree[ nCurPage ] = FALSE;
216 nCurPage = pFat[ nCurPage ];
217 //Stream zu lang
218 if( nCurPage != nExpect && nCount == 1 )
219 return FAT_WRONGLENGTH;
220 //Stream zu kurz
221 if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
222 return FAT_WRONGLENGTH;
223 // letzter Block bei Stream ohne Laenge
224 if( nCurPage == nExpect && nCount == -1 )
225 nCount = 1;
226 if( nCount != -1 )
227 nCount--;
228 // Naechster Block nicht in der FAT
229 if( nCount && ( nCurPage < 0 || nCurPage >= nPages ) )
230 return FAT_OUTOFBOUNDS;
232 return FAT_OK;
235 class Validator
237 ULONG nError;
239 EasyFat aSmallFat;
240 EasyFat aFat;
242 StgIo &rIo;
244 ULONG ValidateMasterFATs();
245 ULONG ValidateDirectoryEntries();
246 ULONG FindUnrefedChains();
247 ULONG MarkAll( StgDirEntry *pEntry );
249 public:
251 Validator( StgIo &rIo );
252 BOOL IsError() { return nError != 0; }
255 Validator::Validator( StgIo &rIoP )
256 : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
257 aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
258 rIo( rIoP )
260 ULONG nErr = nError = FAT_OK;
262 if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
263 nError = nErr;
264 else if( ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
265 nError = nErr;
266 else if( ( nErr = FindUnrefedChains()) != FAT_OK )
267 nError = nErr;
270 ULONG Validator::ValidateMasterFATs()
272 INT32 nCount = rIo.aHdr.GetFATSize();
273 ULONG nErr;
274 for( INT32 i = 0; i < nCount; i++ )
276 if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), FALSE ), aFat.GetPageSize(), -3 )) != FAT_OK )
277 return nErr;
279 if( rIo.aHdr.GetMasters() )
280 if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
281 return nErr;
282 return FAT_OK;
285 ULONG Validator::MarkAll( StgDirEntry *pEntry )
287 StgIterator aIter( *pEntry );
288 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 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 ULONG Validator::ValidateDirectoryEntries()
313 // Normale DirEntries
314 ULONG nErr = MarkAll( rIo.pTOC->GetRoot() );
315 if( nErr != FAT_OK )
316 return nErr;
317 // Small Data
318 nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
319 rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
320 if( nErr != FAT_OK )
321 return nErr;
322 // Small Data FAT
323 nErr = aFat.Mark(
324 rIo.aHdr.GetDataFATStart(),
325 rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
326 if( nErr != FAT_OK )
327 return nErr;
328 // TOC
329 nErr = aFat.Mark(
330 rIo.aHdr.GetTOCStart(), -1, -2 );
331 return nErr;
334 ULONG Validator::FindUnrefedChains()
336 if( aSmallFat.HasUnrefChains() ||
337 aFat.HasUnrefChains() )
338 return FAT_UNREFCHAIN;
339 else
340 return FAT_OK;
343 namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
345 void StgIo::SetErrorLink( const Link& rLink )
347 ErrorLink::get() = rLink;
350 const Link& StgIo::GetErrorLink()
352 return ErrorLink::get();
355 ULONG StgIo::ValidateFATs()
357 if( bFile )
359 Validator *pV = new Validator( *this );
360 BOOL bRet1 = !pV->IsError(), bRet2 = TRUE ;
361 delete pV;
362 SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
363 StgIo aIo;
364 if( aIo.Open( pFileStrm->GetFileName(),
365 STREAM_READ | STREAM_SHARE_DENYNONE) &&
366 aIo.Load() )
368 pV = new Validator( aIo );
369 bRet2 = !pV->IsError();
370 delete pV;
373 ULONG nErr;
374 if( bRet1 != bRet2 )
375 nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
376 else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
377 if( nErr != FAT_OK && !bCopied )
379 StgLinkArg aArg;
380 aArg.aFile = pFileStrm->GetFileName();
381 aArg.nErr = nErr;
382 ErrorLink::get().Call( &aArg );
383 bCopied = TRUE;
385 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
386 return nErr;
388 // DBG_ERROR("Validiere nicht (kein FileStorage)");
389 return FAT_OK;