xref: /trunk/main/sot/source/sdstor/stgelem.cxx (revision 86e1cf34)
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