Branch data 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 <string.h> // memset(), memcpy()
22 : : #include <rtl/ustring.hxx>
23 : : #include <com/sun/star/lang/Locale.hpp>
24 : : #include <unotools/charclass.hxx>
25 : : #include "sot/stg.hxx"
26 : : #include "stgelem.hxx"
27 : : #include "stgcache.hxx"
28 : : #include "stgstrms.hxx"
29 : : #include "stgdir.hxx"
30 : : #include "stgio.hxx"
31 : :
32 : : static const sal_uInt16 nMaxLegalStr = 31;
33 : :
34 : : static sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
35 : :
36 : : ////////////////////////////// struct ClsId /////////////////////////////
37 : :
38 : 4994 : SvStream& operator >>( SvStream& r, ClsId& rId )
39 : : {
40 : 4994 : r >> rId.n1
41 : 4994 : >> rId.n2
42 : 4994 : >> rId.n3
43 : 4994 : >> rId.n4
44 : 4994 : >> rId.n5
45 : 4994 : >> rId.n6
46 : 4994 : >> rId.n7
47 : 4994 : >> rId.n8
48 : 4994 : >> rId.n9
49 : 4994 : >> rId.n10
50 : 4994 : >> rId.n11;
51 : 4994 : return r;
52 : : }
53 : :
54 : 1504 : SvStream& operator <<( SvStream& r, const ClsId& rId )
55 : : {
56 : : return
57 : 1504 : r << (sal_Int32) rId.n1
58 : 1504 : << (sal_Int16) rId.n2
59 : 1504 : << (sal_Int16) rId.n3
60 : 1504 : << (sal_uInt8) rId.n4
61 : 1504 : << (sal_uInt8) rId.n5
62 : 1504 : << (sal_uInt8) rId.n6
63 : 1504 : << (sal_uInt8) rId.n7
64 : 1504 : << (sal_uInt8) rId.n8
65 : 1504 : << (sal_uInt8) rId.n9
66 : 1504 : << (sal_uInt8) rId.n10
67 : 1504 : << (sal_uInt8) rId.n11;
68 : : }
69 : :
70 : : ///////////////////////////// class StgHeader ////////////////////////////
71 : :
72 : 1998 : StgHeader::StgHeader()
73 : : : nVersion( 0 )
74 : : , nByteOrder( 0 )
75 : : , nPageSize( 0 )
76 : : , nDataPageSize( 0 )
77 : : , bDirty( 0 )
78 : : , nFATSize( 0 )
79 : : , nTOCstrm( 0 )
80 : : , nReserved( 0 )
81 : : , nThreshold( 0 )
82 : : , nDataFAT( 0 )
83 : : , nDataFATSize( 0 )
84 : : , nMasterChain( 0 )
85 : 1998 : , nMaster( 0 )
86 : : {
87 : 1998 : memset( cSignature, 0, sizeof( cSignature ) );
88 : 1998 : memset( &aClsId, 0, sizeof( ClsId ) );
89 : 1998 : memset( cReserved, 0, sizeof( cReserved ) );
90 : 1998 : memset( nMasterFAT, 0, sizeof( nMasterFAT ) );
91 : 1998 : }
92 : :
93 : 75 : void StgHeader::Init()
94 : : {
95 : 75 : memcpy( cSignature, cStgSignature, 8 );
96 : 75 : memset( &aClsId, 0, sizeof( ClsId ) );
97 : 75 : nVersion = 0x0003003B;
98 : 75 : nByteOrder = 0xFFFE;
99 : 75 : nPageSize = 9; // 512 bytes
100 : 75 : nDataPageSize = 6; // 64 bytes
101 : 75 : bDirty = 0;
102 : 75 : memset( cReserved, 0, sizeof( cReserved ) );
103 : 75 : nFATSize = 0;
104 : 75 : nTOCstrm = 0;
105 : 75 : nReserved = 0;
106 : 75 : nThreshold = 4096;
107 : 75 : nDataFAT = 0;
108 : 75 : nDataFATSize = 0;
109 : 75 : nMasterChain = STG_EOF;
110 : :
111 : 75 : SetTOCStart( STG_EOF );
112 : 75 : SetDataFATStart( STG_EOF );
113 [ + + ]: 8250 : for( short i = 0; i < 109; i++ )
114 : 8175 : SetFATPage( i, STG_FREE );
115 : 75 : }
116 : :
117 : 300 : sal_Bool StgHeader::Load( StgIo& rIo )
118 : : {
119 : 300 : sal_Bool bResult = sal_False;
120 [ + - ]: 300 : if ( rIo.GetStrm() )
121 : : {
122 : 300 : SvStream& r = *rIo.GetStrm();
123 : 300 : bResult = Load( r );
124 [ + - ][ + + ]: 300 : bResult = ( bResult && rIo.Good() );
125 : : }
126 : :
127 : 300 : return bResult;
128 : : }
129 : :
130 : 1923 : sal_Bool StgHeader::Load( SvStream& r )
131 : : {
132 : 1923 : r.Seek( 0L );
133 : 1923 : r.Read( cSignature, 8 );
134 : 1923 : r >> aClsId // 08 Class ID
135 : 1923 : >> nVersion // 1A version number
136 : 1923 : >> nByteOrder // 1C Unicode byte order indicator
137 : 1923 : >> nPageSize // 1E 1 << nPageSize = block size
138 : 1923 : >> nDataPageSize; // 20 1 << this size == data block size
139 : 1923 : r.SeekRel( 10 );
140 : 1923 : r >> nFATSize // 2C total number of FAT pages
141 : 1923 : >> nTOCstrm // 30 starting page for the TOC stream
142 : 1923 : >> nReserved // 34
143 : 1923 : >> nThreshold // 38 minimum file size for big data
144 : 1923 : >> nDataFAT // 3C page # of 1st data FAT block
145 : 1923 : >> nDataFATSize // 40 # of data FATpages
146 : 1923 : >> nMasterChain // 44 chain to the next master block
147 : 1923 : >> nMaster; // 48 # of additional master blocks
148 [ + + ]: 211530 : for( short i = 0; i < 109; i++ )
149 : 209607 : r >> nMasterFAT[ i ];
150 : :
151 [ + - ][ + + ]: 1923 : return ( r.GetErrorCode() == ERRCODE_NONE && Check() );
152 : : }
153 : :
154 : 150 : sal_Bool StgHeader::Store( StgIo& rIo )
155 : : {
156 [ - + ]: 150 : if( !bDirty )
157 : 0 : return sal_True;
158 : 150 : SvStream& r = *rIo.GetStrm();
159 : 150 : r.Seek( 0L );
160 : 150 : r.Write( cSignature, 8 + 16 );
161 : 150 : r << nVersion // 1A version number
162 : 150 : << nByteOrder // 1C Unicode byte order indicator
163 : 150 : << nPageSize // 1E 1 << nPageSize = block size
164 : 150 : << nDataPageSize // 20 1 << this size == data block size
165 : 150 : << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
166 : 150 : << nFATSize // 2C total number of FAT pages
167 : 150 : << nTOCstrm // 30 starting page for the TOC stream
168 : 150 : << nReserved // 34
169 : 150 : << nThreshold // 38 minimum file size for big data
170 : 150 : << nDataFAT // 3C page # of 1st data FAT block
171 : 150 : << nDataFATSize // 40 # of data FAT pages
172 : 150 : << nMasterChain // 44 chain to the next master block
173 : 150 : << nMaster; // 48 # of additional master blocks
174 [ + + ]: 16500 : for( short i = 0; i < 109; i++ )
175 : 16350 : r << nMasterFAT[ i ];
176 : 150 : bDirty = !rIo.Good();
177 : 150 : return sal_Bool( !bDirty );
178 : : }
179 : :
180 : 3244 : static bool lcl_wontoverflow(short shift)
181 : : {
182 [ + - ][ + - ]: 3244 : return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
183 : : }
184 : :
185 : : // Perform thorough checks also on unknown variables
186 : 2731 : sal_Bool StgHeader::Check()
187 : : {
188 : 2731 : return sal_Bool( memcmp( cSignature, cStgSignature, 8 ) == 0
189 : : && (short) ( nVersion >> 16 ) == 3 )
190 : : && nPageSize == 9
191 : 1622 : && lcl_wontoverflow(nPageSize)
192 : 1622 : && lcl_wontoverflow(nDataPageSize)
193 : : && nFATSize > 0
194 : : && nTOCstrm >= 0
195 : : && nThreshold > 0
196 : : && ( nDataFAT == -2 || ( nDataFAT >= 0 && nDataFATSize > 0 ) )
197 : : && ( nMasterChain == -2 || nMasterChain >=0 )
198 [ + + ][ + - ]: 5975 : && nMaster >= 0;
[ + - + -
+ - ][ + - ]
[ + - ][ + - ]
[ + + ][ + - ]
[ + - ][ - + ]
[ # # ][ + + ]
199 : : }
200 : :
201 : 85864 : sal_Int32 StgHeader::GetFATPage( short n ) const
202 : : {
203 [ + - ][ + - ]: 85864 : if( n >= 0 && n < 109 )
204 : 85864 : return nMasterFAT[ n ];
205 : : else
206 : 85864 : return STG_EOF;
207 : : }
208 : :
209 : 8262 : void StgHeader::SetFATPage( short n, sal_Int32 nb )
210 : : {
211 [ + - ][ + - ]: 8262 : if( n >= 0 && n < 109 )
212 : : {
213 [ + - ]: 8262 : if( nMasterFAT[ n ] != nb )
214 : 8262 : bDirty = sal_True, nMasterFAT[ n ] = nb;
215 : : }
216 : 8262 : }
217 : :
218 : 384 : void StgHeader::SetTOCStart( sal_Int32 n )
219 : : {
220 [ + + ]: 384 : if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
221 : 384 : }
222 : :
223 : 225 : void StgHeader::SetDataFATStart( sal_Int32 n )
224 : : {
225 [ + + ]: 225 : if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
226 : 225 : }
227 : :
228 : 150 : void StgHeader::SetDataFATSize( sal_Int32 n )
229 : : {
230 [ + + ]: 150 : if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
231 : 150 : }
232 : :
233 : 87 : void StgHeader::SetFATSize( sal_Int32 n )
234 : : {
235 [ + - ]: 87 : if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
236 : 87 : }
237 : :
238 : 0 : void StgHeader::SetFATChain( sal_Int32 n )
239 : : {
240 [ # # ]: 0 : if( n != nMasterChain )
241 : 0 : bDirty = sal_True, nMasterChain = n;
242 : 0 : }
243 : :
244 : 0 : void StgHeader::SetMasters( sal_Int32 n )
245 : : {
246 [ # # ]: 0 : if( n != nMaster ) bDirty = sal_True, nMaster = n;
247 : 0 : }
248 : :
249 : : ///////////////////////////// class StgEntry /////////////////////////////
250 : :
251 : 8490 : sal_Bool StgEntry::Init()
252 : : {
253 : 8490 : memset( nName, 0, sizeof( nName ) );
254 : 8490 : nNameLen = 0;
255 : 8490 : cType = 0;
256 : 8490 : cFlags = 0;
257 : 8490 : nLeft = 0;
258 : 8490 : nRight = 0;
259 : 8490 : nChild = 0;
260 : 8490 : memset( &aClsId, 0, sizeof( aClsId ) );
261 : 8490 : nFlags = 0;
262 : 8490 : nMtime[0] = 0; nMtime[1] = 0;
263 : 8490 : nAtime[0] = 0; nAtime[1] = 0;
264 : 8490 : nPage1 = 0;
265 : 8490 : nSize = 0;
266 : 8490 : nUnknown = 0;
267 : :
268 : 8490 : SetLeaf( STG_LEFT, STG_FREE );
269 : 8490 : SetLeaf( STG_RIGHT, STG_FREE );
270 : 8490 : SetLeaf( STG_CHILD, STG_FREE );
271 : 8490 : SetLeaf( STG_DATA, STG_EOF );
272 : 8490 : return sal_True;
273 : : }
274 : :
275 : 11312 : static String ToUpperUnicode( const String & rStr )
276 : : {
277 : : // I don't know the locale, so en_US is hopefully fine
278 : : /*
279 : : com.sun.star.lang.Locale aLocale;
280 : : aLocale.Language = OUString("en");
281 : : aLocale.Country = OUString("US");
282 : : */
283 [ + + ][ + - ]: 11312 : static rtl::OUString aEN("en");
284 [ + + ][ + - ]: 11312 : static rtl::OUString aUS("US");
285 [ + + ][ + - ]: 11312 : static CharClass aCC( com::sun::star::lang::Locale( aEN, aUS, rtl::OUString() ) );
[ + - ][ # # ]
286 [ + - ][ + - ]: 11312 : return aCC.uppercase( rStr );
287 : : }
288 : :
289 : 8331 : sal_Bool StgEntry::SetName( const String& rName )
290 : : {
291 : : // I don't know the locale, so en_US is hopefully fine
292 [ + - ]: 8331 : aName = ToUpperUnicode( rName );
293 : 8331 : aName.Erase( nMaxLegalStr );
294 : :
295 : : int i;
296 [ + + ][ + - ]: 81837 : for( i = 0; i < aName.Len() && i < 32; i++ )
[ + + ]
297 : 73506 : nName[ i ] = rName.GetChar( sal_uInt16( i ));
298 [ + + ]: 201417 : while( i < 32 )
299 : 193086 : nName[ i++ ] = 0;
300 : 8331 : nNameLen = ( aName.Len() + 1 ) << 1;
301 : 8331 : return sal_True;
302 : : }
303 : :
304 : 13879 : sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
305 : : {
306 : 13879 : sal_Int32 n = -1;
307 [ + + + + : 13879 : switch( eRef )
- ]
308 : : {
309 : 2981 : case STG_LEFT: n = nLeft; break;
310 : 2981 : case STG_RIGHT: n = nRight; break;
311 : 4332 : case STG_CHILD: n = nChild; break;
312 : 3585 : case STG_DATA: n = nPage1; break;
313 : : }
314 : 13879 : return n;
315 : : }
316 : :
317 : 39752 : void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
318 : : {
319 [ + + + + : 39752 : switch( eRef )
- ]
320 : : {
321 : 9655 : case STG_LEFT: nLeft = nPage; break;
322 : 9655 : case STG_RIGHT: nRight = nPage; break;
323 : 9655 : case STG_CHILD: nChild = nPage; break;
324 : 10787 : case STG_DATA: nPage1 = nPage; break;
325 : : }
326 : 39752 : }
327 : :
328 : 82 : void StgEntry::SetClassId( const ClsId& r )
329 : : {
330 : 82 : memcpy( &aClsId, &r, sizeof( ClsId ) );
331 : 82 : }
332 : :
333 : 3326 : void StgEntry::GetName( String& rName ) const
334 : : {
335 : 3326 : sal_uInt16 n = nNameLen;
336 [ + + ]: 3326 : if( n )
337 : 3323 : n = ( n >> 1 ) - 1;
338 [ + - ]: 3326 : rName = rtl::OUString(nName, n);
339 : 3326 : }
340 : :
341 : : // Compare two entries. Do this case-insensitive.
342 : :
343 : 76750 : short StgEntry::Compare( const StgEntry& r ) const
344 : : {
345 : : /*
346 : : short nRes = r.nNameLen - nNameLen;
347 : : if( !nRes ) return strcmp( r.aName, aName );
348 : : else return nRes;
349 : : */
350 : 76750 : sal_Int32 nRes = r.nNameLen - nNameLen;
351 [ + + ]: 76750 : if( !nRes )
352 : 31048 : nRes = r.aName.CompareTo( aName );
353 : 76750 : return (short)nRes;
354 : : //return aName.CompareTo( r.aName );
355 : : }
356 : :
357 : : // These load/store operations are a bit more complicated,
358 : : // since they have to copy their contents into a packed structure.
359 : :
360 : 2990 : sal_Bool StgEntry::Load( const void* pFrom, sal_uInt32 nBufSize )
361 : : {
362 [ - + ]: 2990 : if ( nBufSize < 128 )
363 : 0 : return sal_False;
364 : :
365 [ + - ]: 2990 : SvMemoryStream r( (sal_Char*) pFrom, nBufSize, STREAM_READ );
366 [ + + ]: 98670 : for( short i = 0; i < 32; i++ )
367 [ + - ]: 95680 : r >> nName[ i ]; // 00 name as WCHAR
368 [ + - ]: 2990 : r >> nNameLen // 40 size of name in bytes including 00H
369 [ + - ]: 2990 : >> cType // 42 entry type
370 [ + - ]: 2990 : >> cFlags // 43 0 or 1 (tree balance?)
371 [ + - ]: 2990 : >> nLeft // 44 left node entry
372 [ + - ]: 2990 : >> nRight // 48 right node entry
373 [ + - ]: 2990 : >> nChild // 4C 1st child entry if storage
374 [ + - ]: 2990 : >> aClsId // 50 class ID (optional)
375 [ + - ]: 2990 : >> nFlags // 60 state flags(?)
376 [ + - ]: 2990 : >> nMtime[ 0 ] // 64 modification time
377 [ + - ]: 2990 : >> nMtime[ 1 ] // 64 modification time
378 [ + - ]: 2990 : >> nAtime[ 0 ] // 6C creation and access time
379 [ + - ]: 2990 : >> nAtime[ 1 ] // 6C creation and access time
380 [ + - ]: 2990 : >> nPage1 // 74 starting block (either direct or translated)
381 [ + - ]: 2990 : >> nSize // 78 file size
382 [ + - ]: 2990 : >> nUnknown; // 7C unknown
383 : :
384 : 2990 : sal_uInt16 n = nNameLen;
385 [ + + ]: 2990 : if( n )
386 : 2984 : n = ( n >> 1 ) - 1;
387 : :
388 [ + + ]: 2990 : if (n > nMaxLegalStr)
389 : 6 : return sal_False;
390 : :
391 [ + + ][ - + ]: 2984 : if ((nSize < 0 && cType != STG_STORAGE) || (nPage1 < 0 && nPage1 != -2))
[ + + ][ - + ]
392 : : {
393 : : // the size makes no sense for the substorage
394 : : // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
395 : 3 : return sal_False;
396 : : }
397 : :
398 [ + - ]: 2981 : aName = rtl::OUString( nName, n );
399 : : // I don't know the locale, so en_US is hopefully fine
400 [ + - ][ + - ]: 2981 : aName = ToUpperUnicode( aName );
[ + - ]
401 [ + - ]: 2981 : aName.Erase( nMaxLegalStr );
402 : :
403 [ + - ]: 2990 : return sal_True;
404 : : }
405 : :
406 : 1492 : void StgEntry::Store( void* pTo )
407 : : {
408 [ + - ]: 1492 : SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
409 [ + + ]: 49236 : for( short i = 0; i < 32; i++ )
410 [ + - ]: 47744 : r << nName[ i ]; // 00 name as WCHAR
411 [ + - ]: 1492 : r << nNameLen // 40 size of name in bytes including 00H
412 [ + - ]: 1492 : << cType // 42 entry type
413 [ + - ]: 1492 : << cFlags // 43 0 or 1 (tree balance?)
414 [ + - ]: 1492 : << nLeft // 44 left node entry
415 [ + - ]: 1492 : << nRight // 48 right node entry
416 [ + - ]: 1492 : << nChild // 4C 1st child entry if storage;
417 [ + - ]: 1492 : << aClsId // 50 class ID (optional)
418 [ + - ]: 1492 : << nFlags // 60 state flags(?)
419 [ + - ]: 1492 : << nMtime[ 0 ] // 64 modification time
420 [ + - ]: 1492 : << nMtime[ 1 ] // 64 modification time
421 [ + - ]: 1492 : << nAtime[ 0 ] // 6C creation and access time
422 [ + - ]: 1492 : << nAtime[ 1 ] // 6C creation and access time
423 [ + - ]: 1492 : << nPage1 // 74 starting block (either direct or translated)
424 [ + - ]: 1492 : << nSize // 78 file size
425 [ + - ][ + - ]: 1492 : << nUnknown; // 7C unknown
426 : 1492 : }
427 : :
428 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|