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 63 inline explicit DecodedDouble() {} 64 inline explicit DecodedDouble( double fValue ) : mfValue( fValue ) {} 65 }; 66 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 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 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 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 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 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 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 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 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 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 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 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