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