LibreOffice Module sot (master) 1
stgelem.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <string.h>
22
23#include <o3tl/safeint.hxx>
24#include <rtl/ustring.hxx>
25#include <com/sun/star/lang/Locale.hpp>
27#include <sot/stg.hxx>
28#include "stgelem.hxx"
29#include "stgio.hxx"
30
31const sal_uInt16 nMaxLegalStr = 31;
32
33const sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 };
34
36
38{
39 r.ReadUInt32( rId.Data1 )
40 .ReadUInt16( rId.Data2 )
41 .ReadUInt16( rId.Data3 )
42 .ReadUChar( rId.Data4[0] )
43 .ReadUChar( rId.Data4[1] )
44 .ReadUChar( rId.Data4[2] )
45 .ReadUChar( rId.Data4[3] )
46 .ReadUChar( rId.Data4[4] )
47 .ReadUChar( rId.Data4[5] )
48 .ReadUChar( rId.Data4[6] )
49 .ReadUChar( rId.Data4[7] );
50 return r;
51}
52
54{
55 return
56 r .WriteUInt32( rId.Data1 )
57 .WriteUInt16( rId.Data2 )
58 .WriteUInt16( rId.Data3 )
59 .WriteUChar( rId.Data4[0] )
60 .WriteUChar( rId.Data4[1] )
61 .WriteUChar( rId.Data4[2] )
62 .WriteUChar( rId.Data4[3] )
63 .WriteUChar( rId.Data4[4] )
64 .WriteUChar( rId.Data4[5] )
65 .WriteUChar( rId.Data4[6] )
66 .WriteUChar( rId.Data4[7] );
67}
68
70
72: m_nVersion( 0 )
73, m_nByteOrder( 0 )
74, m_nPageSize( 0 )
75, m_nDataPageSize( 0 )
76, m_bDirty( sal_uInt8(false) )
77, m_nFATSize( 0 )
78, m_nTOCstrm( 0 )
79, m_nReserved( 0 )
80, m_nThreshold( 0 )
81, m_nDataFAT( 0 )
82, m_nDataFATSize( 0 )
83, m_nMasterChain( 0 )
84, m_nMaster( 0 )
85{
86}
87
89{
90 memcpy( m_cSignature, cStgSignature, 8 );
91 memset( &m_aClsId, 0, sizeof( ClsId ) );
92 m_nVersion = 0x0003003B;
93 m_nByteOrder = 0xFFFE;
94 m_nPageSize = 9; // 512 bytes
95 m_nDataPageSize = 6; // 64 bytes
96 m_bDirty = sal_uInt8(false);
97 memset( m_cReserved, 0, sizeof( m_cReserved ) );
98 m_nFATSize = 0;
99 m_nTOCstrm = 0;
100 m_nReserved = 0;
101 m_nThreshold = 4096;
102 m_nDataFAT = 0;
103 m_nDataFATSize = 0;
105
108 for( short i = 0; i < cFATPagesInHeader; i++ )
110}
111
113{
114 bool bResult = false;
115 if ( rIo.GetStrm() )
116 {
117 SvStream& r = *rIo.GetStrm();
118 bResult = Load( r );
119 bResult = ( bResult && rIo.Good() );
120 }
121
122 return bResult;
123}
124
126{
127 r.Seek( 0 );
128 r.ReadBytes( m_cSignature, 8 );
129 ReadClsId( r, m_aClsId ); // 08 Class ID
130 r.ReadInt32( m_nVersion ) // 1A version number
131 .ReadUInt16( m_nByteOrder ) // 1C Unicode byte order indicator
132 .ReadInt16( m_nPageSize ) // 1E 1 << nPageSize = block size
133 .ReadInt16( m_nDataPageSize ); // 20 1 << this size == data block size
134 if (!r.good())
135 return false;
136 if (!checkSeek(r, r.Tell() + 10))
137 return false;
138 r.ReadInt32( m_nFATSize ) // 2C total number of FAT pages
139 .ReadInt32( m_nTOCstrm ) // 30 starting page for the TOC stream
140 .ReadInt32( m_nReserved ) // 34
141 .ReadInt32( m_nThreshold ) // 38 minimum file size for big data
142 .ReadInt32( m_nDataFAT ) // 3C page # of 1st data FAT block
143 .ReadInt32( m_nDataFATSize ) // 40 # of data FATpages
144 .ReadInt32( m_nMasterChain ) // 44 chain to the next master block
145 .ReadInt32( m_nMaster ); // 48 # of additional master blocks
146 for(sal_Int32 & i : m_nMasterFAT)
147 r.ReadInt32( i );
148
149 return r.good() && Check();
150}
151
153{
154 if( !m_bDirty )
155 return true;
156
157 SvStream& r = *rIo.GetStrm();
158 r.Seek( 0 );
159 r.WriteBytes( m_cSignature, 8 );
160 WriteClsId( r, m_aClsId ); // 08 Class ID
161 r.WriteInt32( m_nVersion ) // 1A version number
162 .WriteUInt16( m_nByteOrder ) // 1C Unicode byte order indicator
163 .WriteInt16( m_nPageSize ) // 1E 1 << nPageSize = block size
164 .WriteInt16( m_nDataPageSize ) // 20 1 << this size == data block size
165 .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt16( 0 )
166 .WriteInt32( m_nFATSize ) // 2C total number of FAT pages
167 .WriteInt32( m_nTOCstrm ) // 30 starting page for the TOC stream
168 .WriteInt32( m_nReserved ) // 34
169 .WriteInt32( m_nThreshold ) // 38 minimum file size for big data
170 .WriteInt32( m_nDataFAT ) // 3C page # of 1st data FAT block
171 .WriteInt32( m_nDataFATSize ) // 40 # of data FAT pages
172 .WriteInt32( m_nMasterChain ) // 44 chain to the next master block
173 .WriteInt32( m_nMaster ); // 48 # of additional master blocks
174 for(sal_Int32 i : m_nMasterFAT)
175 r.WriteInt32( i );
176 m_bDirty = sal_uInt8(!rIo.Good());
177 return !m_bDirty;
178}
179
180static bool lcl_wontoverflow(short shift)
181{
182 return shift >= 0 && shift < short(sizeof(short)) * 8 - 1;
183}
184
185static bool isKnownSpecial(sal_Int32 nLocation)
186{
187 return (nLocation == STG_FREE ||
188 nLocation == STG_EOF ||
189 nLocation == STG_FAT ||
190 nLocation == STG_MASTER);
191}
192
193// Perform thorough checks also on unknown variables
195{
196 return memcmp( m_cSignature, cStgSignature, 8 ) == 0
197 && static_cast<short>( m_nVersion >> 16 ) == 3
198 && m_nPageSize == 9
201 && m_nFATSize > 0
202 && m_nTOCstrm >= 0
203 && m_nThreshold > 0
204 && ( isKnownSpecial(m_nDataFAT) || ( m_nDataFAT >= 0 && m_nDataFATSize > 0 ) )
206 && m_nMaster >= 0;
207}
208
209sal_Int32 StgHeader::GetFATPage( short n ) const
210{
211 if( n >= 0 && n < cFATPagesInHeader )
212 return m_nMasterFAT[ n ];
213 else
214 return STG_EOF;
215}
216
217void StgHeader::SetFATPage( short n, sal_Int32 nb )
218{
219 if( n >= 0 && n < cFATPagesInHeader )
220 {
221 if( m_nMasterFAT[ n ] != nb )
222 {
223 m_bDirty = sal_uInt8(true);
224 m_nMasterFAT[ n ] = nb;
225 }
226 }
227}
228
229void StgHeader::SetTOCStart( sal_Int32 n )
230{
231 if( n != m_nTOCstrm )
232 {
233 m_bDirty = sal_uInt8(true);
234 m_nTOCstrm = n;
235 }
236}
237
238void StgHeader::SetDataFATStart( sal_Int32 n )
239{
240 if( n != m_nDataFAT )
241 {
242 m_bDirty = sal_uInt8(true);
243 m_nDataFAT = n;
244 }
245}
246
247void StgHeader::SetDataFATSize( sal_Int32 n )
248{
249 if( n != m_nDataFATSize )
250 {
251 m_bDirty = sal_uInt8(true);
253 }
254}
255
256void StgHeader::SetFATSize( sal_Int32 n )
257{
258 if( n != m_nFATSize )
259 {
260 m_bDirty = sal_uInt8(true);
261 m_nFATSize = n;
262 }
263}
264
265void StgHeader::SetFATChain( sal_Int32 n )
266{
267 if( n != m_nMasterChain )
268 {
269 m_bDirty = sal_uInt8(true);
271 }
272}
273
274void StgHeader::SetMasters( sal_Int32 n )
275{
276 if( n != m_nMaster )
277 {
278 m_bDirty = sal_uInt8(true);
279 m_nMaster = n;
280 }
281}
282
284
286{
287 memset( m_nName, 0, sizeof( m_nName ) );
288 m_nNameLen = 0;
289 m_cType = 0;
290 m_cFlags = 0;
291 m_nLeft = 0;
292 m_nRight = 0;
293 m_nChild = 0;
294 memset( &m_aClsId, 0, sizeof( m_aClsId ) );
295 m_nFlags = 0;
296 m_nMtime[0] = 0; m_nMtime[1] = 0;
297 m_nAtime[0] = 0; m_nAtime[1] = 0;
298 m_nPage1 = 0;
299 m_nSize = 0;
300 m_nUnknown = 0;
301
306}
307
308static OUString ToUpperUnicode( const OUString & rStr )
309{
310 // I don't know the locale, so en_US is hopefully fine
311 static CharClass aCC( LanguageTag( css::lang::Locale( "en", "US", "" )) );
312 return aCC.uppercase( rStr );
313}
314
315void StgEntry::SetName( const OUString& rName )
316{
317 // I don't know the locale, so en_US is hopefully fine
318 m_aName = ToUpperUnicode( rName );
319 if(m_aName.getLength() > nMaxLegalStr)
320 {
321 m_aName = m_aName.copy(0, nMaxLegalStr);
322 }
323
324 sal_Int32 i;
325 for( i = 0; i < rName.getLength() && i <= nMaxLegalStr; i++ )
326 {
327 m_nName[ i ] = rName[ i ];
328 }
329 while (i <= nMaxLegalStr)
330 {
331 m_nName[ i++ ] = 0;
332 }
333 m_nNameLen = ( rName.getLength() + 1 ) << 1;
334}
335
336sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const
337{
338 sal_Int32 n = -1;
339 switch( eRef )
340 {
341 case STG_LEFT: n = m_nLeft; break;
342 case STG_RIGHT: n = m_nRight; break;
343 case STG_CHILD: n = m_nChild; break;
344 case STG_DATA: n = m_nPage1; break;
345 }
346 return n;
347}
348
349void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage )
350{
351 switch( eRef )
352 {
353 case STG_LEFT: m_nLeft = nPage; break;
354 case STG_RIGHT: m_nRight = nPage; break;
355 case STG_CHILD: m_nChild = nPage; break;
356 case STG_DATA: m_nPage1 = nPage; break;
357 }
358}
359
361{
362 memcpy( &m_aClsId, &r, sizeof( ClsId ) );
363}
364
365void StgEntry::GetName( OUString& rName ) const
366{
367 sal_uInt16 n = m_nNameLen;
368 if( n )
369 n = ( n >> 1 ) - 1;
370 rName = OUString(m_nName, n);
371}
372
373// Compare two entries. Do this case-insensitive.
374
375sal_Int32 StgEntry::Compare( const StgEntry& r ) const
376{
377 if (r.m_nNameLen != m_nNameLen)
378 return r.m_nNameLen > m_nNameLen ? 1 : -1;
379 else
380 return r.m_aName.compareTo(m_aName);
381}
382
383// These load/store operations are a bit more complicated,
384// since they have to copy their contents into a packed structure.
385
386bool StgEntry::Load(const void* pFrom, sal_uInt32 nBufSize, sal_uInt64 nUnderlyingStreamSize)
387{
388 if ( nBufSize < 128 )
389 return false;
390
391 SvMemoryStream r( const_cast<void *>(pFrom), nBufSize, StreamMode::READ );
392 for(sal_Unicode & i : m_nName)
393 r.ReadUtf16( i ); // 00 name as WCHAR
394 r.ReadUInt16( m_nNameLen ) // 40 size of name in bytes including 00H
395 .ReadUChar( m_cType ) // 42 entry type
396 .ReadUChar( m_cFlags ) // 43 0 or 1 (tree balance?)
397 .ReadInt32( m_nLeft ) // 44 left node entry
398 .ReadInt32( m_nRight ) // 48 right node entry
399 .ReadInt32( m_nChild ); // 4C 1st child entry if storage
400 ReadClsId( r, m_aClsId ); // 50 class ID (optional)
401 r.ReadInt32( m_nFlags ) // 60 state flags(?)
402 .ReadInt32( m_nMtime[ 0 ] ) // 64 modification time
403 .ReadInt32( m_nMtime[ 1 ] ) // 64 modification time
404 .ReadInt32( m_nAtime[ 0 ] ) // 6C creation and access time
405 .ReadInt32( m_nAtime[ 1 ] ) // 6C creation and access time
406 .ReadInt32( m_nPage1 ) // 74 starting block (either direct or translated)
407 .ReadInt32( m_nSize ) // 78 file size
408 .ReadInt32( m_nUnknown ); // 7C unknown
409
410 sal_uInt16 n = m_nNameLen;
411 if( n )
412 n = ( n >> 1 ) - 1;
413
414 if (n > nMaxLegalStr)
415 return false;
416
417 if (m_cType != STG_STORAGE)
418 {
419 if (m_nPage1 < 0 && !isKnownSpecial(m_nPage1))
420 {
421 //bad pageid
422 return false;
423 }
424 if (m_cType == STG_EMPTY)
425 {
426 /*
427 tdf#112399 opens fine in MSOffice 2013 despite a massive m_nSize field
428
429 Free (unused) directory entries are marked with Object Type 0x0
430 (unknown or unallocated). The entire directory entry must consist of
431 all zeroes except for the child, right sibling, and left sibling
432 pointers, which must be initialized to NOSTREAM (0xFFFFFFFF).
433 */
434 m_nSize = 0;
435 }
436 if (m_nSize < 0)
437 {
438 // the size makes no sense for the substorage
439 // TODO/LATER: actually the size should be an unsigned value, but
440 // in this case it would mean a stream of more than 2Gb
441 return false;
442 }
443 if (o3tl::make_unsigned(m_nSize) > nUnderlyingStreamSize)
444 {
445 // surely an entry cannot be larger than the underlying file
446 return false;
447 }
448
449 }
450
451 m_aName = OUString(m_nName , n);
452 // I don't know the locale, so en_US is hopefully fine
454 if(m_aName.getLength() > nMaxLegalStr)
455 {
456 m_aName = m_aName.copy(0, nMaxLegalStr);
457 }
458
459 return true;
460}
461
462void StgEntry::Store( void* pTo )
463{
464 SvMemoryStream r( pTo, 128, StreamMode::WRITE );
465 for(sal_Unicode i : m_nName)
466 r.WriteUInt16( i ); // 00 name as WCHAR
467 r.WriteUInt16( m_nNameLen ) // 40 size of name in bytes including 00H
468 .WriteUChar( m_cType ) // 42 entry type
469 .WriteUChar( m_cFlags ) // 43 0 or 1 (tree balance?)
470 .WriteInt32( m_nLeft ) // 44 left node entry
471 .WriteInt32( m_nRight ) // 48 right node entry
472 .WriteInt32( m_nChild ); // 4C 1st child entry if storage;
473 WriteClsId( r, m_aClsId ); // 50 class ID (optional)
474 r.WriteInt32( m_nFlags ) // 60 state flags(?)
475 .WriteInt32( m_nMtime[ 0 ] ) // 64 modification time
476 .WriteInt32( m_nMtime[ 1 ] ) // 64 modification time
477 .WriteInt32( m_nAtime[ 0 ] ) // 6C creation and access time
478 .WriteInt32( m_nAtime[ 1 ] ) // 6C creation and access time
479 .WriteInt32( m_nPage1 ) // 74 starting block (either direct or translated)
480 .WriteInt32( m_nSize ) // 78 file size
481 .WriteInt32( m_nUnknown ); // 7C unknown
482}
483
484/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
SvStream * GetStrm()
Definition: stgcache.hxx:70
bool Good() const
Definition: stgcache.hxx:73
sal_Int32 Compare(const StgEntry &) const
Definition: stgelem.cxx:375
OUString m_aName
Definition: stgelem.hxx:118
sal_uInt16 m_nNameLen
Definition: stgelem.hxx:105
void Store(void *)
Definition: stgelem.cxx:462
sal_Int32 m_nAtime[2]
Definition: stgelem.hxx:114
void SetLeaf(StgEntryRef, sal_Int32)
Definition: stgelem.cxx:349
void GetName(OUString &rName) const
Definition: stgelem.cxx:365
sal_Int32 m_nSize
Definition: stgelem.hxx:116
sal_Unicode m_nName[32]
Definition: stgelem.hxx:104
sal_Int32 GetLeaf(StgEntryRef) const
Definition: stgelem.cxx:336
ClsId m_aClsId
Definition: stgelem.hxx:111
void SetName(const OUString &)
Definition: stgelem.cxx:315
sal_uInt8 m_cFlags
Definition: stgelem.hxx:107
sal_uInt8 m_cType
Definition: stgelem.hxx:106
void SetClassId(const ClsId &)
Definition: stgelem.cxx:360
sal_Int32 m_nFlags
Definition: stgelem.hxx:112
void Init()
Definition: stgelem.cxx:285
sal_Int32 m_nUnknown
Definition: stgelem.hxx:117
sal_Int32 m_nRight
Definition: stgelem.hxx:109
bool Load(const void *pBuffer, sal_uInt32 nBufSize, sal_uInt64 nUnderlyingStreamSize)
Definition: stgelem.cxx:386
sal_Int32 m_nMtime[2]
Definition: stgelem.hxx:113
sal_Int32 m_nPage1
Definition: stgelem.hxx:115
sal_Int32 m_nLeft
Definition: stgelem.hxx:108
sal_Int32 m_nChild
Definition: stgelem.hxx:110
sal_Int16 m_nDataPageSize
Definition: stgelem.hxx:43
void SetTOCStart(sal_Int32 n)
Definition: stgelem.cxx:229
sal_uInt8 m_cReserved[9]
Definition: stgelem.hxx:47
static const sal_uInt8 cFATPagesInHeader
Definition: stgelem.hxx:36
sal_Int32 m_nTOCstrm
Definition: stgelem.hxx:49
sal_Int16 m_nPageSize
Definition: stgelem.hxx:42
sal_Int32 m_nFATSize
Definition: stgelem.hxx:48
void SetDataFATSize(sal_Int32 n)
Definition: stgelem.cxx:247
void SetDataFATStart(sal_Int32 n)
Definition: stgelem.cxx:238
void SetFATPage(short, sal_Int32)
Definition: stgelem.cxx:217
sal_Int32 m_nReserved
Definition: stgelem.hxx:50
sal_Int32 m_nThreshold
Definition: stgelem.hxx:51
StgHeader()
Definition: stgelem.cxx:71
sal_Int32 m_nVersion
Definition: stgelem.hxx:40
sal_Int32 m_nMasterChain
Definition: stgelem.hxx:54
bool Check()
Definition: stgelem.cxx:194
void SetMasters(sal_Int32 n)
Definition: stgelem.cxx:274
sal_Int32 GetFATPage(short) const
Definition: stgelem.cxx:209
bool Load(StgIo &)
Definition: stgelem.cxx:112
sal_uInt8 m_bDirty
Definition: stgelem.hxx:44
sal_uInt8 m_cSignature[8]
Definition: stgelem.hxx:38
sal_Int32 m_nMasterFAT[cFATPagesInHeader]
Definition: stgelem.hxx:56
sal_Int32 m_nDataFAT
Definition: stgelem.hxx:52
sal_Int32 m_nMaster
Definition: stgelem.hxx:55
bool Store(StgIo &)
Definition: stgelem.cxx:152
void SetFATChain(sal_Int32 n)
Definition: stgelem.cxx:265
void Init()
Definition: stgelem.cxx:88
sal_Int32 m_nDataFATSize
Definition: stgelem.hxx:53
sal_uInt16 m_nByteOrder
Definition: stgelem.hxx:41
ClsId m_aClsId
Definition: stgelem.hxx:39
void SetFATSize(sal_Int32 n)
Definition: stgelem.cxx:256
Definition: stgio.hxx:42
SvStream & WriteInt32(sal_Int32 nInt32)
sal_uInt64 Tell() const
bool good() const
SvStream & ReadInt16(sal_Int16 &rInt16)
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & WriteInt16(sal_Int16 nInt16)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
SvStream & ReadUtf16(sal_Unicode &rUtf16)
sal_uInt64 Seek(sal_uInt64 nPos)
SvStream & ReadInt32(sal_Int32 &rInt32)
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
SvStream & ReadUChar(unsigned char &rChar)
sal_Int32 m_nThreshold
sal_Int64 n
sal_uInt16 m_nPageSize
int i
int shift
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
static bool lcl_wontoverflow(short shift)
Definition: stgelem.cxx:180
static bool isKnownSpecial(sal_Int32 nLocation)
Definition: stgelem.cxx:185
SvStream & ReadClsId(SvStream &r, ClsId &rId)
Definition: stgelem.cxx:37
const sal_uInt16 nMaxLegalStr
Definition: stgelem.cxx:31
const sal_uInt8 cStgSignature[8]
Definition: stgelem.cxx:33
SvStream & WriteClsId(SvStream &r, const ClsId &rId)
Definition: stgelem.cxx:53
static OUString ToUpperUnicode(const OUString &rStr)
Definition: stgelem.cxx:308
#define STG_FREE
Definition: stgelem.hxx:139
@ STG_STORAGE
Definition: stgelem.hxx:87
@ STG_EMPTY
Definition: stgelem.hxx:86
StgEntryRef
Definition: stgelem.hxx:92
@ STG_RIGHT
Definition: stgelem.hxx:94
@ STG_DATA
Definition: stgelem.hxx:96
@ STG_CHILD
Definition: stgelem.hxx:95
@ STG_LEFT
Definition: stgelem.hxx:93
#define STG_MASTER
Definition: stgelem.hxx:142
#define STG_FAT
Definition: stgelem.hxx:141
#define STG_EOF
Definition: stgelem.hxx:140
TOOLS_DLLPUBLIC bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
sal_uInt8 Data4[8]
sal_uInt16 Data3
sal_uInt16 Data2
sal_uInt32 Data1
unsigned char sal_uInt8
sal_uInt16 sal_Unicode