xref: /reactos/sdk/lib/rtl/memstream.c (revision 1734f297)
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
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
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
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
97 RtlFinalReleaseOutOfProcessMemoryStream(
98     _In_ PRTL_MEMORY_STREAM Stream)
99 {
100     UNIMPLEMENTED;
101 }
102 
103 /*
104  * @implemented
105  */
106 HRESULT
107 NTAPI
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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