[PATCH 3/5] msado15: Implement _Stream_Read and _Stream_Write.

Hans Leidekker hans at codeweavers.com
Mon Dec 9 04:24:31 CST 2019


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/msado15/msado15_private.h |  6 +++
 dlls/msado15/stream.c          | 95 +++++++++++++++++++++++++++++++---
 dlls/msado15/tests/msado15.c   | 57 +++++++++++++++++++-
 3 files changed, 149 insertions(+), 9 deletions(-)

diff --git a/dlls/msado15/msado15_private.h b/dlls/msado15/msado15_private.h
index f901791ea9..1078cbf64e 100644
--- a/dlls/msado15/msado15_private.h
+++ b/dlls/msado15/msado15_private.h
@@ -25,4 +25,10 @@ HRESULT Connection_create( void ** ) DECLSPEC_HIDDEN;
 HRESULT Recordset_create( void ** ) DECLSPEC_HIDDEN;
 HRESULT Stream_create( void ** ) DECLSPEC_HIDDEN;
 
+static inline void *heap_realloc_zero( void *mem, SIZE_T len )
+{
+    if (!mem) return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
+    return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len );
+}
+
 #endif /* _WINE_MSADO15_PRIVATE_H_ */
diff --git a/dlls/msado15/stream.c b/dlls/msado15/stream.c
index cc67e930a4..d5a129f869 100644
--- a/dlls/msado15/stream.c
+++ b/dlls/msado15/stream.c
@@ -32,10 +32,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(msado15);
 
 struct stream
 {
-    _Stream         Stream_iface;
-    LONG            refs;
-    ObjectStateEnum state;
-    StreamTypeEnum  type;
+    _Stream          Stream_iface;
+    LONG             refs;
+    ObjectStateEnum  state;
+    StreamTypeEnum   type;
+    LONG             size;
+    LONG             allocated;
+    LONG             pos;
+    BYTE            *buf;
 };
 
 static inline struct stream *impl_from_Stream( _Stream *iface )
@@ -56,6 +60,7 @@ static ULONG WINAPI stream_Release( _Stream *iface )
     if (!refs)
     {
         TRACE( "destroying %p\n", stream );
+        heap_free( stream->buf );
         heap_free( stream );
     }
     return refs;
@@ -124,6 +129,20 @@ static HRESULT WINAPI stream_get_Position( _Stream *iface, LONG *pos )
     return E_NOTIMPL;
 }
 
+static HRESULT resize_buffer( struct stream *stream, LONG size )
+{
+    if (stream->allocated < size)
+    {
+        BYTE *tmp;
+        LONG new_size = max( size, stream->allocated * 2 );
+        if (!(tmp = heap_realloc_zero( stream->buf, new_size ))) return E_OUTOFMEMORY;
+        stream->buf = tmp;
+        stream->allocated = new_size;
+    }
+    stream->size = size;
+    return S_OK;
+}
+
 static HRESULT WINAPI stream_put_Position( _Stream *iface, LONG pos )
 {
     FIXME( "%p, %d\n", iface, pos );
@@ -193,10 +212,49 @@ static HRESULT WINAPI stream_put_Charset( _Stream *iface, BSTR charset )
     return E_NOTIMPL;
 }
 
