| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_filter.hxx" |
| |
| /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ |
| #include <tools/debug.hxx> |
| #include <sfx2/objsh.hxx> |
| #include <sfx2/app.hxx> |
| #include <basic/basmgr.hxx> |
| #include <basic/sbmod.hxx> |
| #include <svx/svxerr.hxx> |
| #include <filter/msfilter/svxmsbas.hxx> |
| #include <msvbasic.hxx> |
| #include <filter/msfilter/msocximex.hxx> |
| #include <sot/storinfo.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/awt/Size.hpp> |
| #include <com/sun/star/awt/XControlModel.hpp> |
| using namespace com::sun::star::beans; |
| using namespace com::sun::star::io; |
| using namespace com::sun::star::awt; |
| #include <comphelper/storagehelper.hxx> |
| |
| #include <com/sun/star/container/XNameContainer.hpp> |
| #include <com/sun/star/script/XLibraryContainer.hpp> |
| #include <com/sun/star/script/ModuleInfo.hpp> |
| #include <com/sun/star/script/ModuleType.hpp> |
| #include <com/sun/star/script/vba/XVBACompatibility.hpp> |
| #include <com/sun/star/script/vba/XVBAModuleInfo.hpp> |
| |
| using namespace com::sun::star::container; |
| using namespace com::sun::star::script; |
| using namespace com::sun::star::uno; |
| using namespace com::sun::star::lang; |
| using namespace com::sun::star; |
| |
| using rtl::OUString; |
| |
| static ::rtl::OUString sVBAOption( RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n" ) ); |
| |
| int SvxImportMSVBasic::Import( const String& rStorageName, |
| const String &rSubStorageName, |
| sal_Bool bAsComment, sal_Bool bStripped ) |
| { |
| std::vector< String > codeNames; |
| return Import( rStorageName, rSubStorageName, codeNames, bAsComment, bStripped ); |
| } |
| |
| int SvxImportMSVBasic::Import( const String& rStorageName, |
| const String &rSubStorageName, |
| const std::vector< String >& codeNames, |
| sal_Bool bAsComment, sal_Bool bStripped ) |
| { |
| int nRet = 0; |
| if( bImport && ImportCode_Impl( rStorageName, rSubStorageName, codeNames, |
| bAsComment, bStripped )) |
| nRet |= 1; |
| |
| if (bImport) |
| ImportForms_Impl(rStorageName, rSubStorageName); |
| |
| if( bCopy && CopyStorage_Impl( rStorageName, rSubStorageName )) |
| nRet |= 2; |
| |
| return nRet; |
| } |
| |
| bool SvxImportMSVBasic::ImportForms_Impl(const String& rStorageName, |
| const String& rSubStorageName) |
| { |
| SvStorageRef xVBAStg(xRoot->OpenSotStorage(rStorageName, |
| STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL)); |
| if (!xVBAStg.Is() || xVBAStg->GetError()) |
| return false; |
| |
| std::vector<String> aUserForms; |
| SvStorageInfoList aContents; |
| xVBAStg->FillInfoList(&aContents); |
| for (sal_uInt16 nI = 0; nI < aContents.Count(); ++nI) |
| { |
| SvStorageInfo& rInfo = aContents.GetObject(nI); |
| if (!rInfo.IsStream() && rInfo.GetName() != rSubStorageName) |
| aUserForms.push_back(rInfo.GetName()); |
| } |
| |
| if (aUserForms.empty()) |
| return false; |
| |
| bool bRet = true; |
| try |
| { |
| Reference<XMultiServiceFactory> xSF(comphelper::getProcessServiceFactory()); |
| |
| Reference<XComponentContext> xContext; |
| Reference<XPropertySet> xProps(xSF, UNO_QUERY); |
| xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("DefaultContext")) ) >>= xContext; |
| |
| |
| Reference<XLibraryContainer> xLibContainer = rDocSh.GetDialogContainer(); |
| DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" ); |
| |
| String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); |
| Reference<XNameContainer> xLib; |
| if (xLibContainer.is()) |
| { |
| if( !xLibContainer->hasByName(aLibName)) |
| xLibContainer->createLibrary(aLibName); |
| |
| Any aLibAny = xLibContainer->getByName( aLibName ); |
| aLibAny >>= xLib; |
| } |
| |
| if(xLib.is()) |
| { |
| typedef std::vector<String>::iterator myIter; |
| myIter aEnd = aUserForms.end(); |
| for (myIter aIter = aUserForms.begin(); aIter != aEnd; ++aIter) |
| { |
| SvStorageRef xForm (xVBAStg->OpenSotStorage(*aIter, |
| STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL)); |
| |
| if (!xForm.Is() || xForm->GetError()) |
| continue; |
| |
| SvStorageStreamRef xFrame = xForm->OpenSotStream( |
| String( RTL_CONSTASCII_USTRINGPARAM( "\3VBFrame" ) ), |
| STREAM_STD_READ | STREAM_NOCREATE); |
| |
| if (!xFrame.Is() || xFrame->GetError()) |
| continue; |
| |
| SvStorageStreamRef xTypes = xForm->OpenSotStream( |
| String( 'f' ), STREAM_STD_READ | STREAM_NOCREATE); |
| |
| if (!xTypes.Is() || xTypes->GetError()) |
| continue; |
| |
| //<UserForm Name=""><VBFrame></VBFrame>" |
| String sData; |
| String sLine; |
| while(xFrame->ReadByteStringLine(sLine, RTL_TEXTENCODING_MS_1252)) |
| { |
| sData += sLine; |
| sData += '\n'; |
| } |
| sData.ConvertLineEnd(); |
| |
| Reference<container::XNameContainer> xDialog( |
| xSF->createInstance( |
| OUString(RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.awt.UnoControlDialogModel"))), uno::UNO_QUERY); |
| |
| OCX_UserForm aForm(xVBAStg, *aIter, *aIter, xDialog, xSF ); |
| aForm.pDocSh = &rDocSh; |
| sal_Bool bOk = aForm.Read(xTypes); |
| DBG_ASSERT(bOk, "Had unexpected content, not risking this module"); |
| if (bOk) |
| aForm.Import(xLib); |
| } |
| } |
| } |
| catch(...) |
| { |
| DBG_ERRORFILE( "SvxImportMSVBasic::ImportForms_Impl - any exception caught" ); |
| //bRet = false; |
| } |
| return bRet; |
| } |
| |
| |
| sal_Bool SvxImportMSVBasic::CopyStorage_Impl( const String& rStorageName, |
| const String& rSubStorageName) |
| { |
| sal_Bool bValidStg = sal_False; |
| { |
| SvStorageRef xVBAStg( xRoot->OpenSotStorage( rStorageName, |
| STREAM_READWRITE | STREAM_NOCREATE | |
| STREAM_SHARE_DENYALL )); |
| if( xVBAStg.Is() && !xVBAStg->GetError() ) |
| { |
| SvStorageRef xVBASubStg( xVBAStg->OpenSotStorage( rSubStorageName, |
| STREAM_READWRITE | STREAM_NOCREATE | |
| STREAM_SHARE_DENYALL )); |
| if( xVBASubStg.Is() && !xVBASubStg->GetError() ) |
| { |
| // then we will copy these storages into the (temporary) storage of the document |
| bValidStg = sal_True; |
| } |
| } |
| } |
| |
| if( bValidStg ) |
| { |
| String aDstStgName( GetMSBasicStorageName() ); |
| SotStorageRef xDst = SotStorage::OpenOLEStorage( rDocSh.GetStorage(), aDstStgName, STREAM_READWRITE | STREAM_TRUNC ); |
| SotStorageRef xSrc = xRoot->OpenSotStorage( rStorageName, STREAM_STD_READ ); |
| |
| // TODO/LATER: should we commit the storage? |
| xSrc->CopyTo( xDst ); |
| xDst->Commit(); |
| ErrCode nError = xDst->GetError(); |
| if ( nError == ERRCODE_NONE ) |
| nError = xSrc->GetError(); |
| if ( nError != ERRCODE_NONE ) |
| xRoot->SetError( nError ); |
| else |
| bValidStg = sal_True; |
| } |
| |
| return bValidStg; |
| } |
| |
| sal_Bool SvxImportMSVBasic::ImportCode_Impl( const String& rStorageName, |
| const String &rSubStorageName, |
| const std::vector< String >& codeNames, |
| sal_Bool bAsComment, sal_Bool bStripped ) |
| { |
| sal_Bool bRet = sal_False; |
| VBA_Impl aVBA( *xRoot, bAsComment ); |
| if( aVBA.Open(rStorageName,rSubStorageName) ) |
| { |
| Reference<XLibraryContainer> xLibContainer = rDocSh.GetBasicContainer(); |
| DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" ); |
| |
| /* Set library container to VBA compatibility mode. This will create |
| the VBA Globals object and store it in the Basic manager of the |
| document. */ |
| if( !bAsComment ) try |
| { |
| Reference< vba::XVBACompatibility >( xLibContainer, UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True ); |
| } |
| catch( Exception& ) |
| { |
| } |
| |
| sal_uInt16 nStreamCount = aVBA.GetNoStreams(); |
| Reference<XNameContainer> xLib; |
| String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) ); |
| if( xLibContainer.is() && nStreamCount ) |
| { |
| if( !xLibContainer->hasByName( aLibName ) ) |
| xLibContainer->createLibrary( aLibName ); |
| |
| Any aLibAny = xLibContainer->getByName( aLibName ); |
| aLibAny >>= xLib; |
| } |
| if( xLib.is() ) |
| { |
| Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY ); |
| Reference< container::XNameAccess > xVBACodeNamedObjectAccess; |
| if ( !bAsComment ) |
| { |
| Reference< XMultiServiceFactory> xSF(rDocSh.GetModel(), UNO_QUERY); |
| if ( xSF.is() ) |
| { |
| try |
| { |
| xVBACodeNamedObjectAccess.set( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), UNO_QUERY ); |
| } |
| catch( Exception& ) { } |
| } |
| } |
| typedef std::hash_map< rtl::OUString, uno::Any, ::rtl::OUStringHash, |
| ::std::equal_to< ::rtl::OUString > > NameModuleDataHash; |
| typedef std::hash_map< rtl::OUString, script::ModuleInfo, ::rtl::OUStringHash, |
| ::std::equal_to< ::rtl::OUString > > NameModuleInfoHash; |
| |
| NameModuleDataHash moduleData; |
| NameModuleInfoHash moduleInfos; |
| |
| for( sal_uInt16 i=0; i<nStreamCount;i++) |
| { |
| StringArray aDecompressed = aVBA.Decompress(i); |
| #if 0 |
| /* DR 2005-08-11 #124850# Do not filter special characters from module name. |
| Just put the original module name and let the Basic interpreter deal with |
| it. Needed for roundtrip... |
| */ |
| ByteString sByteBasic(aVBA.GetStreamName(i), |
| RTL_TEXTENCODING_ASCII_US, |
| (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_UNDERLINE| |
| RTL_UNICODETOTEXT_FLAGS_INVALID_UNDERLINE | |
| RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 | |
| RTL_UNICODETOTEXT_FLAGS_NOCOMPOSITE) |
| ); |
| |
| const String sBasicModule(sByteBasic, |
| RTL_TEXTENCODING_ASCII_US); |
| #else |
| const String &sBasicModule = aVBA.GetStreamName( i); |
| #endif |
| /* #117718# expose information regarding type of Module |
| * Class, Form or plain 'ould VBA module with a REM statment |
| * at the top of the module. Mapping of Module Name |
| * to type is performed in VBA_Impl::Open() method, |
| * ( msvbasic.cxx ) by examining the PROJECT stream. |
| */ |
| |
| // using name from aVBA.GetStreamName |
| // because the encoding of the same returned |
| // is the same as the encoding for the names |
| // that are keys in the map used by GetModuleType method |
| const String &sOrigVBAModName = aVBA.GetStreamName( i ); |
| ModType mType = aVBA.GetModuleType( sOrigVBAModName ); |
| |
| rtl::OUString sClassRem( RTL_CONSTASCII_USTRINGPARAM( "Rem Attribute VBA_ModuleType=" ) ); |
| |
| rtl::OUString modeTypeComment; |
| |
| switch( mType ) |
| { |
| case ModuleType::CLASS: |
| modeTypeComment = sClassRem + |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAClassModule\n" ) ); |
| break; |
| case ModuleType::FORM: |
| modeTypeComment = sClassRem + |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAFormModule\n" ) ); |
| break; |
| case ModuleType::DOCUMENT: |
| modeTypeComment = sClassRem + |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBADocumentModule\n" ) ); |
| break; |
| case ModuleType::NORMAL: |
| modeTypeComment = sClassRem + |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAModule\n" ) ); |
| break; |
| case ModuleType::UNKNOWN: |
| modeTypeComment = sClassRem + |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAUnknown\n" ) ); |
| break; |
| default: |
| DBG_ERRORFILE( "SvxImportMSVBasic::ImportCode_Impl - unknown module type" ); |
| break; |
| } |
| static ::rtl::OUString sClassOption( RTL_CONSTASCII_USTRINGPARAM( "Option ClassModule\n" ) ); |
| if ( !bAsComment ) |
| { |
| modeTypeComment += sVBAOption; |
| if ( mType == ModuleType::CLASS ) |
| modeTypeComment += sClassOption; |
| } |
| |
| String sModule(sBasicModule); //#i52606# no need to split Macros in 64KB blocks any more! |
| String sTemp; |
| if (bAsComment) |
| { |
| sTemp+=String(RTL_CONSTASCII_USTRINGPARAM( "Sub " )); |
| String sMunge(sModule); |
| //Streams can have spaces in them, but modulenames |
| //cannot ! |
| sMunge.SearchAndReplaceAll(' ','_'); |
| |
| sTemp += sMunge; |
| sTemp.AppendAscii("\n"); |
| }; |
| ::rtl::OUString aSource(sTemp); |
| |
| for(sal_uLong j=0;j<aDecompressed.GetSize();j++) |
| { |
| if (bStripped) |
| { |
| String *pStr = aDecompressed.Get(j); |
| bool bMac = true; |
| xub_StrLen nBegin = pStr->Search('\x0D'); |
| if ((STRING_NOTFOUND != nBegin) && (pStr->Len() > 1) && (pStr->GetChar(nBegin+1) == '\x0A')) |
| bMac = false; |
| |
| const char cLineEnd = bMac ? '\x0D' : '\x0A'; |
| const String sAttribute(String::CreateFromAscii( |
| bAsComment ? "Rem Attribute" : "Attribute")); |
| nBegin = 0; |
| while (STRING_NOTFOUND != (nBegin = pStr->Search(sAttribute, nBegin))) |
| { |
| if ((nBegin) && pStr->GetChar(nBegin-1) != cLineEnd) |
| { |
| // npower #i63766# Need to skip instances of Attribute |
| // that are NOT Attribute statements |
| nBegin = nBegin + sAttribute.Len(); |
| continue; |
| } |
| xub_StrLen nEnd = pStr->Search(cLineEnd ,nBegin); |
| // DR #i26521# catch STRING_NOTFOUND, will loop endless otherwise |
| if( nEnd == STRING_NOTFOUND ) |
| pStr->Erase(); |
| else |
| pStr->Erase(nBegin, (nEnd-nBegin)+1); |
| } |
| } |
| if( aDecompressed.Get(j)->Len() ) |
| { |
| aSource+=::rtl::OUString( *aDecompressed.Get(j) ); |
| } |
| |
| } |
| if (bAsComment) |
| { |
| aSource += rtl::OUString::createFromAscii("\nEnd Sub"); |
| } |
| ::rtl::OUString aModName( sModule ); |
| aSource = modeTypeComment + aSource; |
| |
| Any aSourceAny; |
| OSL_TRACE("erm %d", mType ); |
| aSourceAny <<= aSource; |
| if ( !bAsComment ) |
| { |
| OSL_TRACE("vba processing %d", mType ); |
| script::ModuleInfo sModuleInfo; |
| sModuleInfo.ModuleType = mType; |
| moduleInfos[ aModName ] = sModuleInfo; |
| } |
| moduleData[ aModName ] = aSourceAny; |
| } |
| // Hack for missing codenames ( only know to happen in excel but... ) |
| // only makes sense to do this if we are importing non-commented basic |
| if ( !bAsComment ) |
| { |
| for ( std::vector< String >::const_iterator it = codeNames.begin(); it != codeNames.end(); ++it ) |
| { |
| script::ModuleInfo sModuleInfo; |
| sModuleInfo.ModuleType = ModuleType::DOCUMENT; |
| moduleInfos[ *it ] = sModuleInfo; |
| moduleData[ *it ] = uno::makeAny( sVBAOption ); |
| } |
| } |
| NameModuleDataHash::iterator it_end = moduleData.end(); |
| for ( NameModuleDataHash::iterator it = moduleData.begin(); it != it_end; ++it ) |
| { |
| NameModuleInfoHash::iterator it_info = moduleInfos.find( it->first ); |
| if ( it_info != moduleInfos.end() ) |
| { |
| ModuleInfo& sModuleInfo = it_info->second; |
| if ( sModuleInfo.ModuleType == ModuleType::FORM ) |
| // hack, the module ( imo document basic should... |
| // know the XModel... ) but it doesn't |
| sModuleInfo.ModuleObject.set( rDocSh.GetModel(), UNO_QUERY ); |
| // document modules, we should be able to access |
| // the api objects at this time |
| else if ( sModuleInfo.ModuleType == ModuleType::DOCUMENT ) |
| { |
| if ( xVBACodeNamedObjectAccess.is() ) |
| { |
| try |
| { |
| sModuleInfo.ModuleObject.set( xVBACodeNamedObjectAccess->getByName( it->first ), uno::UNO_QUERY ); |
| OSL_TRACE("** Straight up creation of Module"); |
| } |
| catch(uno::Exception& e) |
| { |
| OSL_TRACE("Failed to get documument object for %s", rtl::OUStringToOString( it->first, RTL_TEXTENCODING_UTF8 ).getStr() ); |
| } |
| } |
| } |
| xVBAModuleInfo->insertModuleInfo( it->first, sModuleInfo ); |
| } |
| |
| if( xLib->hasByName( it->first ) ) |
| xLib->replaceByName( it->first, it->second ); |
| else |
| xLib->insertByName( it->first, it->second ); |
| } |
| bRet = true; |
| } |
| } |
| return bRet; |
| } |
| |
| /* vi:set tabstop=4 shiftwidth=4 expandtab: */ |