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