bump product version to 4.2.0.1
[LibreOffice.git] / sot / source / sdstor / stgelem.cxx
blob4299994acc72adbfb49300b9e09842471ce474f7
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>
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 const 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 bool StgHeader::Load( StgIo& rIo )
119 bool bResult = false;
120 if ( rIo.GetStrm() )
122 SvStream& r = *rIo.GetStrm();
123 bResult = Load( r );
124 bResult = ( bResult && rIo.Good() );
127 return bResult;
130 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 bool StgHeader::Store( StgIo& rIo )
156 if( !bDirty )
157 return true;
159 SvStream& r = *rIo.GetStrm();
160 r.Seek( 0L );
161 r.Write( cSignature, 8 );
162 r << aClsId // 08 Class ID
163 << nVersion // 1A version number
164 << nByteOrder // 1C Unicode byte order indicator
165 << nPageSize // 1E 1 << nPageSize = block size
166 << nDataPageSize // 20 1 << this size == data block size
167 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
168 << nFATSize // 2C total number of FAT pages
169 << nTOCstrm // 30 starting page for the TOC stream
170 << nReserved // 34
171 << nThreshold // 38 minimum file size for big data
172 << nDataFAT // 3C page # of 1st data FAT block
173 << nDataFATSize // 40 # of data FAT pages
174 << nMasterChain // 44 chain to the next master block
175 << nMaster; // 48 # of additional master blocks
176 for( short i = 0; i < cFATPagesInHeader; i++ )
177 r << nMasterFAT[ i ];
178 bDirty = !rIo.Good();
179 return !bDirty;
182 static bool lcl_wontoverflow(short shift)
184 return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
187 static bool isKnownSpecial(sal_Int32 nLocation)
189 return (nLocation == STG_FREE ||
190 nLocation == STG_EOF ||
191 nLocation == STG_FAT ||
192 nLocation == STG_MASTER);
195 // Perform thorough checks also on unknown variables
196 bool StgHeader::Check()
198 return memcmp( cSignature, cStgSignature, 8 ) == 0
199 && (short) ( nVersion >> 16 ) == 3
200 && nPageSize == 9
201 && lcl_wontoverflow(nPageSize)
202 && lcl_wontoverflow(nDataPageSize)
203 && nFATSize > 0
204 && nTOCstrm >= 0
205 && nThreshold > 0
206 && ( isKnownSpecial(nDataFAT) || ( nDataFAT >= 0 && nDataFATSize > 0 ) )
207 && ( isKnownSpecial(nMasterChain) || nMasterChain >=0 )
208 && nMaster >= 0;
211 sal_Int32 StgHeader::GetFATPage( short n ) const
213 if( n >= 0 && n < cFATPagesInHeader )
214 return nMasterFAT[ n ];
215 else
216 return STG_EOF;
219 void StgHeader::SetFATPage( short n, sal_Int32 nb )
221 if( n >= 0 && n < cFATPagesInHeader )
223 if( nMasterFAT[ n ] != nb )
224 bDirty = sal_True, nMasterFAT[ n ] = nb;
228 void StgHeader::SetTOCStart( sal_Int32 n )
230 if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
233 void StgHeader::SetDataFATStart( sal_Int32 n )
235 if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
238 void StgHeader::SetDataFATSize( sal_Int32 n )
240 if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
243 void StgHeader::SetFATSize( sal_Int32 n )
245 if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
248 void StgHeader::SetFATChain( sal_Int32 n )
250 if( n != nMasterChain )
251 bDirty = sal_True, nMasterChain = n;
254 void StgHeader::SetMasters( sal_Int32 n )
256 if( n != nMaster ) bDirty = sal_True, nMaster = n;
259 ///////////////////////////// class StgEntry /////////////////////////////
261 bool StgEntry::Init()
263 memset( nName, 0, sizeof( nName ) );
264 nNameLen = 0;
265 cType = 0;
266 cFlags = 0;
267 nLeft = 0;
268 nRight = 0;
269 nChild = 0;
270 memset( &aClsId, 0, sizeof( aClsId ) );
271 nFlags = 0;
272 nMtime[0] = 0; nMtime[1] = 0;
273 nAtime[0] = 0; nAtime[1] = 0;
274 nPage1 = 0;
275 nSize = 0;
276 nUnknown = 0;
278 SetLeaf( STG_LEFT, STG_FREE );
279 SetLeaf( STG_RIGHT, STG_FREE );
280 SetLeaf( STG_CHILD, STG_FREE );
281 SetLeaf( STG_DATA, STG_EOF );
282 return sal_True;
285 static OUString ToUpperUnicode( const OUString & rStr )
287 // I don't know the locale, so en_US is hopefully fine
288 static CharClass aCC( LanguageTag( com::sun::star::lang::Locale( "en", "US", "" )) );
289 return aCC.uppercase( rStr );
292 bool StgEntry::SetName( const OUString& rName )
294 // I don't know the locale, so en_US is hopefully fine
295 aName = ToUpperUnicode( rName );
296 if(aName.getLength() > nMaxLegalStr)
298 aName = aName.copy(0, nMaxLegalStr);
301 int i;
302 for( i = 0; i < aName.getLength() && i < 32; i++ )
304 nName[ i ] = rName[ i ];
306 while( i < 32 )
308 nName[ i++ ] = 0;
310 nNameLen = ( aName.getLength() + 1 ) << 1;
311 return true;
314 sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
316 sal_Int32 n = -1;
317 switch( eRef )
319 case STG_LEFT: n = nLeft; break;
320 case STG_RIGHT: n = nRight; break;
321 case STG_CHILD: n = nChild; break;
322 case STG_DATA: n = nPage1; break;
324 return n;
327 void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
329 switch( eRef )
331 case STG_LEFT: nLeft = nPage; break;
332 case STG_RIGHT: nRight = nPage; break;
333 case STG_CHILD: nChild = nPage; break;
334 case STG_DATA: nPage1 = nPage; break;
338 void StgEntry::SetClassId( const ClsId& r )
340 memcpy( &aClsId, &r, sizeof( ClsId ) );
343 void StgEntry::GetName( OUString& rName ) const
345 sal_uInt16 n = nNameLen;
346 if( n )
347 n = ( n >> 1 ) - 1;
348 rName = OUString(nName, n);
351 // Compare two entries. Do this case-insensitive.
353 short StgEntry::Compare( const StgEntry& r ) const
356 short nRes = r.nNameLen - nNameLen;
357 if( !nRes ) return strcmp( r.aName, aName );
358 else return nRes;
360 sal_Int32 nRes = r.nNameLen - nNameLen;
361 if( !nRes )
362 nRes = r.aName.compareTo( aName );
363 return (short)nRes;
364 //return aName.CompareTo( r.aName );
367 // These load/store operations are a bit more complicated,
368 // since they have to copy their contents into a packed structure.
370 bool StgEntry::Load( const void* pFrom, sal_uInt32 nBufSize )
372 if ( nBufSize < 128 )
373 return false;
375 SvMemoryStream r( (sal_Char*) pFrom, nBufSize, STREAM_READ );
376 for( short i = 0; i < 32; i++ )
377 r >> nName[ i ]; // 00 name as WCHAR
378 r >> nNameLen // 40 size of name in bytes including 00H
379 >> cType // 42 entry type
380 >> cFlags // 43 0 or 1 (tree balance?)
381 >> nLeft // 44 left node entry
382 >> nRight // 48 right node entry
383 >> nChild // 4C 1st child entry if storage
384 >> aClsId // 50 class ID (optional)
385 >> nFlags // 60 state flags(?)
386 >> nMtime[ 0 ] // 64 modification time
387 >> nMtime[ 1 ] // 64 modification time
388 >> nAtime[ 0 ] // 6C creation and access time
389 >> nAtime[ 1 ] // 6C creation and access time
390 >> nPage1 // 74 starting block (either direct or translated)
391 >> nSize // 78 file size
392 >> nUnknown; // 7C unknown
394 sal_uInt16 n = nNameLen;
395 if( n )
396 n = ( n >> 1 ) - 1;
398 if (n > nMaxLegalStr)
399 return false;
401 if ((cType != STG_STORAGE) && ((nSize < 0) || (nPage1 < 0 && !isKnownSpecial(nPage1))))
403 // the size makes no sense for the substorage
404 // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
405 return false;
408 aName = OUString(nName , n);
409 // I don't know the locale, so en_US is hopefully fine
410 aName = ToUpperUnicode( aName );
411 if(aName.getLength() > nMaxLegalStr)
413 aName = aName.copy(0, nMaxLegalStr);
416 return true;
419 void StgEntry::Store( void* pTo )
421 SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
422 for( short i = 0; i < 32; i++ )
423 r << nName[ i ]; // 00 name as WCHAR
424 r << nNameLen // 40 size of name in bytes including 00H
425 << cType // 42 entry type
426 << cFlags // 43 0 or 1 (tree balance?)
427 << nLeft // 44 left node entry
428 << nRight // 48 right node entry
429 << nChild // 4C 1st child entry if storage;
430 << aClsId // 50 class ID (optional)
431 << nFlags // 60 state flags(?)
432 << nMtime[ 0 ] // 64 modification time
433 << nMtime[ 1 ] // 64 modification time
434 << nAtime[ 0 ] // 6C creation and access time
435 << nAtime[ 1 ] // 6C creation and access time
436 << nPage1 // 74 starting block (either direct or translated)
437 << nSize // 78 file size
438 << nUnknown; // 7C unknown
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */