Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
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>
28 :
29 : ///////////////////////////// class StgIo //////////////////////////////
30 :
31 : // This class holds the storage header and all internal streams.
32 :
33 102 : StgIo::StgIo() : StgCache()
34 : {
35 102 : pTOC = NULL;
36 102 : pDataFAT = NULL;
37 102 : pDataStrm = NULL;
38 102 : pFAT = NULL;
39 102 : bCopied = sal_False;
40 102 : }
41 :
42 204 : StgIo::~StgIo()
43 : {
44 102 : delete pTOC;
45 102 : delete pDataFAT;
46 102 : delete pDataStrm;
47 102 : delete pFAT;
48 102 : }
49 :
50 : // Load the header. Do not set an error code if the header is invalid.
51 :
52 86 : sal_Bool StgIo::Load()
53 : {
54 86 : if( pStrm )
55 : {
56 86 : if( aHdr.Load( *this ) )
57 : {
58 86 : if( aHdr.Check() )
59 86 : SetupStreams();
60 : else
61 0 : return sal_False;
62 : }
63 : else
64 0 : return sal_False;
65 : }
66 86 : return Good();
67 : }
68 :
69 : // Set up an initial, empty storage
70 :
71 16 : sal_Bool StgIo::Init()
72 : {
73 16 : aHdr.Init();
74 16 : SetupStreams();
75 16 : return CommitAll();
76 : }
77 :
78 102 : void StgIo::SetupStreams()
79 : {
80 102 : delete pTOC;
81 102 : delete pDataFAT;
82 102 : delete pDataStrm;
83 102 : delete pFAT;
84 102 : pTOC = NULL;
85 102 : pDataFAT = NULL;
86 102 : pDataStrm = NULL;
87 102 : pFAT = NULL;
88 102 : ResetError();
89 102 : SetPhysPageSize( 1 << aHdr.GetPageSize() );
90 102 : pFAT = new StgFATStrm( *this );
91 102 : pTOC = new StgDirStrm( *this );
92 102 : if( !GetError() )
93 : {
94 99 : StgDirEntry* pRoot = pTOC->GetRoot();
95 99 : if( pRoot )
96 : {
97 99 : pDataFAT = new StgDataStrm( *this, aHdr.GetDataFATStart(), -1 );
98 99 : pDataStrm = new StgDataStrm( *this, *pRoot );
99 99 : pDataFAT->SetIncrement( 1 << aHdr.GetPageSize() );
100 99 : pDataStrm->SetIncrement( GetDataPageSize() );
101 99 : pDataStrm->SetEntry( *pRoot );
102 : }
103 : else
104 0 : SetError( SVSTREAM_FILEFORMAT_ERROR );
105 : }
106 102 : }
107 :
108 : // get the logical data page size
109 :
110 983 : short StgIo::GetDataPageSize()
111 : {
112 983 : return 1 << aHdr.GetDataPageSize();
113 : }
114 :
115 : // Commit everything
116 :
117 35 : sal_Bool StgIo::CommitAll()
118 : {
119 : // Store the data (all streams and the TOC)
120 35 : if( pTOC && pTOC->Store() && pDataFAT )
121 : {
122 35 : if( Commit() )
123 : {
124 32 : aHdr.SetDataFATStart( pDataFAT->GetStart() );
125 32 : aHdr.SetDataFATSize( pDataFAT->GetPages() );
126 32 : aHdr.SetTOCStart( pTOC->GetStart() );
127 32 : if( aHdr.Store( *this ) )
128 : {
129 32 : pStrm->Flush();
130 32 : sal_uLong n = pStrm->GetError();
131 32 : SetError( n );
132 : #ifdef DBG_UTIL
133 : if( n==0 ) ValidateFATs();
134 : #endif
135 32 : return sal_Bool( n == 0 );
136 : }
137 : }
138 : }
139 3 : SetError( SVSTREAM_WRITE_ERROR );
140 3 : return sal_False;
141 : }
142 :
143 :
144 : class EasyFat
145 : {
146 : sal_Int32 *pFat;
147 : sal_Bool *pFree;
148 : sal_Int32 nPages;
149 : sal_Int32 nPageSize;
150 :
151 : public:
152 : EasyFat( StgIo & rIo, StgStrm *pFatStream, sal_Int32 nPSize );
153 0 : ~EasyFat() { delete[] pFat; delete[] pFree; }
154 :
155 0 : sal_Int32 GetPageSize() { return nPageSize; }
156 : sal_Int32 Count() { return nPages; }
157 : sal_Int32 operator[]( sal_Int32 nOffset )
158 : {
159 : OSL_ENSURE( nOffset >= 0 && nOffset < nPages, "Unexpected offset!" );
160 : return nOffset >= 0 && nOffset < nPages ? pFat[ nOffset ] : -2;
161 : }
162 :
163 : sal_uLong Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect );
164 : sal_Bool HasUnrefChains();
165 : };
166 :
167 0 : EasyFat::EasyFat( StgIo& rIo, StgStrm* pFatStream, sal_Int32 nPSize )
168 : {
169 0 : nPages = pFatStream->GetSize() >> 2;
170 0 : nPageSize = nPSize;
171 0 : pFat = new sal_Int32[ nPages ];
172 0 : pFree = new sal_Bool[ nPages ];
173 :
174 0 : rtl::Reference< StgPage > pPage;
175 0 : sal_Int32 nFatPageSize = (1 << rIo.aHdr.GetPageSize()) - 2;
176 :
177 0 : for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
178 : {
179 0 : if( ! (nPage % nFatPageSize) )
180 : {
181 0 : pFatStream->Pos2Page( nPage << 2 );
182 0 : sal_Int32 nPhysPage = pFatStream->GetPage();
183 0 : pPage = rIo.Get( nPhysPage, sal_True );
184 : }
185 :
186 0 : pFat[ nPage ] = rIo.GetFromPage( pPage, short( nPage % nFatPageSize ) );
187 0 : pFree[ nPage ] = sal_True;
188 0 : }
189 0 : }
190 :
191 0 : sal_Bool EasyFat::HasUnrefChains()
192 : {
193 0 : for( sal_Int32 nPage = 0; nPage < nPages; nPage++ )
194 : {
195 0 : if( pFree[ nPage ] && pFat[ nPage ] != -1 )
196 0 : return sal_True;
197 : }
198 0 : return sal_False;
199 : }
200 :
201 0 : sal_uLong EasyFat::Mark( sal_Int32 nPage, sal_Int32 nCount, sal_Int32 nExpect )
202 : {
203 0 : if( nCount > 0 )
204 0 : --nCount /= GetPageSize(), nCount++;
205 :
206 0 : sal_Int32 nCurPage = nPage;
207 0 : while( nCount != 0 )
208 : {
209 0 : if( nCurPage < 0 || nCurPage >= nPages )
210 0 : return FAT_OUTOFBOUNDS;
211 0 : pFree[ nCurPage ] = sal_False;
212 0 : nCurPage = pFat[ nCurPage ];
213 : //Stream zu lang
214 0 : if( nCurPage != nExpect && nCount == 1 )
215 0 : return FAT_WRONGLENGTH;
216 : //Stream zu kurz
217 0 : if( nCurPage == nExpect && nCount != 1 && nCount != -1 )
218 0 : return FAT_WRONGLENGTH;
219 : // letzter Block bei Stream ohne Laenge
220 0 : if( nCurPage == nExpect && nCount == -1 )
221 0 : nCount = 1;
222 0 : if( nCount != -1 )
223 0 : nCount--;
224 : }
225 0 : return FAT_OK;
226 : }
227 :
228 0 : class Validator
229 : {
230 : sal_uLong nError;
231 :
232 : EasyFat aSmallFat;
233 : EasyFat aFat;
234 :
235 : StgIo &rIo;
236 :
237 : sal_uLong ValidateMasterFATs();
238 : sal_uLong ValidateDirectoryEntries();
239 : sal_uLong FindUnrefedChains();
240 : sal_uLong MarkAll( StgDirEntry *pEntry );
241 :
242 : public:
243 :
244 : Validator( StgIo &rIo );
245 0 : sal_Bool IsError() { return nError != 0; }
246 : };
247 :
248 0 : Validator::Validator( StgIo &rIoP )
249 0 : : aSmallFat( rIoP, rIoP.pDataFAT, 1 << rIoP.aHdr.GetDataPageSize() ),
250 0 : aFat( rIoP, rIoP.pFAT, 1 << rIoP.aHdr.GetPageSize() ),
251 0 : rIo( rIoP )
252 : {
253 0 : sal_uLong nErr = nError = FAT_OK;
254 :
255 0 : if( ( nErr = ValidateMasterFATs() ) != FAT_OK )
256 0 : nError = nErr;
257 0 : else if( ( nErr = ValidateDirectoryEntries() ) != FAT_OK )
258 0 : nError = nErr;
259 0 : else if( ( nErr = FindUnrefedChains()) != FAT_OK )
260 0 : nError = nErr;
261 0 : }
262 :
263 0 : sal_uLong Validator::ValidateMasterFATs()
264 : {
265 0 : sal_Int32 nCount = rIo.aHdr.GetFATSize();
266 : sal_uLong nErr;
267 0 : if ( !rIo.pFAT )
268 0 : return FAT_INMEMORYERROR;
269 :
270 0 : for( sal_Int32 i = 0; i < nCount; i++ )
271 : {
272 0 : if( ( nErr = aFat.Mark(rIo.pFAT->GetPage( short(i), sal_False ), aFat.GetPageSize(), -3 )) != FAT_OK )
273 0 : return nErr;
274 : }
275 0 : if( rIo.aHdr.GetMasters() )
276 0 : if( ( nErr = aFat.Mark(rIo.aHdr.GetFATChain( ), aFat.GetPageSize(), -4 )) != FAT_OK )
277 0 : return nErr;
278 :
279 0 : return FAT_OK;
280 : }
281 :
282 0 : sal_uLong Validator::MarkAll( StgDirEntry *pEntry )
283 : {
284 0 : if ( !pEntry )
285 0 : return FAT_INMEMORYERROR;
286 :
287 0 : StgIterator aIter( *pEntry );
288 0 : sal_uLong nErr = FAT_OK;
289 0 : for( StgDirEntry* p = aIter.First(); p ; p = aIter.Next() )
290 : {
291 0 : if( p->aEntry.GetType() == STG_STORAGE )
292 : {
293 0 : nErr = MarkAll( p );
294 0 : if( nErr != FAT_OK )
295 0 : return nErr;
296 : }
297 : else
298 : {
299 0 : sal_Int32 nSize = p->aEntry.GetSize();
300 0 : if( nSize < rIo.aHdr.GetThreshold() )
301 0 : nErr = aSmallFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
302 : else
303 0 : nErr = aFat.Mark( p->aEntry.GetStartPage(),nSize, -2 );
304 0 : if( nErr != FAT_OK )
305 0 : return nErr;
306 : }
307 : }
308 0 : return FAT_OK;
309 : }
310 :
311 0 : sal_uLong Validator::ValidateDirectoryEntries()
312 : {
313 0 : if ( !rIo.pTOC )
314 0 : return FAT_INMEMORYERROR;
315 :
316 : // Normale DirEntries
317 0 : sal_uLong nErr = MarkAll( rIo.pTOC->GetRoot() );
318 0 : if( nErr != FAT_OK )
319 0 : return nErr;
320 : // Small Data
321 0 : nErr = aFat.Mark( rIo.pTOC->GetRoot()->aEntry.GetStartPage(),
322 0 : rIo.pTOC->GetRoot()->aEntry.GetSize(), -2 );
323 0 : if( nErr != FAT_OK )
324 0 : return nErr;
325 : // Small Data FAT
326 : nErr = aFat.Mark(
327 : rIo.aHdr.GetDataFATStart(),
328 0 : rIo.aHdr.GetDataFATSize() * aFat.GetPageSize(), -2 );
329 0 : if( nErr != FAT_OK )
330 0 : return nErr;
331 : // TOC
332 : nErr = aFat.Mark(
333 0 : rIo.aHdr.GetTOCStart(), -1, -2 );
334 0 : return nErr;
335 : }
336 :
337 0 : sal_uLong Validator::FindUnrefedChains()
338 : {
339 0 : if( aSmallFat.HasUnrefChains() ||
340 0 : aFat.HasUnrefChains() )
341 0 : return FAT_UNREFCHAIN;
342 : else
343 0 : return FAT_OK;
344 : }
345 :
346 : namespace { struct ErrorLink : public rtl::Static<Link, ErrorLink > {}; }
347 :
348 4 : void StgIo::SetErrorLink( const Link& rLink )
349 : {
350 4 : ErrorLink::get() = rLink;
351 4 : }
352 :
353 4 : const Link& StgIo::GetErrorLink()
354 : {
355 4 : return ErrorLink::get();
356 : }
357 :
358 4 : sal_uLong StgIo::ValidateFATs()
359 : {
360 4 : if( bFile )
361 : {
362 0 : Validator *pV = new Validator( *this );
363 0 : sal_Bool bRet1 = !pV->IsError(), bRet2 = sal_True ;
364 0 : delete pV;
365 :
366 0 : SvFileStream *pFileStrm = ( SvFileStream *) GetStrm();
367 0 : if ( !pFileStrm )
368 0 : return FAT_INMEMORYERROR;
369 :
370 0 : StgIo aIo;
371 0 : if( aIo.Open( pFileStrm->GetFileName(),
372 0 : STREAM_READ | STREAM_SHARE_DENYNONE) &&
373 0 : aIo.Load() )
374 : {
375 0 : pV = new Validator( aIo );
376 0 : bRet2 = !pV->IsError();
377 0 : delete pV;
378 : }
379 :
380 : sal_uLong nErr;
381 0 : if( bRet1 != bRet2 )
382 0 : nErr = bRet1 ? FAT_ONFILEERROR : FAT_INMEMORYERROR;
383 0 : else nErr = bRet1 ? FAT_OK : FAT_BOTHERROR;
384 0 : if( nErr != FAT_OK && !bCopied )
385 : {
386 0 : StgLinkArg aArg;
387 0 : aArg.aFile = pFileStrm->GetFileName();
388 0 : aArg.nErr = nErr;
389 0 : ErrorLink::get().Call( &aArg );
390 0 : bCopied = sal_True;
391 : }
392 : // DBG_ASSERT( nErr == FAT_OK ,"Storage kaputt");
393 0 : return nErr;
394 : }
395 : // OSL_FAIL("Validiere nicht (kein FileStorage)");
396 4 : return FAT_OK;
397 : }
398 :
399 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|