1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
32 #include <basic/sbx.hxx>
33 #include <basic/sbxvar.hxx>
34 #include <runtime.hxx>
35 #include <osl/thread.h>
36 #include <osl/diagnose.h>
37 #include <rtl/ref.hxx>
38 #include <rtl/string.hxx>
39 #include <rtl/ustring.hxx>
40 #include <sal/log.hxx>
41 #include <salhelper/simplereferenceobject.hxx>
42 #include <o3tl/char16_t2wchar_t.hxx>
52 Missing support for functions returning structs (see TODO in call()).
54 Missing support for additional data types (64 bit integers, Any, ...; would
55 trigger OSL_ASSERT(false) in various switches).
57 It is assumed that the variables passed into SbiDllMgr::Call to represent
58 the arguments and return value have types that exactly match the Declare
59 statement; it would be better if this code had access to the function
60 signature from the Declare statement, so that it could convert the passed
61 variables accordingly.
66 char * address(std::vector
< char > & blob
) {
67 return blob
.empty() ? nullptr : blob
.data();
70 ErrCode
convert(OUString
const & source
, OString
* target
) {
72 source
.convertToString(
73 target
, osl_getThreadTextEncoding(),
74 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
75 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
76 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
77 //TODO: more specific errcode?
80 ErrCode
convert(char const * source
, sal_Int32 length
, OUString
* target
) {
82 rtl_convertStringToUString(
83 &target
->pData
, source
, length
, osl_getThreadTextEncoding(),
84 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
85 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
86 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
))
87 ? ERRCODE_NONE
: ERRCODE_BASIC_BAD_ARGUMENT
;
88 //TODO: more specific errcode?
91 struct UnmarshalData
{
92 UnmarshalData(SbxVariable
* theVariable
, void * theBuffer
):
93 variable(theVariable
), buffer(theBuffer
) {}
95 SbxVariable
* variable
;
99 struct StringData
: public UnmarshalData
{
100 StringData(SbxVariable
* theVariable
, void * theBuffer
, bool theSpecial
):
101 UnmarshalData(theVariable
, theBuffer
), special(theSpecial
) {}
108 MarshalData() = default;
109 MarshalData(const MarshalData
&) = delete;
110 const MarshalData
& operator=(const MarshalData
&) = delete;
112 std::vector
< char > * newBlob() {
113 blobs_
.push_back(std::vector
< char >());
114 return &blobs_
.back();
117 std::vector
< UnmarshalData
> unmarshal
;
119 std::vector
< StringData
> unmarshalStrings
;
122 std::vector
< std::vector
< char > > blobs_
;
125 std::size_t align(std::size_t address
, std::size_t alignment
) {
126 // alignment = 2^k for some k >= 0
127 return (address
+ (alignment
- 1)) & ~(alignment
- 1);
131 std::vector
< char > & blob
, std::size_t alignment
, std::size_t offset
,
134 std::vector
< char >::size_type n
= blob
.size();
135 n
= align(n
- offset
, alignment
) + offset
; //TODO: overflow in align()
136 blob
.resize(n
+ add
); //TODO: overflow
137 return address(blob
) + n
;
140 template< typename T
> void add(
141 std::vector
< char > & blob
, T
const & data
, std::size_t alignment
,
144 *reinterpret_cast< T
* >(align(blob
, alignment
, offset
, sizeof (T
))) = data
;
147 std::size_t alignment(SbxVariable
const * variable
) {
148 OSL_ASSERT(variable
!= nullptr);
149 if ((variable
->GetType() & SbxARRAY
) == 0) {
150 switch (variable
->GetType()) {
162 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
164 SbxArray
* props
= pobj
->GetProperties();
165 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
166 n
= std::max(n
, alignment(props
->Get(i
)));
178 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
180 int dims
= arr
->GetDims();
181 std::vector
< sal_Int32
> low(dims
);
182 for (int i
= 0; i
< dims
; ++i
) {
184 arr
->GetDim32(i
+ 1, low
[i
], up
);
186 return alignment(arr
->Get32(low
.data()));
191 bool outer
, SbxVariable
* variable
, bool special
,
192 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
);
194 ErrCode
marshalString(
195 SbxVariable
* variable
, bool special
, MarshalData
& data
, void ** buffer
)
197 OSL_ASSERT(variable
!= nullptr && buffer
!= nullptr);
199 ErrCode e
= convert(variable
->GetOUString(), &str
);
200 if (e
!= ERRCODE_NONE
) {
203 std::vector
< char > * blob
= data
.newBlob();
204 blob
->insert(blob
->begin(), str
.getStr(), str
.getStr() + str
.getLength() + 1);
205 *buffer
= address(*blob
);
206 data
.unmarshalStrings
.push_back(StringData(variable
, *buffer
, special
));
210 ErrCode
marshalStruct(
211 SbxVariable
const * variable
, std::vector
< char > & blob
, std::size_t offset
,
214 OSL_ASSERT(variable
!= nullptr);
215 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
217 SbxArray
* props
= pobj
->GetProperties();
218 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
219 ErrCode e
= marshal(false, props
->Get(i
), false, blob
, offset
, data
);
220 if (e
!= ERRCODE_NONE
) {
227 ErrCode
marshalArray(
228 SbxVariable
const * variable
, std::vector
< char > & blob
, std::size_t offset
,
231 OSL_ASSERT(variable
!= nullptr);
232 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
234 int dims
= arr
->GetDims();
235 std::vector
< sal_Int32
> low(dims
);
236 std::vector
< sal_Int32
> up(dims
);
237 for (int i
= 0; i
< dims
; ++i
) {
238 arr
->GetDim32(i
+ 1, low
[i
], up
[i
]);
240 for (std::vector
< sal_Int32
> idx
= low
;;) {
242 false, arr
->Get32(idx
.data()), false, blob
, offset
, data
);
243 if (e
!= ERRCODE_NONE
) {
247 while (idx
[i
] == up
[i
]) {
258 // 8-aligned structs are only 4-aligned on stack, so alignment of members in
259 // such structs must take that into account via "offset"
261 bool outer
, SbxVariable
* variable
, bool special
,
262 std::vector
< char > & blob
, std::size_t offset
, MarshalData
& data
)
264 OSL_ASSERT(variable
!= nullptr);
266 SbxDataType eVarType
= variable
->GetType();
267 bool bByVal
= !(variable
->GetFlags() & SbxFlagBits::Reference
);
268 if( !bByVal
&& !SbiRuntime::isVBAEnabled() && eVarType
== SbxSTRING
)
272 if ((eVarType
& SbxARRAY
) == 0) {
275 add(blob
, variable
->GetInteger(), outer
? 8 : 2, offset
);
278 add(blob
, variable
->GetLong(), outer
? 8 : 4, offset
);
281 add(blob
, variable
->GetSingle(), outer
? 8 : 4, offset
);
284 add(blob
, variable
->GetDouble(), 8, offset
);
289 ErrCode e
= marshalString(variable
, special
, data
, &p
);
290 if (e
!= ERRCODE_NONE
) {
293 add(blob
, p
, 8, offset
);
298 align(blob
, outer
? 8 : alignment(variable
), offset
, 0);
299 ErrCode e
= marshalStruct(variable
, blob
, offset
, data
);
300 if (e
!= ERRCODE_NONE
) {
306 add(blob
, variable
->GetBool(), outer
? 8 : 1, offset
);
309 add(blob
, variable
->GetByte(), outer
? 8 : 1, offset
);
316 ErrCode e
= marshalArray(variable
, blob
, offset
, data
);
317 if (e
!= ERRCODE_NONE
) {
322 if ((eVarType
& SbxARRAY
) == 0) {
330 add(blob
, variable
->data(), 8, offset
);
335 ErrCode e
= marshalString(variable
, special
, data
, &p
);
336 if (e
!= ERRCODE_NONE
) {
339 std::vector
< char >* blob2
= data
.newBlob();
340 add(*blob2
, p
, 8, 0);
341 add(blob
, address(*blob2
), 8, offset
);
346 std::vector
< char > * blob2
= data
.newBlob();
347 ErrCode e
= marshalStruct(variable
, *blob2
, 0, data
);
348 if (e
!= ERRCODE_NONE
) {
351 void * p
= address(*blob2
);
353 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
355 add(blob
, p
, 8, offset
);
363 std::vector
< char > * blob2
= data
.newBlob();
364 ErrCode e
= marshalArray(variable
, *blob2
, 0, data
);
365 if (e
!= ERRCODE_NONE
) {
368 void * p
= address(*blob2
);
370 data
.unmarshal
.push_back(UnmarshalData(variable
, p
));
372 add(blob
, p
, 8, offset
);
378 template< typename T
> T
read(void const ** pointer
) {
379 T
const * p
= static_cast< T
const * >(*pointer
);
380 *pointer
= static_cast< void const * >(p
+ 1);
384 void const * unmarshal(SbxVariable
* variable
, void const * data
) {
385 OSL_ASSERT(variable
!= nullptr);
386 if ((variable
->GetType() & SbxARRAY
) == 0) {
387 switch (variable
->GetType()) {
389 variable
->PutInteger(read
< sal_Int16
>(&data
));
392 variable
->PutLong(read
< sal_Int32
>(&data
));
395 variable
->PutSingle(read
< float >(&data
));
398 variable
->PutDouble(read
< double >(&data
));
401 read
< char * >(&data
); // handled by unmarshalString
405 data
= reinterpret_cast< void const * >(
407 reinterpret_cast< sal_uIntPtr
>(data
),
408 alignment(variable
)));
409 SbxObject
* pobj
= dynamic_cast<SbxObject
*>(variable
->GetObject());
411 SbxArray
* props
= pobj
->GetProperties();
412 for (sal_uInt16 i
= 0; i
< props
->Count(); ++i
) {
413 data
= unmarshal(props
->Get(i
), data
);
418 variable
->PutBool(read
< sal_Bool
>(&data
));
421 variable
->PutByte(read
< sal_uInt8
>(&data
));
428 SbxDimArray
* arr
= dynamic_cast<SbxDimArray
*>( variable
->GetObject() );
430 int dims
= arr
->GetDims();
431 std::vector
< sal_Int32
> low(dims
);
432 std::vector
< sal_Int32
> up(dims
);
433 for (int i
= 0; i
< dims
; ++i
) {
434 arr
->GetDim32(i
+ 1, low
[i
], up
[i
]);
436 for (std::vector
< sal_Int32
> idx
= low
;;) {
437 data
= unmarshal(arr
->Get32(idx
.data()), data
);
439 while (idx
[i
] == up
[i
]) {
453 ErrCode
unmarshalString(StringData
const & data
, SbxVariable
const & result
) {
455 if (data
.buffer
!= nullptr) {
456 char const * p
= static_cast< char const * >(data
.buffer
);
459 len
= static_cast< sal_Int32
>(result
.GetULong());
460 if (len
< 0) { // i.e., DWORD result >= 2^31
461 return ERRCODE_BASIC_BAD_ARGUMENT
;
462 //TODO: more specific errcode?
465 len
= rtl_str_getLength(p
);
467 ErrCode e
= convert(p
, len
, &str
);
468 if (e
!= ERRCODE_NONE
) {
472 data
.variable
->PutString(str
);
482 OUString
const & dll
, ProcData
const & proc
, SbxArray
* arguments
,
483 SbxVariable
& result
)
485 if (arguments
&& arguments
->Count() > 20)
486 return ERRCODE_BASIC_NOT_IMPLEMENTED
;
488 std::vector
< char > stack
;
491 // For DWORD GetLogicalDriveStringsA(DWORD nBufferLength, LPSTR lpBuffer)
492 // from kernel32, upon return, filled lpBuffer length is result DWORD, which
493 // requires special handling in unmarshalString; other functions might
494 // require similar treatment, too:
496 dll
.equalsIgnoreAsciiCase("KERNEL32.DLL") &&
497 (proc
.name
== OString("GetLogicalDriveStringsA"));
498 for (int i
= 1; i
< (arguments
== nullptr ? 0 : arguments
->Count()); ++i
) {
500 true, arguments
->Get(i
), special
&& i
== 2, stack
, stack
.size(),
502 if (e
!= ERRCODE_NONE
) {
505 align(stack
, 8, 0, 0);
510 // We fake all calls as being to a varargs function,
511 // as this means any floating-point argument among the first four
512 // ones will end up in a XMM register where the callee expects it.
513 sal_Int32 (*proc_i
)(double d
, ...) = reinterpret_cast<sal_Int32 (*)(double, ...)>(proc
.proc
);
514 double (*proc_d
)(double d
, ...) = reinterpret_cast<double (*)(double, ...)>(proc
.proc
);
516 sal_Int64 iRetVal
= 0;
517 double dRetVal
= 0.0;
519 switch (result
.GetType()) {
528 auto const st
= stack
.data();
530 proc_i(*reinterpret_cast<double *>(st
+ 0),
531 *reinterpret_cast<double *>(st
+ 1*8),
532 *reinterpret_cast<double *>(st
+ 2*8),
533 *reinterpret_cast<double *>(st
+ 3*8),
534 *reinterpret_cast<sal_uInt64
*>(st
+ 4*8),
535 *reinterpret_cast<sal_uInt64
*>(st
+ 5*8),
536 *reinterpret_cast<sal_uInt64
*>(st
+ 6*8),
537 *reinterpret_cast<sal_uInt64
*>(st
+ 7*8),
538 *reinterpret_cast<sal_uInt64
*>(st
+ 8*8),
539 *reinterpret_cast<sal_uInt64
*>(st
+ 9*8),
540 *reinterpret_cast<sal_uInt64
*>(st
+ 10*8),
541 *reinterpret_cast<sal_uInt64
*>(st
+ 11*8),
542 *reinterpret_cast<sal_uInt64
*>(st
+ 12*8),
543 *reinterpret_cast<sal_uInt64
*>(st
+ 13*8),
544 *reinterpret_cast<sal_uInt64
*>(st
+ 14*8),
545 *reinterpret_cast<sal_uInt64
*>(st
+ 15*8),
546 *reinterpret_cast<sal_uInt64
*>(st
+ 16*8),
547 *reinterpret_cast<sal_uInt64
*>(st
+ 17*8),
548 *reinterpret_cast<sal_uInt64
*>(st
+ 18*8),
549 *reinterpret_cast<sal_uInt64
*>(st
+ 19*8));
555 auto const st
= stack
.data();
557 proc_d(*reinterpret_cast<double *>(st
+ 0),
558 *reinterpret_cast<double *>(st
+ 1*8),
559 *reinterpret_cast<double *>(st
+ 2*8),
560 *reinterpret_cast<double *>(st
+ 3*8),
561 *reinterpret_cast<sal_uInt64
*>(st
+ 4*8),
562 *reinterpret_cast<sal_uInt64
*>(st
+ 5*8),
563 *reinterpret_cast<sal_uInt64
*>(st
+ 6*8),
564 *reinterpret_cast<sal_uInt64
*>(st
+ 7*8),
565 *reinterpret_cast<sal_uInt64
*>(st
+ 8*8),
566 *reinterpret_cast<sal_uInt64
*>(st
+ 9*8),
567 *reinterpret_cast<sal_uInt64
*>(st
+ 10*8),
568 *reinterpret_cast<sal_uInt64
*>(st
+ 11*8),
569 *reinterpret_cast<sal_uInt64
*>(st
+ 12*8),
570 *reinterpret_cast<sal_uInt64
*>(st
+ 13*8),
571 *reinterpret_cast<sal_uInt64
*>(st
+ 14*8),
572 *reinterpret_cast<sal_uInt64
*>(st
+ 15*8),
573 *reinterpret_cast<sal_uInt64
*>(st
+ 16*8),
574 *reinterpret_cast<sal_uInt64
*>(st
+ 17*8),
575 *reinterpret_cast<sal_uInt64
*>(st
+ 18*8),
576 *reinterpret_cast<sal_uInt64
*>(st
+ 19*8));
583 switch (result
.GetType()) {
587 result
.PutInteger(static_cast< sal_Int16
>(iRetVal
));
590 result
.PutLong(static_cast< sal_Int32
>(iRetVal
));
593 result
.PutSingle(static_cast< float >(dRetVal
));
596 result
.PutDouble(dRetVal
);
600 char const * s1
= reinterpret_cast< char const * >(iRetVal
);
602 ErrCode e
= convert(s1
, rtl_str_getLength(s1
), &s2
);
603 if (e
!= ERRCODE_NONE
) {
606 result
.PutString(s2
);
613 result
.PutBool(bool(iRetVal
));
616 result
.PutByte(static_cast< sal_uInt8
>(iRetVal
));
622 for (int i
= 1; i
< (arguments
== nullptr ? 0 : arguments
->Count()); ++i
) {
623 arguments
->Get(i
)->ResetFlag(SbxFlagBits::Reference
);
624 //TODO: skipped for errors?!?
626 for (auto const& elem
: data
.unmarshal
)
628 unmarshal(elem
.variable
, elem
.buffer
);
630 for (auto const& elem
: data
.unmarshalStrings
)
632 ErrCode e
= unmarshalString(elem
, result
);
633 if (e
!= ERRCODE_NONE
) {
640 ErrCode
getProcData(HMODULE handle
, OUString
const & name
, ProcData
* proc
)
642 OSL_ASSERT(proc
!= nullptr);
643 if (name
.getLength() != 0 && name
[0] == '@') { //TODO: "@" vs. "#"???
644 sal_Int32 n
= name
.copy(1).toInt32(); //TODO: handle bad input
645 if (n
<= 0 || n
> 0xFFFF) {
646 return ERRCODE_BASIC_BAD_ARGUMENT
; //TODO: more specific errcode?
648 FARPROC p
= GetProcAddress(handle
, reinterpret_cast< LPCSTR
>(n
));
650 proc
->name
= "#" + OString::number(n
);
656 ErrCode e
= convert(name
, &name8
);
657 if (e
!= ERRCODE_NONE
) {
660 FARPROC p
= GetProcAddress(handle
, name8
.getStr());
666 sal_Int32 i
= name8
.indexOf('#');
668 name8
= name8
.copy(0, i
);
669 p
= GetProcAddress(handle
, name8
.getStr());
676 OString
real("_" + name8
);
677 p
= GetProcAddress(handle
, real
.getStr());
684 p
= GetProcAddress(handle
, real
.getStr());
691 return ERRCODE_BASIC_PROC_UNDEFINED
;
694 struct Dll
: public salhelper::SimpleReferenceObject
{
696 typedef std::map
< OUString
, ProcData
> Procs
;
698 virtual ~Dll() override
;
701 Dll(): handle(nullptr) {}
703 ErrCode
getProc(OUString
const & name
, ProcData
* proc
);
710 if (handle
!= nullptr && !FreeLibrary(handle
)) {
711 SAL_WARN("basic", "FreeLibrary(" << handle
<< ") failed with " << GetLastError());
715 ErrCode
Dll::getProc(OUString
const & name
, ProcData
* proc
) {
716 Procs::iterator
i(procs
.find(name
));
717 if (i
!= procs
.end()) {
721 ErrCode e
= getProcData(handle
, name
, proc
);
722 if (e
== ERRCODE_NONE
) {
723 procs
.emplace(name
, *proc
);
728 OUString
fullDllName(OUString
const & name
) {
730 if (full
.indexOf('.') == -1) {
738 struct SbiDllMgr::Impl
{
740 typedef std::map
< OUString
, ::rtl::Reference
< Dll
> > Dlls
;
744 Impl(const Impl
&) = delete;
745 const Impl
& operator=(const Impl
&) = delete;
747 Dll
* getDll(OUString
const & name
);
752 Dll
* SbiDllMgr::Impl::getDll(OUString
const & name
) {
753 Dlls::iterator
i(dlls
.find(name
));
754 if (i
== dlls
.end()) {
755 i
= dlls
.emplace(name
, new Dll
).first
;
756 HMODULE h
= LoadLibraryW(o3tl::toW(name
.getStr()));
761 i
->second
->handle
= h
;
763 return i
->second
.get();
766 ErrCode
SbiDllMgr::Call(
767 OUString
const & function
, OUString
const & library
,
768 SbxArray
* arguments
, SbxVariable
& result
, bool cdeclConvention
)
770 if (cdeclConvention
) {
771 return ERRCODE_BASIC_NOT_IMPLEMENTED
;
773 OUString
dllName(fullDllName(library
));
774 Dll
* dll
= impl_
->getDll(dllName
);
775 if (dll
== nullptr) {
776 return ERRCODE_BASIC_BAD_DLL_LOAD
;
779 ErrCode e
= dll
->getProc(function
, &proc
);
780 if (e
!= ERRCODE_NONE
) {
783 return call(dllName
, proc
, arguments
, result
);
786 void SbiDllMgr::FreeDll(OUString
const & library
) {
787 impl_
->dlls
.erase(library
);
790 SbiDllMgr::SbiDllMgr(): impl_(new Impl
) {}
792 SbiDllMgr::~SbiDllMgr() {}
794 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */