xref: /reactos/sdk/lib/rtl/memstream.c (revision d6792047)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/rtl/memstream.c
5  * PURPOSE:         MemoryStream functions
6  * PROGRAMMER:      David Quintana (gigaherz@gmail.com)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <rtl.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* VIRTUAL METHOD TABLES ******************************************************/
17 
18 const struct IStreamVtbl RtlMemoryStreamVtbl =
19 {
20     RtlQueryInterfaceMemoryStream,
21     RtlAddRefMemoryStream,
22     RtlReleaseMemoryStream,
23     RtlReadMemoryStream,
24     RtlWriteMemoryStream,
25     RtlSeekMemoryStream,
26     RtlSetMemoryStreamSize,
27     RtlCopyMemoryStreamTo,
28     RtlCommitMemoryStream,
29     RtlRevertMemoryStream,
30     RtlLockMemoryStreamRegion,
31     RtlUnlockMemoryStreamRegion,
32     RtlStatMemoryStream,
33     RtlCloneMemoryStream,
34 };
35 
36 const struct IStreamVtbl RtlOutOfProcessMemoryStreamVtbl =
37 {
38     RtlQueryInterfaceMemoryStream,
39     RtlAddRefMemoryStream,
40     RtlReleaseMemoryStream,
41     RtlReadOutOfProcessMemoryStream,
42     RtlWriteMemoryStream,
43     RtlSeekMemoryStream,
44     RtlSetMemoryStreamSize,
45     RtlCopyMemoryStreamTo,
46     RtlCommitMemoryStream,
47     RtlRevertMemoryStream,
48     RtlLockMemoryStreamRegion,
49     RtlUnlockMemoryStreamRegion,
50     RtlStatMemoryStream,
51     RtlCloneMemoryStream,
52 };
53 
54 /* FUNCTIONS ******************************************************************/
55 
56 static
57 PRTL_MEMORY_STREAM
IStream_To_RTL_MEMORY_STREAM(_In_ IStream * Interface)58 IStream_To_RTL_MEMORY_STREAM(
59     _In_ IStream *Interface)
60 {
61     if (Interface == NULL)
62         return NULL;
63 
64     return CONTAINING_RECORD(Interface, RTL_MEMORY_STREAM, Vtbl);
65 }
66 
67 /*
68  * @implemented
69  */
70 VOID
71 NTAPI
RtlInitMemoryStream(_Out_ PRTL_MEMORY_STREAM Stream)72 RtlInitMemoryStream(
73     _Out_ PRTL_MEMORY_STREAM Stream)
74 {
75     RtlZeroMemory(Stream, sizeof(RTL_MEMORY_STREAM));
76     Stream->Vtbl = &RtlMemoryStreamVtbl;
77 }
78 
79 /*
80  * @implemented
81  */
82 VOID
83 NTAPI
RtlInitOutOfProcessMemoryStream(_Out_ PRTL_MEMORY_STREAM Stream)84 RtlInitOutOfProcessMemoryStream(
85     _Out_ PRTL_MEMORY_STREAM Stream)
86 {
87     RtlZeroMemory(Stream, sizeof(RTL_MEMORY_STREAM));
88     Stream->Vtbl = &RtlOutOfProcessMemoryStreamVtbl;
89     Stream->FinalRelease = RtlFinalReleaseOutOfProcessMemoryStream;
90 }
91 
92 /*
93  * @unimplemented
94  */
95 VOID
96 NTAPI
RtlFinalReleaseOutOfProcessMemoryStream(_In_ PRTL_MEMORY_STREAM Stream)97 RtlFinalReleaseOutOfProcessMemoryStream(
98     _In_ PRTL_MEMORY_STREAM Stream)
99 {
100     UNIMPLEMENTED;
101 }
102 
103 /*
104  * @implemented
105  */
106 HRESULT
107 NTAPI
RtlQueryInterfaceMemoryStream(_In_ IStream * This,_In_ REFIID RequestedIid,_Outptr_ PVOID * ResultObject)108 RtlQueryInterfaceMemoryStream(
109     _In_ IStream *This,
110     _In_ REFIID RequestedIid,
111     _Outptr_ PVOID *ResultObject)
112 {
113     if (IsEqualGUID(RequestedIid, &IID_IUnknown) ||
114         IsEqualGUID(RequestedIid, &IID_ISequentialStream) ||
115         IsEqualGUID(RequestedIid, &IID_IStream))
116     {
117         IStream_AddRef(This);
118         *ResultObject = This;
119         return S_OK;
120     }
121 
122     *ResultObject = NULL;
123     return E_NOINTERFACE;
124 }
125 
126 /*
127  * @implemented
128  */
129 ULONG
130 NTAPI
RtlAddRefMemoryStream(_In_ IStream * This)131 RtlAddRefMemoryStream(
132     _In_ IStream *This)
133 {
134     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
135 
136     return InterlockedIncrement(&Stream->RefCount);
137 }
138 
139 /*
140  * @implemented
141  */
142 ULONG
143 NTAPI
RtlReleaseMemoryStream(_In_ IStream * This)144 RtlReleaseMemoryStream(
145     _In_ IStream *This)
146 {
147     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
148     LONG Result;
149 
150     Result = InterlockedDecrement(&Stream->RefCount);
151 
152     if (Result == 0)
153     {
154         if (Stream->FinalRelease)
155             Stream->FinalRelease(Stream);
156     }
157 
158     return Result;
159 }
160 
161 /*
162  * @implemented
163  */
164 HRESULT
165 NTAPI
RtlReadMemoryStream(_In_ IStream * This,_Out_writes_bytes_ (Length)PVOID Buffer,_In_ ULONG Length,_Out_opt_ PULONG BytesRead)166 RtlReadMemoryStream(
167     _In_ IStream *This,
168     _Out_writes_bytes_(Length) PVOID Buffer,
169     _In_ ULONG Length,
170     _Out_opt_ PULONG BytesRead)
171 {
172     ULONG CopyLength;
173     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
174     SIZE_T Available = (PUCHAR)Stream->End - (PUCHAR)Stream->Current;
175 
176     if (BytesRead)
177         *BytesRead = 0;
178 
179     if (!Length)
180         return S_OK;
181 
182     CopyLength = min(Available, Length);
183 
184     RtlMoveMemory(Buffer, Stream->Current, CopyLength);
185 
186     Stream->Current = (PUCHAR)Stream->Current + CopyLength;
187 
188     *BytesRead = CopyLength;
189 
190     return S_OK;
191 }
192 
193 /*
194  * @implemented
195  */
196 HRESULT
197 NTAPI
RtlReadOutOfProcessMemoryStream(_In_ IStream * This,_Out_writes_bytes_ (Length)PVOID Buffer,_In_ ULONG Length,_Out_opt_ PULONG BytesRead)198 RtlReadOutOfProcessMemoryStream(
199     _In_ IStream *This,
200     _Out_writes_bytes_(Length) PVOID Buffer,
201     _In_ ULONG Length,
202     _Out_opt_ PULONG BytesRead)
203 {
204     NTSTATUS Status;
205     ULONG CopyLength;
206     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
207     SIZE_T Available = (PUCHAR)Stream->End - (PUCHAR)Stream->Current;
208     SIZE_T LocalBytesRead = 0;
209 
210     if (BytesRead)
211         *BytesRead = 0;
212 
213     if (!Length)
214         return S_OK;
215 
216     CopyLength = min(Available, Length);
217 
218     Status = NtReadVirtualMemory(Stream->ProcessHandle,
219                                  Stream->Current,
220                                  Buffer,
221                                  CopyLength,
222                                  &LocalBytesRead);
223 
224     if (NT_SUCCESS(Status))
225     {
226         Stream->Current = (PUCHAR)Stream->Current + LocalBytesRead;
227         if (BytesRead)
228             *BytesRead = (ULONG)LocalBytesRead;
229     }
230 
231     return HRESULT_FROM_WIN32(RtlNtStatusToDosError(Status));
232 }
233 
234 /*
235  * @implemented
236  */
237 HRESULT
238 NTAPI
RtlSeekMemoryStream(_In_ IStream * This,_In_ LARGE_INTEGER RelativeOffset,_In_ ULONG Origin,_Out_opt_ PULARGE_INTEGER ResultOffset)239 RtlSeekMemoryStream(
240     _In_ IStream *This,
241     _In_ LARGE_INTEGER RelativeOffset,
242     _In_ ULONG Origin,
243     _Out_opt_ PULARGE_INTEGER ResultOffset)
244 {
245     PVOID NewPosition;
246     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
247 
248     switch (Origin)
249     {
250         case STREAM_SEEK_SET:
251             NewPosition = (PUCHAR)Stream->Start + RelativeOffset.QuadPart;
252             break;
253 
254         case STREAM_SEEK_CUR:
255             NewPosition = (PUCHAR)Stream->Current + RelativeOffset.QuadPart;
256             break;
257 
258         case STREAM_SEEK_END:
259             NewPosition = (PUCHAR)Stream->End - RelativeOffset.QuadPart;
260             break;
261 
262         default:
263             return E_INVALIDARG;
264     }
265 
266     if (NewPosition < Stream->Start || NewPosition > Stream->End)
267         return STG_E_INVALIDPOINTER;
268 
269     Stream->Current = NewPosition;
270 
271     if (ResultOffset)
272         ResultOffset->QuadPart = (PUCHAR)Stream->Current - (PUCHAR)Stream->Start;
273 
274     return S_OK;
275 }
276 
277 /*
278  * @implemented
279  */
280 HRESULT
281 NTAPI
RtlCopyMemoryStreamTo(_In_ IStream * This,_In_ IStream * Target,_In_ ULARGE_INTEGER Length,_Out_opt_ PULARGE_INTEGER BytesRead,_Out_opt_ PULARGE_INTEGER BytesWritten)282 RtlCopyMemoryStreamTo(
283     _In_ IStream *This,
284     _In_ IStream *Target,
285     _In_ ULARGE_INTEGER Length,
286     _Out_opt_ PULARGE_INTEGER BytesRead,
287     _Out_opt_ PULARGE_INTEGER BytesWritten)
288 {
289     CHAR Buffer[1024];
290     ULONGLONG TotalSize;
291     ULONG Left, Amount;
292     HRESULT Result;
293 
294     if (BytesRead)
295         BytesRead->QuadPart = 0;
296     if (BytesWritten)
297         BytesWritten->QuadPart = 0;
298 
299     if (!Target)
300         return S_OK;
301 
302     if (!Length.QuadPart)
303         return S_OK;
304 
305     /* Copy data */
306     TotalSize = Length.QuadPart;
307     while (TotalSize)
308     {
309         Left = (ULONG)min(TotalSize, sizeof(Buffer));
310 
311         /* Read */
312         Result = IStream_Read(This, Buffer, Left, &Amount);
313         if (BytesRead)
314             BytesRead->QuadPart += Amount;
315         if (FAILED(Result) || Amount == 0)
316             break;
317 
318         Left = Amount;
319 
320         /* Write */
321         Result = IStream_Write(Target, Buffer, Left, &Amount);
322         if (BytesWritten)
323             BytesWritten->QuadPart += Amount;
324         if (FAILED(Result) || Amount != Left)
325             break;
326 
327         TotalSize -= Left;
328     }
329     return Result;
330 }
331 
332 /*
333  * @implemented
334  */
335 HRESULT
336 NTAPI
RtlStatMemoryStream(_In_ IStream * This,_Out_ STATSTG * Stats,_In_ ULONG Flags)337 RtlStatMemoryStream(
338     _In_ IStream *This,
339     _Out_ STATSTG *Stats,
340     _In_ ULONG Flags)
341 {
342     PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
343 
344     if (!Stats)
345         return STG_E_INVALIDPOINTER;
346 
347     RtlZeroMemory(Stats, sizeof(STATSTG));
348     Stats->type = STGTY_STREAM;
349     Stats->cbSize.QuadPart = (PUCHAR)Stream->End - (PUCHAR)Stream->Start;
350 
351     return S_OK;
352 }
353 
354 /* DUMMY FUNCTIONS ************************************************************/
355 /*
356  * The following functions return E_NOTIMPL in Windows Server 2003.
357  */
358 
359 /*
360  * @implemented
361  */
362 HRESULT
363 NTAPI
RtlWriteMemoryStream(_In_ IStream * This,_In_reads_bytes_ (Length)CONST VOID * Buffer,_In_ ULONG Length,_Out_opt_ PULONG BytesWritten)364 RtlWriteMemoryStream(
365     _In_ IStream *This,
366     _In_reads_bytes_(Length) CONST VOID *Buffer,
367     _In_ ULONG Length,
368     _Out_opt_ PULONG BytesWritten)
369 {
370     UNREFERENCED_PARAMETER(This);
371     UNREFERENCED_PARAMETER(Buffer);
372     UNREFERENCED_PARAMETER(Length);
373     UNREFERENCED_PARAMETER(BytesWritten);
374 
375     return E_NOTIMPL;
376 }
377 
378 /*
379  * @implemented
380  */
381 HRESULT
382 NTAPI
RtlSetMemoryStreamSize(_In_ IStream * This,_In_ ULARGE_INTEGER NewSize)383 RtlSetMemoryStreamSize(
384     _In_ IStream *This,
385     _In_ ULARGE_INTEGER NewSize)
386 {
387     UNREFERENCED_PARAMETER(This);
388     UNREFERENCED_PARAMETER(NewSize);
389 
390     return E_NOTIMPL;
391 }
392 
393 /*
394  * @implemented
395  */
396 HRESULT
397 NTAPI
RtlCommitMemoryStream(_In_ IStream * This,_In_ ULONG CommitFlags)398 RtlCommitMemoryStream(
399     _In_ IStream *This,
400     _In_ ULONG CommitFlags)
401 {
402     UNREFERENCED_PARAMETER(This);
403     UNREFERENCED_PARAMETER(CommitFlags);
404 
405     return E_NOTIMPL;
406 }
407 
408 /*
409  * @implemented
410  */
411 HRESULT
412 NTAPI
RtlRevertMemoryStream(_In_ IStream * This)413 RtlRevertMemoryStream(
414     _In_ IStream *This)
415 {
416     UNREFERENCED_PARAMETER(This);
417 
418     return E_NOTIMPL;
419 }
420 
421 /*
422  * @implemented
423  */
424 HRESULT
425 NTAPI
RtlLockMemoryStreamRegion(_In_ IStream * This,_In_ ULARGE_INTEGER Offset,_In_ ULARGE_INTEGER Length,_In_ ULONG LockType)426 RtlLockMemoryStreamRegion(
427     _In_ IStream *This,
428     _In_ ULARGE_INTEGER Offset,
429     _In_ ULARGE_INTEGER Length,
430     _In_ ULONG LockType)
431 {
432     UNREFERENCED_PARAMETER(This);
433     UNREFERENCED_PARAMETER(Offset);
434     UNREFERENCED_PARAMETER(Length);
435     UNREFERENCED_PARAMETER(LockType);
436 
437     return E_NOTIMPL;
438 }
439 
440 /*
441  * @implemented
442  */
443 HRESULT
444 NTAPI
RtlUnlockMemoryStreamRegion(_In_ IStream * This,_In_ ULARGE_INTEGER Offset,_In_ ULARGE_INTEGER Length,_In_ ULONG LockType)445 RtlUnlockMemoryStreamRegion(
446     _In_ IStream *This,
447     _In_ ULARGE_INTEGER Offset,
448     _In_ ULARGE_INTEGER Length,
449     _In_ ULONG LockType)
450 {
451     UNREFERENCED_PARAMETER(This);
452     UNREFERENCED_PARAMETER(Offset);
453     UNREFERENCED_PARAMETER(Length);
454     UNREFERENCED_PARAMETER(LockType);
455 
456     return E_NOTIMPL;
457 }
458 
459 /*
460  * @implemented
461  */
462 HRESULT
463 NTAPI
RtlCloneMemoryStream(_In_ IStream * This,_Outptr_ IStream ** ResultStream)464 RtlCloneMemoryStream(
465     _In_ IStream *This,
466     _Outptr_ IStream **ResultStream)
467 {
468     UNREFERENCED_PARAMETER(This);
469     UNREFERENCED_PARAMETER(ResultStream);
470 
471     return E_NOTIMPL;
472 }
473 
474 /*
475  * @implemented
476  */
477 NTSTATUS
478 NTAPI
RtlCopyMappedMemory(_Out_writes_bytes_all_ (Size)PVOID Destination,_In_reads_bytes_ (Size)const VOID * Source,_In_ SIZE_T Size)479 RtlCopyMappedMemory(
480     _Out_writes_bytes_all_(Size) PVOID Destination,
481     _In_reads_bytes_(Size) const VOID *Source,
482     _In_ SIZE_T Size)
483 {
484     NTSTATUS Status = STATUS_SUCCESS;
485     _SEH2_TRY
486     {
487         RtlCopyMemory(Destination, Source, Size);
488     }
489     _SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_IN_PAGE_ERROR
490                     ? EXCEPTION_EXECUTE_HANDLER
491                     : EXCEPTION_CONTINUE_SEARCH)
492     {
493         Status = _SEH2_GetExceptionCode();
494     }
495     _SEH2_END;
496     return Status;
497 }
498