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