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