/src/libreoffice/sot/source/sdstor/stgelem.cxx
Line | Count | Source |
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> |
26 | | #include <unotools/charclass.hxx> |
27 | | #include <sot/stg.hxx> |
28 | | #include "stgelem.hxx" |
29 | | #include "stgio.hxx" |
30 | | |
31 | | const sal_uInt16 nMaxLegalStr = 31; |
32 | | |
33 | | const sal_uInt8 cStgSignature[ 8 ] = { 0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1 }; |
34 | | |
35 | | ////////////////////////////// struct ClsId |
36 | | |
37 | | SvStream& ReadClsId( SvStream& r, ClsId& rId ) |
38 | 2.74M | { |
39 | 2.74M | r.ReadUInt32( rId.Data1 ) |
40 | 2.74M | .ReadUInt16( rId.Data2 ) |
41 | 2.74M | .ReadUInt16( rId.Data3 ) |
42 | 2.74M | .ReadUChar( rId.Data4[0] ) |
43 | 2.74M | .ReadUChar( rId.Data4[1] ) |
44 | 2.74M | .ReadUChar( rId.Data4[2] ) |
45 | 2.74M | .ReadUChar( rId.Data4[3] ) |
46 | 2.74M | .ReadUChar( rId.Data4[4] ) |
47 | 2.74M | .ReadUChar( rId.Data4[5] ) |
48 | 2.74M | .ReadUChar( rId.Data4[6] ) |
49 | 2.74M | .ReadUChar( rId.Data4[7] ); |
50 | 2.74M | return r; |
51 | 2.74M | } |
52 | | |
53 | | SvStream& WriteClsId( SvStream& r, const ClsId& rId ) |
54 | 1.83M | { |
55 | 1.83M | return |
56 | 1.83M | r .WriteUInt32( rId.Data1 ) |
57 | 1.83M | .WriteUInt16( rId.Data2 ) |
58 | 1.83M | .WriteUInt16( rId.Data3 ) |
59 | 1.83M | .WriteUChar( rId.Data4[0] ) |
60 | 1.83M | .WriteUChar( rId.Data4[1] ) |
61 | 1.83M | .WriteUChar( rId.Data4[2] ) |
62 | 1.83M | .WriteUChar( rId.Data4[3] ) |
63 | 1.83M | .WriteUChar( rId.Data4[4] ) |
64 | 1.83M | .WriteUChar( rId.Data4[5] ) |
65 | 1.83M | .WriteUChar( rId.Data4[6] ) |
66 | 1.83M | .WriteUChar( rId.Data4[7] ); |
67 | 1.83M | } |
68 | | |
69 | | ///////////////////////////// class StgHeader |
70 | | |
71 | | StgHeader::StgHeader() |
72 | 220k | : m_nVersion( 0 ) |
73 | 220k | , m_nByteOrder( 0 ) |
74 | 220k | , m_nPageSize( 0 ) |
75 | 220k | , m_nDataPageSize( 0 ) |
76 | 220k | , m_bDirty( sal_uInt8(false) ) |
77 | 220k | , m_nFATSize( 0 ) |
78 | 220k | , m_nTOCstrm( 0 ) |
79 | 220k | , m_nReserved( 0 ) |
80 | 220k | , m_nThreshold( 0 ) |
81 | 220k | , m_nDataFAT( 0 ) |
82 | 220k | , m_nDataFATSize( 0 ) |
83 | 220k | , m_nMasterChain( 0 ) |
84 | 220k | , m_nMaster( 0 ) |
85 | 220k | { |
86 | 220k | } |
87 | | |
88 | | void StgHeader::Init() |
89 | 78.8k | { |
90 | 78.8k | memcpy( m_cSignature, cStgSignature, 8 ); |
91 | 78.8k | memset( &m_aClsId, 0, sizeof( ClsId ) ); |
92 | 78.8k | m_nVersion = 0x0003003B; |
93 | 78.8k | m_nByteOrder = 0xFFFE; |
94 | 78.8k | m_nPageSize = 9; // 512 bytes |
95 | 78.8k | m_nDataPageSize = 6; // 64 bytes |
96 | 78.8k | m_bDirty = sal_uInt8(false); |
97 | 78.8k | memset( m_cReserved, 0, sizeof( m_cReserved ) ); |
98 | 78.8k | m_nFATSize = 0; |
99 | 78.8k | m_nTOCstrm = 0; |
100 | 78.8k | m_nReserved = 0; |
101 | 78.8k | m_nThreshold = 4096; |
102 | 78.8k | m_nDataFAT = 0; |
103 | 78.8k | m_nDataFATSize = 0; |
104 | 78.8k | m_nMasterChain = STG_EOF; |
105 | | |
106 | 78.8k | SetTOCStart( STG_EOF ); |
107 | 78.8k | SetDataFATStart( STG_EOF ); |
108 | 8.67M | for( short i = 0; i < cFATPagesInHeader; i++ ) |
109 | 8.59M | SetFATPage( i, STG_FREE ); |
110 | 78.8k | } |
111 | | |
112 | | bool StgHeader::Load( StgIo& rIo ) |
113 | 127k | { |
114 | 127k | bool bResult = false; |
115 | 127k | if ( rIo.GetStrm() ) |
116 | 127k | { |
117 | 127k | SvStream& r = *rIo.GetStrm(); |
118 | 127k | bResult = Load( r ); |
119 | 127k | bResult = ( bResult && rIo.Good() ); |
120 | 127k | } |
121 | | |
122 | 127k | return bResult; |
123 | 127k | } |
124 | | |
125 | | bool StgHeader::Load( SvStream& r ) |
126 | 141k | { |
127 | 141k | r.Seek( 0 ); |
128 | 141k | r.ReadBytes( m_cSignature, 8 ); |
129 | 141k | ReadClsId( r, m_aClsId ); // 08 Class ID |
130 | 141k | r.ReadInt32( m_nVersion ) // 1A version number |
131 | 141k | .ReadUInt16( m_nByteOrder ) // 1C Unicode byte order indicator |
132 | 141k | .ReadInt16( m_nPageSize ) // 1E 1 << nPageSize = block size |
133 | 141k | .ReadInt16( m_nDataPageSize ); // 20 1 << this size == data block size |
134 | 141k | if (!r.good()) |
135 | 1.75k | return false; |
136 | 139k | if (!checkSeek(r, r.Tell() + 10)) |
137 | 233 | return false; |
138 | 139k | r.ReadInt32( m_nFATSize ) // 2C total number of FAT pages |
139 | 139k | .ReadInt32( m_nTOCstrm ) // 30 starting page for the TOC stream |
140 | 139k | .ReadInt32( m_nReserved ) // 34 |
141 | 139k | .ReadInt32( m_nThreshold ) // 38 minimum file size for big data |
142 | 139k | .ReadInt32( m_nDataFAT ) // 3C page # of 1st data FAT block |
143 | 139k | .ReadInt32( m_nDataFATSize ) // 40 # of data FATpages |
144 | 139k | .ReadInt32( m_nMasterChain ) // 44 chain to the next master block |
145 | 139k | .ReadInt32( m_nMaster ); // 48 # of additional master blocks |
146 | 139k | for(sal_Int32 & i : m_nMasterFAT) |
147 | 15.2M | r.ReadInt32( i ); |
148 | | |
149 | 139k | return r.good() && Check(); |
150 | 139k | } |
151 | | |
152 | | bool StgHeader::Store( StgIo& rIo ) |
153 | 155k | { |
154 | 155k | if( !m_bDirty ) |
155 | 0 | return true; |
156 | | |
157 | 155k | SvStream& r = *rIo.GetStrm(); |
158 | 155k | r.Seek( 0 ); |
159 | 155k | r.WriteBytes( m_cSignature, 8 ); |
160 | 155k | WriteClsId( r, m_aClsId ); // 08 Class ID |
161 | 155k | r.WriteInt32( m_nVersion ) // 1A version number |
162 | 155k | .WriteUInt16( m_nByteOrder ) // 1C Unicode byte order indicator |
163 | 155k | .WriteInt16( m_nPageSize ) // 1E 1 << nPageSize = block size |
164 | 155k | .WriteInt16( m_nDataPageSize ) // 20 1 << this size == data block size |
165 | 155k | .WriteInt32( 0 ).WriteInt32( 0 ).WriteInt16( 0 ) |
166 | 155k | .WriteInt32( m_nFATSize ) // 2C total number of FAT pages |
167 | 155k | .WriteInt32( m_nTOCstrm ) // 30 starting page for the TOC stream |
168 | 155k | .WriteInt32( m_nReserved ) // 34 |
169 | 155k | .WriteInt32( m_nThreshold ) // 38 minimum file size for big data |
170 | 155k | .WriteInt32( m_nDataFAT ) // 3C page # of 1st data FAT block |
171 | 155k | .WriteInt32( m_nDataFATSize ) // 40 # of data FAT pages |
172 | 155k | .WriteInt32( m_nMasterChain ) // 44 chain to the next master block |
173 | 155k | .WriteInt32( m_nMaster ); // 48 # of additional master blocks |
174 | 155k | for(sal_Int32 i : m_nMasterFAT) |
175 | 16.9M | r.WriteInt32( i ); |
176 | 155k | m_bDirty = sal_uInt8(!rIo.Good()); |
177 | 155k | return !m_bDirty; |
178 | 155k | } |
179 | | |
180 | | static bool lcl_wontoverflow(short shift) |
181 | 503k | { |
182 | 503k | return shift >= 0 && shift < short(sizeof(short)) * 8 - 1; |
183 | 503k | } |
184 | | |
185 | | static bool isKnownSpecial(sal_Int32 nLocation) |
186 | 1.14M | { |
187 | 1.14M | return (nLocation == STG_FREE || |
188 | 1.11M | nLocation == STG_EOF || |
189 | 199k | nLocation == STG_FAT || |
190 | 188k | nLocation == STG_MASTER); |
191 | 1.14M | } |
192 | | |
193 | | // Perform thorough checks also on unknown variables |
194 | | bool StgHeader::Check() |
195 | 259k | { |
196 | 259k | return memcmp( m_cSignature, cStgSignature, 8 ) == 0 |
197 | 251k | && static_cast<short>( m_nVersion >> 16 ) == 3 |
198 | 251k | && m_nPageSize == 9 |
199 | 251k | && lcl_wontoverflow(m_nPageSize) |
200 | 251k | && lcl_wontoverflow(m_nDataPageSize) |
201 | 251k | && m_nFATSize > 0 |
202 | 251k | && m_nTOCstrm >= 0 |
203 | 251k | && m_nThreshold > 0 |
204 | 251k | && ( isKnownSpecial(m_nDataFAT) || ( m_nDataFAT >= 0 && m_nDataFATSize > 0 ) ) |
205 | 251k | && ( isKnownSpecial(m_nMasterChain) || m_nMasterChain >=0 ) |
206 | 250k | && m_nMaster >= 0; |
207 | 259k | } |
208 | | |
209 | | sal_Int32 StgHeader::GetFATPage( short n ) const |
210 | 11.4M | { |
211 | 11.4M | if( n >= 0 && n < cFATPagesInHeader ) |
212 | 11.4M | return m_nMasterFAT[ n ]; |
213 | 0 | else |
214 | 0 | return STG_EOF; |
215 | 11.4M | } |
216 | | |
217 | | void StgHeader::SetFATPage( short n, sal_Int32 nb ) |
218 | 8.69M | { |
219 | 8.69M | if( n >= 0 && n < cFATPagesInHeader ) |
220 | 8.69M | { |
221 | 8.69M | if( m_nMasterFAT[ n ] != nb ) |
222 | 8.69M | { |
223 | 8.69M | m_bDirty = sal_uInt8(true); |
224 | 8.69M | m_nMasterFAT[ n ] = nb; |
225 | 8.69M | } |
226 | 8.69M | } |
227 | 8.69M | } |
228 | | |
229 | | void StgHeader::SetTOCStart( sal_Int32 n ) |
230 | 390k | { |
231 | 390k | if( n != m_nTOCstrm ) |
232 | 234k | { |
233 | 234k | m_bDirty = sal_uInt8(true); |
234 | 234k | m_nTOCstrm = n; |
235 | 234k | } |
236 | 390k | } |
237 | | |
238 | | void StgHeader::SetDataFATStart( sal_Int32 n ) |
239 | 234k | { |
240 | 234k | if( n != m_nDataFAT ) |
241 | 119k | { |
242 | 119k | m_bDirty = sal_uInt8(true); |
243 | 119k | m_nDataFAT = n; |
244 | 119k | } |
245 | 234k | } |
246 | | |
247 | | void StgHeader::SetDataFATSize( sal_Int32 n ) |
248 | 155k | { |
249 | 155k | if( n != m_nDataFATSize ) |
250 | 40.1k | { |
251 | 40.1k | m_bDirty = sal_uInt8(true); |
252 | 40.1k | m_nDataFATSize = n; |
253 | 40.1k | } |
254 | 155k | } |
255 | | |
256 | | void StgHeader::SetFATSize( sal_Int32 n ) |
257 | 91.2k | { |
258 | 91.2k | if( n != m_nFATSize ) |
259 | 91.2k | { |
260 | 91.2k | m_bDirty = sal_uInt8(true); |
261 | 91.2k | m_nFATSize = n; |
262 | 91.2k | } |
263 | 91.2k | } |
264 | | |
265 | | void StgHeader::SetFATChain( sal_Int32 n ) |
266 | 8 | { |
267 | 8 | if( n != m_nMasterChain ) |
268 | 8 | { |
269 | 8 | m_bDirty = sal_uInt8(true); |
270 | 8 | m_nMasterChain = n; |
271 | 8 | } |
272 | 8 | } |
273 | | |
274 | | void StgHeader::SetMasters( sal_Int32 n ) |
275 | 8 | { |
276 | 8 | if( n != m_nMaster ) |
277 | 8 | { |
278 | 8 | m_bDirty = sal_uInt8(true); |
279 | 8 | m_nMaster = n; |
280 | 8 | } |
281 | 8 | } |
282 | | |
283 | | ///////////////////////////// class StgEntry |
284 | | |
285 | | void StgEntry::Init() |
286 | 7.57M | { |
287 | 7.57M | memset( m_nName, 0, sizeof( m_nName ) ); |
288 | 7.57M | m_nNameLen = 0; |
289 | 7.57M | m_cType = 0; |
290 | 7.57M | m_cFlags = 0; |
291 | 7.57M | m_nLeft = 0; |
292 | 7.57M | m_nRight = 0; |
293 | 7.57M | m_nChild = 0; |
294 | 7.57M | memset( &m_aClsId, 0, sizeof( m_aClsId ) ); |
295 | 7.57M | m_nFlags = 0; |
296 | 7.57M | m_nMtime[0] = 0; m_nMtime[1] = 0; |
297 | 7.57M | m_nAtime[0] = 0; m_nAtime[1] = 0; |
298 | 7.57M | m_nPage1 = 0; |
299 | 7.57M | m_nSize = 0; |
300 | 7.57M | m_nUnknown = 0; |
301 | | |
302 | 7.57M | SetLeaf( STG_LEFT, STG_FREE ); |
303 | 7.57M | SetLeaf( STG_RIGHT, STG_FREE ); |
304 | 7.57M | SetLeaf( STG_CHILD, STG_FREE ); |
305 | 7.57M | SetLeaf( STG_DATA, STG_EOF ); |
306 | 7.57M | } |
307 | | |
308 | | static OUString ToUpperUnicode( const OUString & rStr ) |
309 | 10.0M | { |
310 | | // I don't know the locale, so en_US is hopefully fine |
311 | 10.0M | static CharClass aCC( LanguageTag( css::lang::Locale( u"en"_ustr, u"US"_ustr, u""_ustr )) ); |
312 | 10.0M | return aCC.uppercase( rStr ); |
313 | 10.0M | } |
314 | | |
315 | | void StgEntry::SetName( const OUString& rName ) |
316 | 7.41M | { |
317 | | // I don't know the locale, so en_US is hopefully fine |
318 | 7.41M | m_aName = ToUpperUnicode( rName ); |
319 | 7.41M | if(m_aName.getLength() > nMaxLegalStr) |
320 | 78.1k | { |
321 | 78.1k | m_aName = m_aName.copy(0, nMaxLegalStr); |
322 | 78.1k | } |
323 | | |
324 | 7.41M | sal_Int32 i; |
325 | 67.9M | for( i = 0; i < rName.getLength() && i <= nMaxLegalStr; i++ ) |
326 | 60.5M | { |
327 | 60.5M | m_nName[ i ] = rName[ i ]; |
328 | 60.5M | } |
329 | 184M | while (i <= nMaxLegalStr) |
330 | 176M | { |
331 | 176M | m_nName[ i++ ] = 0; |
332 | 176M | } |
333 | 7.41M | m_nNameLen = ( rName.getLength() + 1 ) << 1; |
334 | 7.41M | } |
335 | | |
336 | | sal_Int32 StgEntry::GetLeaf( StgEntryRef eRef ) const |
337 | 16.6M | { |
338 | 16.6M | sal_Int32 n = -1; |
339 | 16.6M | switch( eRef ) |
340 | 16.6M | { |
341 | 2.59M | case STG_LEFT: n = m_nLeft; break; |
342 | 2.59M | case STG_RIGHT: n = m_nRight; break; |
343 | 8.74M | case STG_CHILD: n = m_nChild; break; |
344 | 2.72M | case STG_DATA: n = m_nPage1; break; |
345 | 16.6M | } |
346 | 16.6M | return n; |
347 | 16.6M | } |
348 | | |
349 | | void StgEntry::SetLeaf( StgEntryRef eRef, sal_Int32 nPage ) |
350 | 36.3M | { |
351 | 36.3M | switch( eRef ) |
352 | 36.3M | { |
353 | 8.87M | case STG_LEFT: m_nLeft = nPage; break; |
354 | 8.87M | case STG_RIGHT: m_nRight = nPage; break; |
355 | 8.87M | case STG_CHILD: m_nChild = nPage; break; |
356 | 9.67M | case STG_DATA: m_nPage1 = nPage; break; |
357 | 36.3M | } |
358 | 36.3M | } |
359 | | |
360 | | void StgEntry::SetClassId( const ClsId& r ) |
361 | 528k | { |
362 | 528k | memcpy( &m_aClsId, &r, sizeof( ClsId ) ); |
363 | 528k | } |
364 | | |
365 | | void StgEntry::GetName( OUString& rName ) const |
366 | 4.06M | { |
367 | 4.06M | sal_uInt16 n = m_nNameLen; |
368 | 4.06M | if( n ) |
369 | 4.05M | n = ( n >> 1 ) - 1; |
370 | 4.06M | rName = OUString(m_nName, n); |
371 | 4.06M | } |
372 | | |
373 | | // Compare two entries. Do this case-insensitive. |
374 | | |
375 | | sal_Int32 StgEntry::Compare( const StgEntry& r ) const |
376 | 33.4M | { |
377 | 33.4M | if (r.m_nNameLen != m_nNameLen) |
378 | 21.4M | return r.m_nNameLen > m_nNameLen ? 1 : -1; |
379 | 12.0M | else |
380 | 12.0M | return r.m_aName.compareTo(m_aName); |
381 | 33.4M | } |
382 | | |
383 | | // These load/store operations are a bit more complicated, |
384 | | // since they have to copy their contents into a packed structure. |
385 | | |
386 | | bool StgEntry::Load(const void* pFrom, sal_uInt32 nBufSize, sal_uInt64 nUnderlyingStreamSize) |
387 | 2.60M | { |
388 | 2.60M | if ( nBufSize < 128 ) |
389 | 0 | return false; |
390 | | |
391 | 2.60M | SvMemoryStream r( const_cast<void *>(pFrom), nBufSize, StreamMode::READ ); |
392 | 2.60M | for(sal_Unicode & i : m_nName) |
393 | 83.3M | r.ReadUtf16( i ); // 00 name as WCHAR |
394 | 2.60M | r.ReadUInt16( m_nNameLen ) // 40 size of name in bytes including 00H |
395 | 2.60M | .ReadUChar( m_cType ) // 42 entry type |
396 | 2.60M | .ReadUChar( m_cFlags ) // 43 0 or 1 (tree balance?) |
397 | 2.60M | .ReadInt32( m_nLeft ) // 44 left node entry |
398 | 2.60M | .ReadInt32( m_nRight ) // 48 right node entry |
399 | 2.60M | .ReadInt32( m_nChild ); // 4C 1st child entry if storage |
400 | 2.60M | ReadClsId( r, m_aClsId ); // 50 class ID (optional) |
401 | 2.60M | r.ReadInt32( m_nFlags ) // 60 state flags(?) |
402 | 2.60M | .ReadInt32( m_nMtime[ 0 ] ) // 64 modification time |
403 | 2.60M | .ReadInt32( m_nMtime[ 1 ] ) // 64 modification time |
404 | 2.60M | .ReadInt32( m_nAtime[ 0 ] ) // 6C creation and access time |
405 | 2.60M | .ReadInt32( m_nAtime[ 1 ] ) // 6C creation and access time |
406 | 2.60M | .ReadInt32( m_nPage1 ) // 74 starting block (either direct or translated) |
407 | 2.60M | .ReadInt32( m_nSize ) // 78 file size |
408 | 2.60M | .ReadInt32( m_nUnknown ); // 7C unknown |
409 | | |
410 | 2.60M | sal_uInt16 n = m_nNameLen; |
411 | 2.60M | if( n ) |
412 | 2.50M | n = ( n >> 1 ) - 1; |
413 | | |
414 | 2.60M | if (n > nMaxLegalStr) |
415 | 3.17k | return false; |
416 | | |
417 | 2.60M | if (m_cType != STG_STORAGE) |
418 | 1.98M | { |
419 | 1.98M | if (m_nPage1 < 0 && !isKnownSpecial(m_nPage1)) |
420 | 2.23k | { |
421 | | //bad pageid |
422 | 2.23k | return false; |
423 | 2.23k | } |
424 | 1.98M | if (m_cType == STG_EMPTY) |
425 | 284k | { |
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 | 284k | m_nSize = 0; |
435 | 284k | } |
436 | 1.98M | if (m_nSize < 0) |
437 | 1.97k | { |
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 | 1.97k | return false; |
442 | 1.97k | } |
443 | 1.98M | if (o3tl::make_unsigned(m_nSize) > nUnderlyingStreamSize) |
444 | 1.86k | { |
445 | | // surely an entry cannot be larger than the underlying file |
446 | 1.86k | return false; |
447 | 1.86k | } |
448 | | |
449 | 1.98M | } |
450 | | |
451 | 2.59M | m_aName = OUString(m_nName , n); |
452 | | // I don't know the locale, so en_US is hopefully fine |
453 | 2.59M | m_aName = ToUpperUnicode( m_aName ); |
454 | 2.59M | if(m_aName.getLength() > nMaxLegalStr) |
455 | 18.5k | { |
456 | 18.5k | m_aName = m_aName.copy(0, nMaxLegalStr); |
457 | 18.5k | } |
458 | | |
459 | 2.59M | return true; |
460 | 2.60M | } |
461 | | |
462 | | void StgEntry::Store( void* pTo ) |
463 | 1.67M | { |
464 | 1.67M | SvMemoryStream r( pTo, 128, StreamMode::WRITE ); |
465 | 1.67M | for(sal_Unicode i : m_nName) |
466 | 53.7M | r.WriteUInt16( i ); // 00 name as WCHAR |
467 | 1.67M | r.WriteUInt16( m_nNameLen ) // 40 size of name in bytes including 00H |
468 | 1.67M | .WriteUChar( m_cType ) // 42 entry type |
469 | 1.67M | .WriteUChar( m_cFlags ) // 43 0 or 1 (tree balance?) |
470 | 1.67M | .WriteInt32( m_nLeft ) // 44 left node entry |
471 | 1.67M | .WriteInt32( m_nRight ) // 48 right node entry |
472 | 1.67M | .WriteInt32( m_nChild ); // 4C 1st child entry if storage; |
473 | 1.67M | WriteClsId( r, m_aClsId ); // 50 class ID (optional) |
474 | 1.67M | r.WriteInt32( m_nFlags ) // 60 state flags(?) |
475 | 1.67M | .WriteInt32( m_nMtime[ 0 ] ) // 64 modification time |
476 | 1.67M | .WriteInt32( m_nMtime[ 1 ] ) // 64 modification time |
477 | 1.67M | .WriteInt32( m_nAtime[ 0 ] ) // 6C creation and access time |
478 | 1.67M | .WriteInt32( m_nAtime[ 1 ] ) // 6C creation and access time |
479 | 1.67M | .WriteInt32( m_nPage1 ) // 74 starting block (either direct or translated) |
480 | 1.67M | .WriteInt32( m_nSize ) // 78 file size |
481 | 1.67M | .WriteInt32( m_nUnknown ); // 7C unknown |
482 | 1.67M | } |
483 | | |
484 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |