1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "oox/xls/biffhelper.hxx"
25
26 #include <rtl/math.hxx>
27 #include <rtl/tencinfo.h>
28 #include "oox/xls/biffinputstream.hxx"
29 #include "oox/xls/biffoutputstream.hxx"
30 #include "oox/xls/worksheethelper.hxx"
31
32 namespace oox {
33 namespace xls {
34
35 // ============================================================================
36
37 using ::rtl::OUString;
38 using ::rtl::OUStringBuffer;
39
40 // ============================================================================
41
42 namespace {
43
44 const sal_Int32 BIFF_RK_100FLAG = 0x00000001;
45 const sal_Int32 BIFF_RK_INTFLAG = 0x00000002;
46 const sal_Int32 BIFF_RK_VALUEMASK = 0xFFFFFFFC;
47
48 const sal_Int32 BITMAPFILEHEADER_SIZE = 14;
49 const sal_Int32 BITMAPCOREHEADER_SIZE = 12;
50 const sal_Int32 BITMAPINFOHEADER_SIZE = 40;
51
52 const sal_uInt16 BIFF_IMGDATA_WMF = 2;
53 const sal_uInt16 BIFF_IMGDATA_DIB = 9;
54 const sal_uInt16 BIFF_IMGDATA_NATIVE = 14;
55
56 // ----------------------------------------------------------------------------
57
58 union DecodedDouble
59 {
60 double mfValue;
61 sal_math_Double maStruct;
62
DecodedDouble()63 inline explicit DecodedDouble() {}
DecodedDouble(double fValue)64 inline explicit DecodedDouble( double fValue ) : mfValue( fValue ) {}
65 };
66
lclCalcRkFromDouble(sal_Int32 & ornRkValue,const DecodedDouble & rDecDbl)67 bool lclCalcRkFromDouble( sal_Int32& ornRkValue, const DecodedDouble& rDecDbl )
68 {
69 // double
70 if( (rDecDbl.maStruct.w32_parts.lsw == 0) && ((rDecDbl.maStruct.w32_parts.msw & 0x3) == 0) )
71 {
72 ornRkValue = static_cast< sal_Int32 >( rDecDbl.maStruct.w32_parts.msw );
73 return true;
74 }
75
76 // integer
77 double fInt = 0.0;
78 double fFrac = modf( rDecDbl.mfValue, &fInt );
79 if( (fFrac == 0.0) && (-536870912.0 <= fInt) && (fInt <= 536870911.0) ) // 2^29
80 {
81 ornRkValue = static_cast< sal_Int32 >( fInt );
82 ornRkValue <<= 2;
83 ornRkValue |= BIFF_RK_INTFLAG;
84 return true;
85 }
86
87 return false;
88 }
89
lclCalcRkFromDouble(sal_Int32 & ornRkValue,double fValue)90 bool lclCalcRkFromDouble( sal_Int32& ornRkValue, double fValue )
91 {
92 DecodedDouble aDecDbl( fValue );
93 if( lclCalcRkFromDouble( ornRkValue, aDecDbl ) )
94 return true;
95
96 aDecDbl.mfValue *= 100.0;
97 if( lclCalcRkFromDouble( ornRkValue, aDecDbl ) )
98 {
99 ornRkValue |= BIFF_RK_100FLAG;
100 return true;
101 }
102
103 return false;
104 }
105
106 // ----------------------------------------------------------------------------
107
lclImportImgDataDib(StreamDataSequence & orDataSeq,BiffInputStream & rStrm,sal_Int32 nBytes,BiffType eBiff)108 void lclImportImgDataDib( StreamDataSequence& orDataSeq, BiffInputStream& rStrm, sal_Int32 nBytes, BiffType eBiff )
109 {
110 /* The IMGDATA record for bitmap format contains a Windows DIB (a bitmap
111 file without the 'BITMAPFILEHEADER' header structure). Usually, the DIB
112 header consists of 12 bytes (called 'OS/2 V1 header' or
113 'BITMAPCOREHEADER', see http://en.wikipedia.org/wiki/BMP_file_format)
114 followed by the remaining pixel data, but the 'Windows V3' or
115 'BITMAPINFOHEADER' is also supported here. This function creates a
116 complete 'BMP file' that can be read by the OOo graphic provider used
117 to import graphic objects. For that, the BITMAPFILEHEADER has to be
118 inserted before the DIB data, and it has to contain the correct offset
119 to the pixel data. Currently, in real life there are only 24-bit and
120 32-bit DIBs (without color palette) in use. This code relies on this
121 fact and calculates the offset to the pixel data according to the size
122 of the DIB header.
123 Remaining tasks are (if really used somewhere):
124 - Support of DIBs with color palette,
125 - Support of 'Windows V4' and 'Windows V5' DIB header. */
126
127 // read and check validity of DIB header
128 sal_Int64 nInStrmPos = rStrm.tell();
129 sal_Int32 nDibHdrSize = rStrm.readInt32();
130 sal_uInt16 nPlanes = 0, nDepth = 0;
131 switch( nDibHdrSize )
132 {
133 case BITMAPCOREHEADER_SIZE:
134 rStrm.skip( 4 ); // width/height as 16-bit integer
135 rStrm >> nPlanes >> nDepth;
136 break;
137 case BITMAPINFOHEADER_SIZE:
138 rStrm.skip( 8 ); // width/height as 32-bit integer
139 rStrm >> nPlanes >> nDepth;
140 break;
141 }
142 rStrm.seek( nInStrmPos );
143
144 if( (nPlanes == 1) && ((nDepth == 24) || (nDepth == 32)) )
145 {
146 // allocate enough space for the BITMAPFILEHEADER and the DIB data
147 orDataSeq.realloc( BITMAPFILEHEADER_SIZE + nBytes );
148 SequenceOutputStream aOutStrm( orDataSeq );
149
150 // write the BITMAPFILEHEADER of a regular BMP file
151 sal_Int32 nBmpSize = BITMAPFILEHEADER_SIZE + nBytes;
152 sal_Int32 nOffset = BITMAPFILEHEADER_SIZE + nDibHdrSize;
153 aOutStrm << sal_uInt16( 0x4D42 ) << nBmpSize << sal_Int32( 0 ) << nOffset;
154
155 // copy the DIB header
156 rStrm.copyToStream( aOutStrm, nDibHdrSize );
157 nBytes -= nDibHdrSize;
158
159 /* Excel 3.x and Excel 4.x seem to write broken or out-dated DIB data.
160 Usually they write a BITMAPCOREHEADER containing width, height,
161 planes as usual. The pixel depth field is set to 32 bit (though
162 this is not allowed according to documentation). Between that
163 header and the actual pixel data, 3 unused bytes are inserted. This
164 does even confuse Excel 5.x and later, which cannot read the image
165 data correctly. */
166 if( (eBiff <= BIFF4) && (nDibHdrSize == BITMAPCOREHEADER_SIZE) && (nDepth == 32) )
167 {
168 // skip the dummy bytes in input stream
169 rStrm.skip( 3 );
170 nBytes -= 3;
171 // correct the total BMP file size in output stream
172 sal_Int64 nOutStrmPos = aOutStrm.tell();
173 aOutStrm.seek( 2 );
174 aOutStrm << sal_Int32( nBmpSize - 3 );
175 aOutStrm.seek( nOutStrmPos );
176 }
177
178 // copy remaining pixel data to output stream
179 rStrm.copyToStream( aOutStrm, nBytes );
180 }
181 rStrm.seek( nInStrmPos + nBytes );
182 }
183
184 } // namespace
185
186 // ============================================================================
187
188 // conversion -----------------------------------------------------------------
189
calcDoubleFromRk(sal_Int32 nRkValue)190 /*static*/ double BiffHelper::calcDoubleFromRk( sal_Int32 nRkValue )
191 {
192 DecodedDouble aDecDbl( 0.0 );
193 if( getFlag( nRkValue, BIFF_RK_INTFLAG ) )
194 {
195 sal_Int32 nTemp = nRkValue >> 2;
196 setFlag< sal_Int32 >( nTemp, 0xE0000000, nRkValue < 0 );
197 aDecDbl.mfValue = nTemp;
198 }
199 else
200 {
201 aDecDbl.maStruct.w32_parts.msw = static_cast< sal_uInt32 >( nRkValue & BIFF_RK_VALUEMASK );
202 }
203
204 if( getFlag( nRkValue, BIFF_RK_100FLAG ) )
205 aDecDbl.mfValue /= 100.0;
206
207 return aDecDbl.mfValue;
208 }
209
calcRkFromDouble(sal_Int32 & ornRkValue,double fValue)210 /*static*/ bool BiffHelper::calcRkFromDouble( sal_Int32& ornRkValue, double fValue )
211 {
212 if( lclCalcRkFromDouble( ornRkValue, fValue ) )
213 return true;
214
215 if( lclCalcRkFromDouble( ornRkValue, fValue * 100 ) )
216 {
217 ornRkValue |= BIFF_RK_100FLAG;
218 return true;
219 }
220
221 return false;
222 }
223
calcDoubleFromError(sal_uInt8 nErrorCode)224 /*static*/ double BiffHelper::calcDoubleFromError( sal_uInt8 nErrorCode )
225 {
226 sal_uInt16 nApiError = 0x7FFF;
227 switch( nErrorCode )
228 {
229 case BIFF_ERR_NULL: nApiError = 521; break;
230 case BIFF_ERR_DIV0: nApiError = 532; break;
231 case BIFF_ERR_VALUE: nApiError = 519; break;
232 case BIFF_ERR_REF: nApiError = 524; break;
233 case BIFF_ERR_NAME: nApiError = 525; break;
234 case BIFF_ERR_NUM: nApiError = 503; break;
235 case BIFF_ERR_NA: nApiError = 0x7FFF; break;
236 default: OSL_ENSURE( false, "BiffHelper::calcDoubleFromError - unknown error code" );
237 }
238 DecodedDouble aDecDbl;
239 ::rtl::math::setNan( &aDecDbl.mfValue );
240 aDecDbl.maStruct.nan_parts.fraction_lo = nApiError;
241 return aDecDbl.mfValue;
242 }
243
calcTextEncodingFromCodePage(sal_uInt16 nCodePage)244 /*static*/ rtl_TextEncoding BiffHelper::calcTextEncodingFromCodePage( sal_uInt16 nCodePage )
245 {
246 // some specials for BIFF
247 switch( nCodePage )
248 {
249 case 1200: return RTL_TEXTENCODING_DONTKNOW; // BIFF8 Unicode
250 case 32768: return RTL_TEXTENCODING_APPLE_ROMAN;
251 case 32769: return RTL_TEXTENCODING_MS_1252; // BIFF2-BIFF3
252 }
253
254 rtl_TextEncoding eTextEnc = rtl_getTextEncodingFromWindowsCodePage( nCodePage );
255 OSL_ENSURE( eTextEnc != RTL_TEXTENCODING_DONTKNOW, "BiffHelper::calcTextEncodingFromCodePage - unknown code page" );
256 return eTextEnc;
257 }
258
calcCodePageFromTextEncoding(rtl_TextEncoding eTextEnc)259 /*static*/ sal_uInt16 BiffHelper::calcCodePageFromTextEncoding( rtl_TextEncoding eTextEnc )
260 {
261 sal_uInt32 nCodePage = rtl_getWindowsCodePageFromTextEncoding( eTextEnc );
262 OSL_ENSURE( (0 < nCodePage) && (nCodePage <= SAL_MAX_UINT16), "BiffHelper::calcCodePageFromTextEncoding - unknown text encoding" );
263 return static_cast< sal_uInt16 >( (nCodePage == 0) ? 1252 : nCodePage );
264 }
265
266 // BIFF12 import --------------------------------------------------------------
267
readString(SequenceInputStream & rStrm,bool b32BitLen,bool bAllowNulChars)268 /*static*/ OUString BiffHelper::readString( SequenceInputStream& rStrm, bool b32BitLen, bool bAllowNulChars )
269 {
270 OUString aString;
271 if( !rStrm.isEof() )
272 {
273 sal_Int32 nCharCount = b32BitLen ? rStrm.readValue< sal_Int32 >() : rStrm.readValue< sal_Int16 >();
274 // string length -1 is often used to indicate a missing string
275 OSL_ENSURE( !rStrm.isEof() && (nCharCount >= -1), "BiffHelper::readString - invalid string length" );
276 if( !rStrm.isEof() && (nCharCount > 0) )
277 {
278 // SequenceInputStream always supports getRemaining()
279 nCharCount = ::std::min( nCharCount, static_cast< sal_Int32 >( rStrm.getRemaining() / 2 ) );
280 aString = rStrm.readUnicodeArray( nCharCount, bAllowNulChars );
281 }
282 }
283 return aString;
284 }
285
286 // BIFF2-BIFF8 import ---------------------------------------------------------
287
isBofRecord(BiffInputStream & rStrm)288 /*static*/ bool BiffHelper::isBofRecord( BiffInputStream& rStrm )
289 {
290 return
291 (rStrm.getRecId() == BIFF2_ID_BOF) ||
292 (rStrm.getRecId() == BIFF3_ID_BOF) ||
293 (rStrm.getRecId() == BIFF4_ID_BOF) ||
294 (rStrm.getRecId() == BIFF5_ID_BOF);
295 }
296
skipRecordBlock(BiffInputStream & rStrm,sal_uInt16 nEndRecId)297 /*static*/ bool BiffHelper::skipRecordBlock( BiffInputStream& rStrm, sal_uInt16 nEndRecId )
298 {
299 sal_uInt16 nStartRecId = rStrm.getRecId();
300 while( rStrm.startNextRecord() && (rStrm.getRecId() != nEndRecId) )
301 if( rStrm.getRecId() == nStartRecId )
302 skipRecordBlock( rStrm, nEndRecId );
303 return !rStrm.isEof() && (rStrm.getRecId() == nEndRecId);
304 }
305
importImgData(StreamDataSequence & orDataSeq,BiffInputStream & rStrm,BiffType eBiff)306 /*static*/ void BiffHelper::importImgData( StreamDataSequence& orDataSeq, BiffInputStream& rStrm, BiffType eBiff )
307 {
308 sal_uInt16 nFormat, nEnv;
309 sal_Int32 nBytes;
310 rStrm >> nFormat >> nEnv >> nBytes;
311 OSL_ENSURE( nBytes > 0, "BiffHelper::importImgData - invalid data size" );
312 if( (0 < nBytes) && (nBytes <= rStrm.getRemaining()) )
313 {
314 switch( nFormat )
315 {
316 // case BIFF_IMGDATA_WMF: /* TODO */ break;
317 case BIFF_IMGDATA_DIB: lclImportImgDataDib( orDataSeq, rStrm, nBytes, eBiff ); break;
318 // case BIFF_IMGDATA_NATIVE: /* TODO */ break;
319 default: OSL_ENSURE( false, "BiffHelper::importImgData - unknown image format" );
320 }
321 }
322 }
323
324 // ============================================================================
325
326 } // namespace xls
327 } // namespace oox
328