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 documument 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