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
; }
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;
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 )
201 sal_uLong
EasyFat::Mark( sal_Int32 nPage
, sal_Int32 nCount
, sal_Int32 nExpect
)
204 --nCount
/= GetPageSize(), nCount
++;
206 sal_Int32 nCurPage
= nPage
;
209 if( nCurPage
< 0 || nCurPage
>= nPages
)
210 return FAT_OUTOFBOUNDS
;
211 pFree
[ nCurPage
] = false;
212 nCurPage
= pFat
[ nCurPage
];
214 if( nCurPage
!= nExpect
&& nCount
== 1 )
215 return FAT_WRONGLENGTH
;
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 )
237 sal_uLong
ValidateMasterFATs();
238 sal_uLong
ValidateDirectoryEntries();
239 sal_uLong
FindUnrefedChains();
240 sal_uLong
MarkAll( StgDirEntry
*pEntry
);
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() ),
253 sal_uLong nErr
= nError
= FAT_OK
;
255 if( ( nErr
= ValidateMasterFATs() ) != FAT_OK
)
257 else if( ( nErr
= ValidateDirectoryEntries() ) != FAT_OK
)
259 else if( ( nErr
= FindUnrefedChains()) != FAT_OK
)
263 sal_uLong
Validator::ValidateMasterFATs()
265 sal_Int32 nCount
= rIo
.aHdr
.GetFATSize();
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
)
275 if( rIo
.aHdr
.GetMasters() )
276 if( ( nErr
= aFat
.Mark(rIo
.aHdr
.GetFATChain( ), aFat
.GetPageSize(), -4 )) != FAT_OK
)
282 sal_uLong
Validator::MarkAll( StgDirEntry
*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
)
299 sal_Int32 nSize
= p
->aEntry
.GetSize();
300 if( nSize
< rIo
.aHdr
.GetThreshold() )
301 nErr
= aSmallFat
.Mark( p
->aEntry
.GetStartPage(),nSize
, -2 );
303 nErr
= aFat
.Mark( p
->aEntry
.GetStartPage(),nSize
, -2 );
311 sal_uLong
Validator::ValidateDirectoryEntries()
314 return FAT_INMEMORYERROR
;
316 // Normale DirEntries
317 sal_uLong nErr
= MarkAll( rIo
.pTOC
->GetRoot() );
321 nErr
= aFat
.Mark( rIo
.pTOC
->GetRoot()->aEntry
.GetStartPage(),
322 rIo
.pTOC
->GetRoot()->aEntry
.GetSize(), -2 );
327 rIo
.aHdr
.GetDataFATStart(),
328 rIo
.aHdr
.GetDataFATSize() * aFat
.GetPageSize(), -2 );
333 rIo
.aHdr
.GetTOCStart(), -1, -2 );
337 sal_uLong
Validator::FindUnrefedChains()
339 if( aSmallFat
.HasUnrefChains() ||
340 aFat
.HasUnrefChains() )
341 return FAT_UNREFCHAIN
;
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()
362 Validator
*pV
= new Validator( *this );
363 bool bRet1
= !pV
->IsError(), bRet2
= true ;
366 SvFileStream
*pFileStrm
= ( SvFileStream
*) GetStrm();
368 return FAT_INMEMORYERROR
;
371 if( aIo
.Open( pFileStrm
->GetFileName(),
372 STREAM_READ
| STREAM_SHARE_DENYNONE
) &&
375 pV
= new Validator( aIo
);
376 bRet2
= !pV
->IsError();
382 nErr
= bRet1
? FAT_ONFILEERROR
: FAT_INMEMORYERROR
;
383 else nErr
= bRet1
? FAT_OK
: FAT_BOTHERROR
;
384 if( nErr
!= FAT_OK
&& !bCopied
)
387 aArg
.aFile
= pFileStrm
->GetFileName();
389 ErrorLink::get().Call( &aArg
);
392 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
395 // OSL_FAIL("Validiere nicht (kein FileStorage)");
399 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */