Line data Source code
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 : #include "oox/ole/axbinaryreader.hxx"
21 :
22 : #include "oox/ole/olehelper.hxx"
23 :
24 : namespace oox {
25 : namespace ole {
26 :
27 : // ============================================================================
28 :
29 : using ::rtl::OUString;
30 :
31 : // ============================================================================
32 :
33 : namespace {
34 :
35 : const sal_uInt32 AX_STRING_SIZEMASK = 0x7FFFFFFF;
36 : const sal_uInt32 AX_STRING_COMPRESSED = 0x80000000;
37 :
38 : } // namespace
39 :
40 : // ============================================================================
41 :
42 8 : AxAlignedInputStream::AxAlignedInputStream( BinaryInputStream& rInStrm ) :
43 : BinaryStreamBase( false ),
44 : mpInStrm( &rInStrm ),
45 : mnStrmPos( 0 ),
46 8 : mnStrmSize( rInStrm.getRemaining() )
47 : {
48 8 : mbEof = mbEof || rInStrm.isEof();
49 8 : }
50 :
51 0 : sal_Int64 AxAlignedInputStream::size() const
52 : {
53 0 : return mpInStrm ? mnStrmSize : -1;
54 : }
55 :
56 15 : sal_Int64 AxAlignedInputStream::tell() const
57 : {
58 15 : return mpInStrm ? mnStrmPos : -1;
59 : }
60 :
61 15 : void AxAlignedInputStream::seek( sal_Int64 nPos )
62 : {
63 15 : mbEof = mbEof || (nPos < mnStrmPos);
64 15 : if( !mbEof )
65 15 : skip( static_cast< sal_Int32 >( nPos - mnStrmPos ) );
66 15 : }
67 :
68 0 : void AxAlignedInputStream::close()
69 : {
70 0 : mpInStrm = 0;
71 0 : mbEof = true;
72 0 : }
73 :
74 0 : sal_Int32 AxAlignedInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
75 : {
76 0 : sal_Int32 nReadSize = 0;
77 0 : if( !mbEof )
78 : {
79 0 : nReadSize = mpInStrm->readData( orData, nBytes, nAtomSize );
80 0 : mnStrmPos += nReadSize;
81 0 : mbEof = mpInStrm->isEof();
82 : }
83 0 : return nReadSize;
84 : }
85 :
86 60 : sal_Int32 AxAlignedInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
87 : {
88 60 : sal_Int32 nReadSize = 0;
89 60 : if( !mbEof )
90 : {
91 60 : nReadSize = mpInStrm->readMemory( opMem, nBytes, nAtomSize );
92 60 : mnStrmPos += nReadSize;
93 60 : mbEof = mpInStrm->isEof();
94 : }
95 60 : return nReadSize;
96 : }
97 :
98 85 : void AxAlignedInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
99 : {
100 85 : if( !mbEof )
101 : {
102 85 : mpInStrm->skip( nBytes, nAtomSize );
103 85 : mnStrmPos += nBytes;
104 85 : mbEof = mpInStrm->isEof();
105 : }
106 85 : }
107 :
108 56 : void AxAlignedInputStream::align( size_t nSize )
109 : {
110 56 : skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
111 56 : }
112 :
113 : // ============================================================================
114 :
115 : namespace {
116 :
117 7 : bool lclReadString( AxAlignedInputStream& rInStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString )
118 : {
119 7 : bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED );
120 7 : sal_uInt32 nBufSize = nSize & AX_STRING_SIZEMASK;
121 : // Unicode: simple strings store byte count, array strings store char count
122 7 : sal_Int32 nChars = static_cast< sal_Int32 >( nBufSize / ((bCompressed || bArrayString) ? 1 : 2) );
123 7 : bool bValidChars = nChars <= 65536;
124 : OSL_ENSURE( bValidChars, "lclReadString - string too long" );
125 7 : sal_Int64 nEndPos = rInStrm.tell() + nChars * (bCompressed ? 1 : 2);
126 7 : nChars = ::std::min< sal_Int32 >( nChars, 65536 );
127 7 : rValue = rInStrm.readCompressedUnicodeArray( nChars, bCompressed );
128 7 : rInStrm.seek( nEndPos );
129 7 : return bValidChars;
130 : }
131 :
132 : } // namespace
133 :
134 : // ----------------------------------------------------------------------------
135 :
136 11 : AxBinaryPropertyReader::ComplexProperty::~ComplexProperty()
137 : {
138 11 : }
139 :
140 4 : bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm )
141 : {
142 4 : rInStrm >> mrPairData.first >> mrPairData.second;
143 4 : return true;
144 : }
145 :
146 7 : bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm )
147 : {
148 7 : return lclReadString( rInStrm, mrValue, mnSize, false );
149 : }
150 :
151 0 : bool AxBinaryPropertyReader::StringArrayProperty::readProperty( AxAlignedInputStream& rInStrm )
152 : {
153 0 : sal_Int64 nEndPos = rInStrm.tell() + mnSize;
154 0 : while( rInStrm.tell() < nEndPos )
155 : {
156 0 : OUString aString;
157 0 : if( !lclReadString( rInStrm, aString, rInStrm.readuInt32(), true ) )
158 0 : return false;
159 0 : mrArray.push_back( aString );
160 : // every array string is aligned on 4 byte boundries
161 0 : rInStrm.align( 4 );
162 0 : }
163 0 : return true;
164 : }
165 :
166 0 : bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm )
167 : {
168 0 : mrGuid = OleHelper::importGuid( rInStrm );
169 0 : return true;
170 : }
171 :
172 0 : bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm )
173 : {
174 0 : return mrFontData.importGuidAndFont( rInStrm );
175 : }
176 :
177 0 : bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm )
178 : {
179 0 : return OleHelper::importStdPic( mrPicData, rInStrm, true );
180 : }
181 :
182 : // ----------------------------------------------------------------------------
183 :
184 8 : AxBinaryPropertyReader::AxBinaryPropertyReader( BinaryInputStream& rInStrm, bool b64BitPropFlags ) :
185 : maInStrm( rInStrm ),
186 8 : mbValid( true )
187 : {
188 : // version and size of property block
189 8 : maInStrm.skip( 2 );
190 8 : sal_uInt16 nBlockSize = maInStrm.readValue< sal_uInt16 >();
191 8 : mnPropsEnd = maInStrm.tell() + nBlockSize;
192 : // flagfield containing existing properties
193 8 : if( b64BitPropFlags )
194 1 : maInStrm >> mnPropFlags;
195 : else
196 7 : mnPropFlags = maInStrm.readuInt32();
197 8 : mnNextProp = 1;
198 8 : }
199 :
200 3 : void AxBinaryPropertyReader::readBoolProperty( bool& orbValue, bool bReverse )
201 : {
202 : // there is no data, the boolean value is equivalent to the property flag itself
203 3 : orbValue = startNextProperty() != bReverse;
204 3 : }
205 :
206 4 : void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData )
207 : {
208 4 : if( startNextProperty() )
209 4 : maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
210 4 : }
211 :
212 10 : void AxBinaryPropertyReader::readStringProperty( OUString& orValue )
213 : {
214 10 : if( startNextProperty() )
215 : {
216 7 : sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >();
217 7 : maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) );
218 : }
219 10 : }
220 :
221 0 : void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid )
222 : {
223 0 : if( startNextProperty() )
224 0 : maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) );
225 0 : }
226 :
227 0 : void AxBinaryPropertyReader::readFontProperty( AxFontData& orFontData )
228 : {
229 0 : if( startNextProperty() )
230 : {
231 0 : sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
232 0 : if( ensureValid( nData == -1 ) )
233 0 : maStreamProps.push_back( ComplexPropVector::value_type( new FontProperty( orFontData ) ) );
234 : }
235 0 : }
236 :
237 8 : void AxBinaryPropertyReader::readPictureProperty( StreamDataSequence& orPicData )
238 : {
239 8 : if( startNextProperty() )
240 : {
241 0 : sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
242 0 : if( ensureValid( nData == -1 ) )
243 0 : maStreamProps.push_back( ComplexPropVector::value_type( new PictureProperty( orPicData ) ) );
244 : }
245 8 : }
246 :
247 8 : bool AxBinaryPropertyReader::finalizeImport()
248 : {
249 : // read large properties
250 8 : maInStrm.align( 4 );
251 8 : if( ensureValid( mnPropFlags == 0 ) && !maLargeProps.empty() )
252 : {
253 16 : for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
254 : {
255 11 : ensureValid( (*aIt)->readProperty( maInStrm ) );
256 11 : maInStrm.align( 4 );
257 : }
258 : }
259 8 : maInStrm.seek( mnPropsEnd );
260 :
261 : // read stream properties (no stream alignment between properties!)
262 8 : if( ensureValid() && !maStreamProps.empty() )
263 0 : for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
264 0 : ensureValid( (*aIt)->readProperty( maInStrm ) );
265 :
266 8 : return mbValid;
267 : }
268 :
269 143 : bool AxBinaryPropertyReader::ensureValid( bool bCondition )
270 : {
271 143 : mbValid = mbValid && bCondition && !maInStrm.isEof();
272 143 : return mbValid;
273 : }
274 :
275 98 : bool AxBinaryPropertyReader::startNextProperty()
276 : {
277 98 : bool bHasProp = getFlag( mnPropFlags, mnNextProp );
278 98 : setFlag( mnPropFlags, mnNextProp, false );
279 98 : mnNextProp <<= 1;
280 98 : return ensureValid() && bHasProp;
281 : }
282 :
283 : // ============================================================================
284 :
285 : } // namespace ole
286 51 : } // namespace oox
287 :
288 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|