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/ole/vbamodule.hxx" 29 30 #include <com/sun/star/container/XNameContainer.hpp> 31 #include <com/sun/star/script/ModuleInfo.hpp> 32 #include <com/sun/star/script/ModuleType.hpp> 33 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp> 34 #include "oox/helper/binaryinputstream.hxx" 35 #include "oox/helper/storagebase.hxx" 36 #include "oox/helper/textinputstream.hxx" 37 #include "oox/ole/vbahelper.hxx" 38 #include "oox/ole/vbainputstream.hxx" 39 40 namespace oox { 41 namespace ole { 42 43 // ============================================================================ 44 45 using namespace ::com::sun::star::container; 46 using namespace ::com::sun::star::frame; 47 using namespace ::com::sun::star::lang; 48 using namespace ::com::sun::star::script; 49 using namespace ::com::sun::star::script::vba; 50 using namespace ::com::sun::star::uno; 51 52 using ::rtl::OUString; 53 using ::rtl::OUStringBuffer; 54 55 // ============================================================================ 56 57 VbaModule::VbaModule( const Reference< XComponentContext >& rxContext, const Reference< XModel >& rxDocModel, 58 const OUString& rName, rtl_TextEncoding eTextEnc, bool bExecutable ) : 59 mxContext( rxContext ), 60 mxDocModel( rxDocModel ), 61 maName( rName ), 62 meTextEnc( eTextEnc ), 63 mnType( ModuleType::UNKNOWN ), 64 mnOffset( SAL_MAX_UINT32 ), 65 mbReadOnly( false ), 66 mbPrivate( false ), 67 mbExecutable( bExecutable ) 68 { 69 } 70 71 void VbaModule::importDirRecords( BinaryInputStream& rDirStrm ) 72 { 73 sal_uInt16 nRecId = 0; 74 StreamDataSequence aRecData; 75 while( VbaHelper::readDirRecord( nRecId, aRecData, rDirStrm ) && (nRecId != VBA_ID_MODULEEND) ) 76 { 77 SequenceInputStream aRecStrm( aRecData ); 78 sal_Int32 nRecSize = aRecData.getLength(); 79 switch( nRecId ) 80 { 81 #define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaModule::importDirRecords - invalid record size" ) 82 case VBA_ID_MODULENAME: 83 OSL_ENSURE( false, "VbaModule::importDirRecords - unexpected MODULENAME record" ); 84 maName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); 85 break; 86 case VBA_ID_MODULENAMEUNICODE: 87 break; 88 case VBA_ID_MODULESTREAMNAME: 89 maStreamName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); 90 break; 91 case VBA_ID_MODULESTREAMNAMEUNICODE: 92 break; 93 case VBA_ID_MODULEDOCSTRING: 94 maDocString = aRecStrm.readCharArrayUC( nRecSize, meTextEnc ); 95 break; 96 case VBA_ID_MODULEDOCSTRINGUNICODE: 97 break; 98 case VBA_ID_MODULEOFFSET: 99 OOX_ENSURE_RECORDSIZE( nRecSize == 4 ); 100 aRecStrm >> mnOffset; 101 break; 102 case VBA_ID_MODULEHELPCONTEXT: 103 OOX_ENSURE_RECORDSIZE( nRecSize == 4 ); 104 break; 105 case VBA_ID_MODULECOOKIE: 106 OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); 107 break; 108 case VBA_ID_MODULETYPEPROCEDURAL: 109 OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); 110 OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" ); 111 mnType = ModuleType::NORMAL; 112 break; 113 case VBA_ID_MODULETYPEDOCUMENT: 114 OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); 115 OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" ); 116 mnType = ModuleType::DOCUMENT; 117 break; 118 case VBA_ID_MODULEREADONLY: 119 OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); 120 mbReadOnly = true; 121 break; 122 case VBA_ID_MODULEPRIVATE: 123 OOX_ENSURE_RECORDSIZE( nRecSize == 0 ); 124 mbPrivate = true; 125 break; 126 default: 127 OSL_ENSURE( false, "VbaModule::importDirRecords - unknown module record" ); 128 #undef OOX_ENSURE_RECORDSIZE 129 } 130 } 131 OSL_ENSURE( maName.getLength() > 0, "VbaModule::importDirRecords - missing module name" ); 132 OSL_ENSURE( maStreamName.getLength() > 0, "VbaModule::importDirRecords - missing module stream name" ); 133 OSL_ENSURE( mnType != ModuleType::UNKNOWN, "VbaModule::importDirRecords - missing module type" ); 134 OSL_ENSURE( mnOffset < SAL_MAX_UINT32, "VbaModule::importDirRecords - missing module stream offset" ); 135 } 136 137 void VbaModule::createAndImportModule( StorageBase& rVbaStrg, const Reference< XNameContainer >& rxBasicLib, 138 const Reference< XNameAccess >& rxDocObjectNA ) const 139 { 140 OUString aVBASourceCode = readSourceCode( rVbaStrg ); 141 createModule( aVBASourceCode, rxBasicLib, rxDocObjectNA ); 142 } 143 144 void VbaModule::createEmptyModule( const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const 145 { 146 createModule( OUString(), rxBasicLib, rxDocObjectNA ); 147 } 148 149 // private -------------------------------------------------------------------- 150 151 OUString VbaModule::readSourceCode( StorageBase& rVbaStrg ) const 152 { 153 OUStringBuffer aSourceCode; 154 if( (maStreamName.getLength() > 0) && (mnOffset != SAL_MAX_UINT32) ) 155 { 156 BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true ); 157 OSL_ENSURE( !aInStrm.isEof(), "VbaModule::readSourceCode - cannot open module stream" ); 158 // skip the 'performance cache' stored before the actual source code 159 aInStrm.seek( mnOffset ); 160 // if stream is still valid, load the source code 161 if( !aInStrm.isEof() ) 162 { 163 // decompression starts at current stream position of aInStrm 164 VbaInputStream aVbaStrm( aInStrm ); 165 // load the source code line-by-line, with some more processing 166 TextInputStream aVbaTextStrm( mxContext, aVbaStrm, meTextEnc ); 167 while( !aVbaTextStrm.isEof() ) 168 { 169 OUString aCodeLine = aVbaTextStrm.readLine(); 170 if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) ) 171 { 172 // normal source code line 173 if( !mbExecutable ) 174 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) ); 175 aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) ); 176 } 177 } 178 } 179 } 180 return aSourceCode.makeStringAndClear(); 181 } 182 183 void VbaModule::createModule( const OUString& rVBASourceCode, 184 const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const 185 { 186 if( maName.getLength() == 0 ) 187 return; 188 189 // prepare the Basic module 190 ModuleInfo aModuleInfo; 191 aModuleInfo.ModuleType = mnType; 192 OUStringBuffer aSourceCode; 193 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem Attribute VBA_ModuleType=" ) ); 194 switch( mnType ) 195 { 196 case ModuleType::NORMAL: 197 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAModule" ) ); 198 break; 199 case ModuleType::CLASS: 200 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAClassModule" ) ); 201 break; 202 case ModuleType::FORM: 203 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAFormModule" ) ); 204 // hack from old filter, document Basic should know the XModel, but it doesn't 205 aModuleInfo.ModuleObject.set( mxDocModel, UNO_QUERY ); 206 break; 207 case ModuleType::DOCUMENT: 208 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBADocumentModule" ) ); 209 // get the VBA implementation object associated to the document module 210 if( rxDocObjectNA.is() ) try 211 { 212 aModuleInfo.ModuleObject.set( rxDocObjectNA->getByName( maName ), UNO_QUERY ); 213 } 214 catch( Exception& ) 215 { 216 } 217 break; 218 default: 219 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAUnknown" ) ); 220 } 221 aSourceCode.append( sal_Unicode( '\n' ) ); 222 if( mbExecutable ) 223 { 224 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option VBASupport 1\n" ) ); 225 if( mnType == ModuleType::CLASS ) 226 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option ClassModule\n" ) ); 227 } 228 else 229 { 230 // add a subroutine named after the module itself 231 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Sub " ) ). 232 append( maName.replace( ' ', '_' ) ).append( sal_Unicode( '\n' ) ); 233 } 234 235 // append passed VBA source code 236 aSourceCode.append( rVBASourceCode ); 237 238 // close the subroutine named after the module 239 if( !mbExecutable ) 240 aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "End Sub\n" ) ); 241 242 // insert extended module info 243 try 244 { 245 Reference< XVBAModuleInfo > xVBAModuleInfo( rxBasicLib, UNO_QUERY_THROW ); 246 xVBAModuleInfo->insertModuleInfo( maName, aModuleInfo ); 247 } 248 catch( Exception& ) 249 { 250 } 251 252 // insert the module into the passed Basic library 253 try 254 { 255 rxBasicLib->insertByName( maName, Any( aSourceCode.makeStringAndClear() ) ); 256 } 257 catch( Exception& ) 258 { 259 OSL_ENSURE( false, "VbaModule::createModule - cannot insert module into library" ); 260 } 261 } 262 263 // ============================================================================ 264 265 } // namespace ole 266 } // namespace oox 267