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