1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
27 #include <rtl/instance.hxx>
29 ///////////////////////////// class StgIo
31 // This class holds the storage header and all internal streams.
33 StgIo::StgIo() : StgCache()
50 // Load the header. Do not set an error code if the header is invalid.
56 if( aHdr
.Load( *this ) )
69 // Set up an initial, empty storage
78 void StgIo::SetupStreams()
89 SetPhysPageSize( 1 << aHdr
.GetPageSize() );
90 pFAT
= new StgFATStrm( *this );
91 pTOC
= new StgDirStrm( *this );
94 StgDirEntry
* pRoot
= pTOC
->GetRoot();
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
);
104 SetError( SVSTREAM_FILEFORMAT_ERROR
);
108 // get the logical data page size
110 short StgIo::GetDataPageSize()
112 return 1 << aHdr
.GetDataPageSize();
117 bool StgIo::CommitAll()
119 // Store the data (all streams and the TOC)
120 if( pTOC
&& pTOC
->Store() && pDataFAT
)
124 aHdr
.SetDataFATStart( pDataFAT
->GetStart() );
125 aHdr
.SetDataFATSize( pDataFAT
->GetPages() );
126 aHdr
.SetTOCStart( pTOC
->GetStart() );
127 if( aHdr
.Store( *this ) )
130 sal_uLong n
= pStrm
->GetError();
133 if( n
==0 ) ValidateFATs();
139 SetError( SVSTREAM_WRITE_ERROR
);
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;
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 )
195 sal_uLong
EasyFat::Mark( sal_Int32 nPage
, sal_Int32 nCount
, sal_Int32 nExpect
)
198 --nCount
/= GetPageSize(), nCount
++;
200 sal_Int32 nCurPage
= nPage
;
203 if( nCurPage
< 0 || nCurPage
>= nPages
)
204 return FAT_OUTOFBOUNDS
;
205 pFree
[ nCurPage
] = false;
206 nCurPage
= pFat
[ nCurPage
];
208 if( nCurPage
!= nExpect
&& nCount
== 1 )
209 return FAT_WRONGLENGTH
;
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 )
231 sal_uLong
ValidateMasterFATs();
232 sal_uLong
ValidateDirectoryEntries();
233 sal_uLong
FindUnrefedChains();
234 sal_uLong
MarkAll( StgDirEntry
*pEntry
);
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() ),
247 sal_uLong nErr
= nError
= FAT_OK
;
249 if( ( nErr
= ValidateMasterFATs() ) != FAT_OK
)
251 else if( ( nErr
= ValidateDirectoryEntries() ) != FAT_OK
)
253 else if( ( nErr
= FindUnrefedChains()) != FAT_OK
)
257 sal_uLong
Validator::ValidateMasterFATs()
259 sal_Int32 nCount
= rIo
.aHdr
.GetFATSize();
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
)
269 if( rIo
.aHdr
.GetMasters() )
270 if( ( nErr
= aFat
.Mark(rIo
.aHdr
.GetFATChain( ), aFat
.GetPageSize(), -4 )) != FAT_OK
)
276 sal_uLong
Validator::MarkAll( StgDirEntry
*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
)
293 sal_Int32 nSize
= p
->aEntry
.GetSize();
294 if( nSize
< rIo
.aHdr
.GetThreshold() )
295 nErr
= aSmallFat
.Mark( p
->aEntry
.GetStartPage(),nSize
, -2 );
297 nErr
= aFat
.Mark( p
->aEntry
.GetStartPage(),nSize
, -2 );
305 sal_uLong
Validator::ValidateDirectoryEntries()
308 return FAT_INMEMORYERROR
;
310 // Normale DirEntries
311 sal_uLong nErr
= MarkAll( rIo
.pTOC
->GetRoot() );
315 nErr
= aFat
.Mark( rIo
.pTOC
->GetRoot()->aEntry
.GetStartPage(),
316 rIo
.pTOC
->GetRoot()->aEntry
.GetSize(), -2 );
321 rIo
.aHdr
.GetDataFATStart(),
322 rIo
.aHdr
.GetDataFATSize() * aFat
.GetPageSize(), -2 );
327 rIo
.aHdr
.GetTOCStart(), -1, -2 );
331 sal_uLong
Validator::FindUnrefedChains()
333 if( aSmallFat
.HasUnrefChains() ||
334 aFat
.HasUnrefChains() )
335 return FAT_UNREFCHAIN
;
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()
356 Validator
*pV
= new Validator( *this );
357 bool bRet1
= !pV
->IsError(), bRet2
= true ;
360 SvFileStream
*pFileStrm
= static_cast<SvFileStream
*>( GetStrm() );
362 return FAT_INMEMORYERROR
;
365 if( aIo
.Open( pFileStrm
->GetFileName(),
366 StreamMode::READ
| StreamMode::SHARE_DENYNONE
) &&
369 pV
= new Validator( aIo
);
370 bRet2
= !pV
->IsError();
376 nErr
= bRet1
? FAT_ONFILEERROR
: FAT_INMEMORYERROR
;
377 else nErr
= bRet1
? FAT_OK
: FAT_BOTHERROR
;
378 if( nErr
!= FAT_OK
&& !bCopied
)
381 aArg
.aFile
= pFileStrm
->GetFileName();
383 ErrorLink::get().Call( &aArg
);
386 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
389 // OSL_FAIL("Validiere nicht (kein FileStorage)");
393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */