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 10cdf0e10cSrcweir * 11*ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 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. 19cdf0e10cSrcweir * 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 63cdf0e10cSrcweir inline explicit DecodedDouble() {} 64cdf0e10cSrcweir inline explicit DecodedDouble( double fValue ) : mfValue( fValue ) {} 65cdf0e10cSrcweir }; 66cdf0e10cSrcweir 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 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 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 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 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 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 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 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 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 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 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 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