bump product version to 4.1.6.2
[LibreOffice.git] / sot / source / sdstor / stgelem.cxx
blobe34f0689f5880b318f34061b3978a6f969468592
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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"
32 static const sal_uInt16 nMaxLegalStr = 31;
34 static sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
36 ////////////////////////////// struct ClsId /////////////////////////////
38 SvStream& operator >>( SvStream& r, ClsId& rId )
40 r >> rId.n1
41 >> rId.n2
42 >> rId.n3
43 >> rId.n4
44 >> rId.n5
45 >> rId.n6
46 >> rId.n7
47 >> rId.n8
48 >> rId.n9
49 >> rId.n10
50 >> rId.n11;
51 return r;
54 SvStream& operator <<( SvStream& r, const ClsId& rId )
56 return
57 r << (sal_Int32) rId.n1
58 << (sal_Int16) rId.n2
59 << (sal_Int16) rId.n3
60 << (sal_uInt8) rId.n4
61 << (sal_uInt8) rId.n5
62 << (sal_uInt8) rId.n6
63 << (sal_uInt8) rId.n7
64 << (sal_uInt8) rId.n8
65 << (sal_uInt8) rId.n9
66 << (sal_uInt8) rId.n10
67 << (sal_uInt8) rId.n11;
70 ///////////////////////////// class StgHeader ////////////////////////////
72 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 , nMaster( 0 )
87 memset( cSignature, 0, sizeof( cSignature ) );
88 memset( &aClsId, 0, sizeof( ClsId ) );
89 memset( cReserved, 0, sizeof( cReserved ) );
90 memset( nMasterFAT, 0, sizeof( nMasterFAT ) );
93 void StgHeader::Init()
95 memcpy( cSignature, cStgSignature, 8 );
96 memset( &aClsId, 0, sizeof( ClsId ) );
97 nVersion = 0x0003003B;
98 nByteOrder = 0xFFFE;
99 nPageSize = 9; // 512 bytes
100 nDataPageSize = 6; // 64 bytes
101 bDirty = 0;
102 memset( cReserved, 0, sizeof( cReserved ) );
103 nFATSize = 0;
104 nTOCstrm = 0;
105 nReserved = 0;
106 nThreshold = 4096;
107 nDataFAT = 0;
108 nDataFATSize = 0;
109 nMasterChain = STG_EOF;
111 SetTOCStart( STG_EOF );
112 SetDataFATStart( STG_EOF );
113 for( short i = 0; i < cFATPagesInHeader; i++ )
114 SetFATPage( i, STG_FREE );
117 sal_Bool StgHeader::Load( StgIo& rIo )
119 sal_Bool bResult = sal_False;
120 if ( rIo.GetStrm() )
122 SvStream& r = *rIo.GetStrm();
123 bResult = Load( r );
124 bResult = ( bResult && rIo.Good() );
127 return bResult;
130 sal_Bool StgHeader::Load( SvStream& r )
132 r.Seek( 0L );
133 r.Read( cSignature, 8 );
134 r >> aClsId // 08 Class ID
135 >> nVersion // 1A version number
136 >> nByteOrder // 1C Unicode byte order indicator
137 >> nPageSize // 1E 1 << nPageSize = block size
138 >> nDataPageSize; // 20 1 << this size == data block size
139 r.SeekRel( 10 );
140 r >> nFATSize // 2C total number of FAT pages
141 >> nTOCstrm // 30 starting page for the TOC stream
142 >> nReserved // 34
143 >> nThreshold // 38 minimum file size for big data
144 >> nDataFAT // 3C page # of 1st data FAT block
145 >> nDataFATSize // 40 # of data FATpages
146 >> nMasterChain // 44 chain to the next master block
147 >> nMaster; // 48 # of additional master blocks
148 for( short i = 0; i < cFATPagesInHeader; i++ )
149 r >> nMasterFAT[ i ];
151 return ( r.GetErrorCode() == ERRCODE_NONE && Check() );
154 sal_Bool StgHeader::Store( StgIo& rIo )
156 if( !bDirty )
157 return sal_True;
158 SvStream& r = *rIo.GetStrm();
159 r.Seek( 0L );
160 r.Write( cSignature, 8 );
161 r << aClsId // 08 Class ID
162 << nVersion // 1A version number
163 << nByteOrder // 1C Unicode byte order indicator
164 << nPageSize // 1E 1 << nPageSize = block size
165 << nDataPageSize // 20 1 << this size == data block size
166 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
167 << nFATSize // 2C total number of FAT pages
168 << nTOCstrm // 30 starting page for the TOC stream
169 << nReserved // 34
170 << nThreshold // 38 minimum file size for big data
171 << nDataFAT // 3C page # of 1st data FAT block
172 << nDataFATSize // 40 # of data FAT pages
173 << nMasterChain // 44 chain to the next master block
174 << nMaster; // 48 # of additional master blocks
175 for( short i = 0; i < cFATPagesInHeader; i++ )
176 r << nMasterFAT[ i ];
177 bDirty = !rIo.Good();
178 return sal_Bool( !bDirty );
181 static bool lcl_wontoverflow(short shift)
183 return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
186 static bool isKnownSpecial(sal_Int32 nLocation)
188 return (nLocation == STG_FREE ||
189 nLocation == STG_EOF ||
190 nLocation == STG_FAT ||
191 nLocation == STG_MASTER);
194 // Perform thorough checks also on unknown variables
195 sal_Bool StgHeader::Check()
197 return sal_Bool( memcmp( cSignature, cStgSignature, 8 ) == 0
198 && (short) ( nVersion >> 16 ) == 3 )
199 && nPageSize == 9
200 && lcl_wontoverflow(nPageSize)
201 && lcl_wontoverflow(nDataPageSize)
202 && nFATSize > 0
203 && nTOCstrm >= 0
204 && nThreshold > 0
205 && ( isKnownSpecial(nDataFAT) || ( nDataFAT >= 0 && nDataFATSize > 0 ) )
206 && ( isKnownSpecial(nMasterChain) || nMasterChain >=0 )
207 && nMaster >= 0;
210 sal_Int32 StgHeader::GetFATPage( short n ) const
212 if( n >= 0 && n < cFATPagesInHeader )
213 return nMasterFAT[ n ];
214 else
215 return STG_EOF;
218 void StgHeader::SetFATPage( short n, sal_Int32 nb )
220 if( n >= 0 && n < cFATPagesInHeader )
222 if( nMasterFAT[ n ] != nb )
223 bDirty = sal_True, nMasterFAT[ n ] = nb;
227 void StgHeader::SetTOCStart( sal_Int32 n )
229 if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
232 void StgHeader::SetDataFATStart( sal_Int32 n )
234 if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
237 void StgHeader::SetDataFATSize( sal_Int32 n )
239 if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
242 void StgHeader::SetFATSize( sal_Int32 n )
244 if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
247 void StgHeader::SetFATChain( sal_Int32 n )
249 if( n != nMasterChain )
250 bDirty = sal_True, nMasterChain = n;
253 void StgHeader::SetMasters( sal_Int32 n )
255 if( n != nMaster ) bDirty = sal_True, nMaster = n;
258 ///////////////////////////// class StgEntry /////////////////////////////
260 sal_Bool StgEntry::Init()
262 memset( nName, 0, sizeof( nName ) );
263 nNameLen = 0;
264 cType = 0;
265 cFlags = 0;
266 nLeft = 0;
267 nRight = 0;
268 nChild = 0;
269 memset( &aClsId, 0, sizeof( aClsId ) );
270 nFlags = 0;
271 nMtime[0] = 0; nMtime[1] = 0;
272 nAtime[0] = 0; nAtime[1] = 0;
273 nPage1 = 0;
274 nSize = 0;
275 nUnknown = 0;
277 SetLeaf( STG_LEFT, STG_FREE );
278 SetLeaf( STG_RIGHT, STG_FREE );
279 SetLeaf( STG_CHILD, STG_FREE );
280 SetLeaf( STG_DATA, STG_EOF );
281 return sal_True;
284 static String ToUpperUnicode( const String & rStr )
286 // I don't know the locale, so en_US is hopefully fine
287 static CharClass aCC( LanguageTag( com::sun::star::lang::Locale( "en", "US", "" )) );
288 return aCC.uppercase( rStr );
291 sal_Bool StgEntry::SetName( const String& rName )
293 // I don't know the locale, so en_US is hopefully fine
294 aName = ToUpperUnicode( rName );
295 aName.Erase( nMaxLegalStr );
297 int i;
298 for( i = 0; i < aName.Len() && i < 32; i++ )
299 nName[ i ] = rName.GetChar( sal_uInt16( i ));
300 while( i < 32 )
301 nName[ i++ ] = 0;
302 nNameLen = ( aName.Len() + 1 ) << 1;
303 return sal_True;
306 sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
308 sal_Int32 n = -1;
309 switch( eRef )
311 case STG_LEFT: n = nLeft; break;
312 case STG_RIGHT: n = nRight; break;
313 case STG_CHILD: n = nChild; break;
314 case STG_DATA: n = nPage1; break;
316 return n;
319 void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
321 switch( eRef )
323 case STG_LEFT: nLeft = nPage; break;
324 case STG_RIGHT: nRight = nPage; break;
325 case STG_CHILD: nChild = nPage; break;
326 case STG_DATA: nPage1 = nPage; break;
330 void StgEntry::SetClassId( const ClsId& r )
332 memcpy( &aClsId, &r, sizeof( ClsId ) );
335 void StgEntry::GetName( String& rName ) const
337 sal_uInt16 n = nNameLen;
338 if( n )
339 n = ( n >> 1 ) - 1;
340 rName = OUString(nName, n);
343 // Compare two entries. Do this case-insensitive.
345 short StgEntry::Compare( const StgEntry& r ) const
348 short nRes = r.nNameLen - nNameLen;
349 if( !nRes ) return strcmp( r.aName, aName );
350 else return nRes;
352 sal_Int32 nRes = r.nNameLen - nNameLen;
353 if( !nRes )
354 nRes = r.aName.CompareTo( aName );
355 return (short)nRes;
356 //return aName.CompareTo( r.aName );
359 // These load/store operations are a bit more complicated,
360 // since they have to copy their contents into a packed structure.
362 sal_Bool StgEntry::Load( const void* pFrom, sal_uInt32 nBufSize )
364 if ( nBufSize < 128 )
365 return sal_False;
367 SvMemoryStream r( (sal_Char*) pFrom, nBufSize, STREAM_READ );
368 for( short i = 0; i < 32; i++ )
369 r >> nName[ i ]; // 00 name as WCHAR
370 r >> nNameLen // 40 size of name in bytes including 00H
371 >> cType // 42 entry type
372 >> cFlags // 43 0 or 1 (tree balance?)
373 >> nLeft // 44 left node entry
374 >> nRight // 48 right node entry
375 >> nChild // 4C 1st child entry if storage
376 >> aClsId // 50 class ID (optional)
377 >> nFlags // 60 state flags(?)
378 >> nMtime[ 0 ] // 64 modification time
379 >> nMtime[ 1 ] // 64 modification time
380 >> nAtime[ 0 ] // 6C creation and access time
381 >> nAtime[ 1 ] // 6C creation and access time
382 >> nPage1 // 74 starting block (either direct or translated)
383 >> nSize // 78 file size
384 >> nUnknown; // 7C unknown
386 sal_uInt16 n = nNameLen;
387 if( n )
388 n = ( n >> 1 ) - 1;
390 if (n > nMaxLegalStr)
391 return sal_False;
393 if ((cType != STG_STORAGE) && ((nSize < 0) || (nPage1 < 0 && !isKnownSpecial(nPage1))))
395 // the size makes no sense for the substorage
396 // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
397 return sal_False;
400 aName = OUString( nName, n );
401 // I don't know the locale, so en_US is hopefully fine
402 aName = ToUpperUnicode( aName );
403 aName.Erase( nMaxLegalStr );
405 return sal_True;
408 void StgEntry::Store( void* pTo )
410 SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
411 for( short i = 0; i < 32; i++ )
412 r << nName[ i ]; // 00 name as WCHAR
413 r << nNameLen // 40 size of name in bytes including 00H
414 << cType // 42 entry type
415 << cFlags // 43 0 or 1 (tree balance?)
416 << nLeft // 44 left node entry
417 << nRight // 48 right node entry
418 << nChild // 4C 1st child entry if storage;
419 << aClsId // 50 class ID (optional)
420 << nFlags // 60 state flags(?)
421 << nMtime[ 0 ] // 64 modification time
422 << nMtime[ 1 ] // 64 modification time
423 << nAtime[ 0 ] // 6C creation and access time
424 << nAtime[ 1 ] // 6C creation and access time
425 << nPage1 // 74 starting block (either direct or translated)
426 << nSize // 78 file size
427 << nUnknown; // 7C unknown
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */