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