diff options
Diffstat (limited to 'svx/source/msfilter/msvbasic.cxx')
-rw-r--r-- | svx/source/msfilter/msvbasic.cxx | 677 |
1 files changed, 0 insertions, 677 deletions
diff --git a/svx/source/msfilter/msvbasic.cxx b/svx/source/msfilter/msvbasic.cxx deleted file mode 100644 index b8df285fbe..0000000000 --- a/svx/source/msfilter/msvbasic.cxx +++ /dev/null @@ -1,677 +0,0 @@ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2008 by Sun Microsystems, Inc. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * $RCSfile: msvbasic.cxx,v $ - * $Revision: 1.22 $ - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_svx.hxx" - -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ - -#include <string.h> // memset(), ... -#ifndef UNX -#include <io.h> // access() -#endif -#include <osl/endian.h> -#include <rtl/tencinfo.h> //rtl_getTextEncodingFromWindowsCodePage -#include "msvbasic.hxx" - -/* -A few urls which may in the future be of some use -http://www.virusbtn.com/vb2000/Programme/papers/bontchev.pdf -*/ - -/* class VBA_Impl: - * The VBA class provides a set of methods to handle Visual Basic For - * Applications streams, the constructor is given the root ole2 stream - * of the document, Open reads the VBA project file and figures out - * the number of VBA streams, and the offset of the data within them. - * Decompress decompresses a particular numbered stream, NoStreams returns - * this number, and StreamName can give you the streams name. Decompress - * will call Output when it has a 4096 byte collection of data to output, - * and also with the final remainder of data if there is still some left - * at the end of compression. Output is virtual to allow custom handling - * of each chunk of decompressed data. So inherit from this to do something - * useful with the data. - * - * cmc - * */ -const int MINVBASTRING = 6; - -VBA_Impl::VBA_Impl(SvStorage &rIn, bool bCmmntd) - : aVBAStrings(0), - sComment(RTL_CONSTASCII_USTRINGPARAM("Rem ")), - xStor(&rIn), pOffsets(0), nOffsets(0), meCharSet(RTL_TEXTENCODING_MS_1252), - bCommented(bCmmntd), mbMac(false), nLines(0) -{ -} - -VBA_Impl::~VBA_Impl() -{ - delete [] pOffsets; - for (ULONG i=0;i<aVBAStrings.GetSize();++i) - delete aVBAStrings.Get(i); -} - -sal_uInt8 VBA_Impl::ReadPString(SvStorageStreamRef &xVBAProject, - bool bIsUnicode) -{ - sal_uInt16 nIdLen, nOut16; - sal_uInt8 nType = 0, nOut8; - String sReference; - - *xVBAProject >> nIdLen; - - if (nIdLen < MINVBASTRING) //Error recovery - xVBAProject->SeekRel(-2); //undo 2 byte len - else - { - for(sal_uInt16 i=0; i < nIdLen / (bIsUnicode ? 2 : 1); i++) - { - if (bIsUnicode) - *xVBAProject >> nOut16; - else - { - *xVBAProject >> nOut8; - nOut16 = nOut8; - } - sReference += nOut16; - if (i==2) - { - if ((nOut16 == 'G') || (nOut16 == 'H') || (nOut16 == 'C') || - nOut16 == 'D') - { - nType = static_cast<sal_uInt8>(nOut16); - } - if (nType == 0) - { - //Error recovery, 2byte len + 3 characters of used type - xVBAProject->SeekRel(-(2 + 3 * (bIsUnicode ? 2 : 1))); - break; - } - } - } - maReferences.push_back(sReference); - } - return nType; -} - -void VBA_Impl::Output( int nLen, const sal_uInt8*pData ) -{ - /* - Each StarBasic module is tragically limited to the maximum len of a - string and WordBasic is not, so each overlarge module must be split - */ - String sTemp((const sal_Char *)pData, (xub_StrLen)nLen, - meCharSet); - int nTmp = sTemp.GetTokenCount('\x0D'); - int nIndex = aVBAStrings.GetSize()-1; - if (aVBAStrings.Get(nIndex)->Len() + - nLen + ((nLines+nTmp) * sComment.Len()) >= STRING_MAXLEN) - { - //DBG_ASSERT(0,"New Module String\n"); - //we are too large for our boots, break out into another - //string - nLines=0; - nIndex++; - aVBAStrings.SetSize(nIndex+1); - aVBAStrings.Put(nIndex,new String); - } - *(aVBAStrings.Get(nIndex)) += sTemp; - nLines+=nTmp; -} - - -int VBA_Impl::ReadVBAProject(const SvStorageRef &rxVBAStorage) -{ - SvStorageStreamRef xVBAProject; - xVBAProject = rxVBAStorage->OpenSotStream( - String( RTL_CONSTASCII_USTRINGPARAM( "_VBA_PROJECT" ) ), - STREAM_STD_READ | STREAM_NOCREATE ); - - if( !xVBAProject.Is() || SVSTREAM_OK != xVBAProject->GetError() ) - { - DBG_WARNING("Not able to find vba project, cannot find macros"); - return 0; - } - - static const sal_uInt8 aKnownId[] = {0xCC, 0x61}; - sal_uInt8 aId[2]; - xVBAProject->Read( aId, sizeof(aId) ); - if (memcmp( aId, aKnownId, sizeof(aId))) - { - DBG_WARNING("unrecognized VBA macro project type"); - return 0; - } - - static const sal_uInt8 aOffice2003LE_2[] = - { - 0x79, 0x00, 0x00, 0x01, 0x00, 0xFF - }; - - static const sal_uInt8 aOffice2003LE[] = - { - 0x76, 0x00, 0x00, 0x01, 0x00, 0xFF - }; - - static const sal_uInt8 aOfficeXPLE[] = - { - 0x73, 0x00, 0x00, 0x01, 0x00, 0xFF - }; - - static const sal_uInt8 aOfficeXPBE[] = - { - 0x63, 0x00, 0x00, 0x0E, 0x00, 0xFF - }; - - static const sal_uInt8 aOffice2000LE[] = - { - 0x6D, 0x00, 0x00, 0x01, 0x00, 0xFF - }; - static const sal_uInt8 aOffice98BE[] = - { - 0x60, 0x00, 0x00, 0x0E, 0x00, 0xFF - }; - static const sal_uInt8 aOffice97LE[] = - { - 0x5E, 0x00, 0x00, 0x01, 0x00, 0xFF - }; - sal_uInt8 aProduct[6]; - xVBAProject->Read( aProduct, sizeof(aProduct) ); - - bool bIsUnicode; - if (!(memcmp(aProduct, aOffice2003LE, sizeof(aProduct))) || - !(memcmp(aProduct, aOffice2003LE_2, sizeof(aProduct))) ) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); - bIsUnicode = true; - } - else if (!(memcmp(aProduct, aOfficeXPLE, sizeof(aProduct)))) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); - bIsUnicode = true; - } - else if (!(memcmp(aProduct, aOfficeXPBE, sizeof(aProduct)))) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); - mbMac = true; - bIsUnicode = false; - } - else if (!(memcmp(aProduct, aOffice2000LE, sizeof(aProduct)))) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); - bIsUnicode = true; - } - else if (!(memcmp(aProduct, aOffice98BE, sizeof(aProduct)))) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); - mbMac = true; - bIsUnicode = false; - } - else if (!(memcmp(aProduct, aOffice97LE, sizeof(aProduct)))) - { - xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); - bIsUnicode = true; - } - else - { - switch (aProduct[3]) - { - case 0x1: - xVBAProject->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); - bIsUnicode = true; - DBG_ASSERT(!this, "unrecognized VBA macro version, report to cmc. Guessing at unicode little endian"); - break; - case 0xe: - xVBAProject->SetNumberFormatInt(NUMBERFORMAT_INT_BIGENDIAN); - mbMac = true; - bIsUnicode = false; - DBG_ASSERT(!this, "unrecognized VBA macro version, report to cmc. Guessing at 8bit big endian"); - break; - default: - DBG_ASSERT(!this, "totally unrecognized VBA macro version, report to cmc"); - return 0; - } - } - - sal_uInt32 nLidA; //Language identifiers - sal_uInt32 nLidB; - sal_uInt16 nCharSet; - sal_uInt16 nLenA; - sal_uInt32 nUnknownB; - sal_uInt32 nUnknownC; - sal_uInt16 nLenB; - sal_uInt16 nLenC; - sal_uInt16 nLenD; - - *xVBAProject >> nLidA >> nLidB >> nCharSet >> nLenA >> nUnknownB; - *xVBAProject >> nUnknownC >> nLenB >> nLenC >> nLenD; - - meCharSet = rtl_getTextEncodingFromWindowsCodePage(nCharSet); - - DBG_ASSERT(meCharSet != RTL_TEXTENCODING_DONTKNOW, - "don't know what vba charset to use"); - if (meCharSet == RTL_TEXTENCODING_DONTKNOW) - meCharSet = RTL_TEXTENCODING_MS_1252; - - if (nLenD != 0x02) - { - DBG_WARNING("Warning VBA number is different, please report"); - return 0; - } - - /* - A sequence of string that are prepended with a len and then begin with G - or H, there are also those that begin with C or D. If a string begins with - C or D, it is really two strings, one right after the other. Each string - then has a 12 bytes suffix - - Recognizing the end of the sequence is done by finding a str len of < 6 - which does not appear to be the beginning of an object id. Admittedly this - isn't a great test, but nothing in the header appears to count the number - of strings, and nothing else seems to match. So it'll have to do, its - protected by a number of secondry tests to prove its a valid string, and - everything gives up if this isn't proven. - */ - bool bPredictsTrailingTwenty = false; - while (1) - { - sal_uInt8 nType = ReadPString(xVBAProject,bIsUnicode); - //Type C and D seem to come as pairs, so skip the following one - if (nType == 'C' || nType == 'D') - { - nType = ReadPString(xVBAProject,bIsUnicode); - DBG_ASSERT( nType == 'C' || nType == 'D', - "VBA: This must be a 'C' or 'D' string!" ); - if (nType != 'C' && nType != 'D') - return 0; - } - if (!nType) - break; - xVBAProject->SeekRel(10); - sal_uInt16 nPredictsTrailingTwenty; - *xVBAProject >> nPredictsTrailingTwenty; - if (nPredictsTrailingTwenty) - bPredictsTrailingTwenty = true; - if (bPredictsTrailingTwenty) - { - sal_uInt16 nTestIsNotString; - *xVBAProject >> nTestIsNotString; - if (nTestIsNotString < MINVBASTRING) - { - DBG_ASSERT(nTestIsNotString <= 1, - "Haven't seen a len like this in VBA, report to CMC"); - xVBAProject->SeekRel(18); - bPredictsTrailingTwenty = false; - } - else - xVBAProject->SeekRel(-2); - } - } - - sal_Int16 nInt16s; - *xVBAProject >> nInt16s; - DBG_ASSERT( nInt16s >= 0, "VBA: Bad no of records in VBA Project, panic!" ); - if (!nInt16s) - return 0; - - xVBAProject->SeekRel(2*nInt16s); - - sal_Int16 nInt32s; - *xVBAProject >> nInt32s; - DBG_ASSERT( nInt32s >= 0, "VBA: Bad no of records in VBA Project, panic!" ); - if (!nInt32s) - return 0; - xVBAProject->SeekRel(4*nInt32s); - - xVBAProject->SeekRel(2); - for(int k=0;k<3;k++) - { - sal_uInt16 nLen; - *xVBAProject >> nLen; - if (nLen != 0xFFFF) - xVBAProject->SeekRel(nLen); - } - xVBAProject->SeekRel(100); //Seems fixed len - - *xVBAProject >> nOffsets; - DBG_ASSERT( nOffsets != 0xFFFF, "VBA: Bad nOffsets, panic!!" ); - if ((nOffsets == 0xFFFF) || (nOffsets == 0)) - return 0; - pOffsets = new VBAOffset_Impl[ nOffsets ]; - - int i, j; - for( i=0; i < nOffsets; i++) - { - sal_uInt16 nLen; - *xVBAProject >> nLen; - - if (bIsUnicode) - { - sal_Unicode* pBuf = pOffsets[i].sName.AllocBuffer( nLen / 2 ); - xVBAProject->Read( (sal_Char*)pBuf, nLen ); - -#ifdef OSL_BIGENDIAN - for( j = 0; j < nLen / 2; ++j, ++pBuf ) - *pBuf = SWAPSHORT( *pBuf ); -#endif // ifdef OSL_BIGENDIAN - } - else - { - ByteString aByteStr; - sal_Char* pByteData = aByteStr.AllocBuffer( nLen ); - sal_Size nWasRead = xVBAProject->Read( pByteData, nLen ); - if( nWasRead != nLen ) - aByteStr.ReleaseBufferAccess(); - pOffsets[i].sName += String( aByteStr, meCharSet); - } - - *xVBAProject >> nLen; - xVBAProject->SeekRel( nLen ); - - //begin section, another problem area - *xVBAProject >> nLen; - if ( nLen == 0xFFFF) - { - xVBAProject->SeekRel(2); - *xVBAProject >> nLen; - xVBAProject->SeekRel( nLen ); - } - else - xVBAProject->SeekRel( nLen+2 ); - - *xVBAProject >> nLen; - DBG_ASSERT( nLen == 0xFFFF, "VBA: Bad field in VBA Project, panic!!" ); - if ( nLen != 0xFFFF) - return 0; - - xVBAProject->SeekRel(6); - sal_uInt16 nOctects; - *xVBAProject >> nOctects; - for(j=0;j<nOctects;j++) - xVBAProject->SeekRel(8); - - xVBAProject->SeekRel(5); - //end section - - *xVBAProject >> pOffsets[i].nOffset; - xVBAProject->SeekRel(2); - } - - return nOffsets; -} - - -/* #117718# For a given Module name return its type, - * Form, Class, Document, Normal or Unknown - * -*/ - -ModuleType VBA_Impl::GetModuleType( const UniString& rModuleName ) -{ - ModuleTypeHash::iterator iter = mhModHash.find( rModuleName ); - ModuleTypeHash::iterator iterEnd = mhModHash.end(); - if ( iter != iterEnd ) - { - return iter->second; - } - return Unknown; -} - -bool VBA_Impl::Open( const String &rToplevel, const String &rSublevel ) -{ - /* beginning test for vba stuff */ - bool bRet = false; - SvStorageRef xMacros= xStor->OpenSotStorage( rToplevel, - STREAM_READWRITE | STREAM_NOCREATE | - STREAM_SHARE_DENYALL ); - if( !xMacros.Is() || SVSTREAM_OK != xMacros->GetError() ) - { - DBG_WARNING("No Macros Storage"); - } - else - { - xVBA = xMacros->OpenSotStorage( rSublevel, - STREAM_READWRITE | STREAM_NOCREATE | - STREAM_SHARE_DENYALL ); - if( !xVBA.Is() || SVSTREAM_OK != xVBA->GetError() ) - { - DBG_WARNING("No Visual Basic in Storage"); - } - else - { - if (ReadVBAProject(xVBA)) - bRet = true; - } - /* #117718# - * Information regarding the type of module is contained in the - * "PROJECT" stream, this stream consists of a number of ascii lines - * entries are of the form Key=Value, the ones that we are interested - * in have the keys; Class, BaseClass & Module indicating the module - * ( value ) is either a Class Module, Form Module or a plain VB Module. */ - SvStorageStreamRef xProject = xMacros->OpenSotStream( - String( RTL_CONSTASCII_USTRINGPARAM( "PROJECT" ) ) ); - SvStorageStream* pStp = xProject; - UniString tmp; - static const String sThisDoc( RTL_CONSTASCII_USTRINGPARAM( "ThisDocument" ) ); - static const String sModule( RTL_CONSTASCII_USTRINGPARAM( "Module" ) ); - static const String sClass( RTL_CONSTASCII_USTRINGPARAM( "Class" ) ); - static const String sBaseClass( RTL_CONSTASCII_USTRINGPARAM( "BaseClass" ) ); - static const String sDocument( RTL_CONSTASCII_USTRINGPARAM( "Document" ) ); - mhModHash[ sThisDoc ] = Class; - while ( pStp->ReadByteStringLine( tmp, meCharSet ) ) - { - xub_StrLen index = tmp.Search( '=' ); - if ( index != STRING_NOTFOUND ) - { - String key = tmp.Copy( 0, index ); - String value = tmp.Copy( index + 1 ); - if ( key == sClass ) - { - mhModHash[ value ] = Class; - OSL_TRACE("Module %s is of type Class", - ::rtl::OUStringToOString( value , - RTL_TEXTENCODING_ASCII_US ).pData->buffer ); - } - else if ( key == sBaseClass ) - { - mhModHash[ value ] = Form; - OSL_TRACE("Module %s is of type Form", - ::rtl::OUStringToOString( value , - RTL_TEXTENCODING_ASCII_US ).pData->buffer ); - } - else if ( key == sDocument ) - { - /* #i37965# DR 2004-12-03: add "Document", used i.e. - in Excel for macros attached to sheet or document. */ - - // value is of form <name>/&H<identifier>, strip the identifier - value.Erase( value.Search( '/' ) ); - - mhModHash[ value ] = Document; - OSL_TRACE("Module %s is of type Document VBA", - ::rtl::OUStringToOString( value , - RTL_TEXTENCODING_ASCII_US ).pData->buffer ); - } - else if ( key == sModule ) - { - mhModHash[ value ] = Normal; - OSL_TRACE("Module %s is of type Normal VBA", - ::rtl::OUStringToOString( value , - RTL_TEXTENCODING_ASCII_US ).pData->buffer ); - } - } - } - } - /* end test for vba stuff */ - return bRet; -} - -const StringArray &VBA_Impl::Decompress(sal_uInt16 nIndex, int *pOverflow) -{ - DBG_ASSERT( nIndex < nOffsets, "Index out of range" ); - SvStorageStreamRef xVBAStream; - aVBAStrings.SetSize(1); - aVBAStrings.Put(0,new String); - - xVBAStream = xVBA->OpenSotStream( pOffsets[nIndex].sName, - STREAM_STD_READ | STREAM_NOCREATE ); - if (pOverflow) - *pOverflow=0; - - if( !xVBAStream.Is() || SVSTREAM_OK != xVBAStream->GetError() ) - { - DBG_WARNING("Not able to open vb module "); - } - else - { - xVBAStream->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); - DecompressVBA( nIndex, xVBAStream ); - /* - * if len was too big for a single string set that variable ? - * if ((len > XX) && (pOverflow)) - *pOverflow=1; - */ - if (bCommented) - { - String sTempStringa; - if (mbMac) - sTempStringa = String( RTL_CONSTASCII_USTRINGPARAM( "\x0D" ) ); - else - sTempStringa = String( RTL_CONSTASCII_USTRINGPARAM( "\x0D\x0A" ) ); - String sTempStringb(sTempStringa); - sTempStringb+=sComment; - for(ULONG i=0;i<aVBAStrings.GetSize();i++) - { - aVBAStrings.Get(i)->SearchAndReplaceAll( - sTempStringa,sTempStringb); - aVBAStrings.Get(i)->Insert(sComment,0); - } - } - } - return aVBAStrings; -} - - -int VBA_Impl::DecompressVBA( int nIndex, SvStorageStreamRef &xVBAStream ) -{ - sal_uInt8 nLeadbyte; - sal_uInt16 nToken; - unsigned int nPos = 0; - int nLen, nDistance, nShift, nClean=1; - - xVBAStream->Seek( pOffsets[ nIndex ].nOffset + 3 ); - - while(xVBAStream->Read(&nLeadbyte,1)) - { - for(int nPosition=0x01;nPosition < 0x100;nPosition=nPosition<<1) - { - //we see if the leadbyte has flagged this location as a dataunit - //which is actually a token which must be looked up in the history - if (nLeadbyte & nPosition) - { - *xVBAStream >> nToken; - - if (nClean == 0) - nClean=1; - - //For some reason the division of the token into the length - //field of the data to be inserted, and the distance back into - //the history differs depending on how full the history is - int nPos2 = nPos % nWINDOWLEN; - if (nPos2 <= 0x10) - nShift = 12; - else if (nPos2 <= 0x20) - nShift = 11; - else if (nPos2 <= 0x40) - nShift = 10; - else if (nPos2 <= 0x80) - nShift = 9; - else if (nPos2 <= 0x100) - nShift = 8; - else if (nPos2 <= 0x200) - nShift = 7; - else if (nPos2 <= 0x400) - nShift = 6; - else if (nPos2 <= 0x800) - nShift = 5; - else - nShift = 4; - - int i; - nLen=0; - for(i=0;i<nShift;i++) - nLen |= nToken & (1<<i); - - nLen += 3; - - nDistance = nToken >> nShift; - - //read the len of data from the history, wrapping around the - //nWINDOWLEN boundary if necessary data read from the history - //is also copied into the recent part of the history as well. - for (i = 0; i < nLen; i++) - { - unsigned char c; - c = aHistory[(nPos-nDistance-1) % nWINDOWLEN]; - aHistory[nPos % nWINDOWLEN] = c; - nPos++; - } - } - else - { - // special boundary case code, not guarantueed to be correct - // seems to work though, there is something wrong with the - // compression scheme (or maybe a feature) where when the data - // ends on a nWINDOWLEN boundary and the excess bytes in the 8 - // dataunit list are discarded, and not interpreted as tokens - // or normal data. - if ((nPos != 0) && ((nPos % nWINDOWLEN) == 0) && (nClean)) - { - xVBAStream->SeekRel(2); - nClean=0; - Output(nWINDOWLEN, aHistory); - break; - } - //This is the normal case for when the data unit is not a - //token to be looked up, but instead some normal data which - //can be output, and placed in the history. - if (xVBAStream->Read(&aHistory[nPos % nWINDOWLEN],1)) - nPos++; - - if (nClean == 0) - nClean=1; - } - } - } - if (nPos % nWINDOWLEN) - Output(nPos % nWINDOWLEN,aHistory); - return(nPos); -} - -/* vi:set tabstop=4 shiftwidth=4 expandtab: */ |