1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stgio.cxx,v $
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"
35 #include "stgelem.hxx"
36 #include "stgcache.hxx"
37 #include "stgstrms.hxx"
40 #include <rtl/instance.hxx>
42 ///////////////////////////// class StgIo //////////////////////////////
44 // This class holds the storage header and all internal streams.
46 StgIo::StgIo() : StgCache()
63 // Load the header. Do not set an error code if the header is invalid.
69 if( aHdr
.Load( *this ) )
80 // Set up an initial, empty storage
89 void StgIo::SetupStreams()
100 SetPhysPageSize( 1 << aHdr
.GetPageSize() );
101 pFAT
= new StgFATStrm( *this );
102 pTOC
= new StgDirStrm( *this );
105 StgDirEntry
* pRoot
= pTOC
->GetRoot();
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
);
115 SetError( SVSTREAM_FILEFORMAT_ERROR
);
119 // get the logical data page size
121 short StgIo::GetDataPageSize()
123 return 1 << aHdr
.GetDataPageSize();
128 BOOL
StgIo::CommitAll()
130 // Store the data (all streams and the TOC)
135 aHdr
.SetDataFATStart( pDataFAT
->GetStart() );
136 aHdr
.SetDataFATSize( pDataFAT
->GetPages() );
137 aHdr
.SetTOCStart( pTOC
->GetStart() );
138 if( aHdr
.Store( *this ) )
141 ULONG n
= pStrm
->GetError();
144 if( n
==0 ) ValidateFATs();
146 return BOOL( n
== 0 );
150 SetError( SVSTREAM_WRITE_ERROR
);
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;
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 )
207 ULONG
EasyFat::Mark( INT32 nPage
, INT32 nCount
, INT32 nExpect
)
210 --nCount
/= GetPageSize(), nCount
++;
212 INT32 nCurPage
= nPage
;
215 pFree
[ nCurPage
] = FALSE
;
216 nCurPage
= pFat
[ nCurPage
];
218 if( nCurPage
!= nExpect
&& nCount
== 1 )
219 return FAT_WRONGLENGTH
;
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 )
228 // Naechster Block nicht in der FAT
229 if( nCount
&& ( nCurPage
< 0 || nCurPage
>= nPages
) )
230 return FAT_OUTOFBOUNDS
;
244 ULONG
ValidateMasterFATs();
245 ULONG
ValidateDirectoryEntries();
246 ULONG
FindUnrefedChains();
247 ULONG
MarkAll( StgDirEntry
*pEntry
);
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() ),
260 ULONG nErr
= nError
= FAT_OK
;
262 if( ( nErr
= ValidateMasterFATs() ) != FAT_OK
)
264 else if( ( nErr
= ValidateDirectoryEntries() ) != FAT_OK
)
266 else if( ( nErr
= FindUnrefedChains()) != FAT_OK
)
270 ULONG
Validator::ValidateMasterFATs()
272 INT32 nCount
= rIo
.aHdr
.GetFATSize();
274 for( INT32 i
= 0; i
< nCount
; i
++ )
276 if( ( nErr
= aFat
.Mark(rIo
.pFAT
->GetPage( short(i
), FALSE
), aFat
.GetPageSize(), -3 )) != FAT_OK
)
279 if( rIo
.aHdr
.GetMasters() )
280 if( ( nErr
= aFat
.Mark(rIo
.aHdr
.GetFATChain( ), aFat
.GetPageSize(), -4 )) != FAT_OK
)
285 ULONG
Validator::MarkAll( StgDirEntry
*pEntry
)
287 StgIterator
aIter( *pEntry
);
289 for( StgDirEntry
* p
= aIter
.First(); p
; p
= aIter
.Next() )
291 if( p
->aEntry
.GetType() == STG_STORAGE
)
299 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 ULONG
Validator::ValidateDirectoryEntries()
313 // Normale DirEntries
314 ULONG nErr
= MarkAll( rIo
.pTOC
->GetRoot() );
318 nErr
= aFat
.Mark( rIo
.pTOC
->GetRoot()->aEntry
.GetStartPage(),
319 rIo
.pTOC
->GetRoot()->aEntry
.GetSize(), -2 );
324 rIo
.aHdr
.GetDataFATStart(),
325 rIo
.aHdr
.GetDataFATSize() * aFat
.GetPageSize(), -2 );
330 rIo
.aHdr
.GetTOCStart(), -1, -2 );
334 ULONG
Validator::FindUnrefedChains()
336 if( aSmallFat
.HasUnrefChains() ||
337 aFat
.HasUnrefChains() )
338 return FAT_UNREFCHAIN
;
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()
359 Validator
*pV
= new Validator( *this );
360 BOOL bRet1
= !pV
->IsError(), bRet2
= TRUE
;
362 SvFileStream
*pFileStrm
= ( SvFileStream
*) GetStrm();
364 if( aIo
.Open( pFileStrm
->GetFileName(),
365 STREAM_READ
| STREAM_SHARE_DENYNONE
) &&
368 pV
= new Validator( aIo
);
369 bRet2
= !pV
->IsError();
375 nErr
= bRet1
? FAT_ONFILEERROR
: FAT_INMEMORYERROR
;
376 else nErr
= bRet1
? FAT_OK
: FAT_BOTHERROR
;
377 if( nErr
!= FAT_OK
&& !bCopied
)
380 aArg
.aFile
= pFileStrm
->GetFileName();
382 ErrorLink::get().Call( &aArg
);
385 // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
388 // DBG_ERROR("Validiere nicht (kein FileStorage)");