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