xref: /aoo42x/main/sot/source/sdstor/stgelem.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sot.hxx"
30 
31 #include <string.h> // memset(), memcpy()
32 #include <rtl/ustring.hxx>
33 #include <com/sun/star/lang/Locale.hpp>
34 #include <unotools/charclass.hxx>
35 #include "sot/stg.hxx"
36 #include "stgelem.hxx"
37 #include "stgcache.hxx"
38 #include "stgstrms.hxx"
39 #include "stgdir.hxx"
40 #include "stgio.hxx"
41 
42 static sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
43 
44 ////////////////////////////// struct ClsId  /////////////////////////////
45 
46 SvStream& operator >>( SvStream& r, ClsId& rId )
47 {
48     r >> rId.n1
49 	  >> rId.n2
50 	  >> rId.n3
51 	  >> rId.n4
52 	  >> rId.n5
53 	  >> rId.n6
54 	  >> rId.n7
55 	  >> rId.n8
56 	  >> rId.n9
57 	  >> rId.n10
58 	  >> rId.n11;
59 	return r;
60 }
61 
62 SvStream& operator <<( SvStream& r, const ClsId& rId )
63 {
64 	return
65 	   r  << (sal_Int32) rId.n1
66 		  << (sal_Int16) rId.n2
67 		  << (sal_Int16) rId.n3
68 		  << (sal_uInt8) rId.n4
69 		  << (sal_uInt8) rId.n5
70 		  << (sal_uInt8) rId.n6
71 		  << (sal_uInt8) rId.n7
72 		  << (sal_uInt8) rId.n8
73 		  << (sal_uInt8) rId.n9
74 		  << (sal_uInt8) rId.n10
75 		  << (sal_uInt8) rId.n11;
76 }
77 
78 ///////////////////////////// class StgHeader ////////////////////////////
79 
80 StgHeader::StgHeader()
81 {
82     memset( this, 0, sizeof( StgHeader ) );
83 }
84 
85 void StgHeader::Init()
86 {
87     memset( this, 0, sizeof( StgHeader ) );
88     memcpy( cSignature, cStgSignature, 8 );
89     nVersion      = 0x0003003B;
90     nByteOrder    = 0xFFFE;
91     nPageSize     = 9;          // 512 bytes
92     nDataPageSize = 6;          // 64 bytes
93     nThreshold    = 4096;
94 	nDataFATSize  = 0;
95     nMasterChain  = STG_EOF;
96     SetTOCStart( STG_EOF );
97     SetDataFATStart( STG_EOF );
98     for( short i = 0; i < 109; i++ )
99         SetFATPage( i, STG_FREE );
100 }
101 
102 sal_Bool StgHeader::Load( StgIo& rIo )
103 {
104 	SvStream& r = *rIo.GetStrm();
105     Load( r );
106 	return rIo.Good();
107 }
108 
109 sal_Bool StgHeader::Load( SvStream& r )
110 {
111 	r.Seek( 0L );
112     r.Read( cSignature, 8 );
113 	r >> aClsId						// 08 Class ID
114 	  >> nVersion 					// 1A version number
115 	  >> nByteOrder 				// 1C Unicode byte order indicator
116 	  >> nPageSize 					// 1E 1 << nPageSize = block size
117 	  >> nDataPageSize;				// 20 1 << this size == data block size
118 	r.SeekRel( 10 );
119 	r >> nFATSize					// 2C total number of FAT pages
120 	  >> nTOCstrm 					// 30 starting page for the TOC stream
121 	  >> nReserved 					// 34
122 	  >> nThreshold  				// 38 minimum file size for big data
123 	  >> nDataFAT 					// 3C page # of 1st data FAT block
124 	  >> nDataFATSize				// 40 # of data FATpages
125 	  >> nMasterChain 				// 44 chain to the next master block
126 	  >> nMaster;					// 48 # of additional master blocks
127 	for( short i = 0; i < 109; i++ )
128 		r >> nMasterFAT[ i ];
129     return r.GetErrorCode() == ERRCODE_NONE;
130 }
131 
132 sal_Bool StgHeader::Store( StgIo& rIo )
133 {
134 	if( !bDirty )
135 		return sal_True;
136 	SvStream& r = *rIo.GetStrm();
137 	r.Seek( 0L );
138     r.Write( cSignature, 8 + 16 );
139 	r << 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 	  << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
144 	  << 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 FAT pages
150 	  << nMasterChain 				// 44 chain to the next master block
151 	  << nMaster;					// 48 # of additional master blocks
152 	for( short i = 0; i < 109; i++ )
153 		r << nMasterFAT[ i ];
154 	bDirty = !rIo.Good();
155 	return sal_Bool( !bDirty );
156 }
157 
158 static bool lcl_wontoverflow(short shift)
159 {
160     return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
161 }
162 
163 // Perform thorough checks also on unknown variables
164 sal_Bool StgHeader::Check()
165 {
166     return sal_Bool( memcmp( cSignature, cStgSignature, 8 ) == 0
167             && (short) ( nVersion >> 16 ) == 3 )
168             && lcl_wontoverflow(nPageSize)
169             && lcl_wontoverflow(nDataPageSize);
170 }
171 
172 sal_Int32 StgHeader::GetFATPage( short n ) const
173 {
174     if( n >= 0 && n < 109 )
175         return nMasterFAT[ n ];
176     else
177         return STG_EOF;
178 }
179 
180 void StgHeader::SetFATPage( short n, sal_Int32 nb )
181 {
182     if( n >= 0 && n < 109 )
183 	{
184 		if( nMasterFAT[ n ] != nb )
185         	bDirty = sal_True, nMasterFAT[ n ] = nb;
186 	}
187 }
188 
189 void StgHeader::SetClassId( const ClsId& r )
190 {
191 	if( memcmp( &aClsId, &r, sizeof( ClsId ) ) )
192 		bDirty = sal_True, memcpy( &aClsId, &r, sizeof( ClsId ) );
193 }
194 
195 void StgHeader::SetTOCStart( sal_Int32 n )
196 {
197 	if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
198 }
199 
200 void StgHeader::SetDataFATStart( sal_Int32 n )
201 {
202 	if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
203 }
204 
205 void StgHeader::SetDataFATSize( sal_Int32 n )
206 {
207 	if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
208 }
209 
210 void StgHeader::SetFATSize( sal_Int32 n )
211 {
212 	if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
213 }
214 
215 void StgHeader::SetFATChain( sal_Int32 n )
216 {
217 	if( n != nMasterChain )
218 		bDirty = sal_True, nMasterChain = n;
219 }
220 
221 void StgHeader::SetMasters( sal_Int32 n )
222 {
223 	if( n != nMaster ) bDirty = sal_True, nMaster = n;
224 }
225 
226 ///////////////////////////// class StgEntry /////////////////////////////
227 
228 // This class is only a wrapper around teh dir entry structure
229 // which retrieves and sets data.
230 
231 // The name must be smaller than 32 chars. Conversion into Unicode
232 // is easy, since the 1st 256 characters of the Windows ANSI set
233 // equal the 1st 256 Unicode characters.
234 /*
235 void ToUnicode_Impl( String& rName )
236 {
237 	rName.Erase( 32 );
238 	rName.Convert( ::GetSystemCharSet(), CHARSET_ANSI );
239 	// brute force is OK
240 	sal_uInt8* p = (sal_uInt8*) rName.GetCharStr();
241     for( sal_uInt16 i = 0; i < rName.Len(); i++, p++ )
242     {
243         // check each character and substitute blanks for illegal ones
244         sal_uInt8 cChar = *p;
245         if( cChar == '!' || cChar == ':' || cChar == '\\' || cChar == '/' )
246 			*p = ' ';
247     }
248 }
249 */
250 /*
251 static void FromUnicode( String& rName )
252 {
253 	rName.Convert( CHARSET_ANSI, ::GetSystemCharSet() );
254 }
255 */
256 sal_Bool StgEntry::Init()
257 {
258     memset( this, 0, sizeof (StgEntry) - sizeof( String ) );
259     SetLeaf( STG_LEFT,  STG_FREE );
260     SetLeaf( STG_RIGHT, STG_FREE );
261     SetLeaf( STG_CHILD, STG_FREE );
262     SetLeaf( STG_DATA,  STG_EOF );
263     return sal_True;
264 }
265 
266 static String ToUpperUnicode( const String & rStr )
267 {
268 	// I don't know the locale, so en_US is hopefully fine
269 	/*
270 	com.sun.star.lang.Locale aLocale;
271 	aLocale.Language = OUString::createFromAscii( "en" );
272 	aLocale.Country  = OUString::createFromAscii( "US" );
273 	*/
274 	static rtl::OUString aEN=rtl::OUString::createFromAscii( "en" );
275 	static rtl::OUString aUS=rtl::OUString::createFromAscii( "US" );
276 	static CharClass aCC( com::sun::star::lang::Locale( aEN, aUS, rtl::OUString() ) );
277 	return aCC.toUpper( rStr, 0, rStr.Len() );
278 }
279 
280 
281 sal_Bool StgEntry::SetName( const String& rName )
282 {
283     // I don't know the locale, so en_US is hopefully fine
284     aName = ToUpperUnicode( rName );
285     aName.Erase( 31 );
286 
287     int i;
288     for( i = 0; i < aName.Len() && i < 32; i++ )
289         nName[ i ] = rName.GetChar( sal_uInt16( i ));
290     while( i < 32 )
291         nName[ i++ ] = 0;
292     nNameLen = ( aName.Len() + 1 ) << 1;
293     return sal_True;
294 }
295 
296 sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
297 {
298     sal_Int32 n = -1;
299     switch( eRef )
300     {
301         case STG_LEFT:  n = nLeft;  break;
302         case STG_RIGHT: n = nRight; break;
303         case STG_CHILD: n = nChild; break;
304         case STG_DATA:  n = nPage1; break;
305     }
306     return n;
307 }
308 
309 void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
310 {
311     switch( eRef )
312     {
313         case STG_LEFT:  nLeft  = nPage; break;
314         case STG_RIGHT: nRight = nPage; break;
315         case STG_CHILD: nChild = nPage; break;
316         case STG_DATA:  nPage1 = nPage; break;
317     }
318 }
319 
320 const sal_Int32* StgEntry::GetTime( StgEntryTime eTime ) const
321 {
322     return( eTime == STG_MODIFIED ) ? nMtime : nAtime;
323 }
324 
325 void StgEntry::SetTime( StgEntryTime eTime, sal_Int32* pTime )
326 {
327     if( eTime == STG_MODIFIED )
328         nMtime[ 0 ] = *pTime++, nMtime[ 1 ] = *pTime;
329     else
330         nAtime[ 0 ] = *pTime++, nAtime[ 1 ] = *pTime;
331 }
332 
333 void StgEntry::SetClassId( const ClsId& r )
334 {
335 	memcpy( &aClsId, &r, sizeof( ClsId ) );
336 }
337 
338 void StgEntry::GetName( String& rName ) const
339 {
340     sal_uInt16 n = nNameLen;
341     if( n )
342         n = ( n >> 1 ) - 1;
343 	rName = String( nName, n );
344 }
345 
346 // Compare two entries. Do this case-insensitive.
347 
348 short StgEntry::Compare( const StgEntry& r ) const
349 {
350 	/*
351     short nRes = r.nNameLen - nNameLen;
352     if( !nRes ) return strcmp( r.aName, aName );
353 	else return nRes;
354 	*/
355     sal_Int32 nRes = r.nNameLen - nNameLen;
356     if( !nRes )
357 		nRes = r.aName.CompareTo( aName );
358 	return (short)nRes;
359 	//return aName.CompareTo( r.aName );
360 }
361 
362 // These load/store operations are a bit more complicated,
363 // since they have to copy their contents into a packed structure.
364 
365 sal_Bool StgEntry::Load( const void* pFrom )
366 {
367 	SvMemoryStream r( (sal_Char*) pFrom, 128, 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
385 
386     sal_uInt16 n = nNameLen;
387     if( n )
388 		n = ( n >> 1 ) - 1;
389 	if( n > 31 || (nSize < 0 && cType != STG_STORAGE) )
390     {
391         // the size makes no sence for the substorage
392         // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
393 		return sal_False;
394     }
395 
396 	aName = String( nName, n );
397 	// I don't know the locale, so en_US is hopefully fine
398 	aName = ToUpperUnicode( aName );
399 	aName.Erase( 31 );
400 
401 	return sal_True;
402 }
403 
404 void StgEntry::Store( void* pTo )
405 {
406 	SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
407 	for( short i = 0; i < 32; i++ )
408 		r << nName[ i ];			// 00 name as WCHAR
409 	r << nNameLen 					// 40 size of name in bytes including 00H
410 	  << cType 						// 42 entry type
411 	  << cFlags						// 43 0 or 1 (tree balance?)
412 	  << nLeft						// 44 left node entry
413 	  << nRight						// 48 right node entry
414 	  << nChild						// 4C 1st child entry if storage;
415 	  << aClsId						// 50 class ID (optional)
416 	  << nFlags						// 60 state flags(?)
417 	  << nMtime[ 0 ]				// 64 modification time
418 	  << nMtime[ 1 ]				// 64 modification time
419 	  << nAtime[ 0 ] 				// 6C creation and access time
420 	  << nAtime[ 1 ] 				// 6C creation and access time
421 	  << nPage1						// 74 starting block (either direct or translated)
422 	  << nSize 						// 78 file size
423 	  << nUnknown;					// 7C unknown
424 }
425 
426