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