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