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>
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 const sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
35 :
36 : ////////////////////////////// struct ClsId
37 :
38 15524 : SvStream& ReadClsId( SvStream& r, ClsId& rId )
39 : {
40 15524 : r.ReadUInt32( rId.Data1 )
41 31048 : .ReadUInt16( rId.Data2 )
42 31048 : .ReadUInt16( rId.Data3 )
43 31048 : .ReadUChar( rId.Data4[0] )
44 31048 : .ReadUChar( rId.Data4[1] )
45 31048 : .ReadUChar( rId.Data4[2] )
46 31048 : .ReadUChar( rId.Data4[3] )
47 31048 : .ReadUChar( rId.Data4[4] )
48 31048 : .ReadUChar( rId.Data4[5] )
49 31048 : .ReadUChar( rId.Data4[6] )
50 31048 : .ReadUChar( rId.Data4[7] );
51 15524 : return r;
52 : }
53 :
54 4233 : SvStream& WriteClsId( SvStream& r, const ClsId& rId )
55 : {
56 : return
57 4233 : r .WriteUInt32( rId.Data1 )
58 8466 : .WriteUInt16( rId.Data2 )
59 8466 : .WriteUInt16( rId.Data3 )
60 8466 : .WriteUChar( rId.Data4[0] )
61 8466 : .WriteUChar( rId.Data4[1] )
62 8466 : .WriteUChar( rId.Data4[2] )
63 8466 : .WriteUChar( rId.Data4[3] )
64 8466 : .WriteUChar( rId.Data4[4] )
65 8466 : .WriteUChar( rId.Data4[5] )
66 8466 : .WriteUChar( rId.Data4[6] )
67 8466 : .WriteUChar( rId.Data4[7] );
68 : }
69 :
70 : ///////////////////////////// class StgHeader
71 :
72 9881 : StgHeader::StgHeader()
73 : : nVersion( 0 )
74 : , nByteOrder( 0 )
75 : , nPageSize( 0 )
76 : , nDataPageSize( 0 )
77 : , bDirty( sal_uInt8(false) )
78 : , nFATSize( 0 )
79 : , nTOCstrm( 0 )
80 : , nReserved( 0 )
81 : , nThreshold( 0 )
82 : , nDataFAT( 0 )
83 : , nDataFATSize( 0 )
84 : , nMasterChain( 0 )
85 9881 : , nMaster( 0 )
86 : {
87 9881 : memset( cSignature, 0, sizeof( cSignature ) );
88 9881 : memset( &aClsId, 0, sizeof( ClsId ) );
89 9881 : memset( cReserved, 0, sizeof( cReserved ) );
90 9881 : memset( nMasterFAT, 0, sizeof( nMasterFAT ) );
91 9881 : }
92 :
93 214 : void StgHeader::Init()
94 : {
95 214 : memcpy( cSignature, cStgSignature, 8 );
96 214 : memset( &aClsId, 0, sizeof( ClsId ) );
97 214 : nVersion = 0x0003003B;
98 214 : nByteOrder = 0xFFFE;
99 214 : nPageSize = 9; // 512 bytes
100 214 : nDataPageSize = 6; // 64 bytes
101 214 : bDirty = sal_uInt8(false);
102 214 : memset( cReserved, 0, sizeof( cReserved ) );
103 214 : nFATSize = 0;
104 214 : nTOCstrm = 0;
105 214 : nReserved = 0;
106 214 : nThreshold = 4096;
107 214 : nDataFAT = 0;
108 214 : nDataFATSize = 0;
109 214 : nMasterChain = STG_EOF;
110 :
111 214 : SetTOCStart( STG_EOF );
112 214 : SetDataFATStart( STG_EOF );
113 23540 : for( short i = 0; i < cFATPagesInHeader; i++ )
114 23326 : SetFATPage( i, STG_FREE );
115 214 : }
116 :
117 3329 : bool StgHeader::Load( StgIo& rIo )
118 : {
119 3329 : bool bResult = false;
120 3329 : if ( rIo.GetStrm() )
121 : {
122 3329 : SvStream& r = *rIo.GetStrm();
123 3329 : bResult = Load( r );
124 3329 : bResult = ( bResult && rIo.Good() );
125 : }
126 :
127 3329 : return bResult;
128 : }
129 :
130 9646 : bool StgHeader::Load( SvStream& r )
131 : {
132 9646 : r.Seek( 0L );
133 9646 : r.Read( cSignature, 8 );
134 9646 : ReadClsId( r, aClsId ); // 08 Class ID
135 9646 : r.ReadInt32( nVersion ) // 1A version number
136 19292 : .ReadUInt16( nByteOrder ) // 1C Unicode byte order indicator
137 19292 : .ReadInt16( nPageSize ) // 1E 1 << nPageSize = block size
138 19292 : .ReadInt16( nDataPageSize ); // 20 1 << this size == data block size
139 9646 : r.SeekRel( 10 );
140 9646 : r.ReadInt32( nFATSize ) // 2C total number of FAT pages
141 19292 : .ReadInt32( nTOCstrm ) // 30 starting page for the TOC stream
142 19292 : .ReadInt32( nReserved ) // 34
143 19292 : .ReadInt32( nThreshold ) // 38 minimum file size for big data
144 19292 : .ReadInt32( nDataFAT ) // 3C page # of 1st data FAT block
145 19292 : .ReadInt32( nDataFATSize ) // 40 # of data FATpages
146 19292 : .ReadInt32( nMasterChain ) // 44 chain to the next master block
147 19292 : .ReadInt32( nMaster ); // 48 # of additional master blocks
148 1061060 : for( short i = 0; i < cFATPagesInHeader; i++ )
149 1051414 : r.ReadInt32( nMasterFAT[ i ] );
150 :
151 9646 : return (r.GetErrorCode() == ERRCODE_NONE) && Check();
152 : }
153 :
154 436 : bool StgHeader::Store( StgIo& rIo )
155 : {
156 436 : if( !bDirty )
157 0 : return true;
158 :
159 436 : SvStream& r = *rIo.GetStrm();
160 436 : r.Seek( 0L );
161 436 : r.Write( cSignature, 8 );
162 436 : WriteClsId( r, aClsId ); // 08 Class ID
163 436 : r.WriteInt32( nVersion ) // 1A version number
164 872 : .WriteUInt16( nByteOrder ) // 1C Unicode byte order indicator
165 872 : .WriteInt16( nPageSize ) // 1E 1 << nPageSize = block size
166 872 : .WriteInt16( nDataPageSize ) // 20 1 << this size == data block size
167 436 : .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt16( 0 )
168 872 : .WriteInt32( nFATSize ) // 2C total number of FAT pages
169 872 : .WriteInt32( nTOCstrm ) // 30 starting page for the TOC stream
170 872 : .WriteInt32( nReserved ) // 34
171 872 : .WriteInt32( nThreshold ) // 38 minimum file size for big data
172 872 : .WriteInt32( nDataFAT ) // 3C page # of 1st data FAT block
173 872 : .WriteInt32( nDataFATSize ) // 40 # of data FAT pages
174 872 : .WriteInt32( nMasterChain ) // 44 chain to the next master block
175 872 : .WriteInt32( nMaster ); // 48 # of additional master blocks
176 47960 : for( short i = 0; i < cFATPagesInHeader; i++ )
177 47524 : r.WriteInt32( nMasterFAT[ i ] );
178 436 : bDirty = sal_uInt8(!rIo.Good());
179 436 : return !bDirty;
180 : }
181 :
182 4420 : static bool lcl_wontoverflow(short shift)
183 : {
184 4420 : return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
185 : }
186 :
187 4529 : static bool isKnownSpecial(sal_Int32 nLocation)
188 : {
189 4527 : return (nLocation == STG_FREE ||
190 1980 : nLocation == STG_EOF ||
191 6509 : nLocation == STG_FAT ||
192 4529 : nLocation == STG_MASTER);
193 : }
194 :
195 : // Perform thorough checks also on unknown variables
196 10749 : bool StgHeader::Check()
197 : {
198 10749 : return memcmp( cSignature, cStgSignature, 8 ) == 0
199 2210 : && (short) ( nVersion >> 16 ) == 3
200 2210 : && nPageSize == 9
201 2210 : && lcl_wontoverflow(nPageSize)
202 2210 : && lcl_wontoverflow(nDataPageSize)
203 2210 : && nFATSize > 0
204 2210 : && nTOCstrm >= 0
205 2210 : && nThreshold > 0
206 2210 : && ( isKnownSpecial(nDataFAT) || ( nDataFAT >= 0 && nDataFATSize > 0 ) )
207 2210 : && ( isKnownSpecial(nMasterChain) || nMasterChain >=0 )
208 12959 : && nMaster >= 0;
209 : }
210 :
211 149996 : sal_Int32 StgHeader::GetFATPage( short n ) const
212 : {
213 149996 : if( n >= 0 && n < cFATPagesInHeader )
214 149996 : return nMasterFAT[ n ];
215 : else
216 0 : return STG_EOF;
217 : }
218 :
219 23573 : void StgHeader::SetFATPage( short n, sal_Int32 nb )
220 : {
221 23573 : if( n >= 0 && n < cFATPagesInHeader )
222 : {
223 23573 : if( nMasterFAT[ n ] != nb )
224 23573 : bDirty = sal_uInt8(true), nMasterFAT[ n ] = nb;
225 : }
226 23573 : }
227 :
228 1090 : void StgHeader::SetTOCStart( sal_Int32 n )
229 : {
230 1090 : if( n != nTOCstrm ) bDirty = sal_uInt8(true), nTOCstrm = n;
231 1090 : }
232 :
233 650 : void StgHeader::SetDataFATStart( sal_Int32 n )
234 : {
235 650 : if( n != nDataFAT ) bDirty = sal_uInt8(true), nDataFAT = n;
236 650 : }
237 :
238 436 : void StgHeader::SetDataFATSize( sal_Int32 n )
239 : {
240 436 : if( n != nDataFATSize ) bDirty = sal_uInt8(true), nDataFATSize = n;
241 436 : }
242 :
243 235 : void StgHeader::SetFATSize( sal_Int32 n )
244 : {
245 235 : if( n != nFATSize ) bDirty = sal_uInt8(true), nFATSize = n;
246 235 : }
247 :
248 0 : void StgHeader::SetFATChain( sal_Int32 n )
249 : {
250 0 : if( n != nMasterChain )
251 0 : bDirty = sal_uInt8(true), nMasterChain = n;
252 0 : }
253 :
254 0 : void StgHeader::SetMasters( sal_Int32 n )
255 : {
256 0 : if( n != nMaster ) bDirty = sal_uInt8(true), nMaster = n;
257 0 : }
258 :
259 : ///////////////////////////// class StgEntry
260 :
261 18146 : bool StgEntry::Init()
262 : {
263 18146 : memset( nName, 0, sizeof( nName ) );
264 18146 : nNameLen = 0;
265 18146 : cType = 0;
266 18146 : cFlags = 0;
267 18146 : nLeft = 0;
268 18146 : nRight = 0;
269 18146 : nChild = 0;
270 18146 : memset( &aClsId, 0, sizeof( aClsId ) );
271 18146 : nFlags = 0;
272 18146 : nMtime[0] = 0; nMtime[1] = 0;
273 18146 : nAtime[0] = 0; nAtime[1] = 0;
274 18146 : nPage1 = 0;
275 18146 : nSize = 0;
276 18146 : nUnknown = 0;
277 :
278 18146 : SetLeaf( STG_LEFT, STG_FREE );
279 18146 : SetLeaf( STG_RIGHT, STG_FREE );
280 18146 : SetLeaf( STG_CHILD, STG_FREE );
281 18146 : SetLeaf( STG_DATA, STG_EOF );
282 18146 : return true;
283 : }
284 :
285 23581 : static OUString ToUpperUnicode( const OUString & rStr )
286 : {
287 : // I don't know the locale, so en_US is hopefully fine
288 23581 : static CharClass aCC( LanguageTag( com::sun::star::lang::Locale( "en", "US", "" )) );
289 23581 : return aCC.uppercase( rStr );
290 : }
291 :
292 17706 : bool StgEntry::SetName( const OUString& rName )
293 : {
294 : // I don't know the locale, so en_US is hopefully fine
295 17706 : aName = ToUpperUnicode( rName );
296 17706 : if(aName.getLength() > nMaxLegalStr)
297 : {
298 0 : aName = aName.copy(0, nMaxLegalStr);
299 : }
300 :
301 : sal_uInt16 i;
302 166829 : for( i = 0; i < rName.getLength() && i <= nMaxLegalStr; i++ )
303 : {
304 149123 : nName[ i ] = rName[ i ];
305 : }
306 452881 : while (i <= nMaxLegalStr)
307 : {
308 417469 : nName[ i++ ] = 0;
309 : }
310 17706 : nNameLen = ( rName.getLength() + 1 ) << 1;
311 17706 : return true;
312 : }
313 :
314 27105 : sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
315 : {
316 27105 : sal_Int32 n = -1;
317 27105 : switch( eRef )
318 : {
319 5875 : case STG_LEFT: n = nLeft; break;
320 5875 : case STG_RIGHT: n = nRight; break;
321 8421 : case STG_CHILD: n = nChild; break;
322 6934 : case STG_DATA: n = nPage1; break;
323 : }
324 27105 : return n;
325 : }
326 :
327 86336 : void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
328 : {
329 86336 : switch( eRef )
330 : {
331 20903 : case STG_LEFT: nLeft = nPage; break;
332 20903 : case STG_RIGHT: nRight = nPage; break;
333 20903 : case STG_CHILD: nChild = nPage; break;
334 23627 : case STG_DATA: nPage1 = nPage; break;
335 : }
336 86336 : }
337 :
338 202 : void StgEntry::SetClassId( const ClsId& r )
339 : {
340 202 : memcpy( &aClsId, &r, sizeof( ClsId ) );
341 202 : }
342 :
343 5903 : void StgEntry::GetName( OUString& rName ) const
344 : {
345 5903 : sal_uInt16 n = nNameLen;
346 5903 : if( n )
347 5902 : n = ( n >> 1 ) - 1;
348 5903 : rName = OUString(nName, n);
349 5903 : }
350 :
351 : // Compare two entries. Do this case-insensitive.
352 :
353 121678 : sal_Int32 StgEntry::Compare( const StgEntry& r ) const
354 : {
355 121678 : if (r.nNameLen != nNameLen)
356 80073 : return r.nNameLen > nNameLen ? 1 : -1;
357 : else
358 41605 : return r.aName.compareTo(aName);
359 : }
360 :
361 : // These load/store operations are a bit more complicated,
362 : // since they have to copy their contents into a packed structure.
363 :
364 5878 : bool StgEntry::Load( const void* pFrom, sal_uInt32 nBufSize )
365 : {
366 5878 : if ( nBufSize < 128 )
367 0 : return false;
368 :
369 5878 : SvMemoryStream r( const_cast<void *>(pFrom), nBufSize, StreamMode::READ );
370 193974 : for( short i = 0; i < 32; i++ )
371 188096 : r.ReadUInt16( nName[ i ] ); // 00 name as WCHAR
372 5878 : r.ReadUInt16( nNameLen ) // 40 size of name in bytes including 00H
373 11756 : .ReadUChar( cType ) // 42 entry type
374 11756 : .ReadUChar( cFlags ) // 43 0 or 1 (tree balance?)
375 11756 : .ReadInt32( nLeft ) // 44 left node entry
376 11756 : .ReadInt32( nRight ) // 48 right node entry
377 11756 : .ReadInt32( nChild ); // 4C 1st child entry if storage
378 5878 : ReadClsId( r, aClsId ); // 50 class ID (optional)
379 5878 : r.ReadInt32( nFlags ) // 60 state flags(?)
380 11756 : .ReadInt32( nMtime[ 0 ] ) // 64 modification time
381 11756 : .ReadInt32( nMtime[ 1 ] ) // 64 modification time
382 11756 : .ReadInt32( nAtime[ 0 ] ) // 6C creation and access time
383 11756 : .ReadInt32( nAtime[ 1 ] ) // 6C creation and access time
384 11756 : .ReadInt32( nPage1 ) // 74 starting block (either direct or translated)
385 11756 : .ReadInt32( nSize ) // 78 file size
386 11756 : .ReadInt32( nUnknown ); // 7C unknown
387 :
388 5878 : sal_uInt16 n = nNameLen;
389 5878 : if( n )
390 5876 : n = ( n >> 1 ) - 1;
391 :
392 5878 : if (n > nMaxLegalStr)
393 2 : return false;
394 :
395 5876 : if ((cType != STG_STORAGE) && ((nSize < 0) || (nPage1 < 0 && !isKnownSpecial(nPage1))))
396 : {
397 : // the size makes no sense for the substorage
398 : // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
399 1 : return false;
400 : }
401 :
402 5875 : aName = OUString(nName , n);
403 : // I don't know the locale, so en_US is hopefully fine
404 5875 : aName = ToUpperUnicode( aName );
405 5875 : if(aName.getLength() > nMaxLegalStr)
406 : {
407 0 : aName = aName.copy(0, nMaxLegalStr);
408 : }
409 :
410 5875 : return true;
411 : }
412 :
413 3744 : void StgEntry::Store( void* pTo )
414 : {
415 3744 : SvMemoryStream r( pTo, 128, StreamMode::WRITE );
416 123552 : for( short i = 0; i < 32; i++ )
417 119808 : r.WriteUInt16( nName[ i ] ); // 00 name as WCHAR
418 3744 : r.WriteUInt16( nNameLen ) // 40 size of name in bytes including 00H
419 7488 : .WriteUChar( cType ) // 42 entry type
420 7488 : .WriteUChar( cFlags ) // 43 0 or 1 (tree balance?)
421 7488 : .WriteInt32( nLeft ) // 44 left node entry
422 7488 : .WriteInt32( nRight ) // 48 right node entry
423 7488 : .WriteInt32( nChild ); // 4C 1st child entry if storage;
424 3744 : WriteClsId( r, aClsId ); // 50 class ID (optional)
425 3744 : r.WriteInt32( nFlags ) // 60 state flags(?)
426 7488 : .WriteInt32( nMtime[ 0 ] ) // 64 modification time
427 7488 : .WriteInt32( nMtime[ 1 ] ) // 64 modification time
428 7488 : .WriteInt32( nAtime[ 0 ] ) // 6C creation and access time
429 7488 : .WriteInt32( nAtime[ 1 ] ) // 6C creation and access time
430 7488 : .WriteInt32( nPage1 ) // 74 starting block (either direct or translated)
431 7488 : .WriteInt32( nSize ) // 78 file size
432 7488 : .WriteInt32( nUnknown ); // 7C unknown
433 3744 : }
434 :
435 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|