xref: /aoo41x/main/sot/source/sdstor/stgelem.cxx (revision 046d9d1f)
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 
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 
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 
76 StgHeader::StgHeader()
77 {
78     memset( this, 0, sizeof( StgHeader ) );
79 }
80 
81 void StgHeader::Init()
82 {
83     memset( this, 0, sizeof( StgHeader ) );
84     memcpy( cSignature, cStgSignature, 8 );
85     nVersion      = 0x0003003B;
86     nByteOrder    = 0xFFFE;
87     nPageSize     = 9;          // 512 bytes
88     nDataPageSize = 6;          // 64 bytes
89     nThreshold    = 4096;
90 	nDataFATSize  = 0;
91     nMasterChain  = STG_EOF;
92     SetTOCStart( STG_EOF );
93     SetDataFATStart( STG_EOF );
94     for( short i = 0; i < 109; i++ )
95         SetFATPage( i, STG_FREE );
96 }
97 
98 sal_Bool StgHeader::Load( StgIo& rIo )
99 {
100 	SvStream& r = *rIo.GetStrm();
101     Load( r );
102 	return rIo.Good();
103 }
104 
105 sal_Bool StgHeader::Load( SvStream& r )
106 {
107 	r.Seek( 0L );
108     r.Read( cSignature, 8 );
109 	r >> aClsId						// 08 Class ID
110 	  >> nVersion 					// 1A version number
111 	  >> nByteOrder 				// 1C Unicode byte order indicator
112 	  >> nPageSize 					// 1E 1 << nPageSize = block size
113 	  >> nDataPageSize;				// 20 1 << this size == data block size
114 	r.SeekRel( 10 );
115 	r >> nFATSize					// 2C total number of FAT pages
116 	  >> nTOCstrm 					// 30 starting page for the TOC stream
117 	  >> nReserved 					// 34
118 	  >> nThreshold  				// 38 minimum file size for big data
119 	  >> nDataFAT 					// 3C page # of 1st data FAT block
120 	  >> nDataFATSize				// 40 # of data FATpages
121 	  >> nMasterChain 				// 44 chain to the next master block
122 	  >> nMaster;					// 48 # of additional master blocks
123 	for( short i = 0; i < 109; i++ )
124 		r >> nMasterFAT[ i ];
125     return r.GetErrorCode() == ERRCODE_NONE;
126 }
127 
128 sal_Bool StgHeader::Store( StgIo& rIo )
129 {
130 	if( !bDirty )
131 		return sal_True;
132 	SvStream& r = *rIo.GetStrm();
133 	r.Seek( 0L );
134     r.Write( cSignature, 8 + 16 );
135 	r << 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 	  << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int16) 0
140 	  << 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 FAT pages
146 	  << nMasterChain 				// 44 chain to the next master block
147 	  << nMaster;					// 48 # of additional master blocks
148 	for( short i = 0; i < 109; i++ )
149 		r << nMasterFAT[ i ];
150 	bDirty = !rIo.Good();
151 	return sal_Bool( !bDirty );
152 }
153 
154 static bool lcl_wontoverflow(short shift)
155 {
156     return shift >= 0 && shift < (short)sizeof(short) * 8 - 1;
157 }
158 
159 // Perform thorough checks also on unknown variables
160 sal_Bool StgHeader::Check()
161 {
162     return sal_Bool( memcmp( cSignature, cStgSignature, 8 ) == 0
163             && (short) ( nVersion >> 16 ) == 3 )
164             && lcl_wontoverflow(nPageSize)
165             && lcl_wontoverflow(nDataPageSize);
166 }
167 
168 sal_Int32 StgHeader::GetFATPage( short n ) const
169 {
170     if( n >= 0 && n < 109 )
171         return nMasterFAT[ n ];
172     else
173         return STG_EOF;
174 }
175 
176 void StgHeader::SetFATPage( short n, sal_Int32 nb )
177 {
178     if( n >= 0 && n < 109 )
179 	{
180 		if( nMasterFAT[ n ] != nb )
181         	bDirty = sal_True, nMasterFAT[ n ] = nb;
182 	}
183 }
184 
185 void StgHeader::SetClassId( const ClsId& r )
186 {
187 	if( memcmp( &aClsId, &r, sizeof( ClsId ) ) )
188 		bDirty = sal_True, memcpy( &aClsId, &r, sizeof( ClsId ) );
189 }
190 
191 void StgHeader::SetTOCStart( sal_Int32 n )
192 {
193 	if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n;
194 }
195 
196 void StgHeader::SetDataFATStart( sal_Int32 n )
197 {
198 	if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n;
199 }
200 
201 void StgHeader::SetDataFATSize( sal_Int32 n )
202 {
203 	if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n;
204 }
205 
206 void StgHeader::SetFATSize( sal_Int32 n )
207 {
208 	if( n != nFATSize ) bDirty = sal_True, nFATSize = n;
209 }
210 
211 void StgHeader::SetFATChain( sal_Int32 n )
212 {
213 	if( n != nMasterChain )
214 		bDirty = sal_True, nMasterChain = n;
215 }
216 
217 void StgHeader::SetMasters( sal_Int32 n )
218 {
219 	if( n != nMaster ) bDirty = sal_True, nMaster = n;
220 }
221 
222 ///////////////////////////// class StgEntry /////////////////////////////
223 
224 // This class is only a wrapper around teh dir entry structure
225 // which retrieves and sets data.
226 
227 // The name must be smaller than 32 chars. Conversion into Unicode
228 // is easy, since the 1st 256 characters of the Windows ANSI set
229 // equal the 1st 256 Unicode characters.
230 /*
231 void ToUnicode_Impl( String& rName )
232 {
233 	rName.Erase( 32 );
234 	rName.Convert( ::GetSystemCharSet(), CHARSET_ANSI );
235 	// brute force is OK
236 	sal_uInt8* p = (sal_uInt8*) rName.GetCharStr();
237     for( sal_uInt16 i = 0; i < rName.Len(); i++, p++ )
238     {
239         // check each character and substitute blanks for illegal ones
240         sal_uInt8 cChar = *p;
241         if( cChar == '!' || cChar == ':' || cChar == '\\' || cChar == '/' )
242 			*p = ' ';
243     }
244 }
245 */
246 /*
247 static void FromUnicode( String& rName )
248 {
249 	rName.Convert( CHARSET_ANSI, ::GetSystemCharSet() );
250 }
251 */
252 sal_Bool StgEntry::Init()
253 {
254     memset( this, 0, sizeof (StgEntry) - sizeof( String ) );
255     SetLeaf( STG_LEFT,  STG_FREE );
256     SetLeaf( STG_RIGHT, STG_FREE );
257     SetLeaf( STG_CHILD, STG_FREE );
258     SetLeaf( STG_DATA,  STG_EOF );
259     return sal_True;
260 }
261 
262 static String ToUpperUnicode( const String & rStr )
263 {
264 	// I don't know the locale, so en_US is hopefully fine
265 	/*
266 	com.sun.star.lang.Locale aLocale;
267 	aLocale.Language = OUString::createFromAscii( "en" );
268 	aLocale.Country  = OUString::createFromAscii( "US" );
269 	*/
270 	static rtl::OUString aEN=rtl::OUString::createFromAscii( "en" );
271 	static rtl::OUString aUS=rtl::OUString::createFromAscii( "US" );
272 	static CharClass aCC( com::sun::star::lang::Locale( aEN, aUS, rtl::OUString() ) );
273 	return aCC.toUpper( rStr, 0, rStr.Len() );
274 }
275 
276 
277 sal_Bool StgEntry::SetName( const String& rName )
278 {
279     // I don't know the locale, so en_US is hopefully fine
280     aName = ToUpperUnicode( rName );
281     aName.Erase( 31 );
282 
283     int i;
284     for( i = 0; i < aName.Len() && i < 32; i++ )
285         nName[ i ] = rName.GetChar( sal_uInt16( i ));
286     while( i < 32 )
287         nName[ i++ ] = 0;
288     nNameLen = ( aName.Len() + 1 ) << 1;
289     return sal_True;
290 }
291 
292 sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
293 {
294     sal_Int32 n = -1;
295     switch( eRef )
296     {
297         case STG_LEFT:  n = nLeft;  break;
298         case STG_RIGHT: n = nRight; break;
299         case STG_CHILD: n = nChild; break;
300         case STG_DATA:  n = nPage1; break;
301     }
302     return n;
303 }
304 
305 void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
306 {
307     switch( eRef )
308     {
309         case STG_LEFT:  nLeft  = nPage; break;
310         case STG_RIGHT: nRight = nPage; break;
311         case STG_CHILD: nChild = nPage; break;
312         case STG_DATA:  nPage1 = nPage; break;
313     }
314 }
315 
316 const sal_Int32* StgEntry::GetTime( StgEntryTime eTime ) const
317 {
318     return( eTime == STG_MODIFIED ) ? nMtime : nAtime;
319 }
320 
321 void StgEntry::SetTime( StgEntryTime eTime, sal_Int32* pTime )
322 {
323     if( eTime == STG_MODIFIED )
324         nMtime[ 0 ] = *pTime++, nMtime[ 1 ] = *pTime;
325     else
326         nAtime[ 0 ] = *pTime++, nAtime[ 1 ] = *pTime;
327 }
328 
329 void StgEntry::SetClassId( const ClsId& r )
330 {
331 	memcpy( &aClsId, &r, sizeof( ClsId ) );
332 }
333 
334 void StgEntry::GetName( String& rName ) const
335 {
336     sal_uInt16 n = nNameLen;
337     if( n )
338         n = ( n >> 1 ) - 1;
339 	rName = String( nName, n );
340 }
341 
342 // Compare two entries. Do this case-insensitive.
343 
344 short StgEntry::Compare( const StgEntry& r ) const
345 {
346 	/*
347     short nRes = r.nNameLen - nNameLen;
348     if( !nRes ) return strcmp( r.aName, aName );
349 	else return nRes;
350 	*/
351     sal_Int32 nRes = r.nNameLen - nNameLen;
352     if( !nRes )
353 		nRes = r.aName.CompareTo( aName );
354 	return (short)nRes;
355 	//return aName.CompareTo( r.aName );
356 }
357 
358 // These load/store operations are a bit more complicated,
359 // since they have to copy their contents into a packed structure.
360 
361 sal_Bool StgEntry::Load( const void* pFrom )
362 {
363 	SvMemoryStream r( (sal_Char*) pFrom, 128, STREAM_READ );
364 	for( short i = 0; i < 32; i++ )
365 		r >> nName[ i ];			// 00 name as WCHAR
366 	r >> nNameLen 					// 40 size of name in bytes including 00H
367 	  >> cType 						// 42 entry type
368 	  >> cFlags						// 43 0 or 1 (tree balance?)
369 	  >> nLeft						// 44 left node entry
370 	  >> nRight						// 48 right node entry
371 	  >> nChild						// 4C 1st child entry if storage
372 	  >> aClsId						// 50 class ID (optional)
373 	  >> nFlags						// 60 state flags(?)
374 	  >> nMtime[ 0 ]				// 64 modification time
375 	  >> nMtime[ 1 ]				// 64 modification time
376 	  >> nAtime[ 0 ] 				// 6C creation and access time
377 	  >> nAtime[ 1 ] 				// 6C creation and access time
378 	  >> nPage1						// 74 starting block (either direct or translated)
379 	  >> nSize 						// 78 file size
380 	  >> nUnknown;					// 7C unknown
381 
382     sal_uInt16 n = nNameLen;
383     if( n )
384 		n = ( n >> 1 ) - 1;
385 	if( n > 31 || (nSize < 0 && cType != STG_STORAGE) )
386     {
387         // the size makes no sence for the substorage
388         // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
389 		return sal_False;
390     }
391 
392 	aName = String( nName, n );
393 	// I don't know the locale, so en_US is hopefully fine
394 	aName = ToUpperUnicode( aName );
395 	aName.Erase( 31 );
396 
397 	return sal_True;
398 }
399 
400 void StgEntry::Store( void* pTo )
401 {
402 	SvMemoryStream r( (sal_Char *)pTo, 128, STREAM_WRITE );
403 	for( short i = 0; i < 32; i++ )
404 		r << nName[ i ];			// 00 name as WCHAR
405 	r << nNameLen 					// 40 size of name in bytes including 00H
406 	  << cType 						// 42 entry type
407 	  << cFlags						// 43 0 or 1 (tree balance?)
408 	  << nLeft						// 44 left node entry
409 	  << nRight						// 48 right node entry
410 	  << nChild						// 4C 1st child entry if storage;
411 	  << aClsId						// 50 class ID (optional)
412 	  << nFlags						// 60 state flags(?)
413 	  << nMtime[ 0 ]				// 64 modification time
414 	  << nMtime[ 1 ]				// 64 modification time
415 	  << nAtime[ 0 ] 				// 6C creation and access time
416 	  << nAtime[ 1 ] 				// 6C creation and access time
417 	  << nPage1						// 74 starting block (either direct or translated)
418 	  << nSize 						// 78 file size
419 	  << nUnknown;					// 7C unknown
420 }
421 
422