1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sot.hxx"
26
27 #include <string.h> // memset(), memcpy()
28 #include <rtl/ustring.hxx>
29 #include <com/sun/star/lang/Locale.hpp>
30 #include <unotools/charclass.hxx>
31 #include "sot/stg.hxx"
32 #include "stgelem.hxx"
33 #include "stgcache.hxx"
34 #include "stgstrms.hxx"
35 #include "stgdir.hxx"
36 #include "stgio.hxx"
37
38 static sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
39
40 ////////////////////////////// struct ClsId /////////////////////////////
41
operator >>(SvStream & r,ClsId & rId)42 SvStream& operator >>( SvStream& r, ClsId& rId )
43 {
44 r >> rId.n1
45 >> rId.n2
46 >> rId.n3
47 >> rId.n4
48 >> rId.n5
49 >> rId.n6
50 >> rId.n7
51 >> rId.n8
52 >> rId.n9
53 >> rId.n10
54 >> rId.n11;
55 return r;
56 }
57
operator <<(SvStream & r,const ClsId & rId)58 SvStream& operator <<( SvStream& r, const ClsId& rId )
59 {
60 return
61 r << (sal_Int32) rId.n1
62 << (sal_Int16) rId.n2
63 << (sal_Int16) rId.n3
64 << (sal_uInt8) rId.n4
65 << (sal_uInt8) rId.n5
66 << (sal_uInt8) rId.n6
67 << (sal_uInt8) rId.n7
68 << (sal_uInt8) rId.n8
69 << (sal_uInt8) rId.n9
70 << (sal_uInt8) rId.n10
71 << (sal_uInt8) rId.n11;
72 }
73
74 ///////////////////////////// class StgHeader ////////////////////////////
75
StgHeader()76 StgHeader::StgHeader()
77 : nVersion( 0 )
78 , nByteOrder( 0 )
79 , nPageSize( 0 )
80 , nDataPageSize( 0 )
81 , bDirty( 0 )
82 , nFATSize( 0 )
83 , nTOCstrm( 0 )
84 , nReserved( 0 )
85 , nThreshold( 0 )
86 , nDataFAT( 0 )
87 , nDataFATSize( 0 )
88 , nMasterChain( 0 )
89 , nMaster( 0 )
90 {
91 memset( cSignature, 0, sizeof( cSignature ) );
92 memset( &aClsId, 0, sizeof( ClsId ) );
93 memset( cReserved, 0, sizeof( cReserved ) );
94 memset( nMasterFAT, 0, sizeof( nMasterFAT ) );
95 }
96
Init()97 void StgHeader::Init()
98 {
99 memcpy( cSignature, cStgSignature, 8 );
100 memset( &aClsId, 0, sizeof( ClsId ) );
101 nVersion = 0x0003003B;
102 nByteOrder = 0xFFFE;
103 nPageSize = 9; // 512 bytes
104 nDataPageSize = 6; // 64 bytes
105 bDirty = 0;
106 memset( cReserved, 0, sizeof( cReserved ) );
107 nFATSize = 0;
108 nTOCstrm = 0;
109 nReserved = 0;
110 nThreshold = 4096;
111 nDataFAT = 0;
112 nDataFATSize = 0;
113 nMasterChain = STG_EOF;
114
115 SetTOCStart( STG_EOF );
116 SetDataFATStart( STG_EOF );
117 for( short i = 0; i < cFATPagesInHeader; i++ )
118 SetFATPage( i, STG_FREE );
119 }
120
Load(StgIo & rIo)121 sal_Bool StgHeader::Load( StgIo& rIo )
122 {
123 sal_Bool bResult = sal_False;
124 if ( rIo.GetStrm() )
125 {
126 SvStream& r = *rIo.GetStrm();
127 bResult = Load( r );
128 bResult = ( bResult && rIo.Good() );
129 }
130
131 return bResult;
132 }
133
Load(SvStream & r)134 sal_Bool StgHeader::Load( SvStream& r )
135 {
136 r.Seek( 0L );
137 r.Read( cSignature, 8 );
138 r >> aClsId // 08 Class ID
139 >> nVersion // 1A version number
140 >> nByteOrder // 1C Unicode byte order indicator
141 >> nPageSize // 1E 1 << nPageSize = block size
142 >> nDataPageSize; // 20 1 << this size == data block size
143 r.SeekRel( 10 );
144 r >> nFATSize // 2C total number of FAT pages
145 >> nTOCstrm // 30 starting page for the TOC stream
146 >> nReserved // 34
147 >> nThreshold // 38 minimum file size for big data
148 >> nDataFAT // 3C page # of 1st data FAT block
149 >> nDataFATSize // 40 # of data FATpages
150 >> nMasterChain // 44 chain to the next master block
151 >> nMaster; // 48 # of additional master blocks
152 for( short i = 0; i < cFATPagesInHeader; i++ )
153 r >> nMasterFAT[ i ];
154
155 return ( r.GetErrorCode() == ERRCODE_NONE && Check() );
156 }
157
Store(StgIo & rIo)158 sal_Bool StgHeader::Store( StgIo& rIo )
159 {
160 if( !bDirty )
161 return sal_True;
162 SvStream& r = *rIo.GetStrm();
163 r.Seek( 0L );
164 r.Write( cSignature, 8 + 16 );
165 r << nVersion // 1A version number
166 << nByteOrder // 1C Unicode byte order indicator
167 << nPageSize // 1E 1 << nPageSize = block size
168 << nDataPageSize // 20 1 << this size == data block size
169 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
170 << nFATSize // 2C total number of FAT pages
171 << nTOCstrm // 30 starting page for the TOC stream
172 << nReserved // 34
173 << nThreshold // 38 minimum file size for big data
174 << nDataFAT // 3C page # of 1st data FAT block
175 << nDataFATSize // 40 # of data FAT pages
176 << nMasterChain // 44 chain to the next master block
177 << nMaster; // 48 # of additional master blocks
178 for( short i = 0; i < cFATPagesInHeader; i++ )
179 r << nMasterFAT[ i ];
180 bDirty = !rIo.Good();
181 return sal_Bool( !bDirty );
182 }
183
lcl_wontoverflow(short shift)184 static bool lcl_wontoverflow(short shift)
185 {
186 return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
187 }
188
189 // Perform thorough checks also on unknown variables
Check()190 sal_Bool StgHeader::Check()
191 {
192 return sal_Bool( memcmp( cSignature, cStgSignature, 8 ) == 0
193 && (short) ( nVersion >> 16 ) == 3 )
194 && nPageSize == 9
195 && lcl_wontoverflow(nPageSize)
196 && lcl_wontoverflow(nDataPageSize)
197 && nFATSize > 0
198 && nTOCstrm >= 0
199 && nThreshold > 0
200 && ( nDataFAT == STG_EOF || ( nDataFAT >= 0 && nDataFATSize > 0 ) )
201 && ( nMasterChain == STG_FREE || nMasterChain == STG_EOF || ( nMasterChain >=0 && nMaster > 0 ) )
202 && nMaster >= 0;
203 }
204
GetFATPage(short n) const205 sal_Int32 StgHeader::GetFATPage( short n ) const
206 {
207 if( n >= 0 && n < cFATPagesInHeader )
208 return nMasterFAT[ n ];
209 else
210 return STG_EOF;
211 }
212
SetFATPage(short n,sal_Int32 nb)213 void StgHeader::SetFATPage( short n, sal_Int32 nb )
214 {
215 if( n >= 0 && n < cFATPagesInHeader )
216 {
217 if( nMasterFAT[ n ] != nb )
218 bDirty = sal_True, nMasterFAT[ n ] = nb;
219 }
220 }
221
SetClassId(const ClsId & r)222 void StgHeader::SetClassId( const ClsId& r )
223 {
224 if( memcmp( &aClsId, &r, sizeof( ClsId ) ) )
225 bDirty = sal_True, memcpy( &aClsId, &r, sizeof( ClsId ) );
226 }
227
SetTOCStart(sal_Int32 n)228 void StgHeader::SetTOCStart( sal_Int32 n )
229 {
230 if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
231 }
232
SetDataFATStart(sal_Int32 n)233 void StgHeader::SetDataFATStart( sal_Int32 n )
234 {
235 if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
236 }
237
SetDataFATSize(sal_Int32 n)238 void StgHeader::SetDataFATSize( sal_Int32 n )
239 {
240 if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
241 }
242
SetFATSize(sal_Int32 n)243 void StgHeader::SetFATSize( sal_Int32 n )
244 {
245 if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
246 }
247
SetFATChain(sal_Int32 n)248 void StgHeader::SetFATChain( sal_Int32 n )
249 {
250 if( n != nMasterChain )
251 bDirty = sal_True, nMasterChain = n;
252 }
253
SetMasters(sal_Int32 n)254 void StgHeader::SetMasters( sal_Int32 n )
255 {
256 if( n != nMaster ) bDirty = sal_True, nMaster = n;
257 }
258
259 ///////////////////////////// class StgEntry /////////////////////////////
260
261 // This class is only a wrapper around the dir entry structure
262 // which retrieves and sets data.
263
264 // The name must be smaller than 32 chars. Conversion into Unicode
265 // is easy, since the 1st 256 characters of the Windows ANSI set
266 // equal the 1st 256 Unicode characters.
267 /*
268 void ToUnicode_Impl( String& rName )
269 {
270 rName.Erase( 32 );
271 rName.Convert( ::GetSystemCharSet(), CHARSET_ANSI );
272 // brute force is OK
273 sal_uInt8* p = (sal_uInt8*) rName.GetCharStr();
274 for( sal_uInt16 i = 0; i < rName.Len(); i++, p++ )
275 {
276 // check each character and substitute blanks for illegal ones
277 sal_uInt8 cChar = *p;
278 if( cChar == '!' || cChar == ':' || cChar == '\\' || cChar == '/' )
279 *p = ' ';
280 }
281 }
282 */
283 /*
284 static void FromUnicode( String& rName )
285 {
286 rName.Convert( CHARSET_ANSI, ::GetSystemCharSet() );
287 }
288 */
Init()289 sal_Bool StgEntry::Init()
290 {
291 memset( nName, 0, sizeof( nName ) );
292 nNameLen = 0;
293 cType = 0;
294 cFlags = 0;
295 nLeft = 0;
296 nRight = 0;
297 nChild = 0;
298 memset( &aClsId, 0, sizeof( aClsId ) );
299 nFlags = 0;
300 nMtime[0] = 0; nMtime[1] = 0;
301 nAtime[0] = 0; nAtime[1] = 0;
302 nPage1 = 0;
303 nSize = 0;
304 nUnknown = 0;
305
306 SetLeaf( STG_LEFT, STG_FREE );
307 SetLeaf( STG_RIGHT, STG_FREE );
308 SetLeaf( STG_CHILD, STG_FREE );
309 SetLeaf( STG_DATA, STG_EOF );
310 return sal_True;
311 }
312
ToUpperUnicode(const String & rStr)313 static String ToUpperUnicode( const String & rStr )
314 {
315 // I don't know the locale, so en_US is hopefully fine
316 /*
317 com.sun.star.lang.Locale aLocale;
318 aLocale.Language = OUString::createFromAscii( "en" );
319 aLocale.Country = OUString::createFromAscii( "US" );
320 */
321 static rtl::OUString aEN=rtl::OUString::createFromAscii( "en" );
322 static rtl::OUString aUS=rtl::OUString::createFromAscii( "US" );
323 static CharClass aCC( com::sun::star::lang::Locale( aEN, aUS, rtl::OUString() ) );
324 return aCC.toUpper( rStr, 0, rStr.Len() );
325 }
326
327
SetName(const String & rName)328 sal_Bool StgEntry::SetName( const String& rName )
329 {
330 // I don't know the locale, so en_US is hopefully fine
331 aName = ToUpperUnicode( rName );
332 aName.Erase( 31 );
333
334 int i;
335 for( i = 0; i < aName.Len() && i < 32; i++ )
336 nName[ i ] = rName.GetChar( sal_uInt16( i ));
337 while( i < 32 )
338 nName[ i++ ] = 0;
339 nNameLen = ( aName.Len() + 1 ) << 1;
340 return sal_True;
341 }
342
GetLeaf(StgEntryRef eRef) const343 sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
344 {
345 sal_Int32 n = -1;
346 switch( eRef )
347 {
348 case STG_LEFT: n = nLeft; break;
349 case STG_RIGHT: n = nRight; break;
350 case STG_CHILD: n = nChild; break;
351 case STG_DATA: n = nPage1; break;
352 }
353 return n;
354 }
355
SetLeaf(StgEntryRef eRef,sal_Int32 nPage)356 void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
357 {
358 switch( eRef )
359 {
360 case STG_LEFT: nLeft = nPage; break;
361 case STG_RIGHT: nRight = nPage; break;
362 case STG_CHILD: nChild = nPage; break;
363 case STG_DATA: nPage1 = nPage; break;
364 }
365 }
366
GetTime(StgEntryTime eTime) const367 const sal_Int32* StgEntry::GetTime( StgEntryTime eTime ) const
368 {
369 return( eTime == STG_MODIFIED ) ? nMtime : nAtime;
370 }
371
SetTime(StgEntryTime eTime,sal_Int32 * pTime)372 void StgEntry::SetTime( StgEntryTime eTime, sal_Int32* pTime )
373 {
374 if( eTime == STG_MODIFIED )
375 nMtime[ 0 ] = *pTime++, nMtime[ 1 ] = *pTime;
376 else
377 nAtime[ 0 ] = *pTime++, nAtime[ 1 ] = *pTime;
378 }
379
SetClassId(const ClsId & r)380 void StgEntry::SetClassId( const ClsId& r )
381 {
382 memcpy( &aClsId, &r, sizeof( ClsId ) );
383 }
384
GetName(String & rName) const385 void StgEntry::GetName( String& rName ) const
386 {
387 sal_uInt16 n = nNameLen;
388 if( n )
389 n = ( n >> 1 ) - 1;
390 rName = String( nName, n );
391 }
392
393 // Compare two entries. Do this case-insensitive.
394
Compare(const StgEntry & r) const395 short StgEntry::Compare( const StgEntry& r ) const
396 {
397 /*
398 short nRes = r.nNameLen - nNameLen;
399 if( !nRes ) return strcmp( r.aName, aName );
400 else return nRes;
401 */
402 sal_Int32 nRes = r.nNameLen - nNameLen;
403 if( !nRes )
404 nRes = r.aName.CompareTo( aName );
405 return (short)nRes;
406 //return aName.CompareTo( r.aName );
407 }
408
409 // These load/store operations are a bit more complicated,
410 // since they have to copy their contents into a packed structure.
411
Load(const void * pFrom,sal_uInt32 nBufSize)412 sal_Bool StgEntry::Load( const void* pFrom, sal_uInt32 nBufSize )
413 {
414 if ( nBufSize < 128 )
415 return sal_False;
416
417 SvMemoryStream r( (sal_Char*) pFrom, nBufSize, STREAM_READ );
418 for( short i = 0; i < 32; i++ )
419 r >> nName[ i ]; // 00 name as WCHAR
420 r >> nNameLen // 40 size of name in bytes including 00H
421 >> cType // 42 entry type
422 >> cFlags // 43 0 or 1 (tree balance?)
423 >> nLeft // 44 left node entry
424 >> nRight // 48 right node entry
425 >> nChild // 4C 1st child entry if storage
426 >> aClsId // 50 class ID (optional)
427 >> nFlags // 60 state flags(?)
428 >> nMtime[ 0 ] // 64 modification time
429 >> nMtime[ 1 ] // 64 modification time
430 >> nAtime[ 0 ] // 6C creation and access time
431 >> nAtime[ 1 ] // 6C creation and access time
432 >> nPage1 // 74 starting block (either direct or translated)
433 >> nSize // 78 file size
434 >> nUnknown; // 7C unknown
435
436 sal_uInt16 n = nNameLen;
437 if( n )
438 n = ( n >> 1 ) - 1;
439 if ( n > 31 ||
440 (nSize < 0 && cType != STG_STORAGE) ||
441 ( nPage1 < 0 && nPage1 != STG_FREE && nPage1 != STG_EOF ) )
442 {
443 // the size makes no sence for the substorage
444 // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
445 return sal_False;
446 }
447
448 aName = String( nName, n );
449 // I don't know the locale, so en_US is hopefully fine
450 aName = ToUpperUnicode( aName );
451 aName.Erase( 31 );
452
453 return sal_True;
454 }
455
Store(void * pTo)456 void StgEntry::Store( void* pTo )
457 {
458 SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
459 for( short i = 0; i < 32; i++ )
460 r << nName[ i ]; // 00 name as WCHAR
461 r << nNameLen // 40 size of name in bytes including 00H
462 << cType // 42 entry type
463 << cFlags // 43 0 or 1 (tree balance?)
464 << nLeft // 44 left node entry
465 << nRight // 48 right node entry
466 << nChild // 4C 1st child entry if storage;
467 << aClsId // 50 class ID (optional)
468 << nFlags // 60 state flags(?)
469 << nMtime[ 0 ] // 64 modification time
470 << nMtime[ 1 ] // 64 modification time
471 << nAtime[ 0 ] // 6C creation and access time
472 << nAtime[ 1 ] // 6C creation and access time
473 << nPage1 // 74 starting block (either direct or translated)
474 << nSize // 78 file size
475 << nUnknown; // 7C unknown
476 }
477
478