[PATCH 2/5] shcore: Add file-based stream.

Nikolay Sivov nsivov at codeweavers.com
Tue Nov 27 02:55:45 CST 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/shcore/Makefile.in |   2 +-
 dlls/shcore/main.c      | 327 +++++++++++++++++++++++++++++++++++++++-
 dlls/shcore/shcore.spec |   6 +-
 3 files changed, 329 insertions(+), 6 deletions(-)

diff --git a/dlls/shcore/Makefile.in b/dlls/shcore/Makefile.in
index 8497198996..050be57804 100644
--- a/dlls/shcore/Makefile.in
+++ b/dlls/shcore/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = shcore.dll
-IMPORTS   = user32 gdi32
+IMPORTS   = user32 gdi32 ole32
 
 C_SRCS = \
 	main.c
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c
index 792f7c85b7..f99479d383 100644
--- a/dlls/shcore/main.c
+++ b/dlls/shcore/main.c
@@ -508,6 +508,12 @@ struct shstream
             DWORD length;
             DWORD position;
         } mem;
+        struct
+        {
+            HANDLE handle;
+            DWORD mode;
+            WCHAR *path;
+        } file;
     } u;
 };
 
@@ -742,7 +748,7 @@ static HRESULT WINAPI shstream_Clone(IStream *iface, IStream **dest)
     return E_NOTIMPL;
 }
 
-static const IStreamVtbl shstreamvtbl =
+static const IStreamVtbl memstreamvtbl =
 {
     shstream_QueryInterface,
     shstream_AddRef,
@@ -786,7 +792,7 @@ IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
         data_len = 0;
 
     stream = heap_alloc(sizeof(*stream));
-    stream->IStream_iface.lpVtbl = &shstreamvtbl;
+    stream->IStream_iface.lpVtbl = &memstreamvtbl;
     stream->refcount = 1;
     stream->u.mem.buffer = heap_alloc(data_len);
     if (!stream->u.mem.buffer)
@@ -800,3 +806,320 @@ IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
 
     return &stream->IStream_iface;
 }
