shcore: Add file-based stream.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2018-11-27 11:55:45 +03:00 committed by Alexandre Julliard
parent b54d72ef0b
commit dd4bb94706
3 changed files with 329 additions and 6 deletions

View File

@ -1,5 +1,5 @@
MODULE = shcore.dll
IMPORTS = user32 gdi32
IMPORTS = user32 gdi32 ole32
C_SRCS = \
main.c

View File

@ -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;
}

View File

@ -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