xref: /AOO42X/main/filter/source/msfilter/svxmsbas.cxx (revision 6532831cf2dffbd9b8c04776b17db4052ccb95df) !
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 
27 #include <tools/debug.hxx>
28 #include <sfx2/objsh.hxx>
29 #include <sfx2/app.hxx>
30 #include <basic/basmgr.hxx>
31 #include <basic/sbmod.hxx>
32 #include <svx/svxerr.hxx>
33 #include <filter/msfilter/svxmsbas.hxx>
34 #include <msvbasic.hxx>
35 #include <filter/msfilter/msocximex.hxx>
36 #include <sot/storinfo.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/awt/Size.hpp>
40 #include <com/sun/star/awt/XControlModel.hpp>
41 using namespace com::sun::star::beans;
42 using namespace com::sun::star::io;
43 using namespace com::sun::star::awt;
44 #include <comphelper/storagehelper.hxx>
45 
46 #include <com/sun/star/container/XNameContainer.hpp>
47 #include <com/sun/star/script/XLibraryContainer.hpp>
48 #include <com/sun/star/script/ModuleInfo.hpp>
49 #include <com/sun/star/script/ModuleType.hpp>
50 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
51 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
52 
53 using namespace com::sun::star::container;
54 using namespace com::sun::star::script;
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::lang;
57 using namespace com::sun::star;
58 
59 using rtl::OUString;
60 
61 static ::rtl::OUString sVBAOption( RTL_CONSTASCII_USTRINGPARAM( "Option VBASupport 1\n" ) );
62 
Import(const String & rStorageName,const String & rSubStorageName,sal_Bool bAsComment,sal_Bool bStripped)63 int SvxImportMSVBasic::Import( const String& rStorageName,
64                                const String &rSubStorageName,
65                                sal_Bool bAsComment, sal_Bool bStripped )
66 {
67     std::vector< String > codeNames;
68     return Import( rStorageName, rSubStorageName, codeNames, bAsComment, bStripped );
69 }
70 
Import(const String & rStorageName,const String & rSubStorageName,const std::vector<String> & codeNames,sal_Bool bAsComment,sal_Bool bStripped)71 int SvxImportMSVBasic::Import( const String& rStorageName,
72                                 const String &rSubStorageName,
73                                 const std::vector< String >& codeNames,
74                                 sal_Bool bAsComment, sal_Bool bStripped )
75 {
76     int nRet = 0;
77     if( bImport && ImportCode_Impl( rStorageName, rSubStorageName, codeNames,
78                                     bAsComment, bStripped ))
79         nRet |= 1;
80 
81     if (bImport)
82         ImportForms_Impl(rStorageName, rSubStorageName);
83 
84     if( bCopy && CopyStorage_Impl( rStorageName, rSubStorageName ))
85         nRet |= 2;
86 
87     return nRet;
88 }
89 
ImportForms_Impl(const String & rStorageName,const String & rSubStorageName)90 bool SvxImportMSVBasic::ImportForms_Impl(const String& rStorageName,
91     const String& rSubStorageName)
92 {
93     SvStorageRef xVBAStg(xRoot->OpenSotStorage(rStorageName,
94         STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL));
95     if (!xVBAStg.Is() || xVBAStg->GetError())
96         return false;
97 
98     std::vector<String> aUserForms;
99     SvStorageInfoList aContents;
100     xVBAStg->FillInfoList(&aContents);
101     for (sal_uInt16 nI = 0; nI < aContents.Count(); ++nI)
102     {
103         SvStorageInfo& rInfo = aContents.GetObject(nI);
104         if (!rInfo.IsStream() && rInfo.GetName() != rSubStorageName)
105             aUserForms.push_back(rInfo.GetName());
106     }
107 
108     if (aUserForms.empty())
109         return false;
110 
111     bool bRet = true;
112     try
113     {
114         Reference<XMultiServiceFactory> xSF(comphelper::getProcessServiceFactory());
115 
116         Reference<XComponentContext> xContext;
117         Reference<XPropertySet> xProps(xSF, UNO_QUERY);
118         xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("DefaultContext")) ) >>= xContext;
119 
120 
121         Reference<XLibraryContainer> xLibContainer = rDocSh.GetDialogContainer();
122         DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
123 
124         String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
125         Reference<XNameContainer> xLib;
126         if (xLibContainer.is())
127         {
128             if( !xLibContainer->hasByName(aLibName))
129                 xLibContainer->createLibrary(aLibName);
130 
131             Any aLibAny = xLibContainer->getByName( aLibName );
132             aLibAny >>= xLib;
133         }
134 
135         if(xLib.is())
136         {
137             typedef std::vector<String>::iterator myIter;
138             myIter aEnd = aUserForms.end();
139             for (myIter aIter = aUserForms.begin(); aIter != aEnd; ++aIter)
140             {
141                 SvStorageRef xForm (xVBAStg->OpenSotStorage(*aIter,
142                     STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYALL));
143 
144                 if (!xForm.Is() || xForm->GetError())
145                     continue;
146 
147                 SvStorageStreamRef xFrame = xForm->OpenSotStream(
148                     String( RTL_CONSTASCII_USTRINGPARAM( "\3VBFrame" ) ),
149                     STREAM_STD_READ | STREAM_NOCREATE);
150 
151                 if (!xFrame.Is() || xFrame->GetError())
152                     continue;
153 
154                 SvStorageStreamRef xTypes = xForm->OpenSotStream(
155                     String( 'f' ), STREAM_STD_READ | STREAM_NOCREATE);
156 
157                 if (!xTypes.Is() || xTypes->GetError())
158                     continue;
159 
160                 //<UserForm Name=""><VBFrame></VBFrame>"
161                 String sData;
162                 String sLine;
163                 while(xFrame->ReadByteStringLine(sLine, RTL_TEXTENCODING_MS_1252))
164                 {
165                     sData += sLine;
166                     sData += '\n';
167                 }
168                 sData.ConvertLineEnd();
169 
170                 Reference<container::XNameContainer> xDialog(
171                     xSF->createInstance(
172                         OUString(RTL_CONSTASCII_USTRINGPARAM(
173                             "com.sun.star.awt.UnoControlDialogModel"))), uno::UNO_QUERY);
174 
175                 OCX_UserForm aForm(xVBAStg, *aIter, *aIter, xDialog, xSF );
176                 aForm.pDocSh = &rDocSh;
177                 sal_Bool bOk = aForm.Read(xTypes);
178                 DBG_ASSERT(bOk, "Had unexpected content, not risking this module");
179                 if (bOk)
180                     aForm.Import(xLib);
181             }
182         }
183     }
184     catch(...)
185     {
186         DBG_ERRORFILE( "SvxImportMSVBasic::ImportForms_Impl - any exception caught" );
187         //bRet = false;
188     }
189     return bRet;
190 }
191 
192 
CopyStorage_Impl(const String & rStorageName,const String & rSubStorageName)193 sal_Bool SvxImportMSVBasic::CopyStorage_Impl( const String& rStorageName,
194                                         const String& rSubStorageName)
195 {
196     sal_Bool bValidStg = sal_False;
197     {
198         SvStorageRef xVBAStg( xRoot->OpenSotStorage( rStorageName,
199                                     STREAM_READWRITE | STREAM_NOCREATE |
200                                     STREAM_SHARE_DENYALL ));
201         if( xVBAStg.Is() && !xVBAStg->GetError() )
202         {
203             SvStorageRef xVBASubStg( xVBAStg->OpenSotStorage( rSubStorageName,
204                                     STREAM_READWRITE | STREAM_NOCREATE |
205                                     STREAM_SHARE_DENYALL ));
206             if( xVBASubStg.Is() && !xVBASubStg->GetError() )
207             {
208                 // then we will copy these storages into the (temporary) storage of the document
209                 bValidStg = sal_True;
210             }
211         }
212     }
213 
214     if( bValidStg )
215     {
216         String aDstStgName( GetMSBasicStorageName() );
217         SotStorageRef xDst = SotStorage::OpenOLEStorage( rDocSh.GetStorage(), aDstStgName, STREAM_READWRITE | STREAM_TRUNC );
218         SotStorageRef xSrc = xRoot->OpenSotStorage( rStorageName, STREAM_STD_READ );
219 
220         // TODO/LATER: should we commit the storage?
221         xSrc->CopyTo( xDst );
222         xDst->Commit();
223         ErrCode nError = xDst->GetError();
224         if ( nError == ERRCODE_NONE )
225             nError = xSrc->GetError();
226         if ( nError != ERRCODE_NONE )
227             xRoot->SetError( nError );
228         else
229             bValidStg = sal_True;
230     }
231 
232     return bValidStg;
233 }
234 
ImportCode_Impl(const String & rStorageName,const String & rSubStorageName,const std::vector<String> & codeNames,sal_Bool bAsComment,sal_Bool bStripped)235 sal_Bool SvxImportMSVBasic::ImportCode_Impl( const String& rStorageName,
236                                         const String &rSubStorageName,
237                                         const std::vector< String >& codeNames,
238                                         sal_Bool bAsComment, sal_Bool bStripped )
239 {
240     sal_Bool bRet = sal_False;
241     VBA_Impl aVBA( *xRoot, bAsComment );
242     if( aVBA.Open(rStorageName,rSubStorageName) )
243     {
244         Reference<XLibraryContainer> xLibContainer = rDocSh.GetBasicContainer();
245         DBG_ASSERT( xLibContainer.is(), "No BasicContainer!" );
246 
247         /*  Set library container to VBA compatibility mode. This will create
248             the VBA Globals object and store it in the Basic manager of the
249             document. */
250         if( !bAsComment ) try
251         {
252             Reference< vba::XVBACompatibility >( xLibContainer, UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True );
253         }
254         catch( Exception& )
255         {
256         }
257 
258         sal_uInt16 nStreamCount = aVBA.GetNoStreams();
259         Reference<XNameContainer> xLib;
260         String aLibName( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
261         if( xLibContainer.is() && nStreamCount )
262         {
263             if( !xLibContainer->hasByName( aLibName ) )
264                 xLibContainer->createLibrary( aLibName );
265 
266             Any aLibAny = xLibContainer->getByName( aLibName );
267             aLibAny >>= xLib;
268         }
269         if( xLib.is() )
270         {
271             Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
272             Reference< container::XNameAccess > xVBACodeNamedObjectAccess;
273             if ( !bAsComment )
274             {
275                 Reference< XMultiServiceFactory> xSF(rDocSh.GetModel(), UNO_QUERY);
276                 if ( xSF.is() )
277                 {
278                     try
279                     {
280                         xVBACodeNamedObjectAccess.set( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAObjectModuleObjectProvider"))), UNO_QUERY );
281                     }
282                     catch( Exception& ) { }
283                 }
284             }
285             typedef  std::hash_map< rtl::OUString, uno::Any, ::rtl::OUStringHash,
286 ::std::equal_to< ::rtl::OUString > > NameModuleDataHash;
287             typedef  std::hash_map< rtl::OUString, script::ModuleInfo, ::rtl::OUStringHash,
288 ::std::equal_to< ::rtl::OUString > > NameModuleInfoHash;
289 
290             NameModuleDataHash moduleData;
291             NameModuleInfoHash moduleInfos;
292 
293             for( sal_uInt16 i=0; i<nStreamCount;i++)
294             {
295                 StringArray aDecompressed = aVBA.Decompress(i);
296 #if 0
297 /*  DR 2005-08-11 #124850# Do not filter special characters from module name.
298     Just put the original module name and let the Basic interpreter deal with
299     it. Needed for roundtrip...
300  */
301                 ByteString sByteBasic(aVBA.GetStreamName(i),
302                     RTL_TEXTENCODING_ASCII_US,
303                         (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_UNDERLINE|
304                         RTL_UNICODETOTEXT_FLAGS_INVALID_UNDERLINE |
305                         RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 |
306                         RTL_UNICODETOTEXT_FLAGS_NOCOMPOSITE)
307                 );
308 
309                 const String sBasicModule(sByteBasic,
310                     RTL_TEXTENCODING_ASCII_US);
311 #else
312                 const String &sBasicModule = aVBA.GetStreamName( i);
313 #endif
314                 /* #117718# expose information regarding type of Module
315                 * Class, Form or plain 'ould VBA module with a REM statement
316                 * at the top of the module. Mapping of Module Name
317                 * to type is performed in VBA_Impl::Open() method,
318                 * ( msvbasic.cxx ) by examining the PROJECT stream.
319                 */
320 
321                 // using name from aVBA.GetStreamName
322                 // because the encoding of the same returned
323                 // is the same as the encoding for the names
324                 // that are keys in the map used by GetModuleType method
325                 const String &sOrigVBAModName = aVBA.GetStreamName( i );
326                 ModType mType = aVBA.GetModuleType( sOrigVBAModName );
327 
328                 rtl::OUString sClassRem( RTL_CONSTASCII_USTRINGPARAM( "Rem Attribute VBA_ModuleType=" ) );
329 
330                 rtl::OUString modeTypeComment;
331 
332                 switch( mType )
333                 {
334                     case ModuleType::CLASS:
335                         modeTypeComment = sClassRem +
336                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAClassModule\n" ) );
337                         break;
338                     case ModuleType::FORM:
339                         modeTypeComment = sClassRem +
340                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAFormModule\n" ) );
341                         break;
342                     case ModuleType::DOCUMENT:
343                         modeTypeComment = sClassRem +
344                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBADocumentModule\n" ) );
345                         break;
346                     case ModuleType::NORMAL:
347                         modeTypeComment = sClassRem +
348                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAModule\n" ) );
349                         break;
350                     case ModuleType::UNKNOWN:
351                         modeTypeComment = sClassRem +
352                             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "VBAUnknown\n" ) );
353                         break;
354                     default:
355                         DBG_ERRORFILE( "SvxImportMSVBasic::ImportCode_Impl - unknown module type" );
356                         break;
357                 }
358                 static ::rtl::OUString sClassOption( RTL_CONSTASCII_USTRINGPARAM( "Option ClassModule\n" ) );
359                 if ( !bAsComment )
360                 {
361                     modeTypeComment += sVBAOption;
362                     if ( mType == ModuleType::CLASS )
363                         modeTypeComment += sClassOption;
364                 }
365 
366                 String sModule(sBasicModule); // #i52606# no need to split Macros in 64KB blocks any more!
367                 String sTemp;
368                 if (bAsComment)
369                 {
370                     sTemp+=String(RTL_CONSTASCII_USTRINGPARAM( "Sub " ));
371                     String sMunge(sModule);
372                     // Streams can have spaces in them, but modulenames
373                     // cannot !
374                     sMunge.SearchAndReplaceAll(' ','_');
375 
376                     sTemp += sMunge;
377                     sTemp.AppendAscii("\n");
378                 };
379                 ::rtl::OUString aSource(sTemp);
380 
381                 for(sal_uLong j=0;j<aDecompressed.GetSize();j++)
382                 {
383                     if (bStripped)
384                     {
385                         String *pStr = aDecompressed.Get(j);
386                         bool bMac = true;
387                         xub_StrLen nBegin = pStr->Search('\x0D');
388                         if ((STRING_NOTFOUND != nBegin) && (pStr->Len() > 1) && (pStr->GetChar(nBegin+1) == '\x0A'))
389                             bMac = false;
390 
391                         const char cLineEnd = bMac ? '\x0D' : '\x0A';
392                         const String sAttribute(String::CreateFromAscii(
393                             bAsComment ? "Rem Attribute" : "Attribute"));
394                         nBegin = 0;
395                         while (STRING_NOTFOUND != (nBegin = pStr->Search(sAttribute, nBegin)))
396                         {
397                             if ((nBegin) && pStr->GetChar(nBegin-1) != cLineEnd)
398                             {
399                                 // npower #i63766# Need to skip instances of Attribute
400                                 // that are NOT Attribute statements
401                                 nBegin = nBegin + sAttribute.Len();
402                                 continue;
403                             }
404                             xub_StrLen nEnd = pStr->Search(cLineEnd ,nBegin);
405                             // DR #i26521# catch STRING_NOTFOUND, will loop endless otherwise
406                             if( nEnd == STRING_NOTFOUND )
407                                 pStr->Erase();
408                             else
409                                 pStr->Erase(nBegin, (nEnd-nBegin)+1);
410                         }
411                     }
412                     if( aDecompressed.Get(j)->Len() )
413                     {
414                         aSource+=::rtl::OUString( *aDecompressed.Get(j) );
415                     }
416 
417                 }
418                 if (bAsComment)
419                 {
420                         aSource += rtl::OUString::createFromAscii("\nEnd Sub");
421                 }
422                 ::rtl::OUString aModName( sModule );
423                 aSource = modeTypeComment + aSource;
424 
425                 Any aSourceAny;
426                 OSL_TRACE("erm %d", mType );
427                     aSourceAny <<= aSource;
428                 if ( !bAsComment )
429                 {
430                     OSL_TRACE("vba processing %d", mType );
431                     script::ModuleInfo sModuleInfo;
432                     sModuleInfo.ModuleType = mType;
433                     moduleInfos[ aModName ] = sModuleInfo;
434                 }
435                 moduleData[ aModName ] = aSourceAny;
436             }
437             // Hack for missing codenames ( only known to happen in Excel but... )
438             // only makes sense to do this if we are importing non-commented basic
439             if ( !bAsComment )
440             {
441                 for ( std::vector< String >::const_iterator it = codeNames.begin(); it != codeNames.end(); ++it )
442                 {
443                     script::ModuleInfo sModuleInfo;
444                     sModuleInfo.ModuleType = ModuleType::DOCUMENT;
445                     moduleInfos[ *it ] = sModuleInfo;
446                     moduleData[ *it ] = uno::makeAny( sVBAOption );
447                 }
448             }
449             NameModuleDataHash::iterator it_end = moduleData.end();
450             for ( NameModuleDataHash::iterator it = moduleData.begin(); it != it_end; ++it )
451             {
452                 NameModuleInfoHash::iterator it_info = moduleInfos.find( it->first );
453                 if ( it_info != moduleInfos.end() )
454                 {
455                     ModuleInfo& sModuleInfo = it_info->second;
456                     if ( sModuleInfo.ModuleType == ModuleType::FORM )
457                         // hack, the module ( imo document basic should...
458                         // know the XModel... ) but it doesn't
459                         sModuleInfo.ModuleObject.set( rDocSh.GetModel(), UNO_QUERY );
460                     // document modules, we should be able to access
461                     // the api objects at this time
462                     else if ( sModuleInfo.ModuleType == ModuleType::DOCUMENT )
463                     {
464                         if ( xVBACodeNamedObjectAccess.is() )
465                         {
466                             try
467                             {
468                                 sModuleInfo.ModuleObject.set( xVBACodeNamedObjectAccess->getByName( it->first ), uno::UNO_QUERY );
469                                 OSL_TRACE("** Straight up creation of Module");
470                             }
471                             catch(uno::Exception& e)
472                             {
473                                 OSL_TRACE("Failed to get document object for %s", rtl::OUStringToOString( it->first, RTL_TEXTENCODING_UTF8 ).getStr() );
474                             }
475                         }
476                     }
477                     xVBAModuleInfo->insertModuleInfo( it->first, sModuleInfo );
478                 }
479 
480                 if( xLib->hasByName( it->first ) )
481                     xLib->replaceByName( it->first, it->second );
482                 else
483                     xLib->insertByName( it->first, it->second );
484             }
485             bRet = true;
486         }
487     }
488     return bRet;
489 }
490 
491 /* vim: set noet sw=4 ts=4: */
492