reactos/sdk/lib/rtl/memstream.c
2017-12-20 06:56:09 +01:00

497 lines
9.9 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/rtl/memstream.c
* PURPOSE: MemoryStream functions
* PROGRAMMER: David Quintana (gigaherz@gmail.com)
*/
/* INCLUDES *******************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
/* VIRTUAL METHOD TABLES ******************************************************/
const struct IStreamVtbl RtlMemoryStreamVtbl =
{
RtlQueryInterfaceMemoryStream,
RtlAddRefMemoryStream,
RtlReleaseMemoryStream,
RtlReadMemoryStream,
RtlWriteMemoryStream,
RtlSeekMemoryStream,
RtlSetMemoryStreamSize,
RtlCopyMemoryStreamTo,
RtlCommitMemoryStream,
RtlRevertMemoryStream,
RtlLockMemoryStreamRegion,
RtlUnlockMemoryStreamRegion,
RtlStatMemoryStream,
RtlCloneMemoryStream,
};
const struct IStreamVtbl RtlOutOfProcessMemoryStreamVtbl =
{
RtlQueryInterfaceMemoryStream,
RtlAddRefMemoryStream,
RtlReleaseMemoryStream,
RtlReadOutOfProcessMemoryStream,
RtlWriteMemoryStream,
RtlSeekMemoryStream,
RtlSetMemoryStreamSize,
RtlCopyMemoryStreamTo,
RtlCommitMemoryStream,
RtlRevertMemoryStream,
RtlLockMemoryStreamRegion,
RtlUnlockMemoryStreamRegion,
RtlStatMemoryStream,
RtlCloneMemoryStream,
};
/* FUNCTIONS ******************************************************************/
static
PRTL_MEMORY_STREAM
IStream_To_RTL_MEMORY_STREAM(
_In_ IStream *Interface)
{
if (Interface == NULL)
return NULL;
return CONTAINING_RECORD(Interface, RTL_MEMORY_STREAM, Vtbl);
}
/*
* @implemented
*/
VOID
NTAPI
RtlInitMemoryStream(
_Out_ PRTL_MEMORY_STREAM Stream)
{
RtlZeroMemory(Stream, sizeof(RTL_MEMORY_STREAM));
Stream->Vtbl = &RtlMemoryStreamVtbl;
}
/*
* @implemented
*/
VOID
NTAPI
RtlInitOutOfProcessMemoryStream(
_Out_ PRTL_MEMORY_STREAM Stream)
{
RtlZeroMemory(Stream, sizeof(RTL_MEMORY_STREAM));
Stream->Vtbl = &RtlOutOfProcessMemoryStreamVtbl;
Stream->FinalRelease = RtlFinalReleaseOutOfProcessMemoryStream;
}
/*
* @unimplemented
*/
VOID
NTAPI
RtlFinalReleaseOutOfProcessMemoryStream(
_In_ PRTL_MEMORY_STREAM Stream)
{
UNIMPLEMENTED;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlQueryInterfaceMemoryStream(
_In_ IStream *This,
_In_ REFIID RequestedIid,
_Outptr_ PVOID *ResultObject)
{
if (IsEqualGUID(RequestedIid, &IID_IUnknown) ||
IsEqualGUID(RequestedIid, &IID_ISequentialStream) ||
IsEqualGUID(RequestedIid, &IID_IStream))
{
IStream_AddRef(This);
*ResultObject = This;
return S_OK;
}
*ResultObject = NULL;
return E_NOINTERFACE;
}
/*
* @implemented
*/
ULONG
NTAPI
RtlAddRefMemoryStream(
_In_ IStream *This)
{
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
return InterlockedIncrement(&Stream->RefCount);
}
/*
* @implemented
*/
ULONG
NTAPI
RtlReleaseMemoryStream(
_In_ IStream *This)
{
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
LONG Result;
Result = InterlockedDecrement(&Stream->RefCount);
if (Result == 0)
{
if (Stream->FinalRelease)
Stream->FinalRelease(Stream);
}
return Result;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlReadMemoryStream(
_In_ IStream *This,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG BytesRead)
{
ULONG CopyLength;
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
SIZE_T Available = (PUCHAR)Stream->End - (PUCHAR)Stream->Current;
if (BytesRead)
*BytesRead = 0;
if (!Length)
return S_OK;
CopyLength = min(Available, Length);
RtlMoveMemory(Buffer, Stream->Current, CopyLength);
Stream->Current = (PUCHAR)Stream->Current + CopyLength;
*BytesRead = CopyLength;
return S_OK;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlReadOutOfProcessMemoryStream(
_In_ IStream *This,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG BytesRead)
{
NTSTATUS Status;
ULONG CopyLength;
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
SIZE_T Available = (PUCHAR)Stream->End - (PUCHAR)Stream->Current;
SIZE_T LocalBytesRead = 0;
if (BytesRead)
*BytesRead = 0;
if (!Length)
return S_OK;
CopyLength = min(Available, Length);
Status = NtReadVirtualMemory(Stream->ProcessHandle,
Stream->Current,
Buffer,
CopyLength,
&LocalBytesRead);
if (NT_SUCCESS(Status))
{
Stream->Current = (PUCHAR)Stream->Current + LocalBytesRead;
if (BytesRead)
*BytesRead = (ULONG)LocalBytesRead;
}
return HRESULT_FROM_WIN32(RtlNtStatusToDosError(Status));
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlSeekMemoryStream(
_In_ IStream *This,
_In_ LARGE_INTEGER RelativeOffset,
_In_ ULONG Origin,
_Out_opt_ PULARGE_INTEGER ResultOffset)
{
PVOID NewPosition;
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
switch (Origin)
{
case STREAM_SEEK_SET:
NewPosition = (PUCHAR)Stream->Start + RelativeOffset.QuadPart;
break;
case STREAM_SEEK_CUR:
NewPosition = (PUCHAR)Stream->Current + RelativeOffset.QuadPart;
break;
case STREAM_SEEK_END:
NewPosition = (PUCHAR)Stream->End - RelativeOffset.QuadPart;
break;
default:
return E_INVALIDARG;
}
if (NewPosition < Stream->Start || NewPosition > Stream->End)
return STG_E_INVALIDPOINTER;
Stream->Current = NewPosition;
if (ResultOffset)
ResultOffset->QuadPart = (PUCHAR)Stream->Current - (PUCHAR)Stream->Start;
return S_OK;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlCopyMemoryStreamTo(
_In_ IStream *This,
_In_ IStream *Target,
_In_ ULARGE_INTEGER Length,
_Out_opt_ PULARGE_INTEGER BytesRead,
_Out_opt_ PULARGE_INTEGER BytesWritten)
{
CHAR Buffer[1024];
ULONGLONG TotalSize;
ULONG Left, Amount;
HRESULT Result;
if (BytesRead)
BytesRead->QuadPart = 0;
if (BytesWritten)
BytesWritten->QuadPart = 0;
if (!Target)
return S_OK;
if (!Length.QuadPart)
return S_OK;
/* Copy data */
TotalSize = Length.QuadPart;
while (TotalSize)
{
Left = (ULONG)min(TotalSize, sizeof(Buffer));
/* Read */
Result = IStream_Read(This, Buffer, Left, &Amount);
if (BytesRead)
BytesRead->QuadPart += Amount;
if (FAILED(Result) || Amount == 0)
break;
Left = Amount;
/* Write */
Result = IStream_Write(Target, Buffer, Left, &Amount);
if (BytesWritten)
BytesWritten->QuadPart += Amount;
if (FAILED(Result) || Amount != Left)
break;
TotalSize -= Left;
}
return Result;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlStatMemoryStream(
_In_ IStream *This,
_Out_ STATSTG *Stats,
_In_ ULONG Flags)
{
PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
if (!Stats)
return STG_E_INVALIDPOINTER;
RtlZeroMemory(Stats, sizeof(STATSTG));
Stats->type = STGTY_STREAM;
Stats->cbSize.QuadPart = (PUCHAR)Stream->End - (PUCHAR)Stream->Start;
return S_OK;
}
/* DUMMY FUNCTIONS ************************************************************/
/*
* The following functions return E_NOTIMPL in Windows Server 2003.
*/
/*
* @implemented
*/
HRESULT
NTAPI
RtlWriteMemoryStream(
_In_ IStream *This,
_In_reads_bytes_(Length) CONST VOID *Buffer,
_In_ ULONG Length,
_Out_opt_ PULONG BytesWritten)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(Buffer);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(BytesWritten);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlSetMemoryStreamSize(
_In_ IStream *This,
_In_ ULARGE_INTEGER NewSize)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(NewSize);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlCommitMemoryStream(
_In_ IStream *This,
_In_ ULONG CommitFlags)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(CommitFlags);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlRevertMemoryStream(
_In_ IStream *This)
{
UNREFERENCED_PARAMETER(This);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlLockMemoryStreamRegion(
_In_ IStream *This,
_In_ ULARGE_INTEGER Offset,
_In_ ULARGE_INTEGER Length,
_In_ ULONG LockType)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(Offset);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(LockType);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlUnlockMemoryStreamRegion(
_In_ IStream *This,
_In_ ULARGE_INTEGER Offset,
_In_ ULARGE_INTEGER Length,
_In_ ULONG LockType)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(Offset);
UNREFERENCED_PARAMETER(Length);
UNREFERENCED_PARAMETER(LockType);
return E_NOTIMPL;
}
/*
* @implemented
*/
HRESULT
NTAPI
RtlCloneMemoryStream(
_In_ IStream *This,
_Outptr_ IStream **ResultStream)
{
UNREFERENCED_PARAMETER(This);
UNREFERENCED_PARAMETER(ResultStream);
return E_NOTIMPL;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
RtlCopyMappedMemory(
_Out_writes_bytes_all_(Size) PVOID Destination,
_In_reads_bytes_(Size) const VOID *Source,
_In_ SIZE_T Size)
{
NTSTATUS Status = STATUS_SUCCESS;
_SEH2_TRY
{
RtlCopyMemory(Destination, Source, Size);
}
_SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_IN_PAGE_ERROR
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
return Status;
}