0549424ca45938f04bf03b1f3a8d7ef79597ab4f
[reactos.git] / sdk / lib / rtl / memstream.c
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
209 if (BytesRead)
210 *BytesRead = 0;
211
212 if (!Length)
213 return S_OK;
214
215 CopyLength = min(Available, Length);
216
217 Status = NtReadVirtualMemory(Stream->ProcessHandle,
218 Stream->Current,
219 Buffer,
220 CopyLength,
221 BytesRead);
222
223 if (NT_SUCCESS(Status))
224 Stream->Current = (PUCHAR)Stream->Current + *BytesRead;
225
226 return HRESULT_FROM_WIN32(RtlNtStatusToDosError(Status));
227 }
228
229 /*
230 * @implemented
231 */
232 HRESULT
233 NTAPI
234 RtlSeekMemoryStream(
235 _In_ IStream *This,
236 _In_ LARGE_INTEGER RelativeOffset,
237 _In_ ULONG Origin,
238 _Out_opt_ PULARGE_INTEGER ResultOffset)
239 {
240 PVOID NewPosition;
241 PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
242
243 switch (Origin)
244 {
245 case STREAM_SEEK_SET:
246 NewPosition = (PUCHAR)Stream->Start + RelativeOffset.QuadPart;
247 break;
248
249 case STREAM_SEEK_CUR:
250 NewPosition = (PUCHAR)Stream->Current + RelativeOffset.QuadPart;
251 break;
252
253 case STREAM_SEEK_END:
254 NewPosition = (PUCHAR)Stream->End - RelativeOffset.QuadPart;
255 break;
256
257 default:
258 return E_INVALIDARG;
259 }
260
261 if (NewPosition < Stream->Start || NewPosition > Stream->End)
262 return STG_E_INVALIDPOINTER;
263
264 Stream->Current = NewPosition;
265
266 if (ResultOffset)
267 ResultOffset->QuadPart = (PUCHAR)Stream->Current - (PUCHAR)Stream->Start;
268
269 return S_OK;
270 }
271
272 /*
273 * @implemented
274 */
275 HRESULT
276 NTAPI
277 RtlCopyMemoryStreamTo(
278 _In_ IStream *This,
279 _In_ IStream *Target,
280 _In_ ULARGE_INTEGER Length,
281 _Out_opt_ PULARGE_INTEGER BytesRead,
282 _Out_opt_ PULARGE_INTEGER BytesWritten)
283 {
284 CHAR Buffer[1024];
285 ULONGLONG TotalSize;
286 ULONG Left, Amount;
287 HRESULT Result;
288
289 if (BytesRead)
290 BytesRead->QuadPart = 0;
291 if (BytesWritten)
292 BytesWritten->QuadPart = 0;
293
294 if (!Target)
295 return S_OK;
296
297 if (!Length.QuadPart)
298 return S_OK;
299
300 /* Copy data */
301 TotalSize = Length.QuadPart;
302 while (TotalSize)
303 {
304 Left = (ULONG)min(TotalSize, sizeof(Buffer));
305
306 /* Read */
307 Result = IStream_Read(This, Buffer, Left, &Amount);
308 if (BytesRead)
309 BytesRead->QuadPart += Amount;
310 if (FAILED(Result) || Amount == 0)
311 break;
312
313 Left = Amount;
314
315 /* Write */
316 Result = IStream_Write(Target, Buffer, Left, &Amount);
317 if (BytesWritten)
318 BytesWritten->QuadPart += Amount;
319 if (FAILED(Result) || Amount != Left)
320 break;
321
322 TotalSize -= Left;
323 }
324 return Result;
325 }
326
327 /*
328 * @implemented
329 */
330 HRESULT
331 NTAPI
332 RtlStatMemoryStream(
333 _In_ IStream *This,
334 _Out_ STATSTG *Stats,
335 _In_ ULONG Flags)
336 {
337 PRTL_MEMORY_STREAM Stream = IStream_To_RTL_MEMORY_STREAM(This);
338
339 if (!Stats)
340 return STG_E_INVALIDPOINTER;
341
342 RtlZeroMemory(Stats, sizeof(STATSTG));
343 Stats->type = STGTY_STREAM;
344 Stats->cbSize.QuadPart = (PUCHAR)Stream->End - (PUCHAR)Stream->Start;
345
346 return S_OK;
347 }
348
349 /* DUMMY FUNCTIONS ************************************************************/
350 /*
351 * The following functions return E_NOTIMPL in Windows Server 2003.
352 */
353
354 /*
355 * @implemented
356 */
357 HRESULT
358 NTAPI
359 RtlWriteMemoryStream(
360 _In_ IStream *This,
361 _In_reads_bytes_(Length) CONST VOID *Buffer,
362 _In_ ULONG Length,
363 _Out_opt_ PULONG BytesWritten)
364 {
365 UNREFERENCED_PARAMETER(This);
366 UNREFERENCED_PARAMETER(Buffer);
367 UNREFERENCED_PARAMETER(Length);
368 UNREFERENCED_PARAMETER(BytesWritten);
369
370 return E_NOTIMPL;
371 }
372
373 /*
374 * @implemented
375 */
376 HRESULT
377 NTAPI
378 RtlSetMemoryStreamSize(
379 _In_ IStream *This,
380 _In_ ULARGE_INTEGER NewSize)
381 {
382 UNREFERENCED_PARAMETER(This);
383 UNREFERENCED_PARAMETER(NewSize);
384
385 return E_NOTIMPL;
386 }
387
388 /*
389 * @implemented
390 */
391 HRESULT
392 NTAPI
393 RtlCommitMemoryStream(
394 _In_ IStream *This,
395 _In_ ULONG CommitFlags)
396 {
397 UNREFERENCED_PARAMETER(This);
398 UNREFERENCED_PARAMETER(CommitFlags);
399
400 return E_NOTIMPL;
401 }
402
403 /*
404 * @implemented
405 */
406 HRESULT
407 NTAPI
408 RtlRevertMemoryStream(
409 _In_ IStream *This)
410 {
411 UNREFERENCED_PARAMETER(This);
412
413 return E_NOTIMPL;
414 }
415
416 /*
417 * @implemented
418 */
419 HRESULT
420 NTAPI
421 RtlLockMemoryStreamRegion(
422 _In_ IStream *This,
423 _In_ ULARGE_INTEGER Offset,
424 _In_ ULARGE_INTEGER Length,
425 _In_ ULONG LockType)
426 {
427 UNREFERENCED_PARAMETER(This);
428 UNREFERENCED_PARAMETER(Offset);
429 UNREFERENCED_PARAMETER(Length);
430 UNREFERENCED_PARAMETER(LockType);
431
432 return E_NOTIMPL;
433 }
434
435 /*
436 * @implemented
437 */
438 HRESULT
439 NTAPI
440 RtlUnlockMemoryStreamRegion(
441 _In_ IStream *This,
442 _In_ ULARGE_INTEGER Offset,
443 _In_ ULARGE_INTEGER Length,
444 _In_ ULONG LockType)
445 {
446 UNREFERENCED_PARAMETER(This);
447 UNREFERENCED_PARAMETER(Offset);
448 UNREFERENCED_PARAMETER(Length);
449 UNREFERENCED_PARAMETER(LockType);
450
451 return E_NOTIMPL;
452 }
453
454 /*
455 * @implemented
456 */
457 HRESULT
458 NTAPI
459 RtlCloneMemoryStream(
460 _In_ IStream *This,
461 _Outptr_ IStream **ResultStream)
462 {
463 UNREFERENCED_PARAMETER(This);
464 UNREFERENCED_PARAMETER(ResultStream);
465
466 return E_NOTIMPL;
467 }
468
469 /*
470 * @implemented
471 */
472 NTSTATUS
473 NTAPI
474 RtlCopyMappedMemory(
475 _Out_writes_bytes_all_(Size) PVOID Destination,
476 _In_reads_bytes_(Size) const VOID *Source,
477 _In_ SIZE_T Size)
478 {
479 NTSTATUS Status = STATUS_SUCCESS;
480 _SEH2_TRY
481 {
482 RtlCopyMemory(Destination, Source, Size);
483 }
484 _SEH2_EXCEPT(_SEH2_GetExceptionCode() == STATUS_IN_PAGE_ERROR
485 ? EXCEPTION_EXECUTE_HANDLER
486 : EXCEPTION_CONTINUE_SEARCH)
487 {
488 Status = _SEH2_GetExceptionCode();
489 }
490 _SEH2_END;
491 return Status;
492 }