1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <string.h> // memset(), memcpy()
22 #include <rtl/ustring.hxx>
23 #include <com/sun/star/lang/Locale.hpp>
24 #include <unotools/charclass.hxx>
25 #include "sot/stg.hxx"
26 #include "stgelem.hxx"
27 #include "stgcache.hxx"
28 #include "stgstrms.hxx"
32 static const sal_uInt16 nMaxLegalStr
= 31;
34 static sal_uInt8 cStgSignature
[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
36 ////////////////////////////// struct ClsId /////////////////////////////
38 SvStream
& operator >>( SvStream
& r
, ClsId
& rId
)
54 SvStream
& operator <<( SvStream
& r
, const ClsId
& rId
)
57 r
<< (sal_Int32
) rId
.n1
66 << (sal_uInt8
) rId
.n10
67 << (sal_uInt8
) rId
.n11
;
70 ///////////////////////////// class StgHeader ////////////////////////////
72 StgHeader::StgHeader()
87 memset( cSignature
, 0, sizeof( cSignature
) );
88 memset( &aClsId
, 0, sizeof( ClsId
) );
89 memset( cReserved
, 0, sizeof( cReserved
) );
90 memset( nMasterFAT
, 0, sizeof( nMasterFAT
) );
93 void StgHeader::Init()
95 memcpy( cSignature
, cStgSignature
, 8 );
96 memset( &aClsId
, 0, sizeof( ClsId
) );
97 nVersion
= 0x0003003B;
99 nPageSize
= 9; // 512 bytes
100 nDataPageSize
= 6; // 64 bytes
102 memset( cReserved
, 0, sizeof( cReserved
) );
109 nMasterChain
= STG_EOF
;
111 SetTOCStart( STG_EOF
);
112 SetDataFATStart( STG_EOF
);
113 for( short i
= 0; i
< cFATPagesInHeader
; i
++ )
114 SetFATPage( i
, STG_FREE
);
117 sal_Bool
StgHeader::Load( StgIo
& rIo
)
119 sal_Bool bResult
= sal_False
;
122 SvStream
& r
= *rIo
.GetStrm();
124 bResult
= ( bResult
&& rIo
.Good() );
130 sal_Bool
StgHeader::Load( SvStream
& r
)
133 r
.Read( cSignature
, 8 );
134 r
>> aClsId
// 08 Class ID
135 >> 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
140 r
>> nFATSize
// 2C total number of FAT pages
141 >> nTOCstrm
// 30 starting page for the TOC stream
143 >> nThreshold
// 38 minimum file size for big data
144 >> nDataFAT
// 3C page # of 1st data FAT block
145 >> nDataFATSize
// 40 # of data FATpages
146 >> nMasterChain
// 44 chain to the next master block
147 >> nMaster
; // 48 # of additional master blocks
148 for( short i
= 0; i
< cFATPagesInHeader
; i
++ )
149 r
>> nMasterFAT
[ i
];
151 return ( r
.GetErrorCode() == ERRCODE_NONE
&& Check() );
154 sal_Bool
StgHeader::Store( StgIo
& rIo
)
158 SvStream
& r
= *rIo
.GetStrm();
160 r
.Write( cSignature
, 8 );
161 r
<< aClsId
// 08 Class ID
162 << nVersion
// 1A version number
163 << nByteOrder
// 1C Unicode byte order indicator
164 << nPageSize
// 1E 1 << nPageSize = block size
165 << nDataPageSize
// 20 1 << this size == data block size
166 << (sal_Int32
) 0 << (sal_Int32
) 0 << (sal_Int16
) 0
167 << nFATSize
// 2C total number of FAT pages
168 << nTOCstrm
// 30 starting page for the TOC stream
170 << nThreshold
// 38 minimum file size for big data
171 << nDataFAT
// 3C page # of 1st data FAT block
172 << nDataFATSize
// 40 # of data FAT pages
173 << nMasterChain
// 44 chain to the next master block
174 << nMaster
; // 48 # of additional master blocks
175 for( short i
= 0; i
< cFATPagesInHeader
; i
++ )
176 r
<< nMasterFAT
[ i
];
177 bDirty
= !rIo
.Good();
178 return sal_Bool( !bDirty
);
181 static bool lcl_wontoverflow(short shift
)
183 return shift
>= 0 && shift
< (short)sizeof(short) * 8 - 1;
186 static bool isKnownSpecial(sal_Int32 nLocation
)
188 return (nLocation
== STG_FREE
||
189 nLocation
== STG_EOF
||
190 nLocation
== STG_FAT
||
191 nLocation
== STG_MASTER
);
194 // Perform thorough checks also on unknown variables
195 sal_Bool
StgHeader::Check()
197 return sal_Bool( memcmp( cSignature
, cStgSignature
, 8 ) == 0
198 && (short) ( nVersion
>> 16 ) == 3 )
200 && lcl_wontoverflow(nPageSize
)
201 && lcl_wontoverflow(nDataPageSize
)
205 && ( isKnownSpecial(nDataFAT
) || ( nDataFAT
>= 0 && nDataFATSize
> 0 ) )
206 && ( isKnownSpecial(nMasterChain
) || nMasterChain
>=0 )
210 sal_Int32
StgHeader::GetFATPage( short n
) const
212 if( n
>= 0 && n
< cFATPagesInHeader
)
213 return nMasterFAT
[ n
];
218 void StgHeader::SetFATPage( short n
, sal_Int32 nb
)
220 if( n
>= 0 && n
< cFATPagesInHeader
)
222 if( nMasterFAT
[ n
] != nb
)
223 bDirty
= sal_True
, nMasterFAT
[ n
] = nb
;
227 void StgHeader::SetTOCStart( sal_Int32 n
)
229 if( n
!= nTOCstrm
) bDirty
= sal_True
, nTOCstrm
= n
;
232 void StgHeader::SetDataFATStart( sal_Int32 n
)
234 if( n
!= nDataFAT
) bDirty
= sal_True
, nDataFAT
= n
;
237 void StgHeader::SetDataFATSize( sal_Int32 n
)
239 if( n
!= nDataFATSize
) bDirty
= sal_True
, nDataFATSize
= n
;
242 void StgHeader::SetFATSize( sal_Int32 n
)
244 if( n
!= nFATSize
) bDirty
= sal_True
, nFATSize
= n
;
247 void StgHeader::SetFATChain( sal_Int32 n
)
249 if( n
!= nMasterChain
)
250 bDirty
= sal_True
, nMasterChain
= n
;
253 void StgHeader::SetMasters( sal_Int32 n
)
255 if( n
!= nMaster
) bDirty
= sal_True
, nMaster
= n
;
258 ///////////////////////////// class StgEntry /////////////////////////////
260 sal_Bool
StgEntry::Init()
262 memset( nName
, 0, sizeof( nName
) );
269 memset( &aClsId
, 0, sizeof( aClsId
) );
271 nMtime
[0] = 0; nMtime
[1] = 0;
272 nAtime
[0] = 0; nAtime
[1] = 0;
277 SetLeaf( STG_LEFT
, STG_FREE
);
278 SetLeaf( STG_RIGHT
, STG_FREE
);
279 SetLeaf( STG_CHILD
, STG_FREE
);
280 SetLeaf( STG_DATA
, STG_EOF
);
284 static String
ToUpperUnicode( const String
& rStr
)
286 // I don't know the locale, so en_US is hopefully fine
287 static CharClass
aCC( LanguageTag( com::sun::star::lang::Locale( "en", "US", "" )) );
288 return aCC
.uppercase( rStr
);
291 sal_Bool
StgEntry::SetName( const String
& rName
)
293 // I don't know the locale, so en_US is hopefully fine
294 aName
= ToUpperUnicode( rName
);
295 aName
.Erase( nMaxLegalStr
);
298 for( i
= 0; i
< aName
.Len() && i
< 32; i
++ )
299 nName
[ i
] = rName
.GetChar( sal_uInt16( i
));
302 nNameLen
= ( aName
.Len() + 1 ) << 1;
306 sal_Int32
StgEntry::GetLeaf( StgEntryRef eRef
) const
311 case STG_LEFT
: n
= nLeft
; break;
312 case STG_RIGHT
: n
= nRight
; break;
313 case STG_CHILD
: n
= nChild
; break;
314 case STG_DATA
: n
= nPage1
; break;
319 void StgEntry::SetLeaf( StgEntryRef eRef
, sal_Int32 nPage
)
323 case STG_LEFT
: nLeft
= nPage
; break;
324 case STG_RIGHT
: nRight
= nPage
; break;
325 case STG_CHILD
: nChild
= nPage
; break;
326 case STG_DATA
: nPage1
= nPage
; break;
330 void StgEntry::SetClassId( const ClsId
& r
)
332 memcpy( &aClsId
, &r
, sizeof( ClsId
) );
335 void StgEntry::GetName( String
& rName
) const
337 sal_uInt16 n
= nNameLen
;
340 rName
= OUString(nName
, n
);
343 // Compare two entries. Do this case-insensitive.
345 short StgEntry::Compare( const StgEntry
& r
) const
348 short nRes = r.nNameLen - nNameLen;
349 if( !nRes ) return strcmp( r.aName, aName );
352 sal_Int32 nRes
= r
.nNameLen
- nNameLen
;
354 nRes
= r
.aName
.CompareTo( aName
);
356 //return aName.CompareTo( r.aName );
359 // These load/store operations are a bit more complicated,
360 // since they have to copy their contents into a packed structure.
362 sal_Bool
StgEntry::Load( const void* pFrom
, sal_uInt32 nBufSize
)
364 if ( nBufSize
< 128 )
367 SvMemoryStream
r( (sal_Char
*) pFrom
, nBufSize
, 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
386 sal_uInt16 n
= nNameLen
;
390 if (n
> nMaxLegalStr
)
393 if ((cType
!= STG_STORAGE
) && ((nSize
< 0) || (nPage1
< 0 && !isKnownSpecial(nPage1
))))
395 // the size makes no sense for the substorage
396 // TODO/LATER: actually the size should be an unsigned value, but in this case it would mean a stream of more than 2Gb
400 aName
= OUString( nName
, n
);
401 // I don't know the locale, so en_US is hopefully fine
402 aName
= ToUpperUnicode( aName
);
403 aName
.Erase( nMaxLegalStr
);
408 void StgEntry::Store( void* pTo
)
410 SvMemoryStream
r( (sal_Char
*)pTo
, 128, STREAM_WRITE
);
411 for( short i
= 0; i
< 32; i
++ )
412 r
<< nName
[ i
]; // 00 name as WCHAR
413 r
<< nNameLen
// 40 size of name in bytes including 00H
414 << cType
// 42 entry type
415 << cFlags
// 43 0 or 1 (tree balance?)
416 << nLeft
// 44 left node entry
417 << nRight
// 48 right node entry
418 << nChild
// 4C 1st child entry if storage;
419 << aClsId
// 50 class ID (optional)
420 << nFlags
// 60 state flags(?)
421 << nMtime
[ 0 ] // 64 modification time
422 << nMtime
[ 1 ] // 64 modification time
423 << nAtime
[ 0 ] // 6C creation and access time
424 << nAtime
[ 1 ] // 6C creation and access time
425 << nPage1
// 74 starting block (either direct or translated)
426 << nSize
// 78 file size
427 << nUnknown
; // 7C unknown
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */