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