+
+static ULONG WINAPI filestream_Release(IStream *iface)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+    TRACE("(%p)->(%u)\n", stream, refcount);
+
+    if (!refcount)
+    {
+        CloseHandle(stream->u.file.handle);
+        heap_free(stream);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *read_len)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    DWORD read = 0;
+
+    TRACE("(%p, %p, %u, %p)\n", stream, buff, size, read_len);
+
+    if (!ReadFile(stream->u.file.handle, buff, size, &read, NULL))
+    {
+        WARN("error %d reading file\n", GetLastError());
+        return S_FALSE;
+    }
+
+    if (read_len)
+        *read_len = read;
+
+    return read == size ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI filestream_Write(IStream *iface, const void *buff, ULONG size, ULONG *written)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    DWORD written_len = 0;
+
+    TRACE("(%p, %p, %u, %p)\n", stream, buff, size, written);
+
+    switch (stream->u.file.mode & 0xf)
+    {
+        case STGM_WRITE:
+        case STGM_READWRITE:
+            break;
+        default:
+            return STG_E_ACCESSDENIED;
+    }
+
+    if (!WriteFile(stream->u.file.handle, buff, size, &written_len, NULL))
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    if (written)
+        *written = written_len;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    DWORD position;
+
+    TRACE("(%p, %s, %d, %p)\n", stream, wine_dbgstr_longlong(move.QuadPart), origin, new_pos);
+
+    position = SetFilePointer(stream->u.file.handle, move.u.LowPart, NULL, origin);
+    if (position == INVALID_SET_FILE_POINTER)
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    if (new_pos)
+    {
+        new_pos->u.HighPart = 0;
+        new_pos->u.LowPart = position;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI filestream_SetSize(IStream *iface, ULARGE_INTEGER size)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+
+    TRACE("(%p, %s)\n", stream, wine_dbgstr_longlong(size.QuadPart));
+
+    if (!SetFilePointer(stream->u.file.handle, size.QuadPart, NULL, FILE_BEGIN))
+        return E_FAIL;
+
+    if (!SetEndOfFile(stream->u.file.handle))
+        return E_FAIL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
+        ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    HRESULT hr = S_OK;
+    char buff[1024];
+
+    TRACE("(%p, %p, %s, %p, %p)\n", stream, dest, wine_dbgstr_longlong(size.QuadPart), read_len, written);
+
+    if (read_len)
+        read_len->QuadPart = 0;
+    if (written)
+        written->QuadPart = 0;
+
+    if (!dest)
+        return S_OK;
+
+    while (size.QuadPart)
+    {
+        ULONG left, read_chunk, written_chunk;
+
+        left = size.QuadPart > sizeof(buff) ? sizeof(buff) : size.QuadPart;
+
+        /* Read */
+        hr = IStream_Read(iface, buff, left, &read_chunk);
+        if (FAILED(hr) || read_chunk == 0)
+            break;
+        if (read_len)
+            read_len->QuadPart += read_chunk;
+
+        /* Write */
+        hr = IStream_Write(dest, buff, read_chunk, &written_chunk);
+        if (written_chunk)
+            written->QuadPart += written_chunk;
+        if (FAILED(hr) || written_chunk != left)
+            break;
+
+        size.QuadPart -= left;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flags)
+{
+    struct shstream *stream = impl_from_IStream(iface);
+    BY_HANDLE_FILE_INFORMATION fi;
+
+    TRACE("(%p, %p, %#x)\n", stream, statstg, flags);
+
+    if (!statstg)
+        return STG_E_INVALIDPOINTER;
+
+    memset(&fi, 0, sizeof(fi));
+    GetFileInformationByHandle(stream->u.file.handle, &fi);
+
+    if (flags & STATFLAG_NONAME)
+        statstg->pwcsName = NULL;
+    else
+    {
+        int len = strlenW(stream->u.file.path);
+        if ((statstg->pwcsName = CoTaskMemAlloc((len + 1) * sizeof(WCHAR))))
+            memcpy(statstg->pwcsName, stream->u.file.path, (len + 1) * sizeof(WCHAR));
+    }
+    statstg->type = 0;
+    statstg->cbSize.u.LowPart = fi.nFileSizeLow;
+    statstg->cbSize.u.HighPart = fi.nFileSizeHigh;
+    statstg->mtime = fi.ftLastWriteTime;
+    statstg->ctime = fi.ftCreationTime;
+    statstg->atime = fi.ftLastAccessTime;
+    statstg->grfMode = stream->u.file.mode;
+    statstg->grfLocksSupported = 0;
+    memcpy(&statstg->clsid, &IID_IStream, sizeof(CLSID));
+    statstg->grfStateBits = 0;
+    statstg->reserved = 0;
+
+    return S_OK;
+}
+
+static const IStreamVtbl filestreamvtbl =
+{
+    shstream_QueryInterface,
+    shstream_AddRef,
+    filestream_Release,
+    filestream_Read,
+    filestream_Write,
+    filestream_Seek,
+    filestream_SetSize,
+    filestream_CopyTo,
+    shstream_Commit,
+    shstream_Revert,
+    shstream_LockRegion,
+    shstream_UnlockRegion,
+    filestream_Stat,
+    shstream_Clone,
+};
+
+/*************************************************************************
+ * SHCreateStreamOnFileEx   [SHCORE.@]
+ */
+HRESULT WINAPI SHCreateStreamOnFileEx(const WCHAR *path, DWORD mode, DWORD attributes,
+    BOOL create, IStream *template, IStream **ret)
+{
+    DWORD access, share, creation_disposition, len;
+    struct shstream *stream;
+    HANDLE hFile;
+
+    TRACE("(%s, %d, 0x%08X, %d, %p, %p)\n", debugstr_w(path), mode, attributes,
+        create, template, ret);
+
+    if (!path || !ret || template)
+        return E_INVALIDARG;
+
+    *ret = NULL;
+
+    /* Access */
+    switch (mode & 0xf)
+    {
+        case STGM_WRITE:
+        case STGM_READWRITE:
+            access = GENERIC_READ | GENERIC_WRITE;
+            break;
+        case STGM_READ:
+            access = GENERIC_READ;
+            break;
+        default:
+            return E_INVALIDARG;
+    }
+
+    /* Sharing */
+    switch (mode & 0xf0)
+    {
+        case 0:
+        case STGM_SHARE_DENY_NONE:
+            share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+            break;
+        case STGM_SHARE_DENY_READ:
+            share = FILE_SHARE_WRITE;
+            break;
+        case STGM_SHARE_DENY_WRITE:
+            share = FILE_SHARE_READ;
+            break;
+        case STGM_SHARE_EXCLUSIVE:
+            share = 0;
+            break;
+        default:
+            return E_INVALIDARG;
+    }
+
+    switch (mode & 0xf000)
+    {
+        case STGM_FAILIFTHERE:
+            creation_disposition = create ? CREATE_NEW : OPEN_EXISTING;
+            break;
+        case STGM_CREATE:
+            creation_disposition = CREATE_ALWAYS;
+            break;
+        default:
+            return E_INVALIDARG;
+    }
+
+    hFile = CreateFileW(path, access, share, NULL, creation_disposition, attributes, 0);
+    if (hFile == INVALID_HANDLE_VALUE)
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    stream = heap_alloc(sizeof(*stream));
+    stream->IStream_iface.lpVtbl = &filestreamvtbl;
+    stream->refcount = 1;
+    stream->u.file.handle = hFile;
+    stream->u.file.mode = mode;
+
+    len = strlenW(path);
+    stream->u.file.path = heap_alloc((len + 1) * sizeof(WCHAR));
+    memcpy(stream->u.file.path, path, (len + 1) * sizeof(WCHAR));
+
+    *ret = &stream->IStream_iface;
+
+    return S_OK;
+}
+
+/*************************************************************************
+ * SHCreateStreamOnFileW   [SHCORE.@]
+ */
+HRESULT WINAPI SHCreateStreamOnFileW(const WCHAR *path, DWORD mode, IStream **stream)
+{
+    TRACE("(%s, %#x, %p)\n", debugstr_w(path), mode, stream);
+
+    if (!path || !stream)
+        return E_INVALIDARG;
+
+    if ((mode & (STGM_CONVERT | STGM_DELETEONRELEASE | STGM_TRANSACTED)) != 0)
+        return E_INVALIDARG;
+
+    return SHCreateStreamOnFileEx(path, mode, 0, FALSE, NULL, stream);
+}
+
+/*************************************************************************
+ * SHCreateStreamOnFileA   [SHCORE.@]
+ */
+HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **stream)
+{
+    WCHAR *pathW;
+    HRESULT hr;
+    DWORD len;
+
+    TRACE("(%s, %#x, %p)\n", debugstr_a(path), mode, stream);
+
+    if (!path)
+        return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+
+    len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
+    pathW = heap_alloc(len * sizeof(WCHAR));
+    if (!pathW)
+        return E_OUTOFMEMORY;
+
+    MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
+    hr = SHCreateStreamOnFileW(pathW, mode, stream);
+    heap_free(pathW);
+
+    return hr;
+}
diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec
index e8643d8691..c3bb8d27e4 100644
--- a/dlls/shcore/shcore.spec
+++ b/dlls/shcore/shcore.spec
@@ -34,9 +34,9 @@
 @ stdcall SHCopyKeyA(long str long long) shlwapi.SHCopyKeyA
 @ stdcall SHCopyKeyW(long wstr long long) shlwapi.SHCopyKeyW
 @ stdcall SHCreateMemStream(ptr long)
-@ stdcall SHCreateStreamOnFileA(str long ptr) shlwapi.SHCreateStreamOnFileA
-@ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr) shlwapi.SHCreateStreamOnFileEx
-@ stdcall SHCreateStreamOnFileW(wstr long ptr) shlwapi.SHCreateStreamOnFileW
+@ stdcall SHCreateStreamOnFileA(str long ptr)
+@ stdcall SHCreateStreamOnFileEx(wstr long long long ptr ptr)
+@ stdcall SHCreateStreamOnFileW(wstr long ptr)
 @ stdcall SHCreateThread(ptr ptr long ptr) shlwapi.SHCreateThread
 @ stdcall SHCreateThreadRef(ptr ptr) shlwapi.SHCreateThreadRef
 @ stub SHCreateThreadWithHandle
-- 
2.19.2




More information about the wine-devel mailing list