1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: biffhelper.cxx,v $
10 * $Revision: 1.3.22.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/biffhelper.hxx"
33 #include <rtl/math.hxx>
34 #include "oox/xls/biffinputstream.hxx"
35 #include "oox/xls/biffoutputstream.hxx"
36 #include "oox/xls/worksheethelper.hxx"
38 using ::rtl::OUString
;
39 using ::rtl::OUStringBuffer
;
44 // ============================================================================
48 const sal_Int32 BIFF_RK_100FLAG
= 0x00000001;
49 const sal_Int32 BIFF_RK_INTFLAG
= 0x00000002;
50 const sal_Int32 BIFF_RK_VALUEMASK
= 0xFFFFFFFC;
52 const sal_Int32 BITMAPFILEHEADER_SIZE
= 14;
53 const sal_Int32 BITMAPCOREHEADER_SIZE
= 12;
54 const sal_Int32 BITMAPINFOHEADER_SIZE
= 40;
56 const sal_uInt16 BIFF_IMGDATA_WMF
= 2;
57 const sal_uInt16 BIFF_IMGDATA_DIB
= 9;
58 const sal_uInt16 BIFF_IMGDATA_NATIVE
= 14;
60 // ----------------------------------------------------------------------------
62 static const struct CodePageEntry
64 sal_uInt16 mnCodePage
;
65 rtl_TextEncoding meTextEnc
;
69 { 437, RTL_TEXTENCODING_IBM_437
}, // OEM US
70 // { 720, RTL_TEXTENCODING_IBM_720 }, // OEM Arabic
71 { 737, RTL_TEXTENCODING_IBM_737
}, // OEM Greek
72 { 775, RTL_TEXTENCODING_IBM_775
}, // OEM Baltic
73 { 850, RTL_TEXTENCODING_IBM_850
}, // OEM Latin I
74 { 852, RTL_TEXTENCODING_IBM_852
}, // OEM Latin II (Central European)
75 { 855, RTL_TEXTENCODING_IBM_855
}, // OEM Cyrillic
76 { 857, RTL_TEXTENCODING_IBM_857
}, // OEM Turkish
77 // { 858, RTL_TEXTENCODING_IBM_858 }, // OEM Multilingual Latin I with Euro
78 { 860, RTL_TEXTENCODING_IBM_860
}, // OEM Portugese
79 { 861, RTL_TEXTENCODING_IBM_861
}, // OEM Icelandic
80 { 862, RTL_TEXTENCODING_IBM_862
}, // OEM Hebrew
81 { 863, RTL_TEXTENCODING_IBM_863
}, // OEM Canadian (French)
82 { 864, RTL_TEXTENCODING_IBM_864
}, // OEM Arabic
83 { 865, RTL_TEXTENCODING_IBM_865
}, // OEM Nordic
84 { 866, RTL_TEXTENCODING_IBM_866
}, // OEM Cyrillic (Russian)
85 { 869, RTL_TEXTENCODING_IBM_869
}, // OEM Greek (Modern)
86 { 874, RTL_TEXTENCODING_MS_874
}, // MS Windows Thai
87 { 932, RTL_TEXTENCODING_MS_932
}, // MS Windows Japanese Shift-JIS
88 { 936, RTL_TEXTENCODING_MS_936
}, // MS Windows Chinese Simplified GBK
89 { 949, RTL_TEXTENCODING_MS_949
}, // MS Windows Korean (Wansung)
90 { 950, RTL_TEXTENCODING_MS_950
}, // MS Windows Chinese Traditional BIG5
91 { 1200, RTL_TEXTENCODING_DONTKNOW
}, // Unicode (BIFF8) - return *_DONTKNOW to preserve old code page
92 { 1250, RTL_TEXTENCODING_MS_1250
}, // MS Windows Latin II (Central European)
93 { 1251, RTL_TEXTENCODING_MS_1251
}, // MS Windows Cyrillic
94 { 1252, RTL_TEXTENCODING_MS_1252
}, // MS Windows Latin I (BIFF4-BIFF8)
95 { 1253, RTL_TEXTENCODING_MS_1253
}, // MS Windows Greek
96 { 1254, RTL_TEXTENCODING_MS_1254
}, // MS Windows Turkish
97 { 1255, RTL_TEXTENCODING_MS_1255
}, // MS Windows Hebrew
98 { 1256, RTL_TEXTENCODING_MS_1256
}, // MS Windows Arabic
99 { 1257, RTL_TEXTENCODING_MS_1257
}, // MS Windows Baltic
100 { 1258, RTL_TEXTENCODING_MS_1258
}, // MS Windows Vietnamese
101 { 1361, RTL_TEXTENCODING_MS_1361
}, // MS Windows Korean (Johab)
102 { 10000, RTL_TEXTENCODING_APPLE_ROMAN
}, // Apple Roman
103 { 32768, RTL_TEXTENCODING_APPLE_ROMAN
}, // Apple Roman
104 { 32769, RTL_TEXTENCODING_MS_1252
} // MS Windows Latin I (BIFF2-BIFF3)
107 /** Predicate to search by given code page. */
108 struct CodePageEntry_CPPred
110 inline explicit CodePageEntry_CPPred( sal_uInt16 nCodePage
) : mnCodePage( nCodePage
) {}
111 inline bool operator()( const CodePageEntry
& rEntry
) const { return rEntry
.mnCodePage
== mnCodePage
; }
112 sal_uInt16 mnCodePage
;
115 /** Predicate to search by given text encoding. */
116 struct CodePageEntry_TEPred
118 inline explicit CodePageEntry_TEPred( rtl_TextEncoding eTextEnc
) : meTextEnc( eTextEnc
) {}
119 inline bool operator()( const CodePageEntry
& rEntry
) const { return rEntry
.meTextEnc
== meTextEnc
; }
120 rtl_TextEncoding meTextEnc
;
123 // ----------------------------------------------------------------------------
125 bool lclCalcRkFromDouble( sal_Int32
& ornRkValue
, double fValue
)
128 const sal_math_Double
* pValue
= reinterpret_cast< const sal_math_Double
* >( &fValue
);
129 if( (pValue
->w32_parts
.lsw
== 0) && ((pValue
->w32_parts
.msw
& 0x3) == 0) )
131 ornRkValue
= static_cast< sal_Int32
>( pValue
->w32_parts
.msw
);
137 double fFrac
= modf( fValue
, &fInt
);
138 if( (fFrac
== 0.0) && (-536870912.0 <= fInt
) && (fInt
<= 536870911.0) ) // 2^29
140 ornRkValue
= static_cast< sal_Int32
>( fInt
);
142 ornRkValue
|= BIFF_RK_INTFLAG
;
149 // ----------------------------------------------------------------------------
151 void lclImportImgDataDib( StreamDataSequence
& orDataSeq
, BiffInputStream
& rStrm
, sal_Int32 nBytes
, BiffType eBiff
)
153 /* The IMGDATA record for bitmap format contains a Windows DIB (a bitmap
154 file without the 'BITMAPFILEHEADER' header structure). Usually, the DIB
155 header consists of 12 bytes (called 'OS/2 V1 header' or
156 'BITMAPCOREHEADER', see http://en.wikipedia.org/wiki/BMP_file_format)
157 followed by the remaining pixel data, but the 'Windows V3' or
158 'BITMAPINFOHEADER' is also supported here. This function creates a
159 complete 'BMP file' that can be read by the OOo graphic provider used
160 to import graphic objects. For that, the BITMAPFILEHEADER has to be
161 inserted before the DIB data, and it has to contain the correct offset
162 to the pixel data. Currently, in real life there are only 24-bit and
163 32-bit DIBs (without color palette) in use. This code relies on this
164 fact and calculates the offset to the pixel data according to the size
166 Remaining tasks are (if really used somewhere):
167 - Support of DIBs with color palette,
168 - Support of 'Windows V4' and 'Windows V5' DIB header. */
170 // read and check validity of DIB header
171 sal_Int64 nInStrmPos
= rStrm
.tell();
172 sal_Int32 nDibHdrSize
= rStrm
.readInt32();
173 sal_uInt16 nPlanes
= 0, nDepth
= 0;
174 switch( nDibHdrSize
)
176 case BITMAPCOREHEADER_SIZE
:
177 rStrm
.skip( 4 ); // width/height as 16-bit integer
178 rStrm
>> nPlanes
>> nDepth
;
180 case BITMAPINFOHEADER_SIZE
:
181 rStrm
.skip( 8 ); // width/height as 32-bit integer
182 rStrm
>> nPlanes
>> nDepth
;
185 rStrm
.seek( nInStrmPos
);
187 if( (nPlanes
== 1) && ((nDepth
== 24) || (nDepth
== 32)) )
189 // allocate enough space for the BITMAPFILEHEADER and the DIB data
190 orDataSeq
.realloc( BITMAPFILEHEADER_SIZE
+ nBytes
);
191 SequenceOutputStream
aOutStrm( orDataSeq
);
193 // write the BITMAPFILEHEADER of a regular BMP file
194 sal_Int32 nBmpSize
= BITMAPFILEHEADER_SIZE
+ nBytes
;
195 sal_Int32 nOffset
= BITMAPFILEHEADER_SIZE
+ nDibHdrSize
;
196 aOutStrm
<< sal_uInt16( 0x4D42 ) << nBmpSize
<< sal_Int32( 0 ) << nOffset
;
198 // copy the DIB header
199 aOutStrm
.copyStream( rStrm
, nDibHdrSize
);
200 nBytes
-= nDibHdrSize
;
202 /* Excel 3.x and Excel 4.x seem to write broken or out-dated DIB data.
203 Usually they write a BITMAPCOREHEADER containing width, height,
204 planes as usual. The pixel depth field is set to 32 bit (though
205 this is not allowed according to documentation). Between that
206 header and the actual pixel data, 3 unused bytes are inserted. This
207 does even confuse Excel 5.x and later, which cannot read the image
209 if( (eBiff
<= BIFF4
) && (nDibHdrSize
== BITMAPCOREHEADER_SIZE
) && (nDepth
== 32) )
211 // skip the dummy bytes in input stream
214 // correct the total BMP file size in output stream
215 sal_Int64 nOutStrmPos
= aOutStrm
.tell();
217 aOutStrm
<< sal_Int32( nBmpSize
- 3 );
218 aOutStrm
.seek( nOutStrmPos
);
221 // copy remaining pixel data top output stream
222 aOutStrm
.copyStream( rStrm
, nBytes
);
224 rStrm
.seek( nInStrmPos
+ nBytes
);
229 // ============================================================================
231 // conversion -----------------------------------------------------------------
233 /*static*/ double BiffHelper::calcDoubleFromRk( sal_Int32 nRkValue
)
236 if( getFlag( nRkValue
, BIFF_RK_INTFLAG
) )
238 sal_Int32 nTemp
= nRkValue
>> 2;
239 setFlag
< sal_Int32
>( nTemp
, 0xE0000000, nRkValue
< 0 );
244 sal_math_Double
* pDouble
= reinterpret_cast< sal_math_Double
* >( &fValue
);
245 pDouble
->w32_parts
.msw
= static_cast< sal_uInt32
>( nRkValue
& BIFF_RK_VALUEMASK
);
248 if( getFlag( nRkValue
, BIFF_RK_100FLAG
) )
254 /*static*/ bool BiffHelper::calcRkFromDouble( sal_Int32
& ornRkValue
, double fValue
)
256 if( lclCalcRkFromDouble( ornRkValue
, fValue
) )
259 if( lclCalcRkFromDouble( ornRkValue
, fValue
* 100 ) )
261 ornRkValue
|= BIFF_RK_100FLAG
;
268 /*static*/ double BiffHelper::calcDoubleFromError( sal_uInt8 nErrorCode
)
270 sal_uInt16 nApiError
= 0x7FFF;
273 case BIFF_ERR_NULL
: nApiError
= 521; break;
274 case BIFF_ERR_DIV0
: nApiError
= 532; break;
275 case BIFF_ERR_VALUE
: nApiError
= 519; break;
276 case BIFF_ERR_REF
: nApiError
= 524; break;
277 case BIFF_ERR_NAME
: nApiError
= 525; break;
278 case BIFF_ERR_NUM
: nApiError
= 503; break;
279 case BIFF_ERR_NA
: nApiError
= 0x7FFF; break;
280 default: OSL_ENSURE( false, "BiffHelper::calcDoubleFromError - unknown error code" );
283 ::rtl::math::setNan( &fValue
);
284 reinterpret_cast< sal_math_Double
* >( &fValue
)->nan_parts
.fraction_lo
= nApiError
;
288 /*static*/ rtl_TextEncoding
BiffHelper::calcTextEncodingFromCodePage( sal_uInt16 nCodePage
)
290 const CodePageEntry
* pEntry
= ::std::find_if( spCodePages
, STATIC_ARRAY_END( spCodePages
), CodePageEntry_CPPred( nCodePage
) );
291 if( pEntry
== STATIC_ARRAY_END( spCodePages
) )
293 OSL_ENSURE( false, "UnitConverter::calcTextEncodingFromCodePage - unknown code page" );
294 return RTL_TEXTENCODING_DONTKNOW
;
296 return pEntry
->meTextEnc
;
299 /*static*/ sal_uInt16
BiffHelper::calcCodePageFromTextEncoding( rtl_TextEncoding eTextEnc
)
301 const CodePageEntry
* pEntry
= ::std::find_if( spCodePages
, STATIC_ARRAY_END( spCodePages
), CodePageEntry_TEPred( eTextEnc
) );
302 if( pEntry
== STATIC_ARRAY_END( spCodePages
) )
304 OSL_ENSURE( false, "UnitConverter::calcCodePageFromTextEncoding - unsupported text encoding" );
307 return pEntry
->mnCodePage
;
310 /*static*/ void BiffHelper::importImgData( StreamDataSequence
& orDataSeq
, BiffInputStream
& rStrm
, BiffType eBiff
)
312 sal_uInt16 nFormat
, nEnv
;
314 rStrm
>> nFormat
>> nEnv
>> nBytes
;
315 OSL_ENSURE( (nFormat
== BIFF_IMGDATA_WMF
) || (nFormat
== BIFF_IMGDATA_DIB
) || (nFormat
== BIFF_IMGDATA_NATIVE
), "BiffHelper::importImgData - unknown format" );
316 OSL_ENSURE( nBytes
> 0, "BiffHelper::importImgData - invalid data size" );
317 if( (0 < nBytes
) && (nBytes
<= rStrm
.getRemaining()) )
321 case BIFF_IMGDATA_WMF
: /* TODO */ break;
322 case BIFF_IMGDATA_DIB
: lclImportImgDataDib( orDataSeq
, rStrm
, nBytes
, eBiff
); break;
323 case BIFF_IMGDATA_NATIVE
: /* TODO */ break;
324 default: OSL_ENSURE( false, "BiffHelper::importImgData - unknown image format" );
329 // ============================================================================