The MR adds implementations (+ a few tests) for the following methods in `bluetoothapis.h`:
* `BluetoothSdpEnumAttributes` * `BluetoothSdpGetContainerElementData` * `BluetoothSdpGetElementData` * `BluetoothSdpGetAttributeValue`
-- v23: bluetoothapis: Implement BluetoothSdpGetAttributeValue. bluetoothapis/tests: Add tests for BluetoothSdpGetAttributeValue. bluetoothapis: Add stub for BluetoothSdpGetAttributeValue. bluetoothapis: Implement BluetoothSdpEnumAttributes. bluetoothapis/tests: Add tests for BluetoothSdpEnumAttributes.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/Makefile.in | 3 +- dlls/bluetoothapis/bluetoothapis.spec | 2 +- dlls/bluetoothapis/sdp.c | 40 +++++++++++++++++++++++++++ dlls/bthprops.cpl/bthprops.cpl.spec | 2 +- dlls/irprops.cpl/irprops.cpl.spec | 2 +- 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 dlls/bluetoothapis/sdp.c
diff --git a/dlls/bluetoothapis/Makefile.in b/dlls/bluetoothapis/Makefile.in index 78518822519..1fd74074703 100644 --- a/dlls/bluetoothapis/Makefile.in +++ b/dlls/bluetoothapis/Makefile.in @@ -4,4 +4,5 @@ IMPORTLIB = bluetoothapis EXTRADLLFLAGS = -Wb,--prefer-native
SOURCES = \ - main.c + main.c \ + sdp.c diff --git a/dlls/bluetoothapis/bluetoothapis.spec b/dlls/bluetoothapis/bluetoothapis.spec index 625dffb8254..a35e1e22ecc 100644 --- a/dlls/bluetoothapis/bluetoothapis.spec +++ b/dlls/bluetoothapis/bluetoothapis.spec @@ -56,7 +56,7 @@ @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue @ stub BluetoothSdpGetContainerElementData -@ stub BluetoothSdpGetElementData +@ stdcall BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSendAuthenticationResponse @ stub BluetoothSendAuthenticationResponseEx diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c new file mode 100644 index 00000000000..e3c6b27afc2 --- /dev/null +++ b/dlls/bluetoothapis/sdp.c @@ -0,0 +1,40 @@ +/* + * SDP APIs + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> +#include <winternl.h> + +#include "wine/debug.h" +#include "bthsdpdef.h" +#include "bluetoothapis.h" + +WINE_DEFAULT_DEBUG_CHANNEL( bluetoothapis ); + +/********************************************************************* + * BluetoothSdpGetElementData + */ +DWORD WINAPI BluetoothSdpGetElementData( BYTE *stream, ULONG stream_size, SDP_ELEMENT_DATA *data ) +{ + FIXME( "(%p, %lu, %p) stub!\n", stream, stream_size, data ); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/dlls/bthprops.cpl/bthprops.cpl.spec b/dlls/bthprops.cpl/bthprops.cpl.spec index 1698344581e..0bef83810db 100644 --- a/dlls/bthprops.cpl/bthprops.cpl.spec +++ b/dlls/bthprops.cpl/bthprops.cpl.spec @@ -47,7 +47,7 @@ @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue @ stub BluetoothSdpGetContainerElementData -@ stub BluetoothSdpGetElementData +@ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSelectDevices @ stub BluetoothSelectDevicesFree diff --git a/dlls/irprops.cpl/irprops.cpl.spec b/dlls/irprops.cpl/irprops.cpl.spec index b2bdf3c3b2a..c9cd4df62d6 100644 --- a/dlls/irprops.cpl/irprops.cpl.spec +++ b/dlls/irprops.cpl/irprops.cpl.spec @@ -41,7 +41,7 @@ @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue @ stub BluetoothSdpGetContainerElementData -@ stub BluetoothSdpGetElementData +@ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSelectDevices @ stub BluetoothSelectDevicesFree
From: Vibhav Pant vibhavp@gmail.com
--- configure.ac | 1 + dlls/bluetoothapis/tests/Makefile.in | 5 + dlls/bluetoothapis/tests/sdp.c | 284 +++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 dlls/bluetoothapis/tests/Makefile.in create mode 100644 dlls/bluetoothapis/tests/sdp.c
diff --git a/configure.ac b/configure.ac index d729fb56b89..c0a7d364f86 100644 --- a/configure.ac +++ b/configure.ac @@ -2415,6 +2415,7 @@ WINE_CONFIG_MAKEFILE(dlls/bcrypt) WINE_CONFIG_MAKEFILE(dlls/bcrypt/tests) WINE_CONFIG_MAKEFILE(dlls/bcryptprimitives) WINE_CONFIG_MAKEFILE(dlls/bluetoothapis) +WINE_CONFIG_MAKEFILE(dlls/bluetoothapis/tests) WINE_CONFIG_MAKEFILE(dlls/browseui) WINE_CONFIG_MAKEFILE(dlls/browseui/tests) WINE_CONFIG_MAKEFILE(dlls/bthprops.cpl) diff --git a/dlls/bluetoothapis/tests/Makefile.in b/dlls/bluetoothapis/tests/Makefile.in new file mode 100644 index 00000000000..c2e8bc0377a --- /dev/null +++ b/dlls/bluetoothapis/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = bluetoothapis.dll +IMPORTS = bluetoothapis + +SOURCES = \ + sdp.c diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c new file mode 100644 index 00000000000..6aead0d2883 --- /dev/null +++ b/dlls/bluetoothapis/tests/sdp.c @@ -0,0 +1,284 @@ +/* Tests for bluetoothapis.dll's SDP API + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> + +#include "bthsdpdef.h" +#include "bluetoothapis.h" + +#include "wine/test.h" + +static const char *debugstr_SDP_ELEMENT_DATA( const SDP_ELEMENT_DATA *data ) +{ + return wine_dbg_sprintf( "{%#x %#x {%llu %llu}}", data->type, data->specificType, + data->data.uint128.LowPart, data->data.uint128.HighPart ); +} + +static void test_BluetoothSdpGetElementData( BYTE *stream, SIZE_T size, DWORD error, + const SDP_ELEMENT_DATA *sdp_data ) +{ + DWORD ret; + SDP_ELEMENT_DATA result = {0}; + + ret = BluetoothSdpGetElementData( stream, size, &result ); + ok( ret == error, "%ld != %ld.\n", error, ret ); + if (ret == error && error == ERROR_SUCCESS) + { + ok( result.type == sdp_data->type, "%#x != %#x.\n", sdp_data->type, result.type ); + ok( result.specificType == sdp_data->specificType, + "%#x != %#x.\n", sdp_data->specificType, + result.specificType ); + ok( !memcmp( &sdp_data->data, &result.data, sizeof( result.data ) ), + "%s != %s.\n", debugstr_SDP_ELEMENT_DATA( sdp_data ), + debugstr_SDP_ELEMENT_DATA( &result ) ); + } +} + +#define TEST_CASE_NAME( n ) ("%s %d"), __func__, (int)(n) + +static void test_BluetoothSdpGetElementData_invalid( void ) +{ + SDP_ELEMENT_DATA data; + BYTE stream[] = {0}; + DWORD ret; + + ret = BluetoothSdpGetElementData( NULL, 10, &data ); + todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + + ret = BluetoothSdpGetElementData( stream, 1, NULL ); + todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + + ret = BluetoothSdpGetElementData( stream, 0, &data ); + todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + + ret = BluetoothSdpGetElementData( NULL, 0, NULL ); + todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); +} + +static void test_BluetoothSdpGetElementData_nil( void ) +{ + static struct + { + BYTE data_elem; + DWORD error; + SDP_ELEMENT_DATA data; + } test_cases[] = { + {0x0, ERROR_SUCCESS, {.type = SDP_TYPE_NIL, .specificType = SDP_ST_NONE }}, + {0x1, ERROR_INVALID_PARAMETER}, + {0x3, ERROR_INVALID_PARAMETER}, + {0x4, ERROR_INVALID_PARAMETER}, + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context(TEST_CASE_NAME( i )); + todo_wine test_BluetoothSdpGetElementData( &test_cases[i].data_elem, 1, test_cases[i].error, + &test_cases[i].data ); + winetest_pop_context(); + } +} + +#define SDP_SIZE_DESC_1_BYTE 0 +#define SDP_SIZE_DESC_2_BYTES 1 +#define SDP_SIZE_DESC_4_BYTES 2 +#define SDP_SIZE_DESC_8_BYTES 3 +#define SDP_SIZE_DESC_16_BYTES 4 +#define SDP_SIZE_DESC_NEXT_UINT8 5 +#define SDP_SIZE_DESC_NEXT_UINT16 6 +#define SDP_SIZE_DESC_NEXT_UINT32 7 + +#define SDP_DATA_ELEM_TYPE_DESC(t,s) ((t) << 3 | SDP_SIZE_DESC_##s) + +#define SDP_DEF_TYPE(n, t, s) const static BYTE SDP_TYPE_DESC_##n = SDP_DATA_ELEM_TYPE_DESC(SDP_TYPE_##t, s) +#define SDP_DEF_INTEGRAL( w, s ) \ + SDP_DEF_TYPE( INT##w, INT, s ); \ + SDP_DEF_TYPE( UINT##w, UINT, s); + +SDP_DEF_INTEGRAL( 8, 1_BYTE ); +SDP_DEF_INTEGRAL( 16, 2_BYTES ); +SDP_DEF_INTEGRAL( 32, 4_BYTES ); +SDP_DEF_INTEGRAL( 64, 8_BYTES ); +SDP_DEF_INTEGRAL( 128, 16_BYTES ); + +SDP_DEF_TYPE( STR8, STRING, NEXT_UINT8 ); +SDP_DEF_TYPE( STR16, STRING, NEXT_UINT16 ); +SDP_DEF_TYPE( STR32, STRING, NEXT_UINT32 ); + +static void test_BluetoothSdpGetElementData_ints( void ) +{ + static struct + { + BYTE data_elem[17]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + } test_cases[] = { + { + {SDP_TYPE_DESC_INT8, 0xde}, + 2, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT8, {.int8 = 0xde}} + }, + { + {SDP_TYPE_DESC_UINT8, 0xde}, + 2, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + }, + { + {SDP_TYPE_DESC_INT16, 0xde, 0xad}, + 3, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT16, {.int16 = 0xdead}}, + }, + { + {SDP_TYPE_DESC_UINT16, 0xde, 0xad }, + 3, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0xdead}}, + }, + { + {SDP_TYPE_DESC_INT32, 0xde, 0xad, 0xbe, 0xef}, + 5, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT32, {.int32 = 0xdeadbeef}}, + }, + { + {SDP_TYPE_DESC_UINT32, 0xde, 0xad, 0xbe, 0xef}, + 5, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT32, {.uint32 = 0xdeadbeef}}, + }, + { + {SDP_TYPE_DESC_INT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT64, {.int64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPE_DESC_UINT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT64, {.uint64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPE_DESC_INT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT64, {.int64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPE_DESC_UINT64, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT64, {.uint64 = 0xdeadbeefdeadbeef}}, + }, + { + {SDP_TYPE_DESC_INT128, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }, + 17, + ERROR_SUCCESS, + {SDP_TYPE_INT, SDP_ST_INT128, {.int128 = {0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef}}}, + }, + { + {SDP_TYPE_DESC_UINT128, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}, + 17, + ERROR_SUCCESS, + {SDP_TYPE_UINT, SDP_ST_UINT128, {.uint128 = {0xdeadbeefdeadbeef, 0xdeadbeefdeadbeef}}}, + } + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context( TEST_CASE_NAME( i ) ); + todo_wine test_BluetoothSdpGetElementData( test_cases[i].data_elem, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); + winetest_pop_context(); + } +} + +static void test_BluetoothSdpGetElementData_str( void ) +{ + static struct { + BYTE stream[11]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + const char *string; + } test_cases[] = { + { + {SDP_TYPE_DESC_STR8, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 8, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, {.string = {&test_cases[0].stream[2], 6}}}, + "foobar", + }, + { + {SDP_TYPE_DESC_STR16, 0x00, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, {.string = {&test_cases[1].stream[3], 6}}}, + "foobar", + }, + { + {SDP_TYPE_DESC_STR32, 0x00, 0x00, 0x00, 0x06, 'f', 'o', 'o', 'b', 'a', 'r'}, + 11, + ERROR_SUCCESS, + {SDP_TYPE_STRING, SDP_ST_NONE, {.string = {&test_cases[2].stream[5], 6}}}, + "foobar", + } + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + winetest_push_context( TEST_CASE_NAME( i ) ); + todo_wine test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); + if (test_cases[i].error == ERROR_SUCCESS) + { + SDP_ELEMENT_DATA result = {0}; + if (!BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, &result )) + { + todo_wine ok( strlen( test_cases[i].string ) == result.data.string.length, + "%s != %s.\n", debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, + result.data.string.length ) ); + todo_wine ok( !memcmp( result.data.string.value, test_cases[i].string, + result.data.string.length ), + "%s != %s.\n", debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, + result.data.string.length ) ); + } + } + winetest_pop_context(); + } +} + +START_TEST( sdp ) +{ + test_BluetoothSdpGetElementData_nil(); + test_BluetoothSdpGetElementData_ints(); + test_BluetoothSdpGetElementData_invalid(); + test_BluetoothSdpGetElementData_str(); +}
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/sdp.c | 228 ++++++++++++++++++++++++++++++++- dlls/bluetoothapis/tests/sdp.c | 38 +++--- 2 files changed, 245 insertions(+), 21 deletions(-)
diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index e3c6b27afc2..0b87e9488da 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -30,11 +30,235 @@
WINE_DEFAULT_DEBUG_CHANNEL( bluetoothapis );
+#ifdef WORDS_BIGENDIAN +#define BTH_READ_UINT16( s ) (s) +#define BTH_READ_UINT32( s ) (s) +#define BTH_READ_UINT64( s ) (s) +#else +#define BTH_READ_UINT16( s ) RtlUshortByteSwap( *(USHORT *)(s) ) +#define BTH_READ_UINT32( s ) RtlUlongByteSwap( *(ULONG *)(s) ) +#define BTH_READ_UINT64( s ) RtlUlonglongByteSwap( *(ULONGLONG *)(s) ) +#endif + +#define SDP_SIZE_DESC_1_BYTE 0 +#define SDP_SIZE_DESC_2_BYTES 1 +#define SDP_SIZE_DESC_4_BYTES 2 +#define SDP_SIZE_DESC_8_BYTES 3 +#define SDP_SIZE_DESC_16_BYTES 4 +#define SDP_SIZE_DESC_NEXT_UINT8 5 +#define SDP_SIZE_DESC_NEXT_UINT16 6 +#define SDP_SIZE_DESC_NEXT_UINT32 7 + +static void bth_read_uint128( BYTE *s, SDP_ULARGE_INTEGER_16 *v ) +{ + v->HighPart = BTH_READ_UINT64( s ); + v->LowPart = BTH_READ_UINT64( s + 8 ); +} + +static BYTE data_elem_type( BYTE elem ) { return (elem & 0xf8) >> 3; } +static BYTE data_elem_size_desc( BYTE elem ) { return elem & 0x7; } + +#define SDP_ELEMENT_IS_UINT16( d ) ( (d)->type == SDP_TYPE_UINT && (d)->specificType == SDP_ST_UINT16 ) +#define SDP_ELEMENT_IS_ATTRID( d ) SDP_ELEMENT_IS_UINT16((d)) + +/* Read the data element's size/length as described by the size descriptor, starting from stream. Only + * valid for SDP_SIZE_DESC_NEXT_* types. */ +static BOOL sdp_elem_read_var_size( BYTE *stream, ULONG stream_size, SIZE_T *read, BYTE size_desc, + UINT32 *size ) +{ + switch (size_desc) + { + case SDP_SIZE_DESC_NEXT_UINT8: + if (stream_size < sizeof( UINT8 )) return FALSE; + *size = *stream; + *read += sizeof( UINT8 ); + return TRUE; + case SDP_SIZE_DESC_NEXT_UINT16: + if (stream_size < sizeof( UINT16 )) return FALSE; + *size = BTH_READ_UINT16( stream ); + *read += sizeof( UINT16 ); + return TRUE; + case SDP_SIZE_DESC_NEXT_UINT32: + if (stream_size < sizeof( UINT32 )) return FALSE; + *size = BTH_READ_UINT32( stream ); + *read += sizeof( UINT32 ); + return TRUE; + default: + return FALSE; + } +} + +const static SDP_SPECIFICTYPE SDP_BASIC_TYPES[4][5] = { + [SDP_TYPE_UINT] = + { + [SDP_SIZE_DESC_1_BYTE] = SDP_ST_UINT8, + [SDP_SIZE_DESC_2_BYTES] = SDP_ST_UINT16, + [SDP_SIZE_DESC_4_BYTES] = SDP_ST_UINT32, + [SDP_SIZE_DESC_8_BYTES] = SDP_ST_UINT64, + [SDP_SIZE_DESC_16_BYTES] = SDP_ST_UINT128, + }, + [SDP_TYPE_INT] = + { + [SDP_SIZE_DESC_1_BYTE] = SDP_ST_INT8, + [SDP_SIZE_DESC_2_BYTES] = SDP_ST_INT16, + [SDP_SIZE_DESC_4_BYTES] = SDP_ST_INT32, + [SDP_SIZE_DESC_8_BYTES] = SDP_ST_INT64, + [SDP_SIZE_DESC_16_BYTES] = SDP_ST_INT128, + }, + [SDP_TYPE_UUID] = + { + [SDP_SIZE_DESC_2_BYTES] = SDP_ST_UUID16, + [SDP_SIZE_DESC_4_BYTES] = SDP_ST_UUID32, + [SDP_SIZE_DESC_16_BYTES] = SDP_ST_UUID128, + }, +}; + +static BOOL sdp_read_specific_type( BYTE *stream, ULONG stream_size, SDP_SPECIFICTYPE st, + SDP_ELEMENT_DATA *data, SIZE_T *read ) +{ + switch (st) + { + case SDP_ST_UINT8: + case SDP_ST_INT8: + if (stream_size < sizeof( UINT8 )) return FALSE; + data->data.uint8 = *stream; + *read += sizeof( UINT8 ); + break; + case SDP_ST_UINT16: + case SDP_ST_INT16: + case SDP_ST_UUID16: + if (stream_size < sizeof( UINT16 )) return FALSE; + data->data.uint16 = BTH_READ_UINT16( stream ); + *read += sizeof( UINT16 ); + break; + case SDP_ST_UINT32: + case SDP_ST_INT32: + if (stream_size < sizeof( UINT32 )) return FALSE; + data->data.uint32 = BTH_READ_UINT32( stream ); + *read += sizeof( UINT32 ); + break; + case SDP_ST_UINT64: + case SDP_ST_INT64: + if (stream_size < sizeof( UINT64 )) return FALSE; + data->data.uint64 = BTH_READ_UINT64( stream ); + *read += sizeof( UINT64 ); + break; + case SDP_ST_UINT128: + case SDP_ST_INT128: + case SDP_ST_UUID128: + if (stream_size < sizeof( SDP_ULARGE_INTEGER_16 )) return FALSE; + bth_read_uint128( stream, &data->data.uint128 ); + *read += sizeof( SDP_ULARGE_INTEGER_16 ); + break; + default: + return FALSE; + } + + return TRUE; +} + +static DWORD sdp_read_element_data( BYTE *stream, ULONG stream_size, SDP_ELEMENT_DATA *data, + SIZE_T *read ) +{ + BYTE type, size_desc, elem; + SDP_SPECIFICTYPE st; + + if (stream_size < sizeof( BYTE )) return ERROR_INVALID_PARAMETER; + + elem = *stream; + type = data_elem_type( elem ); + size_desc = data_elem_size_desc( elem ); + + stream += sizeof( BYTE ); + *read += sizeof( BYTE ); + stream_size -= sizeof( BYTE ); + + memset( data, 0, sizeof( *data ) ); + switch (type) + { + case SDP_TYPE_NIL: + if (size_desc != 0) return ERROR_INVALID_PARAMETER; + + data->type = type; + data->specificType = SDP_ST_NONE; + break; + case SDP_TYPE_UINT: + case SDP_TYPE_INT: + case SDP_TYPE_UUID: + if (size_desc > SDP_SIZE_DESC_16_BYTES) return ERROR_INVALID_PARAMETER; + + st = SDP_BASIC_TYPES[type][size_desc]; + if (st == SDP_ST_NONE) return ERROR_INVALID_PARAMETER; + + if (!sdp_read_specific_type( stream, stream_size, st, data, read )) + return ERROR_INVALID_PARAMETER; + + data->type = type; + data->specificType = st; + break; + case SDP_TYPE_BOOLEAN: + if (size_desc != SDP_SIZE_DESC_1_BYTE) return ERROR_INVALID_PARAMETER; + if (stream_size < sizeof( BYTE )) return ERROR_INVALID_PARAMETER; + + data->type = type; + data->specificType = SDP_ST_NONE; + data->data.booleanVal = *stream; + *read += sizeof( BYTE ); + break; + case SDP_TYPE_STRING: + case SDP_TYPE_URL: + case SDP_TYPE_SEQUENCE: + case SDP_TYPE_ALTERNATIVE: + { + UINT32 elems_size; + SIZE_T size_read = 0; + + if (!(size_desc >= SDP_SIZE_DESC_NEXT_UINT8 && size_desc <= SDP_SIZE_DESC_NEXT_UINT32)) + return ERROR_INVALID_PARAMETER; + if (!sdp_elem_read_var_size( stream, stream_size, &size_read, size_desc, &elems_size )) + return ERROR_INVALID_PARAMETER; + + stream_size -= size_read; + if (type == SDP_TYPE_STRING || type == SDP_TYPE_URL) + stream += size_read; + + if (stream_size < elems_size) return ERROR_INVALID_PARAMETER; + + data->type = type; + data->specificType = SDP_ST_NONE; + if (type == SDP_TYPE_STRING || type == SDP_TYPE_URL) + { + data->data.string.value = stream; + data->data.string.length = elems_size; + } + else + { + /* For sequence and alternative containers, the stream should begin at the container + * header. */ + data->data.sequence.value = stream - sizeof( BYTE ); + data->data.sequence.length = elems_size + *read + size_read; + } + *read += size_read + elems_size; + break; + } + default: + return ERROR_INVALID_PARAMETER; + } + + return ERROR_SUCCESS; +} + /********************************************************************* * BluetoothSdpGetElementData */ DWORD WINAPI BluetoothSdpGetElementData( BYTE *stream, ULONG stream_size, SDP_ELEMENT_DATA *data ) { - FIXME( "(%p, %lu, %p) stub!\n", stream, stream_size, data ); - return ERROR_CALL_NOT_IMPLEMENTED; + SIZE_T read = 0; + + TRACE( "(%p, %lu, %p)\n", stream, stream_size, data ); + + if (stream == NULL || stream_size < sizeof( BYTE ) || data == NULL) + return ERROR_INVALID_PARAMETER; + + return sdp_read_element_data( stream, stream_size, data, &read ); } diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index 6aead0d2883..47c5bd46615 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -62,16 +62,16 @@ static void test_BluetoothSdpGetElementData_invalid( void ) DWORD ret;
ret = BluetoothSdpGetElementData( NULL, 10, &data ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret );
ret = BluetoothSdpGetElementData( stream, 1, NULL ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret );
ret = BluetoothSdpGetElementData( stream, 0, &data ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret );
ret = BluetoothSdpGetElementData( NULL, 0, NULL ); - todo_wine ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); + ok( ret == ERROR_INVALID_PARAMETER, "%d != %ld.\n", ERROR_INVALID_PARAMETER, ret ); }
static void test_BluetoothSdpGetElementData_nil( void ) @@ -92,8 +92,8 @@ static void test_BluetoothSdpGetElementData_nil( void ) for (i = 0; i < ARRAY_SIZE( test_cases ); i++) { winetest_push_context(TEST_CASE_NAME( i )); - todo_wine test_BluetoothSdpGetElementData( &test_cases[i].data_elem, 1, test_cases[i].error, - &test_cases[i].data ); + test_BluetoothSdpGetElementData( &test_cases[i].data_elem, 1, test_cases[i].error, + &test_cases[i].data ); winetest_pop_context(); } } @@ -211,8 +211,8 @@ static void test_BluetoothSdpGetElementData_ints( void ) for (i = 0; i < ARRAY_SIZE( test_cases ); i++) { winetest_push_context( TEST_CASE_NAME( i ) ); - todo_wine test_BluetoothSdpGetElementData( test_cases[i].data_elem, test_cases[i].size, - test_cases[i].error, &test_cases[i].data ); + test_BluetoothSdpGetElementData( test_cases[i].data_elem, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); winetest_pop_context(); } } @@ -253,22 +253,22 @@ static void test_BluetoothSdpGetElementData_str( void ) for (i = 0; i < ARRAY_SIZE( test_cases ); i++) { winetest_push_context( TEST_CASE_NAME( i ) ); - todo_wine test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, - test_cases[i].error, &test_cases[i].data ); + test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); if (test_cases[i].error == ERROR_SUCCESS) { SDP_ELEMENT_DATA result = {0}; if (!BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, &result )) { - todo_wine ok( strlen( test_cases[i].string ) == result.data.string.length, - "%s != %s.\n", debugstr_a( test_cases[i].string ), - debugstr_an( (const char *)result.data.string.value, - result.data.string.length ) ); - todo_wine ok( !memcmp( result.data.string.value, test_cases[i].string, - result.data.string.length ), - "%s != %s.\n", debugstr_a( test_cases[i].string ), - debugstr_an( (const char *)result.data.string.value, - result.data.string.length ) ); + ok( strlen( test_cases[i].string ) == result.data.string.length, "%s != %s.\n", + debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, + result.data.string.length ) ); + ok( !memcmp( result.data.string.value, test_cases[i].string, + result.data.string.length ), + "%s != %s.\n", debugstr_a( test_cases[i].string ), + debugstr_an( (const char *)result.data.string.value, + result.data.string.length ) ); } } winetest_pop_context();
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/bluetoothapis.spec | 2 +- dlls/bluetoothapis/sdp.c | 12 ++++++++++++ dlls/bthprops.cpl/bthprops.cpl.spec | 2 +- dlls/irprops.cpl/irprops.cpl.spec | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/dlls/bluetoothapis/bluetoothapis.spec b/dlls/bluetoothapis/bluetoothapis.spec index a35e1e22ecc..51fdf55d8ed 100644 --- a/dlls/bluetoothapis/bluetoothapis.spec +++ b/dlls/bluetoothapis/bluetoothapis.spec @@ -55,7 +55,7 @@ @ stub BluetoothRemoveDevice @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue -@ stub BluetoothSdpGetContainerElementData +@ stdcall BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSendAuthenticationResponse diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index 0b87e9488da..30aff8d0fd4 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -262,3 +262,15 @@ DWORD WINAPI BluetoothSdpGetElementData( BYTE *stream, ULONG stream_size, SDP_EL
return sdp_read_element_data( stream, stream_size, data, &read ); } + +/********************************************************************* + * BluetoothSdpGetContainerElementData + */ +DWORD WINAPI BluetoothSdpGetContainerElementData( BYTE *stream, ULONG stream_size, + HBLUETOOTH_CONTAINER_ELEMENT *handle, + SDP_ELEMENT_DATA *data ) +{ + FIXME( "(%p, %lu, %p, %p) stub!\n", stream, stream_size, handle, data ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + diff --git a/dlls/bthprops.cpl/bthprops.cpl.spec b/dlls/bthprops.cpl/bthprops.cpl.spec index 0bef83810db..cd17f0f108c 100644 --- a/dlls/bthprops.cpl/bthprops.cpl.spec +++ b/dlls/bthprops.cpl/bthprops.cpl.spec @@ -46,7 +46,7 @@ @ stub BluetoothRemoveDevice @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue -@ stub BluetoothSdpGetContainerElementData +@ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSelectDevices diff --git a/dlls/irprops.cpl/irprops.cpl.spec b/dlls/irprops.cpl/irprops.cpl.spec index c9cd4df62d6..847b1552603 100644 --- a/dlls/irprops.cpl/irprops.cpl.spec +++ b/dlls/irprops.cpl/irprops.cpl.spec @@ -40,7 +40,7 @@ @ stub BluetoothRemoveDevice @ stub BluetoothSdpEnumAttributes @ stub BluetoothSdpGetAttributeValue -@ stub BluetoothSdpGetContainerElementData +@ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString @ stub BluetoothSelectDevices
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/tests/sdp.c | 106 +++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+)
diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index 47c5bd46615..a91cc9f3dd3 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -124,6 +124,10 @@ SDP_DEF_TYPE( STR8, STRING, NEXT_UINT8 ); SDP_DEF_TYPE( STR16, STRING, NEXT_UINT16 ); SDP_DEF_TYPE( STR32, STRING, NEXT_UINT32 );
+SDP_DEF_TYPE( SEQ8, SEQUENCE, NEXT_UINT8 ); +SDP_DEF_TYPE( SEQ16, SEQUENCE, NEXT_UINT16 ); +SDP_DEF_TYPE( SEQ32, SEQUENCE, NEXT_UINT32 ); + static void test_BluetoothSdpGetElementData_ints( void ) { static struct @@ -275,10 +279,112 @@ static void test_BluetoothSdpGetElementData_str( void ) } }
+static void test_BluetoothSdpGetContainerElementData( void ) +{ + static struct { + BYTE stream[11]; + SIZE_T size; + DWORD error; + SDP_ELEMENT_DATA data; + SDP_ELEMENT_DATA sequence[6]; + SIZE_T container_size; + } test_cases[] = { + { + {SDP_TYPE_DESC_SEQ8, 0x06, SDP_TYPE_DESC_UINT8, 0xde, SDP_TYPE_DESC_UINT8, 0xad, SDP_TYPE_DESC_UINT8, 0xbe}, + 8, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&test_cases[0].stream[0], 8}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPE_DESC_SEQ16, 0x00, 0x06, SDP_TYPE_DESC_UINT8, 0xde, SDP_TYPE_DESC_UINT8, 0xad, SDP_TYPE_DESC_UINT8, 0xbe}, + 9, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&test_cases[1].stream[0], 9}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPE_DESC_SEQ32, 0x00, 0x00, 0x00, 0x06, SDP_TYPE_DESC_UINT8, 0xde, SDP_TYPE_DESC_UINT8, 0xad, SDP_TYPE_DESC_UINT8, 0xbe}, + 11, + ERROR_SUCCESS, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&test_cases[2].stream[0], 11}}}, + { + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xde}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xad}}, + {SDP_TYPE_UINT, SDP_ST_UINT8, {.uint8 = 0xbe}} + }, + 3 + }, + { + {SDP_TYPE_DESC_SEQ8, SDP_TYPE_DESC_UINT8, 0xde, SDP_TYPE_DESC_UINT8, 0xad, SDP_TYPE_DESC_UINT8, 0xbe}, + 1, + ERROR_INVALID_PARAMETER, + }, + }; + SIZE_T i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++) + { + SIZE_T n = 0; + HBLUETOOTH_CONTAINER_ELEMENT handle = NULL; + DWORD ret; + + winetest_push_context( TEST_CASE_NAME( i ) ); + test_BluetoothSdpGetElementData( test_cases[i].stream, test_cases[i].size, + test_cases[i].error, &test_cases[i].data ); + if (test_cases[i].error != ERROR_SUCCESS) + { + winetest_pop_context(); + continue; + } + + while (n < test_cases[i].container_size) + { + SDP_ELEMENT_DATA container_elem = {0}; + + winetest_push_context( "test_cases[%d].sequence[%d]", (int)i, (int)n ); + ret = BluetoothSdpGetContainerElementData( test_cases[i].data.data.sequence.value, + test_cases[i].data.data.sequence.length, + &handle, &container_elem ); + if (ret == ERROR_NO_MORE_ITEMS) + { + todo_wine ok( n == test_cases[i].container_size, "%d != %d.\n", + (int)test_cases[i].container_size, (int)n ); + winetest_pop_context(); + break; + } + todo_wine ok( ret == ERROR_SUCCESS, + "BluetoothSdpGetContainerElementData failed: %ld.\n", ret ); + if (ret == ERROR_SUCCESS) + { + todo_wine ok( !memcmp( &test_cases[i].sequence[n], &container_elem, + sizeof( container_elem ) ), + "%s != %s.\n", + debugstr_SDP_ELEMENT_DATA( &test_cases[i].sequence[n] ), + debugstr_SDP_ELEMENT_DATA( &container_elem ) ); + } + n++; + winetest_pop_context(); + } + winetest_pop_context(); + } +} + START_TEST( sdp ) { test_BluetoothSdpGetElementData_nil(); test_BluetoothSdpGetElementData_ints(); test_BluetoothSdpGetElementData_invalid(); test_BluetoothSdpGetElementData_str(); + test_BluetoothSdpGetContainerElementData(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/sdp.c | 50 ++++++++++++++++++++++++++++++++-- dlls/bluetoothapis/tests/sdp.c | 16 +++++------ 2 files changed, 55 insertions(+), 11 deletions(-)
diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index 30aff8d0fd4..72b36e50cb5 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -270,7 +270,53 @@ DWORD WINAPI BluetoothSdpGetContainerElementData( BYTE *stream, ULONG stream_siz HBLUETOOTH_CONTAINER_ELEMENT *handle, SDP_ELEMENT_DATA *data ) { - FIXME( "(%p, %lu, %p, %p) stub!\n", stream, stream_size, handle, data ); - return ERROR_CALL_NOT_IMPLEMENTED; + BYTE *cursor; + DWORD result; + SIZE_T read = 0; + + TRACE( "(%p, %lu, %p, %p)\n", stream, stream_size, handle, data ); + + if (stream == NULL || stream_size < sizeof( BYTE ) || handle == NULL || data == NULL) + return ERROR_INVALID_PARAMETER; + + cursor = (BYTE *)(*handle); + + if (cursor == NULL) + { + BYTE header, type, size_desc; + UINT32 elems_size = 0; + SIZE_T read = 0; + + header = *stream; + type = data_elem_type( header ); + size_desc = data_elem_size_desc( header ); + + if (type != SDP_TYPE_SEQUENCE && type != SDP_TYPE_ALTERNATIVE) + return ERROR_INVALID_PARAMETER; + if (!(size_desc >= SDP_SIZE_DESC_NEXT_UINT8 && size_desc <= SDP_SIZE_DESC_NEXT_UINT32)) + return ERROR_INVALID_PARAMETER; + + stream++; + if (!sdp_elem_read_var_size( stream, stream_size, &read, size_desc, &elems_size )) + return ERROR_INVALID_PARAMETER; + + stream += read; + stream_size -= read; + } + else + { + if (cursor < stream) return ERROR_INVALID_PARAMETER; + if (cursor == (stream + stream_size)) return ERROR_NO_MORE_ITEMS; + + stream = cursor; + stream_size = stream_size - (cursor - stream); + } + result = sdp_read_element_data( stream, stream_size, data, &read ); + if (result != ERROR_SUCCESS) return result; + + stream += read; + TRACE( "handle=%p\n", stream ); + *handle = stream; + return ERROR_SUCCESS; }
diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index a91cc9f3dd3..ebdd70a4abc 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -358,20 +358,18 @@ static void test_BluetoothSdpGetContainerElementData( void ) &handle, &container_elem ); if (ret == ERROR_NO_MORE_ITEMS) { - todo_wine ok( n == test_cases[i].container_size, "%d != %d.\n", - (int)test_cases[i].container_size, (int)n ); + ok( n == test_cases[i].container_size, "%d != %d.\n", + (int)test_cases[i].container_size, (int)n ); winetest_pop_context(); break; } - todo_wine ok( ret == ERROR_SUCCESS, - "BluetoothSdpGetContainerElementData failed: %ld.\n", ret ); + ok( ret == ERROR_SUCCESS, "BluetoothSdpGetContainerElementData failed: %ld.\n", ret ); if (ret == ERROR_SUCCESS) { - todo_wine ok( !memcmp( &test_cases[i].sequence[n], &container_elem, - sizeof( container_elem ) ), - "%s != %s.\n", - debugstr_SDP_ELEMENT_DATA( &test_cases[i].sequence[n] ), - debugstr_SDP_ELEMENT_DATA( &container_elem ) ); + ok( !memcmp( &test_cases[i].sequence[n], &container_elem, + sizeof( container_elem ) ), + "%s != %s.\n", debugstr_SDP_ELEMENT_DATA( &test_cases[i].sequence[n] ), + debugstr_SDP_ELEMENT_DATA( &container_elem ) ); } n++; winetest_pop_context();
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/bluetoothapis.spec | 2 +- dlls/bluetoothapis/sdp.c | 10 ++++++++++ dlls/bthprops.cpl/bthprops.cpl.spec | 2 +- dlls/irprops.cpl/irprops.cpl.spec | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/bluetoothapis/bluetoothapis.spec b/dlls/bluetoothapis/bluetoothapis.spec index 51fdf55d8ed..3531e2f901c 100644 --- a/dlls/bluetoothapis/bluetoothapis.spec +++ b/dlls/bluetoothapis/bluetoothapis.spec @@ -53,7 +53,7 @@ @ stub BluetoothRegisterForAuthentication @ stdcall BluetoothRegisterForAuthenticationEx(ptr ptr ptr ptr) @ stub BluetoothRemoveDevice -@ stub BluetoothSdpEnumAttributes +@ stdcall BluetoothSdpEnumAttributes(ptr long ptr ptr) @ stub BluetoothSdpGetAttributeValue @ stdcall BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall BluetoothSdpGetElementData(ptr long ptr) diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index 72b36e50cb5..06b1b957848 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -320,3 +320,13 @@ DWORD WINAPI BluetoothSdpGetContainerElementData( BYTE *stream, ULONG stream_siz return ERROR_SUCCESS; }
+/********************************************************************* + * BluetoothSdpEnumAttributes + */ +BOOL WINAPI BluetoothSdpEnumAttributes( BYTE *stream, ULONG stream_size, + PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK callback, void *param ) +{ + FIXME( "(%p, %ld, %p, %p) stub!\n", stream, stream_size, callback, param ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} diff --git a/dlls/bthprops.cpl/bthprops.cpl.spec b/dlls/bthprops.cpl/bthprops.cpl.spec index cd17f0f108c..8e4d2e02a42 100644 --- a/dlls/bthprops.cpl/bthprops.cpl.spec +++ b/dlls/bthprops.cpl/bthprops.cpl.spec @@ -44,7 +44,7 @@ @ stub BluetoothRegisterForAuthentication @ stdcall -import BluetoothRegisterForAuthenticationEx(ptr ptr ptr ptr) @ stub BluetoothRemoveDevice -@ stub BluetoothSdpEnumAttributes +@ stdcall -import BluetoothSdpEnumAttributes(ptr long ptr ptr) @ stub BluetoothSdpGetAttributeValue @ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr) diff --git a/dlls/irprops.cpl/irprops.cpl.spec b/dlls/irprops.cpl/irprops.cpl.spec index 847b1552603..a4cc145dc8f 100644 --- a/dlls/irprops.cpl/irprops.cpl.spec +++ b/dlls/irprops.cpl/irprops.cpl.spec @@ -38,7 +38,7 @@ @ stub BluetoothMapClassOfDeviceToString @ stub BluetoothRegisterForAuthentication @ stub BluetoothRemoveDevice -@ stub BluetoothSdpEnumAttributes +@ stdcall -import BluetoothSdpEnumAttributes(ptr long ptr ptr) @ stub BluetoothSdpGetAttributeValue @ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr)
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/tests/sdp.c | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index ebdd70a4abc..99b0488715b 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -378,6 +378,73 @@ static void test_BluetoothSdpGetContainerElementData( void ) } }
+struct attr_callback_data +{ + const ULONG *attrs_id; + const SDP_ELEMENT_DATA *attrs; + const SIZE_T attrs_n; + SIZE_T i; +}; + +static BYTE sdp_record_bytes[] = { + 0x35, 0x48, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x09, 0x00, 0x01, 0x35, 0x03, + 0x19, 0x12, 0x00, 0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10, 0x02, 0x09, 0x00, 0x09, 0x35, + 0x08, 0x35, 0x06, 0x19, 0x12, 0x00, 0x09, 0x01, 0x03, 0x09, 0x02, 0x00, 0x09, 0x01, 0x03, + 0x09, 0x02, 0x01, 0x09, 0x1d, 0x6b, 0x09, 0x02, 0x02, 0x09, 0x02, 0x46, 0x09, 0x02, 0x03, + 0x09, 0x05, 0x4d, 0x09, 0x02, 0x04, 0x28, 0x01, 0x09, 0x02, 0x05, 0x09, 0x00, 0x02 }; + +static BOOL WINAPI enum_attr_callback( ULONG attr_id, BYTE *stream, ULONG stream_size, void *param ) +{ + struct attr_callback_data *params = param; + winetest_push_context( TEST_CASE_NAME( params->i ) ); + if (params->i < params->attrs_n) + { + SDP_ELEMENT_DATA data = {0}; + DWORD result; + + todo_wine ok( attr_id == params->attrs_id[params->i], + "Expected attribute id %lu, got %lu.\n", params->attrs_id[params->i], + attr_id ); + result = BluetoothSdpGetElementData( stream, stream_size, &data ); + todo_wine ok( result == ERROR_SUCCESS, "BluetoothSdpGetElementData failed: %ld.\n", + result ); + todo_wine ok( !memcmp( ¶ms->attrs[params->i], &data, sizeof( data ) ), + "Expected %s, got %s.\n", + debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), + debugstr_SDP_ELEMENT_DATA( &data ) ); + + params->i++; + } + winetest_pop_context(); + return TRUE; +} + +static void test_BluetoothSdpEnumAttributes( void ) +{ + static SDP_ELEMENT_DATA attributes[] = { + {SDP_TYPE_UINT, SDP_ST_UINT32, {.uint32 = 0x10000}}, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&sdp_record_bytes[13], 5}}}, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&sdp_record_bytes[21], 5}}}, + {SDP_TYPE_SEQUENCE, SDP_ST_NONE, {.sequence = {&sdp_record_bytes[29], 10}}}, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0x0103}}, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0x1d6b}}, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0x0246}}, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0x054d}}, + {SDP_TYPE_BOOLEAN, SDP_ST_NONE, {.booleanVal = 1}}, + {SDP_TYPE_UINT, SDP_ST_UINT16, {.uint16 = 0x02}}, + }; + const ULONG attrs_id[] = {0x0, 0x1, 0x5, 0x9, 0x200, 0x201, 0x202, 0x203, 0x204, 0x205}; + struct attr_callback_data data = {attrs_id, attributes, ARRAY_SIZE( attributes ), 0}; + + BOOL ret; + + SetLastError( 0xdeadbeef ); + ret = BluetoothSdpEnumAttributes( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), enum_attr_callback, + &data ); + todo_wine ok( ret, "BluetoothSdpEnumAttributes failed with %ld.\n", GetLastError() ); + todo_wine ok( data.i == data.attrs_n, "%d != %d\n", (int)data.i, (int)data.attrs_n ); +} + START_TEST( sdp ) { test_BluetoothSdpGetElementData_nil(); @@ -385,4 +452,5 @@ START_TEST( sdp ) test_BluetoothSdpGetElementData_invalid(); test_BluetoothSdpGetElementData_str(); test_BluetoothSdpGetContainerElementData(); + test_BluetoothSdpEnumAttributes(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/sdp.c | 55 ++++++++++++++++++++++++++++++++-- dlls/bluetoothapis/tests/sdp.c | 19 +++++------- 2 files changed, 60 insertions(+), 14 deletions(-)
diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index 06b1b957848..d375645ef67 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -326,7 +326,56 @@ DWORD WINAPI BluetoothSdpGetContainerElementData( BYTE *stream, ULONG stream_siz BOOL WINAPI BluetoothSdpEnumAttributes( BYTE *stream, ULONG stream_size, PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK callback, void *param ) { - FIXME( "(%p, %ld, %p, %p) stub!\n", stream, stream_size, callback, param ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + SDP_ELEMENT_DATA data = {0}; + DWORD result; + HBLUETOOTH_CONTAINER_ELEMENT cursor = NULL; + + TRACE( "(%p, %ld, %p, %p)\n", stream, stream_size, callback, param ); + + if (stream == NULL || callback == NULL) return ERROR_INVALID_PARAMETER; + + result = BluetoothSdpGetElementData( stream, stream_size, &data ); + if (result != ERROR_SUCCESS) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + + switch (data.type) + { + case SDP_TYPE_SEQUENCE: + case SDP_TYPE_ALTERNATIVE: + break; + default: + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + + for (;;) + { + SDP_ELEMENT_DATA attrid = {0}; + SDP_ELEMENT_DATA attr = {0}; + BYTE *raw_attr_stream; + + result = BluetoothSdpGetContainerElementData( data.data.sequence.value, + data.data.sequence.length, &cursor, &attrid ); + if (result == ERROR_NO_MORE_ITEMS) return TRUE; + if (result || !SDP_ELEMENT_IS_ATTRID( &attrid )) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + + raw_attr_stream = cursor; + result = BluetoothSdpGetContainerElementData( data.data.sequence.value, + data.data.sequence.length, &cursor, &attr ); + if (result != ERROR_SUCCESS) + { + SetLastError( ERROR_INVALID_DATA ); + return FALSE; + } + if (!callback( attrid.data.uint16, raw_attr_stream, ((BYTE *)cursor - raw_attr_stream), + param )) + return TRUE; + } } diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index 99b0488715b..126cdf2c83d 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -402,16 +402,13 @@ static BOOL WINAPI enum_attr_callback( ULONG attr_id, BYTE *stream, ULONG stream SDP_ELEMENT_DATA data = {0}; DWORD result;
- todo_wine ok( attr_id == params->attrs_id[params->i], - "Expected attribute id %lu, got %lu.\n", params->attrs_id[params->i], - attr_id ); + ok( attr_id == params->attrs_id[params->i], "Expected attribute id %lu, got %lu.\n", + params->attrs_id[params->i], attr_id ); result = BluetoothSdpGetElementData( stream, stream_size, &data ); - todo_wine ok( result == ERROR_SUCCESS, "BluetoothSdpGetElementData failed: %ld.\n", - result ); - todo_wine ok( !memcmp( ¶ms->attrs[params->i], &data, sizeof( data ) ), - "Expected %s, got %s.\n", - debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), - debugstr_SDP_ELEMENT_DATA( &data ) ); + ok( result == ERROR_SUCCESS, "BluetoothSdpGetElementData failed: %ld.\n", result ); + ok( !memcmp( ¶ms->attrs[params->i], &data, sizeof( data ) ), "Expected %s, got %s.\n", + debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), + debugstr_SDP_ELEMENT_DATA( &data ) );
params->i++; } @@ -441,8 +438,8 @@ static void test_BluetoothSdpEnumAttributes( void ) SetLastError( 0xdeadbeef ); ret = BluetoothSdpEnumAttributes( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), enum_attr_callback, &data ); - todo_wine ok( ret, "BluetoothSdpEnumAttributes failed with %ld.\n", GetLastError() ); - todo_wine ok( data.i == data.attrs_n, "%d != %d\n", (int)data.i, (int)data.attrs_n ); + ok( ret, "BluetoothSdpEnumAttributes failed with %ld.\n", GetLastError() ); + ok( data.i == data.attrs_n, "%d != %d\n", (int)data.i, (int)data.attrs_n ); }
START_TEST( sdp )
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/bluetoothapis.spec | 2 +- dlls/bluetoothapis/sdp.c | 10 ++++++++++ dlls/bthprops.cpl/bthprops.cpl.spec | 2 +- dlls/irprops.cpl/irprops.cpl.spec | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/dlls/bluetoothapis/bluetoothapis.spec b/dlls/bluetoothapis/bluetoothapis.spec index 3531e2f901c..939072d308c 100644 --- a/dlls/bluetoothapis/bluetoothapis.spec +++ b/dlls/bluetoothapis/bluetoothapis.spec @@ -54,7 +54,7 @@ @ stdcall BluetoothRegisterForAuthenticationEx(ptr ptr ptr ptr) @ stub BluetoothRemoveDevice @ stdcall BluetoothSdpEnumAttributes(ptr long ptr ptr) -@ stub BluetoothSdpGetAttributeValue +@ stdcall BluetoothSdpGetAttributeValue(ptr long long ptr) @ stdcall BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index d375645ef67..7740a8a371e 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -379,3 +379,13 @@ BOOL WINAPI BluetoothSdpEnumAttributes( BYTE *stream, ULONG stream_size, return TRUE; } } + +/********************************************************************* + * BluetoothSdpGetAttributeValue + */ +DWORD WINAPI BluetoothSdpGetAttributeValue( BYTE *stream, ULONG stream_size, USHORT attr_id, + SDP_ELEMENT_DATA *data ) +{ + FIXME( "(%p %lu %u %p) stub!\n", stream, stream_size, attr_id, data ); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/dlls/bthprops.cpl/bthprops.cpl.spec b/dlls/bthprops.cpl/bthprops.cpl.spec index 8e4d2e02a42..7fe1d82ac89 100644 --- a/dlls/bthprops.cpl/bthprops.cpl.spec +++ b/dlls/bthprops.cpl/bthprops.cpl.spec @@ -45,7 +45,7 @@ @ stdcall -import BluetoothRegisterForAuthenticationEx(ptr ptr ptr ptr) @ stub BluetoothRemoveDevice @ stdcall -import BluetoothSdpEnumAttributes(ptr long ptr ptr) -@ stub BluetoothSdpGetAttributeValue +@ stdcall -import BluetoothSdpGetAttributeValue(ptr long long ptr) @ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString diff --git a/dlls/irprops.cpl/irprops.cpl.spec b/dlls/irprops.cpl/irprops.cpl.spec index a4cc145dc8f..0baeb9179e3 100644 --- a/dlls/irprops.cpl/irprops.cpl.spec +++ b/dlls/irprops.cpl/irprops.cpl.spec @@ -39,7 +39,7 @@ @ stub BluetoothRegisterForAuthentication @ stub BluetoothRemoveDevice @ stdcall -import BluetoothSdpEnumAttributes(ptr long ptr ptr) -@ stub BluetoothSdpGetAttributeValue +@ stdcall -import BluetoothSdpGetAttributeValue(ptr long long ptr) @ stdcall -import BluetoothSdpGetContainerElementData(ptr long ptr ptr) @ stdcall -import BluetoothSdpGetElementData(ptr long ptr) @ stub BluetoothSdpGetString
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/tests/sdp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index 126cdf2c83d..859ddbae37b 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -399,7 +399,7 @@ static BOOL WINAPI enum_attr_callback( ULONG attr_id, BYTE *stream, ULONG stream winetest_push_context( TEST_CASE_NAME( params->i ) ); if (params->i < params->attrs_n) { - SDP_ELEMENT_DATA data = {0}; + SDP_ELEMENT_DATA data = {0}, data2 = {0}; DWORD result;
ok( attr_id == params->attrs_id[params->i], "Expected attribute id %lu, got %lu.\n", @@ -410,6 +410,15 @@ static BOOL WINAPI enum_attr_callback( ULONG attr_id, BYTE *stream, ULONG stream debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), debugstr_SDP_ELEMENT_DATA( &data ) );
+ result = BluetoothSdpGetAttributeValue( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), + params->attrs_id[params->i], &data2 ); + todo_wine ok( result == ERROR_SUCCESS, "BluetoothSdpGetAttributeValue failed: %ld.\n", + result ); + todo_wine ok( !memcmp( ¶ms->attrs[params->i], &data2, sizeof( data2 ) ), + "Expected %s, got %s.\n", + debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), + debugstr_SDP_ELEMENT_DATA( &data2 ) ); + params->i++; } winetest_pop_context(); @@ -432,6 +441,8 @@ static void test_BluetoothSdpEnumAttributes( void ) }; const ULONG attrs_id[] = {0x0, 0x1, 0x5, 0x9, 0x200, 0x201, 0x202, 0x203, 0x204, 0x205}; struct attr_callback_data data = {attrs_id, attributes, ARRAY_SIZE( attributes ), 0}; + SDP_ELEMENT_DATA elem_data = {0}; + DWORD result;
BOOL ret;
@@ -440,6 +451,10 @@ static void test_BluetoothSdpEnumAttributes( void ) &data ); ok( ret, "BluetoothSdpEnumAttributes failed with %ld.\n", GetLastError() ); ok( data.i == data.attrs_n, "%d != %d\n", (int)data.i, (int)data.attrs_n ); + + result = BluetoothSdpGetAttributeValue( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), 0xff, + &elem_data ); + todo_wine ok( result == ERROR_FILE_NOT_FOUND, "%d != %ld.\n", ERROR_FILE_NOT_FOUND, result ); }
START_TEST( sdp )
From: Vibhav Pant vibhavp@gmail.com
--- dlls/bluetoothapis/sdp.c | 34 ++++++++++++++++++++++++++++++++-- dlls/bluetoothapis/tests/sdp.c | 12 +++++------- 2 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/dlls/bluetoothapis/sdp.c b/dlls/bluetoothapis/sdp.c index 7740a8a371e..be74839ce09 100644 --- a/dlls/bluetoothapis/sdp.c +++ b/dlls/bluetoothapis/sdp.c @@ -380,12 +380,42 @@ BOOL WINAPI BluetoothSdpEnumAttributes( BYTE *stream, ULONG stream_size, } }
+struct get_attr_value_data +{ + USHORT attr_id; + BYTE *attr_stream; + ULONG stream_size; +}; + +static BOOL WINAPI get_attr_value_callback( ULONG attr_id, BYTE *stream, ULONG stream_size, + void *params ) +{ + struct get_attr_value_data *args = params; + if (attr_id == args->attr_id) + { + args->attr_stream = stream; + args->stream_size = stream_size; + return FALSE; + } + return TRUE; +} + /********************************************************************* * BluetoothSdpGetAttributeValue */ DWORD WINAPI BluetoothSdpGetAttributeValue( BYTE *stream, ULONG stream_size, USHORT attr_id, SDP_ELEMENT_DATA *data ) { - FIXME( "(%p %lu %u %p) stub!\n", stream, stream_size, attr_id, data ); - return ERROR_CALL_NOT_IMPLEMENTED; + struct get_attr_value_data args = {0}; + + TRACE( "(%p %lu %u %p)\n", stream, stream_size, attr_id, data ); + + if (stream == NULL || data == NULL) return ERROR_INVALID_PARAMETER; + + args.attr_id = attr_id; + if (!BluetoothSdpEnumAttributes( stream, stream_size, get_attr_value_callback, &args )) + return ERROR_INVALID_PARAMETER; + if (!args.attr_stream) return ERROR_FILE_NOT_FOUND; + + return BluetoothSdpGetElementData( args.attr_stream, args.stream_size, data ); } diff --git a/dlls/bluetoothapis/tests/sdp.c b/dlls/bluetoothapis/tests/sdp.c index 859ddbae37b..ff5059dc66e 100644 --- a/dlls/bluetoothapis/tests/sdp.c +++ b/dlls/bluetoothapis/tests/sdp.c @@ -412,12 +412,10 @@ static BOOL WINAPI enum_attr_callback( ULONG attr_id, BYTE *stream, ULONG stream
result = BluetoothSdpGetAttributeValue( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), params->attrs_id[params->i], &data2 ); - todo_wine ok( result == ERROR_SUCCESS, "BluetoothSdpGetAttributeValue failed: %ld.\n", - result ); - todo_wine ok( !memcmp( ¶ms->attrs[params->i], &data2, sizeof( data2 ) ), - "Expected %s, got %s.\n", - debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), - debugstr_SDP_ELEMENT_DATA( &data2 ) ); + ok( result == ERROR_SUCCESS, "BluetoothSdpGetAttributeValue failed: %ld.\n", result ); + ok( !memcmp( ¶ms->attrs[params->i], &data2, sizeof( data2 ) ), "Expected %s, got %s.\n", + debugstr_SDP_ELEMENT_DATA( ¶ms->attrs[params->i] ), + debugstr_SDP_ELEMENT_DATA( &data2 ) );
params->i++; } @@ -454,7 +452,7 @@ static void test_BluetoothSdpEnumAttributes( void )
result = BluetoothSdpGetAttributeValue( sdp_record_bytes, ARRAY_SIZE( sdp_record_bytes ), 0xff, &elem_data ); - todo_wine ok( result == ERROR_FILE_NOT_FOUND, "%d != %ld.\n", ERROR_FILE_NOT_FOUND, result ); + ok( result == ERROR_FILE_NOT_FOUND, "%d != %ld.\n", ERROR_FILE_NOT_FOUND, result ); }
START_TEST( sdp )
On Fri Sep 20 21:12:06 2024 +0000, Rémi Bernon wrote:
This is a lot of code for debug printing, do we really need it in the tests? There's a lot of tests in Wine, and I don't think being verbose in the test messages have been considered very useful yet. After a couple hundred of written tests you will likely find the `ok("got %#x", err)` pattern very appealing. In general tests aren't supposed to fail, so the messages don't matter much. When they do, you will anyway likely need to reproduce the failure locally, where you can add as much detail about it as you like. Note that we also have a test output size limit of 32K, and any todo_wine that is printed out should stay as little verbose as possible in order to not reach that limit and fail the test.
I understand, I have simplified most of the test logs.