Reactos
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
18const 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
36const 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
56static
57PRTL_MEMORY_STREAM
58IStream_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 */
70VOID
71NTAPI
72RtlInitMemoryStream(
73 _Out_ PRTL_MEMORY_STREAM Stream)
74{
75 RtlZeroMemory(Stream, sizeof(RTL_MEMORY_STREAM));
76 Stream->Vtbl = &RtlMemoryStreamVtbl;
77}
78
79/*
80 * @implemented
81 */
82VOID
83NTAPI
84RtlInitOutOfProcessMemoryStream(
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 */
95VOID
96NTAPI
97RtlFinalReleaseOutOfProcessMemoryStream(
98 _In_ PRTL_MEMORY_STREAM Stream)
99{
100 UNIMPLEMENTED;
101}
102
103/*
104 * @implemented
105 */
106HRESULT
107NTAPI
108RtlQueryInterfaceMemoryStream(
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 */
129ULONG
130NTAPI
131RtlAddRefMemoryStream(
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 */
142ULONG
143NTAPI
144RtlReleaseMemoryStream(
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 */
164HRESULT
165NTAPI
166RtlReadMemoryStream(
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 */
196HRESULT
197NTAPI
198RtlReadOutOfProcessMemoryStream(
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 */
237HRESULT
238NTAPI
239RtlSeekMemoryStream(
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 */
280HRESULT
281NTAPI
282RtlCopyMemoryStreamTo(
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 */
335HRESULT
336NTAPI
337RtlStatMemoryStream(
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 */
362HRESULT
363NTAPI
364RtlWriteMemoryStream(
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 */
381HRESULT
382NTAPI
383RtlSetMemoryStreamSize(
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 */
396HRESULT
397NTAPI
398RtlCommitMemoryStream(
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 */
411HRESULT
412NTAPI
413RtlRevertMemoryStream(
414 _In_ IStream *This)
415{
416 UNREFERENCED_PARAMETER(This);
417
418 return E_NOTIMPL;
419}
420
421/*
422 * @implemented
423 */
424HRESULT
425NTAPI
426RtlLockMemoryStreamRegion(
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 */
443HRESULT
444NTAPI
445RtlUnlockMemoryStreamRegion(
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 */
462HRESULT
463NTAPI
464RtlCloneMemoryStream(
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 */
477NTSTATUS
478NTAPI
479RtlCopyMappedMemory(
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}