diff options
Diffstat (limited to 'sw/source/filter/ww8/dump/msvbasic.cxx')
-rw-r--r-- | sw/source/filter/ww8/dump/msvbasic.cxx | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/dump/msvbasic.cxx b/sw/source/filter/ww8/dump/msvbasic.cxx new file mode 100644 index 000000000000..bbbab5f9eba6 --- /dev/null +++ b/sw/source/filter/ww8/dump/msvbasic.cxx @@ -0,0 +1,539 @@ +/************************************************************************* + * + * 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.8 $ + * + * 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_sw.hxx" + + +#include <string.h> // memset(), ... +#ifndef UNX +#include <io.h> // access() +#endif +#include <msvbasic.hxx> + +/* 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 + * */ + +BYTE VBA_Impl::ReadPString(SvStorageStreamRef &xVBAProject) +{ + UINT16 idlen; + BYTE type=0; + *xVBAProject >> idlen; + BYTE out; + int i=0; + if (idlen < 6) + { + type=0; + xVBAProject->SeekRel(-2); + return(type); + } + + for(i=0;i<idlen/2;i++) + { + *xVBAProject >> out; + xVBAProject->SeekRel(1); + if (i==2) + { + type=out; + if ((type != 'G') && (type != 'C')) + type=0; + if (type == 0) + { + xVBAProject->SeekRel(-8); + break; + } + } + } + + + return(type); +} + +void VBA_Impl::ConfirmFixedOctect(SvStorageStreamRef &xVBAProject) +{ + static const BYTE stest[8] = + { + 0x06, 0x02, 0x01, 0x00, 0x08, 0x02, 0x00, 0x00 + }; + + BYTE test[8]; + xVBAProject->Read(test,8); + if (memcmp(stest,test,8) != 0) + DBG_WARNING("Found a different octect, please report"); +} + +void VBA_Impl::Confirm12Zeros(SvStorageStreamRef &xVBAProject) +{ + static const BYTE stest[12]={0}; + BYTE test[12]; + xVBAProject->Read(test,12); + if (memcmp(stest,test,12) != 0) + DBG_WARNING("Found a Non Zero block, please report"); +} + +void VBA_Impl::ConfirmHalfWayMarker(SvStorageStreamRef &xVBAProject) +{ + static const BYTE stest[12]={0,0,0,0,0,0,0,0,0,0,1,0}; + BYTE test[12]; + xVBAProject->Read(test,12); + if (memcmp(stest,test,12) != 0) + DBG_WARNING("Found a different halfway marker, please report"); +} + +void VBA_Impl::ConfirmFixedMiddle(SvStorageStreamRef &xVBAProject) +{ + static const BYTE stest[20] = + { + 0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, + 0x1a, 0x10, 0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, + 0x0b, 0xb4, 0x00, 0x00 + }; + + BYTE test[20]; + xVBAProject->Read(test,20); + if (memcmp(stest,test,20) != 0) + { + DBG_WARNING("Found a different middle marker, please report"); + xVBAProject->SeekRel(-20); + } +} + +void VBA_Impl::ConfirmFixedMiddle2(SvStorageStreamRef &xVBAProject) +{ + static const BYTE stest[20] = + { + 0x00, 0x00, 0x2e, 0xc9, 0x27, 0x8e, 0x64, 0x12, + 0x1c, 0x10, 0x8a, 0x2f, 0x04, 0x02, 0x24, 0x00, + 0x9c, 0x02, 0x00, 0x00 + }; + + BYTE test[20]; + xVBAProject->Read(test,20); + if (memcmp(stest,test,20) != 0) + { + DBG_WARNING("Found a different middle2 marker, please report"); + xVBAProject->SeekRel(-20); + } +} + + +void VBA_Impl::Output( int nLen, const BYTE *pData) +{ + sVBAString += String( (const sal_Char *)pData, nLen ); +/* +//For debugging purposes + for(int i=0;i<len;i++) + *pOut << data[i]; +*/ +} + + +int VBA_Impl::ReadVBAProject(const SvStorageRef &rxVBAStorage) + { + SvStorageStreamRef xVBAProject; + xVBAProject = rxVBAStorage->OpenStream( + String::CreateFromAscii( "_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); + } + xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + //*pOut << hex; + BYTE header[30] = + { + 0xcc, 0x61, 0x5e, 0x00, 0x00, 0x01, 0x00, 0xff, + 0x07, 0x04, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, + 0xe4, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 + }; + BYTE headerin[30]; + + xVBAProject->Read(headerin,30); + if (memcmp(header,headerin,30) != 0) + DBG_WARNING("Warning VBA header is different, please report"); + UINT16 value; + *xVBAProject >> value; + //*pOut << "Trigger value 1 is " << value << endl; + UINT16 svalue; + *xVBAProject >> svalue; + if (svalue != 0x02) + DBG_WARNING("Warning VBA number is different, please report"); + + int count=0; + BYTE testc=0; + + //*pOut << "Other strings after the middle are..." << endl; + //There appears to be almost any number of strings acceptable + //most begin with */G , and sometimes with + //*/C. Those with G always have a trailer of 12 bytes, those + //with C come in pairs, the first with no trailer, and the + //second with one of 12 bytes. The following code attemts + //to read these strings and ends when it reaches a sequence of + //bytes which fails a test to be a valid string. So this + //while loop here is the particular piece of code which is + //very suspect and likely to be the cause of any crashes and + //problems. + while ((testc = ReadPString(xVBAProject)) != 0) + { + //*pOut << endl; + //*pOut << "testcharacter is " << testc << endl; + switch (testc) + { + case 'C': + count++; + if (count == 2) + { + Confirm12Zeros(xVBAProject); + count=0; + } + break; + default: + case 'G': + Confirm12Zeros(xVBAProject); + break; + } + } + + //appears to be a fixed 20 byte sequence here, and then the strings + //continue + ConfirmFixedMiddle(xVBAProject); + + count=0; + testc=0; + + while ((testc = ReadPString(xVBAProject)) != 0) + { + //*pOut << endl; + //*pOut << "testcharacter is " << testc << endl; + switch (testc) + { + case 'C': + count++; + if (count == 2) + { + Confirm12Zeros(xVBAProject); + count=0; + } + break; + default: + case 'G': + Confirm12Zeros(xVBAProject); + break; + } + } + + //there *may* be another different 20byte fixed string + ConfirmFixedMiddle2(xVBAProject); + + //*pOut << "testc is " << testc << endl; + //*pOut << "position is " << xVBAProject->Tell() << endl; + + UINT16 nModules; + *xVBAProject >> nModules; + + //begin section, this section isn't really 100% correct + //*pOut << nModules << hex << " vba modules" << endl; + xVBAProject->SeekRel(2*nModules); + xVBAProject->SeekRel(4); + //*pOut << "position is " << xVBAProject->Tell() << endl; + ConfirmFixedOctect(xVBAProject); + + UINT16 junksize; + while(junksize != 0xFFFF) + { + xVBAProject->Read(&junksize,2); // usually 18 02, sometimes 1e 02 + //but sometimes its a run of numbers until 0xffff, gagh!!! + //*pOut << "position is " << xVBAProject->Tell() << "len is " + // << junksize << endl; + } + + UINT16 ftest; + *xVBAProject >> ftest; + if (ftest != 0xFFFF) + xVBAProject->SeekRel(ftest); + *xVBAProject >> ftest; + if (ftest != 0xFFFF) + xVBAProject->SeekRel(ftest); + + xVBAProject->SeekRel(100); + //*pOut << "position is " << xVBAProject->Tell() << endl; + //end section + + + *xVBAProject >> nOffsets; + pOffsets = new VBAOffset_Impl[nOffsets]; + int i; + for (i=0;i<nOffsets;i++) + { + BYTE discard; + UINT16 len; + *xVBAProject >> len; + int j; + for (j=0;j<len/2;j++) + { + *xVBAProject >> discard; + pOffsets[i].sName += discard; + *xVBAProject >> discard; + } + *xVBAProject >> len; + xVBAProject->SeekRel(len); + + //begin section, another problem area + *xVBAProject >> len; + if (len == 0xFFFF) + { + xVBAProject->SeekRel(2); + *xVBAProject >> len; + xVBAProject->SeekRel(len); + } + else + xVBAProject->SeekRel(len+2); + // + /* I have a theory that maybe you read a 16bit len, and + * if it has 0x02 for the second byte then it is a special + * token of its own that affects nothing else, otherwise + * it is a len of the following data. C. I must test this + * theory later. + */ + //end section + + xVBAProject->SeekRel(8); + BYTE no_of_octects; + *xVBAProject >> no_of_octects; + for(j=0;j<no_of_octects;j++) + xVBAProject->SeekRel(8); + xVBAProject->SeekRel(6); + + *xVBAProject >> pOffsets[i].nOffset; + //*pOut << pOffsets[i].pName.GetStr() << " at 0x" << hex << pOffsets[i].nOffset << endl; + xVBAProject->SeekRel(2); + } + + //*pOut << endl; + return(nOffsets); + } + +BOOL VBA_Impl::Open( const String &rToplevel,const String &rSublevel ) +{ + /* beginning test for vba stuff */ + BOOL bRet = FALSE; + SvStorageRef xMacros= xStor->OpenStorage(rToplevel); + if( !xMacros.Is() || SVSTREAM_OK != xMacros->GetError() ) + { + DBG_WARNING("No Macros Storage"); + } + else + { + xVBA = xMacros->OpenStorage(rSublevel); + if( !xVBA.Is() || SVSTREAM_OK != xVBA->GetError() ) + { + DBG_WARNING("No Visual Basic in Storage"); + } + else + { + if (ReadVBAProject(xVBA)) + bRet = TRUE; + } + } + /* end test for vba stuff */ + return bRet; +} + +const String &VBA_Impl::Decompress( UINT16 nIndex, int *pOverflow) +{ + SvStorageStreamRef xVBAStream; + sVBAString.Erase(); + + DBG_ASSERT( nIndex < nOffsets, "Index out of range" ); + xVBAStream = xVBA->OpenStream( 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 "); +// DBG_WARNING((pOffsets[nIndex].sName).GetStr()); + } + 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(String::CreateFromAscii( "\x0D\x0A")); + String sTempStringb(String::CreateFromAscii( "\x0D\x0ARem ")); + sVBAString.SearchAndReplaceAll(sTempStringa,sTempStringb); + sVBAString.InsertAscii("Rem ",0); + } + } + return sVBAString; +} + + +int VBA_Impl::DecompressVBA( int nIndex, SvStorageStreamRef &xVBAStream ) +{ + BYTE leadbyte; + unsigned int pos = 0; + + //*pOut << "jumping to " << hex << offsets[nIndex].offset << endl; + xVBAStream->Seek(pOffsets[nIndex].nOffset+3); + + int len; + UINT16 token; + int distance, shift, clean=1; + + while(xVBAStream->Read(&leadbyte,1)) + { + //*pOut << "reading 8 data unit block beginning with " << leadbyte << int(leadbyte) << " at pos " << xVBAStream->Tell() << " real pos " << pos << endl; + for(int position=0x01;position < 0x100;position=position<<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 (leadbyte & position) + { + *xVBAStream >> token; + + if (clean == 0) + clean=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 pos2 = pos%WINDOWLEN; + if (pos2 <= 0x10) + shift = 12; + else if (pos2 <= 0x20) + shift = 11; + else if (pos2 <= 0x40) + shift = 10; + else if (pos2 <= 0x80) + shift = 9; + else if (pos2 <= 0x100) + shift = 8; + else if (pos2 <= 0x200) + shift = 7; + else if (pos2 <= 0x400) + shift = 6; + else if (pos2 <= 0x800) + shift = 5; + else + shift = 4; + + int i; + len=0; + for(i=0;i<shift;i++) + len |= token & (1<<i); + + //*pOut << endl << "match lookup token " << int(token) << "len " << int(len) << endl; + + len += 3; + //*pOut << endl << "len is " << len << "shift is " << shift << endl; + + distance = token >> shift; + //*pOut << "distance token shift is " << distance << " " << int(token) << " " << shift << "pos is " << pos << " " << xVBAStream->Tell() << endl; + + //read the len of data from the history, wrapping around the + //WINDOWLEN boundary if necessary + //data read from the history is also copied into the recent + //part of the history as well. + for (i = 0; i < len; i++) + { + unsigned char c; + //*pOut << endl << (pos%WINDOWLEN)-distance-1 << " " << pos << " " << distance << endl; + c = aHistory[(pos-distance-1)%WINDOWLEN]; + aHistory[pos%WINDOWLEN] = c; + pos++; + //*pOut << "real pos is " << pos << endl; + // + //temp removed + //*pOut << c ; + } + } + 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 WINDOWLEN boundary and the excess + // bytes in the 8 dataunit list are discarded, and not + // interpreted as tokens or normal data. + if ((pos != 0) && ((pos%WINDOWLEN) == 0) && (clean)) + { + //*pOut << "at boundary position is " << position << " " << xVBAStream->Tell() << " pos is " << pos << endl; + //if (position != 0x01) + //*pOut << "must restart by eating remainder single byte data units" << endl; + xVBAStream->SeekRel(2); + clean=0; + Output(WINDOWLEN,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[pos%WINDOWLEN],1)) + { + pos++; + //temp removed + //*pOut << aHistory[pos++%WINDOWLEN]; + } + if (clean == 0) + clean=1; + //*pOut << "pos is " << pos << " " << xVBAStream->Tell() << endl; + } + } + } + if (pos%WINDOWLEN) + Output(pos%WINDOWLEN,aHistory); + return(pos); +} + |