From: Francis De Brabandere <francisdb@gmail.com> --- dlls/vbscript/global.c | 163 ++++++++++++++++++++++++++++++++++-- dlls/vbscript/tests/api.vbs | 33 ++++++++ 2 files changed, 187 insertions(+), 9 deletions(-) diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c index 32cf7c5cd2b..14b58b017ef 100644 --- a/dlls/vbscript/global.c +++ b/dlls/vbscript/global.c @@ -1360,10 +1360,49 @@ static HRESULT Global_Left(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, return return_bstr(res, ret); } -static HRESULT Global_LeftB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_LeftB(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR str, conv_str = NULL; + int len, byte_len; + HRESULT hres; + + TRACE("(%s %s)\n", debugstr_variant(args+1), debugstr_variant(args)); + + if(V_VT(args) == VT_BSTR) { + str = V_BSTR(args); + }else { + hres = to_string(This->ctx->lcid, args, &conv_str); + if(FAILED(hres)) + return hres; + str = conv_str; + } + + hres = to_int(args+1, &len); + if(FAILED(hres)) { + SysFreeString(conv_str); + return hres; + } + + if(len < 0) { + SysFreeString(conv_str); + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + + byte_len = SysStringByteLen(str); + if(len > byte_len) + len = byte_len; + + if(res) { + V_VT(res) = VT_BSTR; + V_BSTR(res) = SysAllocStringByteLen((const char*)str, len); + if(!V_BSTR(res)) { + SysFreeString(conv_str); + return E_OUTOFMEMORY; + } + } + + SysFreeString(conv_str); + return S_OK; } static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) @@ -1408,10 +1447,51 @@ static HRESULT Global_Right(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, return return_bstr(res, ret); } -static HRESULT Global_RightB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_RightB(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + BSTR str, conv_str = NULL; + int len, byte_len; + HRESULT hres; + + TRACE("(%s %s)\n", debugstr_variant(args), debugstr_variant(args+1)); + + if(V_VT(args+1) == VT_NULL) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + hres = to_int(args+1, &len); + if(FAILED(hres)) + return hres; + + if(len < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + if(V_VT(args) == VT_NULL) + return return_null(res); + + if(V_VT(args) == VT_BSTR) { + str = V_BSTR(args); + }else { + hres = to_string(This->ctx->lcid, args, &conv_str); + if(FAILED(hres)) + return hres; + str = conv_str; + } + + byte_len = SysStringByteLen(str); + if(len > byte_len) + len = byte_len; + + if(res) { + V_VT(res) = VT_BSTR; + V_BSTR(res) = SysAllocStringByteLen((const char*)str + byte_len - len, len); + if(!V_BSTR(res)) { + SysFreeString(conv_str); + return E_OUTOFMEMORY; + } + } + + SysFreeString(conv_str); + return S_OK; } static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) @@ -1486,10 +1566,75 @@ static HRESULT Global_Mid(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, V return hres; } -static HRESULT Global_MidB(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res) +static HRESULT Global_MidB(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) { - FIXME("\n"); - return E_NOTIMPL; + int len = -1, start, byte_len; + BSTR str, conv_str = NULL; + HRESULT hres; + + TRACE("(%s %s ...)\n", debugstr_variant(args), debugstr_variant(args+1)); + + assert(args_cnt == 2 || args_cnt == 3); + + if(V_VT(args+1) == VT_NULL || (args_cnt == 3 && V_VT(args+2) == VT_NULL)) + return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE); + + if(V_VT(args+1) == VT_EMPTY) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + hres = to_int(args+1, &start); + if(FAILED(hres)) + return hres; + + if(start <= 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + if(args_cnt == 3) { + if(V_VT(args+2) == VT_EMPTY) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + + hres = to_int(args+2, &len); + if(FAILED(hres)) + return hres; + + if(len < 0) + return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL); + } + + if(V_VT(args) == VT_EMPTY) + return return_string(res, L""); + + if(V_VT(args) == VT_NULL) + return return_null(res); + + if(V_VT(args) == VT_BSTR) { + str = V_BSTR(args); + }else { + hres = to_string(This->ctx->lcid, args, &conv_str); + if(FAILED(hres)) + return hres; + str = conv_str; + } + + byte_len = SysStringByteLen(str); + start--; + if(start > byte_len) + start = byte_len; + + if(len == -1) + len = byte_len - start; + else if(len > byte_len - start) + len = byte_len - start; + + if(res) { + V_VT(res) = VT_BSTR; + V_BSTR(res) = SysAllocStringByteLen((const char*)str + start, len); + if(!V_BSTR(res)) + hres = E_OUTOFMEMORY; + } + + SysFreeString(conv_str); + return hres; } static HRESULT Global_StrComp(BuiltinDisp *This, VARIANT *args, unsigned args_cnt, VARIANT *res) diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs index 257d7c428d0..f3878e7836c 100644 --- a/dlls/vbscript/tests/api.vbs +++ b/dlls/vbscript/tests/api.vbs @@ -2960,4 +2960,37 @@ Call ok(LenB("hello") = 10, "LenB(""hello"") = " & LenB("hello")) Call ok(getVT(LenB("A")) = "VT_I4", "getVT(LenB) = " & getVT(LenB("A"))) Call ok(IsNull(LenB(Null)), "LenB(Null) should be Null") +' LeftB tests +Call ok(LeftB("ABC", 0) = "", "LeftB(""ABC"", 0) = """ & LeftB("ABC", 0) & """") +Call ok(LeftB("ABC", 2) = "A", "LeftB(""ABC"", 2) = " & LeftB("ABC", 2)) +Call ok(LeftB("ABC", 4) = "AB", "LeftB(""ABC"", 4) = " & LeftB("ABC", 4)) +Call ok(LeftB("ABC", 6) = "ABC", "LeftB(""ABC"", 6) = " & LeftB("ABC", 6)) +Call ok(LeftB("ABC", 100) = "ABC", "LeftB(""ABC"", 100) = " & LeftB("ABC", 100)) +Call ok(LenB(LeftB("ABC", 3)) = 3, "LenB(LeftB(""ABC"", 3)) = " & LenB(LeftB("ABC", 3))) + +' RightB tests +Call ok(RightB("ABC", 0) = "", "RightB(""ABC"", 0) = """ & RightB("ABC", 0) & """") +Call ok(RightB("ABC", 2) = "C", "RightB(""ABC"", 2) = " & RightB("ABC", 2)) +Call ok(RightB("ABC", 4) = "BC", "RightB(""ABC"", 4) = " & RightB("ABC", 4)) +Call ok(RightB("ABC", 100) = "ABC", "RightB(""ABC"", 100) = " & RightB("ABC", 100)) +Call ok(LenB(RightB("ABC", 3)) = 3, "LenB(RightB(""ABC"", 3)) = " & LenB(RightB("ABC", 3))) + +' MidB tests +Call ok(MidB("ABC", 1, 2) = "A", "MidB(""ABC"", 1, 2) = " & MidB("ABC", 1, 2)) +Call ok(MidB("ABC", 3, 2) = "B", "MidB(""ABC"", 3, 2) = " & MidB("ABC", 3, 2)) +Call ok(MidB("ABC", 1) = "ABC", "MidB(""ABC"", 1) = " & MidB("ABC", 1)) +Call ok(MidB("ABC", 3) = "BC", "MidB(""ABC"", 3) = " & MidB("ABC", 3)) +Call ok(LenB(MidB("ABC", 2, 2)) = 2, "LenB(MidB(""ABC"", 2, 2)) = " & LenB(MidB("ABC", 2, 2))) + +sub testByteSubstrErrors() + on error resume next + dim r + + call Err.clear() + r = LeftB("ABC", -1) + Call ok(Err.number = 5, "LeftB(-1) Err.number = " & Err.number) +end sub + +call testByteSubstrErrors() + Call reportSuccess() -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10510