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 : 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 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 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 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 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 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 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_EOF || ( nMasterChain >=0 && nMaster > 0 ) ) 202 && nMaster >= 0; 203 } 204 205 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 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 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 228 void StgHeader::SetTOCStart( sal_Int32 n ) 229 { 230 if( n != nTOCstrm ) bDirty = sal_True, nTOCstrm = n; 231 } 232 233 void StgHeader::SetDataFATStart( sal_Int32 n ) 234 { 235 if( n != nDataFAT ) bDirty = sal_True, nDataFAT = n; 236 } 237 238 void StgHeader::SetDataFATSize( sal_Int32 n ) 239 { 240 if( n != nDataFATSize ) bDirty = sal_True, nDataFATSize = n; 241 } 242 243 void StgHeader::SetFATSize( sal_Int32 n ) 244 { 245 if( n != nFATSize ) bDirty = sal_True, nFATSize = n; 246 } 247 248 void StgHeader::SetFATChain( sal_Int32 n ) 249 { 250 if( n != nMasterChain ) 251 bDirty = sal_True, nMasterChain = n; 252 } 253 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 teh 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 */ 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 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 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 343 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 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 367 const sal_Int32* StgEntry::GetTime( StgEntryTime eTime ) const 368 { 369 return( eTime == STG_MODIFIED ) ? nMtime : nAtime; 370 } 371 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 380 void StgEntry::SetClassId( const ClsId& r ) 381 { 382 memcpy( &aClsId, &r, sizeof( ClsId ) ); 383 } 384 385 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 395 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 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_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 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