Update to m13
[ooovba.git] / svx / source / msfilter / svxmsbas.cxx
blob0ebc0745c99dea743cd541d8737f07ffe2f2873d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svxmsbas.cxx,v $
10 * $Revision: 1.24 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
35 #include <tools/debug.hxx>
36 #include <sfx2/objsh.hxx>
37 #include <sfx2/app.hxx>
38 #include <basic/basmgr.hxx>
39 #include <basic/sbmod.hxx>
40 #include <svxerr.hxx>
41 #include <svxmsbas.hxx>
42 #include <msvbasic.hxx>
43 #include <svx/msocximex.hxx>
44 #include <sot/storinfo.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/awt/Size.hpp>
48 #include <com/sun/star/awt/XControlModel.hpp>
49 using namespace com::sun::star::beans;
50 using namespace com::sun::star::io;
51 using namespace com::sun::star::awt;
52 #include <comphelper/storagehelper.hxx>
54 #include <com/sun/star/container/XNameContainer.hpp>
55 #include <com/sun/star/script/XLibraryContainer.hpp>
56 #include <com/sun/star/script/ModuleInfo.hpp>
57 using namespace com::sun::star::container;
58 using namespace com::sun::star::script;
59 using namespace com::sun::star::uno;
60 using namespace com::sun::star::lang;
61 using namespace com::sun::star;
63 using rtl::OUString;
65 static ::rtl::OUString sVBAOption( RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n" ) );
67 void SvxImportMSVBasic::extractAttribute( const String& rAttribute, const String& rModName )
69 // format of the attribute we are interested in is
70 // Attribute VB_Control = "ControlName", intString, MSForms, ControlTypeAsString
71 // e.g.
72 // Attribute VB_Control = "CommandButton1, 201, 19, MSForms, CommandButton"
73 String sControlAttribute( RTL_CONSTASCII_USTRINGPARAM("Attribute VB_Control = \"") );
74 if ( rAttribute.Search( sControlAttribute ) != STRING_NOTFOUND )
76 String sRest = rAttribute.Copy( sControlAttribute.Len() );
77 xub_StrLen nPos = 0;
78 String sCntrlName = sRest.GetToken( 0, ',', nPos );
80 sal_Int32 nCntrlId = sRest.GetToken( 0, ',', nPos).ToInt32();
81 m_ModuleNameToObjIdHash[ rModName ][ nCntrlId ] = sCntrlName;
84 int SvxImportMSVBasic::Import( const String& rStorageName,
85 const String &rSubStorageName,
86 BOOL bAsComment, BOOL bStripped )
88 std::vector< String > codeNames;
89 return Import( rStorageName, rSubStorageName, codeNames, bAsComment, bStripped );
91 int SvxImportMSVBasic::Import( const String& rStorageName,
92 const String &rSubStorageName,
93 const std::vector< String >& codeNames,
94 BOOL bAsComment, BOOL bStripped )
96 msProjectName = rtl::OUString();
97 int nRet = 0;
98 if( bImport && ImportCode_Impl( rStorageName, rSubStorageName, codeNames,
99 bAsComment, bStripped ))
100 nRet |= 1;
102 if (bImport)
103 ImportForms_Impl(rStorageName, rSubStorageName, !bAsComment);
105 if( bCopy && CopyStorage_Impl( rStorageName, rSubStorageName ))
106 nRet |= 2;
108 return nRet;
111 bool SvxImportMSVBasic::ImportForms_Impl(const String& rStorageName,
112 const String& rSubStorageName, BOOL bVBAMode )
114 BOOL bRet = FALSE;
115 // #FIXME VBA_Impl ( or some other new class ) should handle both userforms
116 // and code
117 VBA_Impl aVBA( *xRoot, TRUE );
118 // This call is a waste we read the source ( again ) only to get the refereneces
119 // *AGAIN*, we really need to rewrite all of this
120 aVBA.Open( rStorageName, rSubStorageName );
122 bRet = ImportForms_Impl( aVBA, rStorageName, rSubStorageName, bVBAMode );
123 std::vector<rtl::OUString> sProjectRefs = aVBA.ProjectReferences();
125 for ( std::vector<rtl::OUString>::iterator it = sProjectRefs.begin(); it != sProjectRefs.end(); ++it )
127 rtl::OUString sFileName = *it;
128 #ifndef WIN
129 #ifdef DEBUG
130 // hacky test code to read referenced projects on linux
131 sal_Int32 nPos = (*it).lastIndexOf('\\');
132 sFileName = (*it).copy( nPos + 1 );
133 sFileName = rtl::OUString::createFromAscii("~/Documents/") + sFileName;
134 #endif
135 #endif
136 SotStorageRef rRoot = new SotStorage( sFileName, STREAM_STD_READWRITE, STORAGE_TRANSACTED );
137 VBA_Impl refVBA( *rRoot, TRUE );
138 refVBA.Open( rStorageName, rSubStorageName );
139 // The return from ImportForms doesn't indicate and error ( it could )
140 // but also it just means no userforms were imported
141 if ( ImportForms_Impl( refVBA, rStorageName, rSubStorageName, bVBAMode ) )
142 bRet = true; // mark that at least on userform was imported
144 return bRet;
147 bool SvxImportMSVBasic::ImportForms_Impl( VBA_Impl& rVBA, const String& rStorageName, const String& rSubStorageName, BOOL bVBAMode )
149 SvStorageRef xVBAStg(rVBA.GetStorage()->OpenSotStorage(rStorageName,
150 STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL));
151 if (!xVBAStg.Is() || xVBAStg->GetError())
152 return false;
154 std::vector<String> aUserForms;
155 SvStorageInfoList aContents;
156 xVBAStg->FillInfoList(&aContents);
157 for (USHORT nI = 0; nI < aContents.Count(); ++nI)
159 SvStorageInfo& rInfo = aContents.GetObject(nI);
160 if (!rInfo.IsStream() && rInfo.GetName() != rSubStorageName)
161 aUserForms.push_back(rInfo.GetName());
164 if (aUserForms.empty())
165 return false;
167 bool bRet = true;
168 SFX_APP()->EnterBasicCall();
171 Reference<XMultiServiceFactory> xSF(comphelper::getProcessServiceFactory());
173 Reference<XComponentContext> xContext;
174 Reference<XPropertySet> xProps(xSF, UNO_QUERY);
175 xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("DefaultContext")) ) >>= xContext;
178 Reference<XLibraryContainer> xLibContainer = rDocSh.GetDialogContainer();
179 DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
181 String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
183 if (rVBA.ProjectName().getLength() )
184 aLibName = rVBA.ProjectName();
185 OSL_TRACE( "userformage lib name %s", rtl::OUStringToOString( aLibName, RTL_TEXTENCODING_UTF8 ).getStr() );
186 Reference<XNameContainer> xLib;
187 if (xLibContainer.is())
189 if( !xLibContainer->hasByName(aLibName))
190 xLibContainer->createLibrary(aLibName);
192 Any aLibAny = xLibContainer->getByName( aLibName );
193 aLibAny >>= xLib;
196 if(xLib.is())
198 typedef std::vector<String>::iterator myIter;
199 myIter aEnd = aUserForms.end();
200 for (myIter aIter = aUserForms.begin(); aIter != aEnd; ++aIter)
202 SvStorageRef xForm (xVBAStg->OpenSotStorage(*aIter,
203 STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL));
205 if (!xForm.Is() || xForm->GetError())
206 continue;
208 SvStorageStreamRef xFrame = xForm->OpenSotStream(
209 String( RTL_CONSTASCII_USTRINGPARAM( "\3VBFrame" ) ),
210 STREAM_STD_READ | STREAM_NOCREATE);
212 if (!xFrame.Is() || xFrame->GetError())
213 continue;
215 SvStorageStreamRef xTypes = xForm->OpenSotStream(
216 String( 'f' ), STREAM_STD_READ | STREAM_NOCREATE);
218 if (!xTypes.Is() || xTypes->GetError())
219 continue;
221 //<UserForm Name=""><VBFrame></VBFrame>"
222 String sData;
223 String sLine;
224 while(xFrame->ReadByteStringLine(sLine, RTL_TEXTENCODING_MS_1252))
226 sData += sLine;
227 sData += '\n';
229 sData.ConvertLineEnd();
231 Reference<container::XNameContainer> xDialog(
232 xSF->createInstance(
233 OUString(RTL_CONSTASCII_USTRINGPARAM(
234 "com.sun.star.awt.UnoControlDialogModel"))), uno::UNO_QUERY);
235 // #FIXME HACK - mark the Model with the VBA mode
236 // In vba mode the imported userform uses 100th mm as units
237 // or geometry
238 // In non vba mode MAP_APPFONT is used ( same as normal basic
239 // dialogs
240 if ( bVBAMode )
242 Reference<XPropertySet> xDlgProps(xDialog, UNO_QUERY);
243 if ( xDlgProps.is() )
244 xDlgProps->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("VBAForm") ), uno::makeAny( sal_True ) );
246 OCX_UserForm aForm(xVBAStg, *aIter, *aIter, xDialog, xSF );
247 aForm.pDocSh = &rDocSh;
248 sal_Bool bOk = aForm.Read(xTypes);
249 DBG_ASSERT(bOk, "Had unexpected content, not risking this module");
250 if (bOk)
251 aForm.Import(xLib);
255 catch(...)
257 DBG_ERRORFILE( "SvxImportMSVBasic::ImportForms_Impl - any exception caught" );
258 //bRet = false;
260 SFX_APP()->LeaveBasicCall();
261 return bRet;
265 BOOL SvxImportMSVBasic::CopyStorage_Impl( const String& rStorageName,
266 const String& rSubStorageName)
268 BOOL bValidStg = FALSE;
270 SvStorageRef xVBAStg( xRoot->OpenSotStorage( rStorageName,
271 STREAM_READWRITE | STREAM_NOCREATE |
272 STREAM_SHARE_DENYALL ));
273 if( xVBAStg.Is() && !xVBAStg->GetError() )
275 SvStorageRef xVBASubStg( xVBAStg->OpenSotStorage( rSubStorageName,
276 STREAM_READWRITE | STREAM_NOCREATE |
277 STREAM_SHARE_DENYALL ));
278 if( xVBASubStg.Is() && !xVBASubStg->GetError() )
280 // then we will copy these storages into the (temporary) storage of the document
281 bValidStg = TRUE;
286 if( bValidStg )
288 String aDstStgName( GetMSBasicStorageName() );
289 SotStorageRef xDst = SotStorage::OpenOLEStorage( rDocSh.GetStorage(), aDstStgName, STREAM_READWRITE | STREAM_TRUNC );
290 SotStorageRef xSrc = xRoot->OpenSotStorage( rStorageName, STREAM_STD_READ );
292 // TODO/LATER: should we commit the storage?
293 xSrc->CopyTo( xDst );
294 xDst->Commit();
295 ErrCode nError = xDst->GetError();
296 if ( nError == ERRCODE_NONE )
297 nError = xSrc->GetError();
298 if ( nError != ERRCODE_NONE )
299 xRoot->SetError( nError );
300 else
301 bValidStg = TRUE;
304 return bValidStg;
307 BOOL SvxImportMSVBasic::ImportCode_Impl( const String& rStorageName,
308 const String &rSubStorageName,
309 const std::vector< String >& codeNames,
310 BOOL bAsComment, BOOL bStripped )
312 BOOL bRet = FALSE;
313 VBA_Impl aVBA( *xRoot, bAsComment );
315 if( aVBA.Open(rStorageName,rSubStorageName) )
317 msProjectName = aVBA.ProjectName();
319 if ( msProjectName.getLength() )
320 rDocSh.GetBasicManager()->SetName( msProjectName ); // set name of Project
322 bRet = ImportCode_Impl( aVBA, codeNames, bAsComment, bStripped );
323 std::vector<rtl::OUString> sProjectRefs = aVBA.ProjectReferences();
325 for ( std::vector<rtl::OUString>::iterator it = sProjectRefs.begin(); it != sProjectRefs.end(); ++it )
327 rtl::OUString sFileName = *it;
328 OSL_TRACE("referenced project %s ", rtl::OUStringToOString( sFileName, RTL_TEXTENCODING_UTF8 ).getStr() );
329 SotStorageRef rRoot = new SotStorage( sFileName, STREAM_STD_READWRITE, STORAGE_TRANSACTED );
330 VBA_Impl refVBA( *rRoot, bAsComment );
331 std::vector< String > codeNamesNone;
332 if( refVBA.Open(rStorageName,rSubStorageName) && ImportCode_Impl( refVBA, codeNamesNone, bAsComment, bStripped ) )
333 bRet = TRUE; // mark that some code was imported
336 return bRet;
339 BOOL SvxImportMSVBasic::ImportCode_Impl( VBA_Impl& aVBA, const std::vector< String >& codeNames, BOOL bAsComment, BOOL bStripped )
341 BOOL bRet = FALSE;
342 SFX_APP()->EnterBasicCall();
343 Reference<XLibraryContainer> xLibContainer = rDocSh.GetBasicContainer();
344 DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
346 UINT16 nStreamCount = aVBA.GetNoStreams();
347 Reference<XNameContainer> xLib;
349 String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
351 if( xLibContainer.is() && nStreamCount )
353 if ( aVBA.ProjectName().getLength() )
354 aLibName = aVBA.ProjectName();
356 if( !xLibContainer->hasByName( aLibName ) )
357 xLibContainer->createLibrary( aLibName );
359 Any aLibAny = xLibContainer->getByName( aLibName );
360 aLibAny >>= xLib;
362 if( xLib.is() )
364 Reference< container::XNameAccess > xVBACodeNamedObjectAccess;
365 if ( !bAsComment )
367 rDocSh.GetBasicManager()->GetLib( aLibName )->SetVBAEnabled( true );
368 Reference< XMultiServiceFactory> xSF(rDocSh.GetModel(), UNO_QUERY);
369 if ( xSF.is() )
373 xVBACodeNamedObjectAccess.set( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), UNO_QUERY );
375 catch( Exception& ) { }
378 typedef std::hash_map< rtl::OUString, uno::Any, ::rtl::OUStringHash,
379 ::std::equal_to< ::rtl::OUString > > NameModuleDataHash;
381 NameModuleDataHash moduleData;
383 for( UINT16 i=0; i<nStreamCount;i++)
385 StringArray aDecompressed = aVBA.Decompress(i);
386 #if 0
387 /* DR 2005-08-11 #124850# Do not filter special characters from module name.
388 Just put the original module name and let the Basic interpreter deal with
389 it. Needed for roundtrip...
391 ByteString sByteBasic(aVBA.GetStreamName(i),
392 RTL_TEXTENCODING_ASCII_US,
393 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_UNDERLINE|
394 RTL_UNICODETOTEXT_FLAGS_INVALID_UNDERLINE |
395 RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 |
396 RTL_UNICODETOTEXT_FLAGS_NOCOMPOSITE)
399 const String sBasicModule(sByteBasic,
400 RTL_TEXTENCODING_ASCII_US);
401 #else
402 const String &sBasicModule = aVBA.GetStreamName( i);
403 #endif
404 /* #117718# expose information regarding type of Module
405 * Class, Form or plain 'ould VBA module with a REM statment
406 * at the top of the module. Mapping of Module Name
407 * to type is performed in VBA_Impl::Open() method,
408 * ( msvbasic.cxx ) by examining the PROJECT stream.
411 // using name from aVBA.GetStreamName
412 // because the encoding of the same returned
413 // is the same as the encoding for the names
414 // that are keys in the map used by GetModuleType method
415 const String &sOrigVBAModName = aVBA.GetStreamName( i );
416 ModType mType = aVBA.GetModuleType( sOrigVBAModName );
418 rtl::OUString sClassRem( RTL_CONSTASCII_USTRINGPARAM( "Rem Attribute VBA_ModuleType=" ) );
420 rtl::OUString modeTypeComment;
422 switch( mType )
424 case ModuleType::Class:
425 modeTypeComment = sClassRem +
426 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAClassModule\n" ) );
427 break;
428 case ModuleType::Form:
429 modeTypeComment = sClassRem +
430 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAFormModule\n" ) );
431 break;
432 case ModuleType::Document:
433 modeTypeComment = sClassRem +
434 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBADocumentModule\n" ) );
435 break;
436 case ModuleType::Normal:
437 modeTypeComment = sClassRem +
438 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAModule\n" ) );
439 break;
440 case ModuleType::Unknown:
441 modeTypeComment = sClassRem +
442 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAUnknown\n" ) );
443 break;
444 default:
445 DBG_ERRORFILE( "SvxImportMSVBasic::ImportCode_Impl - unknown module type" );
446 break;
448 static ::rtl::OUString sClassOption( RTL_CONSTASCII_USTRINGPARAM( "Option ClassModule\n" ) );
449 if ( !bAsComment /*&& !rDocSh.GetBasic()->isVBAEnabled() */)
451 modeTypeComment = modeTypeComment + sVBAOption;
452 if ( mType == ModuleType::Class )
453 modeTypeComment = modeTypeComment + sClassOption;
457 String sModule(sBasicModule); //#i52606# no need to split Macros in 64KB blocks any more!
458 String sTemp;
459 if (bAsComment)
461 sTemp+=String(RTL_CONSTASCII_USTRINGPARAM( "Sub " ));
462 String sMunge(sModule);
463 //Streams can have spaces in them, but modulenames
464 //cannot !
465 sMunge.SearchAndReplaceAll(' ','_');
467 sTemp += sMunge;
468 sTemp.AppendAscii("\n");
470 ::rtl::OUString aSource(sTemp);
472 for(ULONG j=0;j<aDecompressed.GetSize();j++)
474 if (bStripped)
476 String *pStr = aDecompressed.Get(j);
477 bool bMac = true;
478 xub_StrLen nBegin = pStr->Search('\x0D');
479 if ((STRING_NOTFOUND != nBegin) && (pStr->Len() > 1) && (pStr->GetChar(nBegin+1) == '\x0A'))
480 bMac = false;
482 const char cLineEnd = bMac ? '\x0D' : '\x0A';
483 const String sAttribute(String::CreateFromAscii(
484 bAsComment ? "Rem Attribute" : "Attribute"));
485 nBegin = 0;
486 while (STRING_NOTFOUND != (nBegin = pStr->Search(sAttribute, nBegin)))
488 if ((nBegin) && pStr->GetChar(nBegin-1) != cLineEnd)
490 // npower #i63766# Need to skip instances of Attribute
491 // that are NOT Attribute statements
492 nBegin = nBegin + sAttribute.Len();
493 continue;
495 xub_StrLen nEnd = pStr->Search(cLineEnd ,nBegin);
496 // DR #i26521# catch STRING_NOTFOUND, will loop endless otherwise
497 if( nEnd == STRING_NOTFOUND )
498 pStr->Erase();
499 else
501 //OSL_TRACE("Erase %s", rtl::OUStringToOString(*pStr, RTL_TEXTENCODING_UTF8 ).getStr() );
502 String sAttr= pStr->Copy( nBegin, (nEnd-nBegin)+1);
503 extractAttribute( sAttr, sModule );
504 pStr->Erase(nBegin, (nEnd-nBegin)+1);
508 if( aDecompressed.Get(j)->Len() )
510 aSource+=::rtl::OUString( *aDecompressed.Get(j) );
514 if (bAsComment)
516 aSource += rtl::OUString::createFromAscii("\nEnd Sub");
518 ::rtl::OUString aModName( sModule );
519 aSource = modeTypeComment + aSource;
521 Any aSourceAny;
522 OSL_TRACE("erm %d", mType );
523 if ( !bAsComment )
525 OSL_TRACE("vba processing %d", mType );
526 script::ModuleInfo sModuleInfo;
527 sModuleInfo.ModuleName = aModName;
528 sModuleInfo.ModuleSource = aSource;
529 sModuleInfo.ModuleType = mType;
530 aSourceAny <<= sModuleInfo;
532 else
533 aSourceAny <<= aSource;
534 moduleData[ aModName ] = aSourceAny;
537 // Hack for missing codenames ( only know to happen in excel but... )
538 // only makes sense to do this if we are importing non-commented basic
539 if ( !bAsComment )
541 for ( std::vector< String >::const_iterator it = codeNames.begin(); it != codeNames.end(); ++it )
543 script::ModuleInfo sModuleInfo;
544 sModuleInfo.ModuleName = *it;
545 sModuleInfo.ModuleType = ModuleType::Document ;
546 sModuleInfo.ModuleSource = sVBAOption;
547 moduleData[ *it ] = uno::makeAny( sModuleInfo );
550 NameModuleDataHash::iterator it_end = moduleData.end();
551 for ( NameModuleDataHash::iterator it = moduleData.begin(); it != it_end; ++it )
553 script::ModuleInfo sModuleInfo;
554 if ( it->second >>=sModuleInfo )
557 if ( sModuleInfo.ModuleType == ModuleType::Form )
558 // hack, the module ( imo document basic should...
559 // know the XModel... ) but it doesn't
560 sModuleInfo.ModuleObject.set( rDocSh.GetModel(), UNO_QUERY );
561 // document modules, we should be able to access
562 // the api objects at this time
563 else if ( sModuleInfo.ModuleType == ModuleType::Document )
565 if ( xVBACodeNamedObjectAccess.is() )
569 sModuleInfo.ModuleObject.set( xVBACodeNamedObjectAccess->getByName( sModuleInfo.ModuleName ), uno::UNO_QUERY );
570 OSL_TRACE("** Straight up creation of Module");
572 catch(uno::Exception& e)
574 OSL_TRACE("Failed to get documument object for %s", rtl::OUStringToOString( sModuleInfo.ModuleName, RTL_TEXTENCODING_UTF8 ).getStr() );
578 it->second = uno::makeAny( sModuleInfo );
581 if( xLib->hasByName( it->first ) )
582 xLib->replaceByName( it->first, it->second );
583 else
584 xLib->insertByName( it->first, it->second );
585 bRet = true;
589 if( bRet )
590 SFX_APP()->LeaveBasicCall();
591 return bRet;
594 /* vi:set tabstop=4 shiftwidth=4 expandtab: */