1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svxmsbas.cxx,v $
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>
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
;
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
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() );
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();
98 if( bImport
&& ImportCode_Impl( rStorageName
, rSubStorageName
, codeNames
,
99 bAsComment
, bStripped
))
103 ImportForms_Impl(rStorageName
, rSubStorageName
, !bAsComment
);
105 if( bCopy
&& CopyStorage_Impl( rStorageName
, rSubStorageName
))
111 bool SvxImportMSVBasic::ImportForms_Impl(const String
& rStorageName
,
112 const String
& rSubStorageName
, BOOL bVBAMode
)
115 // #FIXME VBA_Impl ( or some other new class ) should handle both userforms
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
;
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
;
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
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())
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())
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
);
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())
208 SvStorageStreamRef xFrame
= xForm
->OpenSotStream(
209 String( RTL_CONSTASCII_USTRINGPARAM( "\3VBFrame" ) ),
210 STREAM_STD_READ
| STREAM_NOCREATE
);
212 if (!xFrame
.Is() || xFrame
->GetError())
215 SvStorageStreamRef xTypes
= xForm
->OpenSotStream(
216 String( 'f' ), STREAM_STD_READ
| STREAM_NOCREATE
);
218 if (!xTypes
.Is() || xTypes
->GetError())
221 //<UserForm Name=""><VBFrame></VBFrame>"
224 while(xFrame
->ReadByteStringLine(sLine
, RTL_TEXTENCODING_MS_1252
))
229 sData
.ConvertLineEnd();
231 Reference
<container::XNameContainer
> xDialog(
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
238 // In non vba mode MAP_APPFONT is used ( same as normal basic
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");
257 DBG_ERRORFILE( "SvxImportMSVBasic::ImportForms_Impl - any exception caught" );
260 SFX_APP()->LeaveBasicCall();
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
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
);
295 ErrCode nError
= xDst
->GetError();
296 if ( nError
== ERRCODE_NONE
)
297 nError
= xSrc
->GetError();
298 if ( nError
!= ERRCODE_NONE
)
299 xRoot
->SetError( nError
);
307 BOOL
SvxImportMSVBasic::ImportCode_Impl( const String
& rStorageName
,
308 const String
&rSubStorageName
,
309 const std::vector
< String
>& codeNames
,
310 BOOL bAsComment
, BOOL bStripped
)
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
339 BOOL
SvxImportMSVBasic::ImportCode_Impl( VBA_Impl
& aVBA
, const std::vector
< String
>& codeNames
, BOOL bAsComment
, BOOL bStripped
)
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
);
364 Reference
< container::XNameAccess
> xVBACodeNamedObjectAccess
;
367 rDocSh
.GetBasicManager()->GetLib( aLibName
)->SetVBAEnabled( true );
368 Reference
< XMultiServiceFactory
> xSF(rDocSh
.GetModel(), UNO_QUERY
);
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
);
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
);
402 const String
&sBasicModule
= aVBA
.GetStreamName( i
);
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
;
424 case ModuleType::Class
:
425 modeTypeComment
= sClassRem
+
426 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAClassModule\n" ) );
428 case ModuleType::Form
:
429 modeTypeComment
= sClassRem
+
430 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAFormModule\n" ) );
432 case ModuleType::Document
:
433 modeTypeComment
= sClassRem
+
434 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBADocumentModule\n" ) );
436 case ModuleType::Normal
:
437 modeTypeComment
= sClassRem
+
438 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAModule\n" ) );
440 case ModuleType::Unknown
:
441 modeTypeComment
= sClassRem
+
442 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAUnknown\n" ) );
445 DBG_ERRORFILE( "SvxImportMSVBasic::ImportCode_Impl - unknown module type" );
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!
461 sTemp
+=String(RTL_CONSTASCII_USTRINGPARAM( "Sub " ));
462 String
sMunge(sModule
);
463 //Streams can have spaces in them, but modulenames
465 sMunge
.SearchAndReplaceAll(' ','_');
468 sTemp
.AppendAscii("\n");
470 ::rtl::OUString
aSource(sTemp
);
472 for(ULONG j
=0;j
<aDecompressed
.GetSize();j
++)
476 String
*pStr
= aDecompressed
.Get(j
);
478 xub_StrLen nBegin
= pStr
->Search('\x0D');
479 if ((STRING_NOTFOUND
!= nBegin
) && (pStr
->Len() > 1) && (pStr
->GetChar(nBegin
+1) == '\x0A'))
482 const char cLineEnd
= bMac
? '\x0D' : '\x0A';
483 const String
sAttribute(String::CreateFromAscii(
484 bAsComment
? "Rem Attribute" : "Attribute"));
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();
495 xub_StrLen nEnd
= pStr
->Search(cLineEnd
,nBegin
);
496 // DR #i26521# catch STRING_NOTFOUND, will loop endless otherwise
497 if( nEnd
== STRING_NOTFOUND
)
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
) );
516 aSource
+= rtl::OUString::createFromAscii("\nEnd Sub");
518 ::rtl::OUString
aModName( sModule
);
519 aSource
= modeTypeComment
+ aSource
;
522 OSL_TRACE("erm %d", mType
);
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
;
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
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
);
584 xLib
->insertByName( it
->first
, it
->second
);
590 SFX_APP()->LeaveBasicCall();
594 /* vi:set tabstop=4 shiftwidth=4 expandtab: */