+static HRESULT create_byte_array( BYTE *data, LONG len, VARIANT *ret )
+{
+    SAFEARRAY *vector;
+    LONG i;
+    HRESULT hr;
+
+    if (!len)
+    {
+        V_VT( ret ) = VT_NULL;
+        return S_OK;
+    }
+    if (!(vector = SafeArrayCreateVector( VT_UI1, 0, len ))) return E_OUTOFMEMORY;
+    for (i = 0; i < len; i++)
+    {
+        if ((hr = SafeArrayPutElement( vector, &i, &data[i] )) != S_OK)
+        {
+            SafeArrayDestroy( vector );
+            return hr;
+        }
+    }
+
+    V_VT( ret ) = VT_ARRAY | VT_UI1;
+    V_ARRAY( ret ) = vector;
+    return S_OK;
+}
+
 static HRESULT WINAPI stream_Read( _Stream *iface, LONG size, VARIANT *val )
 {
-    FIXME( "%p, %d, %p\n", iface, size, val );
-    return E_NOTIMPL;
+    struct stream *stream = impl_from_Stream( iface );
+    HRESULT hr;
+
+    TRACE( "%p, %d, %p\n", stream, size, val );
+
+    if (stream->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
+    if (stream->type != adTypeBinary) return MAKE_ADO_HRESULT( adErrIllegalOperation );
+    if (size < adReadAll) return MAKE_ADO_HRESULT( adErrInvalidArgument );
+
+    if (size == adReadAll) size = stream->size - stream->pos;
+    else size = min( size, stream->size - stream->pos );
+
+    if ((hr = create_byte_array( stream->buf + stream->pos, size, val )) != S_OK) return hr;
+    stream->pos += size;
+    return S_OK;
 }
 
 static HRESULT WINAPI stream_Open( _Stream *iface, VARIANT src, ConnectModeEnum mode, StreamOpenOptionsEnum options,
@@ -219,6 +277,10 @@ static HRESULT WINAPI stream_Close( _Stream *iface )
 
     if (stream->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
 
+    heap_free( stream->buf );
+    stream->buf  = NULL;
+    stream->size = stream->allocated = stream->pos = 0;
+
     stream->state = adStateClosed;
     return S_OK;
 }
@@ -231,8 +293,25 @@ static HRESULT WINAPI stream_SkipLine( _Stream *iface )
 
 static HRESULT WINAPI stream_Write( _Stream *iface, VARIANT buf )
 {
-    FIXME( "%p, %s\n", iface, debugstr_variant(&buf) );
-    return E_NOTIMPL;
+    struct stream *stream = impl_from_Stream( iface );
+    LONG bound, i;
+    HRESULT hr;
+
+    TRACE( "%p, %s\n", stream, debugstr_variant(&buf) );
+
+    if (stream->state == adStateClosed) return MAKE_ADO_HRESULT( adErrObjectClosed );
+    if (stream->type != adTypeBinary) return MAKE_ADO_HRESULT( adErrIllegalOperation );
+    if (V_VT( &buf ) != (VT_ARRAY | VT_UI1)) return MAKE_ADO_HRESULT( adErrInvalidArgument );
+
+    if ((hr = SafeArrayGetUBound( V_ARRAY( &buf ), 1, &bound )) != S_OK) return hr;
+    if ((hr = resize_buffer( stream, stream->size + bound + 1 )) != S_OK) return hr;
+
+    for (i = 0; i <= bound; i++)
+    {
+        if ((hr = SafeArrayGetElement( V_ARRAY( &buf ), &i, &stream->buf[stream->pos++] )) != S_OK) return hr;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI stream_SetEOS( _Stream *iface )
diff --git a/dlls/msado15/tests/msado15.c b/dlls/msado15/tests/msado15.c
index 9733116151..257d1c26fa 100644
--- a/dlls/msado15/tests/msado15.c
+++ b/dlls/msado15/tests/msado15.c
@@ -25,13 +25,34 @@
 
 #define MAKE_ADO_HRESULT( err ) MAKE_HRESULT( SEVERITY_ERROR, FACILITY_CONTROL, err )
 
+static HRESULT str_to_byte_array( const char *data, VARIANT *ret )
+{
+    SAFEARRAY *vector;
+    LONG i, len = strlen(data);
+    HRESULT hr;
+
+    if (!(vector = SafeArrayCreateVector( VT_UI1, 0, len ))) return E_OUTOFMEMORY;
+    for (i = 0; i < len; i++)
+    {
+        if ((hr = SafeArrayPutElement( vector, &i, (void *)&data[i] )) != S_OK)
+        {
+            SafeArrayDestroy( vector );
+            return hr;
+        }
+    }
+
+    V_VT( ret ) = VT_ARRAY | VT_UI1;
+    V_ARRAY( ret ) = vector;
+    return S_OK;
+}
+
 static void test_Stream(void)
 {
     _Stream *stream;
     StreamTypeEnum type;
     LONG refs;
     ObjectStateEnum state;
-    VARIANT missing;
+    VARIANT missing, val;
     HRESULT hr;
 
     hr = CoCreateInstance( &CLSID_Stream, NULL, CLSCTX_INPROC_SERVER, &IID__Stream, (void **)&stream );
@@ -60,6 +81,9 @@ static void test_Stream(void)
     ok( hr == S_OK, "got %08x\n", hr );
     ok( state == adStateClosed, "got %u\n", state );
 
+    hr = _Stream_Read( stream, 2, &val );
+    ok( hr == MAKE_ADO_HRESULT( adErrObjectClosed ), "got %08x\n", hr );
+
     V_VT( &missing ) = VT_ERROR;
     V_ERROR( &missing ) = DISP_E_PARAMNOTFOUND;
     hr = _Stream_Open( stream, missing, adModeUnknown, adOpenStreamUnspecified, NULL, NULL );
@@ -73,6 +97,9 @@ static void test_Stream(void)
     ok( hr == S_OK, "got %08x\n", hr );
     ok( state == adStateOpen, "got %u\n", state );
 
+    hr = _Stream_Read( stream, 2, &val );
+    ok( hr == MAKE_ADO_HRESULT( adErrIllegalOperation ), "got %08x\n", hr );
+
     hr = _Stream_Close( stream );
     ok( hr == S_OK, "got %08x\n", hr );
 
@@ -86,6 +113,34 @@ static void test_Stream(void)
 
     refs = _Stream_Release( stream );
     ok( !refs, "got %d\n", refs );
+
+    /* binary type */
+    hr = CoCreateInstance( &CLSID_Stream, NULL, CLSCTX_INPROC_SERVER, &IID__Stream, (void **)&stream );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = _Stream_put_Type( stream, adTypeBinary );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = _Stream_Open( stream, missing, adModeUnknown, adOpenStreamUnspecified, NULL, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    VariantInit( &val );
+    hr = _Stream_Read( stream, 1, &val );
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok( V_VT( &val ) == VT_NULL, "got %u\n", V_VT( &val ) );
+
+    VariantInit( &val );
+    hr = _Stream_Write( stream, val );
+    ok( hr == MAKE_ADO_HRESULT( adErrInvalidArgument ), "got %08x\n", hr );
+
+    hr = str_to_byte_array( "data", &val );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = _Stream_Write( stream, val );
+    ok( hr == S_OK, "got %08x\n", hr );
+    VariantClear( &val );
+
+    refs = _Stream_Release( stream );
+    ok( !refs, "got %d\n", refs );
 }
 
 START_TEST(msado15)
-- 
2.20.1




More information about the wine-devel mailing list