1 /* 2 * Copyright 2009 Tony Wasserka 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "wine/debug.h" 20 21 #define COBJMACROS 22 #include "windef.h" 23 #include "winbase.h" 24 #include "winreg.h" 25 #include "objbase.h" 26 #include "shlwapi.h" 27 #include "wincodecs_private.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 30 31 /****************************************** 32 * StreamOnMemory implementation 33 * 34 * Used by IWICStream_InitializeFromMemory 35 * 36 */ 37 typedef struct StreamOnMemory { 38 IStream IStream_iface; 39 LONG ref; 40 41 BYTE *pbMemory; 42 DWORD dwMemsize; 43 DWORD dwCurPos; 44 45 CRITICAL_SECTION lock; /* must be held when pbMemory or dwCurPos is accessed */ 46 } StreamOnMemory; 47 48 static inline StreamOnMemory *StreamOnMemory_from_IStream(IStream *iface) 49 { 50 return CONTAINING_RECORD(iface, StreamOnMemory, IStream_iface); 51 } 52 53 static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface, 54 REFIID iid, void **ppv) 55 { 56 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 57 58 if (!ppv) return E_INVALIDARG; 59 60 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 61 IsEqualIID(&IID_ISequentialStream, iid)) 62 { 63 *ppv = iface; 64 IUnknown_AddRef((IUnknown*)*ppv); 65 return S_OK; 66 } 67 else 68 { 69 *ppv = NULL; 70 return E_NOINTERFACE; 71 } 72 } 73 74 static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface) 75 { 76 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 77 ULONG ref = InterlockedIncrement(&This->ref); 78 79 TRACE("(%p) refcount=%u\n", iface, ref); 80 81 return ref; 82 } 83 84 static ULONG WINAPI StreamOnMemory_Release(IStream *iface) 85 { 86 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 87 ULONG ref = InterlockedDecrement(&This->ref); 88 89 TRACE("(%p) refcount=%u\n", iface, ref); 90 91 if (ref == 0) { 92 This->lock.DebugInfo->Spare[0] = 0; 93 DeleteCriticalSection(&This->lock); 94 HeapFree(GetProcessHeap(), 0, This); 95 } 96 return ref; 97 } 98 99 static HRESULT WINAPI StreamOnMemory_Read(IStream *iface, 100 void *pv, ULONG cb, ULONG *pcbRead) 101 { 102 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 103 ULONG uBytesRead; 104 TRACE("(%p)\n", This); 105 106 if (!pv) return E_INVALIDARG; 107 108 EnterCriticalSection(&This->lock); 109 uBytesRead = min(cb, This->dwMemsize - This->dwCurPos); 110 memmove(pv, This->pbMemory + This->dwCurPos, uBytesRead); 111 This->dwCurPos += uBytesRead; 112 LeaveCriticalSection(&This->lock); 113 114 if (pcbRead) *pcbRead = uBytesRead; 115 116 return S_OK; 117 } 118 119 static HRESULT WINAPI StreamOnMemory_Write(IStream *iface, 120 void const *pv, ULONG cb, ULONG *pcbWritten) 121 { 122 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 123 HRESULT hr; 124 TRACE("(%p)\n", This); 125 126 if (!pv) return E_INVALIDARG; 127 128 EnterCriticalSection(&This->lock); 129 if (cb > This->dwMemsize - This->dwCurPos) { 130 hr = STG_E_MEDIUMFULL; 131 } 132 else { 133 memmove(This->pbMemory + This->dwCurPos, pv, cb); 134 This->dwCurPos += cb; 135 hr = S_OK; 136 if (pcbWritten) *pcbWritten = cb; 137 } 138 LeaveCriticalSection(&This->lock); 139 140 return hr; 141 } 142 143 static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface, 144 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 145 { 146 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 147 LARGE_INTEGER NewPosition; 148 HRESULT hr=S_OK; 149 TRACE("(%p)\n", This); 150 151 EnterCriticalSection(&This->lock); 152 if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart; 153 else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart; 154 else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart; 155 else hr = E_INVALIDARG; 156 157 if (SUCCEEDED(hr)) { 158 if (NewPosition.u.HighPart) hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); 159 else if (NewPosition.QuadPart > This->dwMemsize) hr = E_INVALIDARG; 160 else if (NewPosition.QuadPart < 0) hr = E_INVALIDARG; 161 } 162 163 if (SUCCEEDED(hr)) { 164 This->dwCurPos = NewPosition.u.LowPart; 165 166 if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos; 167 } 168 LeaveCriticalSection(&This->lock); 169 170 return hr; 171 } 172 173 /* SetSize isn't implemented in the native windowscodecs DLL either */ 174 static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface, 175 ULARGE_INTEGER libNewSize) 176 { 177 TRACE("(%p)\n", iface); 178 return E_NOTIMPL; 179 } 180 181 /* CopyTo isn't implemented in the native windowscodecs DLL either */ 182 static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface, 183 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 184 { 185 TRACE("(%p)\n", iface); 186 return E_NOTIMPL; 187 } 188 189 /* Commit isn't implemented in the native windowscodecs DLL either */ 190 static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface, 191 DWORD grfCommitFlags) 192 { 193 TRACE("(%p)\n", iface); 194 return E_NOTIMPL; 195 } 196 197 /* Revert isn't implemented in the native windowscodecs DLL either */ 198 static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface) 199 { 200 TRACE("(%p)\n", iface); 201 return E_NOTIMPL; 202 } 203 204 /* LockRegion isn't implemented in the native windowscodecs DLL either */ 205 static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface, 206 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 207 { 208 TRACE("(%p)\n", iface); 209 return E_NOTIMPL; 210 } 211 212 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */ 213 static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface, 214 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 215 { 216 TRACE("(%p)\n", iface); 217 return E_NOTIMPL; 218 } 219 220 static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface, 221 STATSTG *pstatstg, DWORD grfStatFlag) 222 { 223 StreamOnMemory *This = StreamOnMemory_from_IStream(iface); 224 TRACE("(%p)\n", This); 225 226 if (!pstatstg) return E_INVALIDARG; 227 228 ZeroMemory(pstatstg, sizeof(STATSTG)); 229 pstatstg->type = STGTY_STREAM; 230 pstatstg->cbSize.QuadPart = This->dwMemsize; 231 232 return S_OK; 233 } 234 235 /* Clone isn't implemented in the native windowscodecs DLL either */ 236 static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface, 237 IStream **ppstm) 238 { 239 TRACE("(%p)\n", iface); 240 return E_NOTIMPL; 241 } 242 243 244 static const IStreamVtbl StreamOnMemory_Vtbl = 245 { 246 /*** IUnknown methods ***/ 247 StreamOnMemory_QueryInterface, 248 StreamOnMemory_AddRef, 249 StreamOnMemory_Release, 250 /*** ISequentialStream methods ***/ 251 StreamOnMemory_Read, 252 StreamOnMemory_Write, 253 /*** IStream methods ***/ 254 StreamOnMemory_Seek, 255 StreamOnMemory_SetSize, 256 StreamOnMemory_CopyTo, 257 StreamOnMemory_Commit, 258 StreamOnMemory_Revert, 259 StreamOnMemory_LockRegion, 260 StreamOnMemory_UnlockRegion, 261 StreamOnMemory_Stat, 262 StreamOnMemory_Clone, 263 }; 264 265 /****************************************** 266 * StreamOnFileHandle implementation (internal) 267 * 268 */ 269 typedef struct StreamOnFileHandle { 270 IStream IStream_iface; 271 LONG ref; 272 273 HANDLE map; 274 void *mem; 275 IWICStream *stream; 276 } StreamOnFileHandle; 277 278 static inline StreamOnFileHandle *StreamOnFileHandle_from_IStream(IStream *iface) 279 { 280 return CONTAINING_RECORD(iface, StreamOnFileHandle, IStream_iface); 281 } 282 283 static HRESULT WINAPI StreamOnFileHandle_QueryInterface(IStream *iface, 284 REFIID iid, void **ppv) 285 { 286 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 287 288 if (!ppv) return E_INVALIDARG; 289 290 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 291 IsEqualIID(&IID_ISequentialStream, iid)) 292 { 293 *ppv = iface; 294 IUnknown_AddRef((IUnknown*)*ppv); 295 return S_OK; 296 } 297 else 298 { 299 *ppv = NULL; 300 return E_NOINTERFACE; 301 } 302 } 303 304 static ULONG WINAPI StreamOnFileHandle_AddRef(IStream *iface) 305 { 306 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 307 ULONG ref = InterlockedIncrement(&This->ref); 308 309 TRACE("(%p) refcount=%u\n", iface, ref); 310 311 return ref; 312 } 313 314 static ULONG WINAPI StreamOnFileHandle_Release(IStream *iface) 315 { 316 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 317 ULONG ref = InterlockedDecrement(&This->ref); 318 319 TRACE("(%p) refcount=%u\n", iface, ref); 320 321 if (ref == 0) { 322 IWICStream_Release(This->stream); 323 UnmapViewOfFile(This->mem); 324 CloseHandle(This->map); 325 HeapFree(GetProcessHeap(), 0, This); 326 } 327 return ref; 328 } 329 330 static HRESULT WINAPI StreamOnFileHandle_Read(IStream *iface, 331 void *pv, ULONG cb, ULONG *pcbRead) 332 { 333 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 334 TRACE("(%p)\n", This); 335 336 return IWICStream_Read(This->stream, pv, cb, pcbRead); 337 } 338 339 static HRESULT WINAPI StreamOnFileHandle_Write(IStream *iface, 340 void const *pv, ULONG cb, ULONG *pcbWritten) 341 { 342 ERR("(%p)\n", iface); 343 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); 344 } 345 346 static HRESULT WINAPI StreamOnFileHandle_Seek(IStream *iface, 347 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 348 { 349 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 350 TRACE("(%p)\n", This); 351 352 return IWICStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); 353 } 354 355 static HRESULT WINAPI StreamOnFileHandle_SetSize(IStream *iface, 356 ULARGE_INTEGER libNewSize) 357 { 358 TRACE("(%p)\n", iface); 359 return E_NOTIMPL; 360 } 361 362 static HRESULT WINAPI StreamOnFileHandle_CopyTo(IStream *iface, 363 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 364 { 365 TRACE("(%p)\n", iface); 366 return E_NOTIMPL; 367 } 368 369 static HRESULT WINAPI StreamOnFileHandle_Commit(IStream *iface, 370 DWORD grfCommitFlags) 371 { 372 TRACE("(%p)\n", iface); 373 return E_NOTIMPL; 374 } 375 376 static HRESULT WINAPI StreamOnFileHandle_Revert(IStream *iface) 377 { 378 TRACE("(%p)\n", iface); 379 return E_NOTIMPL; 380 } 381 382 static HRESULT WINAPI StreamOnFileHandle_LockRegion(IStream *iface, 383 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 384 { 385 TRACE("(%p)\n", iface); 386 return E_NOTIMPL; 387 } 388 389 static HRESULT WINAPI StreamOnFileHandle_UnlockRegion(IStream *iface, 390 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 391 { 392 TRACE("(%p)\n", iface); 393 return E_NOTIMPL; 394 } 395 396 static HRESULT WINAPI StreamOnFileHandle_Stat(IStream *iface, 397 STATSTG *pstatstg, DWORD grfStatFlag) 398 { 399 StreamOnFileHandle *This = StreamOnFileHandle_from_IStream(iface); 400 TRACE("(%p)\n", This); 401 402 return IWICStream_Stat(This->stream, pstatstg, grfStatFlag); 403 } 404 405 static HRESULT WINAPI StreamOnFileHandle_Clone(IStream *iface, 406 IStream **ppstm) 407 { 408 TRACE("(%p)\n", iface); 409 return E_NOTIMPL; 410 } 411 412 413 static const IStreamVtbl StreamOnFileHandle_Vtbl = 414 { 415 /*** IUnknown methods ***/ 416 StreamOnFileHandle_QueryInterface, 417 StreamOnFileHandle_AddRef, 418 StreamOnFileHandle_Release, 419 /*** ISequentialStream methods ***/ 420 StreamOnFileHandle_Read, 421 StreamOnFileHandle_Write, 422 /*** IStream methods ***/ 423 StreamOnFileHandle_Seek, 424 StreamOnFileHandle_SetSize, 425 StreamOnFileHandle_CopyTo, 426 StreamOnFileHandle_Commit, 427 StreamOnFileHandle_Revert, 428 StreamOnFileHandle_LockRegion, 429 StreamOnFileHandle_UnlockRegion, 430 StreamOnFileHandle_Stat, 431 StreamOnFileHandle_Clone, 432 }; 433 434 /****************************************** 435 * StreamOnStreamRange implementation 436 * 437 * Used by IWICStream_InitializeFromIStreamRegion 438 * 439 */ 440 typedef struct StreamOnStreamRange { 441 IStream IStream_iface; 442 LONG ref; 443 444 IStream *stream; 445 ULARGE_INTEGER pos; 446 ULARGE_INTEGER offset; 447 ULARGE_INTEGER max_size; 448 449 CRITICAL_SECTION lock; 450 } StreamOnStreamRange; 451 452 static inline StreamOnStreamRange *StreamOnStreamRange_from_IStream(IStream *iface) 453 { 454 return CONTAINING_RECORD(iface, StreamOnStreamRange, IStream_iface); 455 } 456 457 static HRESULT WINAPI StreamOnStreamRange_QueryInterface(IStream *iface, 458 REFIID iid, void **ppv) 459 { 460 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 461 462 if (!ppv) return E_INVALIDARG; 463 464 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 465 IsEqualIID(&IID_ISequentialStream, iid)) 466 { 467 *ppv = iface; 468 IUnknown_AddRef((IUnknown*)*ppv); 469 return S_OK; 470 } 471 else 472 { 473 *ppv = NULL; 474 return E_NOINTERFACE; 475 } 476 } 477 478 static ULONG WINAPI StreamOnStreamRange_AddRef(IStream *iface) 479 { 480 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 481 ULONG ref = InterlockedIncrement(&This->ref); 482 483 TRACE("(%p) refcount=%u\n", iface, ref); 484 485 return ref; 486 } 487 488 static ULONG WINAPI StreamOnStreamRange_Release(IStream *iface) 489 { 490 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 491 ULONG ref = InterlockedDecrement(&This->ref); 492 493 TRACE("(%p) refcount=%u\n", iface, ref); 494 495 if (ref == 0) { 496 This->lock.DebugInfo->Spare[0] = 0; 497 DeleteCriticalSection(&This->lock); 498 IStream_Release(This->stream); 499 HeapFree(GetProcessHeap(), 0, This); 500 } 501 return ref; 502 } 503 504 static HRESULT WINAPI StreamOnStreamRange_Read(IStream *iface, 505 void *pv, ULONG cb, ULONG *pcbRead) 506 { 507 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 508 ULONG uBytesRead=0; 509 HRESULT hr; 510 ULARGE_INTEGER OldPosition; 511 LARGE_INTEGER SetPosition; 512 TRACE("(%p)\n", This); 513 514 if (!pv) return E_INVALIDARG; 515 516 EnterCriticalSection(&This->lock); 517 SetPosition.QuadPart = 0; 518 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition); 519 if (SUCCEEDED(hr)) 520 { 521 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart; 522 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 523 } 524 if (SUCCEEDED(hr)) 525 { 526 if (This->pos.QuadPart + cb > This->max_size.QuadPart) 527 { 528 /* This would read past the end of the stream. */ 529 if (This->pos.QuadPart > This->max_size.QuadPart) 530 cb = 0; 531 else 532 cb = This->max_size.QuadPart - This->pos.QuadPart; 533 } 534 hr = IStream_Read(This->stream, pv, cb, &uBytesRead); 535 SetPosition.QuadPart = OldPosition.QuadPart; 536 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 537 } 538 if (SUCCEEDED(hr)) 539 This->pos.QuadPart += uBytesRead; 540 LeaveCriticalSection(&This->lock); 541 542 if (SUCCEEDED(hr) && pcbRead) *pcbRead = uBytesRead; 543 544 return hr; 545 } 546 547 static HRESULT WINAPI StreamOnStreamRange_Write(IStream *iface, 548 void const *pv, ULONG cb, ULONG *pcbWritten) 549 { 550 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 551 HRESULT hr; 552 ULARGE_INTEGER OldPosition; 553 LARGE_INTEGER SetPosition; 554 ULONG uBytesWritten=0; 555 TRACE("(%p)\n", This); 556 557 if (!pv) return E_INVALIDARG; 558 559 EnterCriticalSection(&This->lock); 560 SetPosition.QuadPart = 0; 561 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_CUR, &OldPosition); 562 if (SUCCEEDED(hr)) 563 { 564 SetPosition.QuadPart = This->pos.QuadPart + This->offset.QuadPart; 565 hr = IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 566 } 567 if (SUCCEEDED(hr)) 568 { 569 if (This->pos.QuadPart + cb > This->max_size.QuadPart) 570 { 571 /* This would read past the end of the stream. */ 572 if (This->pos.QuadPart > This->max_size.QuadPart) 573 cb = 0; 574 else 575 cb = This->max_size.QuadPart - This->pos.QuadPart; 576 } 577 hr = IStream_Write(This->stream, pv, cb, &uBytesWritten); 578 SetPosition.QuadPart = OldPosition.QuadPart; 579 IStream_Seek(This->stream, SetPosition, STREAM_SEEK_SET, NULL); 580 } 581 if (SUCCEEDED(hr)) 582 This->pos.QuadPart += uBytesWritten; 583 LeaveCriticalSection(&This->lock); 584 585 if (SUCCEEDED(hr) && pcbWritten) *pcbWritten = uBytesWritten; 586 587 return hr; 588 } 589 590 static HRESULT WINAPI StreamOnStreamRange_Seek(IStream *iface, 591 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 592 { 593 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 594 ULARGE_INTEGER NewPosition, actual_size; 595 HRESULT hr=S_OK; 596 STATSTG statstg; 597 TRACE("(%p)\n", This); 598 599 EnterCriticalSection(&This->lock); 600 actual_size = This->max_size; 601 if (dwOrigin == STREAM_SEEK_SET) 602 NewPosition.QuadPart = dlibMove.QuadPart; 603 else if (dwOrigin == STREAM_SEEK_CUR) 604 NewPosition.QuadPart = This->pos.QuadPart + dlibMove.QuadPart; 605 else if (dwOrigin == STREAM_SEEK_END) 606 { 607 hr = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME); 608 if (SUCCEEDED(hr)) 609 { 610 if (This->max_size.QuadPart + This->offset.QuadPart > statstg.cbSize.QuadPart) 611 actual_size.QuadPart = statstg.cbSize.QuadPart - This->offset.QuadPart; 612 NewPosition.QuadPart = dlibMove.QuadPart + actual_size.QuadPart; 613 } 614 } 615 else hr = E_INVALIDARG; 616 617 if (SUCCEEDED(hr) && (NewPosition.u.HighPart != 0 || NewPosition.QuadPart > actual_size.QuadPart)) 618 hr = WINCODEC_ERR_VALUEOUTOFRANGE; 619 620 if (SUCCEEDED(hr)) { 621 This->pos.QuadPart = NewPosition.QuadPart; 622 623 if(plibNewPosition) plibNewPosition->QuadPart = This->pos.QuadPart; 624 } 625 LeaveCriticalSection(&This->lock); 626 627 return hr; 628 } 629 630 /* SetSize isn't implemented in the native windowscodecs DLL either */ 631 static HRESULT WINAPI StreamOnStreamRange_SetSize(IStream *iface, 632 ULARGE_INTEGER libNewSize) 633 { 634 TRACE("(%p)\n", iface); 635 return E_NOTIMPL; 636 } 637 638 /* CopyTo isn't implemented in the native windowscodecs DLL either */ 639 static HRESULT WINAPI StreamOnStreamRange_CopyTo(IStream *iface, 640 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 641 { 642 TRACE("(%p)\n", iface); 643 return E_NOTIMPL; 644 } 645 646 /* Commit isn't implemented in the native windowscodecs DLL either */ 647 static HRESULT WINAPI StreamOnStreamRange_Commit(IStream *iface, 648 DWORD grfCommitFlags) 649 { 650 TRACE("(%p)\n", iface); 651 return E_NOTIMPL; 652 } 653 654 /* Revert isn't implemented in the native windowscodecs DLL either */ 655 static HRESULT WINAPI StreamOnStreamRange_Revert(IStream *iface) 656 { 657 TRACE("(%p)\n", iface); 658 return E_NOTIMPL; 659 } 660 661 /* LockRegion isn't implemented in the native windowscodecs DLL either */ 662 static HRESULT WINAPI StreamOnStreamRange_LockRegion(IStream *iface, 663 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 664 { 665 TRACE("(%p)\n", iface); 666 return E_NOTIMPL; 667 } 668 669 /* UnlockRegion isn't implemented in the native windowscodecs DLL either */ 670 static HRESULT WINAPI StreamOnStreamRange_UnlockRegion(IStream *iface, 671 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 672 { 673 TRACE("(%p)\n", iface); 674 return E_NOTIMPL; 675 } 676 677 static HRESULT WINAPI StreamOnStreamRange_Stat(IStream *iface, 678 STATSTG *pstatstg, DWORD grfStatFlag) 679 { 680 StreamOnStreamRange *This = StreamOnStreamRange_from_IStream(iface); 681 HRESULT hr; 682 TRACE("(%p)\n", This); 683 684 if (!pstatstg) return E_INVALIDARG; 685 686 EnterCriticalSection(&This->lock); 687 hr = IStream_Stat(This->stream, pstatstg, grfStatFlag); 688 if (SUCCEEDED(hr)) 689 { 690 pstatstg->cbSize.QuadPart -= This->offset.QuadPart; 691 if (This->max_size.QuadPart < pstatstg->cbSize.QuadPart) 692 pstatstg->cbSize.QuadPart = This->max_size.QuadPart; 693 } 694 695 LeaveCriticalSection(&This->lock); 696 697 return hr; 698 } 699 700 /* Clone isn't implemented in the native windowscodecs DLL either */ 701 static HRESULT WINAPI StreamOnStreamRange_Clone(IStream *iface, 702 IStream **ppstm) 703 { 704 TRACE("(%p)\n", iface); 705 return E_NOTIMPL; 706 } 707 708 709 static const IStreamVtbl StreamOnStreamRange_Vtbl = 710 { 711 /*** IUnknown methods ***/ 712 StreamOnStreamRange_QueryInterface, 713 StreamOnStreamRange_AddRef, 714 StreamOnStreamRange_Release, 715 /*** ISequentialStream methods ***/ 716 StreamOnStreamRange_Read, 717 StreamOnStreamRange_Write, 718 /*** IStream methods ***/ 719 StreamOnStreamRange_Seek, 720 StreamOnStreamRange_SetSize, 721 StreamOnStreamRange_CopyTo, 722 StreamOnStreamRange_Commit, 723 StreamOnStreamRange_Revert, 724 StreamOnStreamRange_LockRegion, 725 StreamOnStreamRange_UnlockRegion, 726 StreamOnStreamRange_Stat, 727 StreamOnStreamRange_Clone, 728 }; 729 730 731 /****************************************** 732 * IWICStream implementation 733 * 734 */ 735 typedef struct IWICStreamImpl 736 { 737 IWICStream IWICStream_iface; 738 LONG ref; 739 740 IStream *pStream; 741 } IWICStreamImpl; 742 743 static inline IWICStreamImpl *impl_from_IWICStream(IWICStream *iface) 744 { 745 return CONTAINING_RECORD(iface, IWICStreamImpl, IWICStream_iface); 746 } 747 748 static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface, 749 REFIID iid, void **ppv) 750 { 751 IWICStreamImpl *This = impl_from_IWICStream(iface); 752 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 753 754 if (!ppv) return E_INVALIDARG; 755 756 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || 757 IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid)) 758 { 759 *ppv = &This->IWICStream_iface; 760 IUnknown_AddRef((IUnknown*)*ppv); 761 return S_OK; 762 } 763 else 764 { 765 *ppv = NULL; 766 return E_NOINTERFACE; 767 } 768 } 769 770 static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface) 771 { 772 IWICStreamImpl *This = impl_from_IWICStream(iface); 773 ULONG ref = InterlockedIncrement(&This->ref); 774 775 TRACE("(%p) refcount=%u\n", iface, ref); 776 777 return ref; 778 } 779 780 static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface) 781 { 782 IWICStreamImpl *This = impl_from_IWICStream(iface); 783 ULONG ref = InterlockedDecrement(&This->ref); 784 785 TRACE("(%p) refcount=%u\n", iface, ref); 786 787 if (ref == 0) { 788 if (This->pStream) IStream_Release(This->pStream); 789 HeapFree(GetProcessHeap(), 0, This); 790 } 791 return ref; 792 } 793 794 static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface, 795 void *pv, ULONG cb, ULONG *pcbRead) 796 { 797 IWICStreamImpl *This = impl_from_IWICStream(iface); 798 TRACE("(%p): relay\n", This); 799 800 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 801 return IStream_Read(This->pStream, pv, cb, pcbRead); 802 } 803 804 static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface, 805 void const *pv, ULONG cb, ULONG *pcbWritten) 806 { 807 IWICStreamImpl *This = impl_from_IWICStream(iface); 808 TRACE("(%p): relay\n", This); 809 810 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 811 return IStream_Write(This->pStream, pv, cb, pcbWritten); 812 } 813 814 static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface, 815 LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 816 { 817 IWICStreamImpl *This = impl_from_IWICStream(iface); 818 TRACE("(%p): relay\n", This); 819 820 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 821 return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition); 822 } 823 824 static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface, 825 ULARGE_INTEGER libNewSize) 826 { 827 IWICStreamImpl *This = impl_from_IWICStream(iface); 828 TRACE("(%p): relay\n", This); 829 830 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 831 return IStream_SetSize(This->pStream, libNewSize); 832 } 833 834 static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface, 835 IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 836 { 837 IWICStreamImpl *This = impl_from_IWICStream(iface); 838 TRACE("(%p): relay\n", This); 839 840 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 841 return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten); 842 } 843 844 static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface, 845 DWORD grfCommitFlags) 846 { 847 IWICStreamImpl *This = impl_from_IWICStream(iface); 848 TRACE("(%p): relay\n", This); 849 850 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 851 return IStream_Commit(This->pStream, grfCommitFlags); 852 } 853 854 static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface) 855 { 856 IWICStreamImpl *This = impl_from_IWICStream(iface); 857 TRACE("(%p): relay\n", This); 858 859 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 860 return IStream_Revert(This->pStream); 861 } 862 863 static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface, 864 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 865 { 866 IWICStreamImpl *This = impl_from_IWICStream(iface); 867 TRACE("(%p): relay\n", This); 868 869 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 870 return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType); 871 } 872 873 static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface, 874 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 875 { 876 IWICStreamImpl *This = impl_from_IWICStream(iface); 877 TRACE("(%p): relay\n", This); 878 879 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 880 return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType); 881 } 882 883 static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface, 884 STATSTG *pstatstg, DWORD grfStatFlag) 885 { 886 IWICStreamImpl *This = impl_from_IWICStream(iface); 887 TRACE("(%p): relay\n", This); 888 889 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 890 return IStream_Stat(This->pStream, pstatstg, grfStatFlag); 891 } 892 893 static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface, 894 IStream **ppstm) 895 { 896 IWICStreamImpl *This = impl_from_IWICStream(iface); 897 TRACE("(%p): relay\n", This); 898 899 if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED; 900 return IStream_Clone(This->pStream, ppstm); 901 } 902 903 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface, 904 IStream *pIStream) 905 { 906 ULARGE_INTEGER offset, size; 907 TRACE("(%p): relay\n", iface); 908 909 offset.QuadPart = 0; 910 size.u.LowPart = 0xffffffff; 911 size.u.HighPart = 0xffffffff; 912 return IWICStream_InitializeFromIStreamRegion(iface, pIStream, offset, size); 913 } 914 915 static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface, 916 LPCWSTR wzFileName, DWORD dwDesiredAccess) 917 { 918 IWICStreamImpl *This = impl_from_IWICStream(iface); 919 HRESULT hr; 920 DWORD dwMode; 921 IStream *stream; 922 923 TRACE("(%p, %s, %u)\n", iface, debugstr_w(wzFileName), dwDesiredAccess); 924 925 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 926 927 if(dwDesiredAccess & GENERIC_WRITE) 928 dwMode = STGM_SHARE_DENY_WRITE | STGM_WRITE | STGM_CREATE; 929 else if(dwDesiredAccess & GENERIC_READ) 930 dwMode = STGM_SHARE_DENY_WRITE | STGM_READ | STGM_FAILIFTHERE; 931 else 932 return E_INVALIDARG; 933 934 hr = SHCreateStreamOnFileW(wzFileName, dwMode, &stream); 935 936 if (SUCCEEDED(hr)) 937 { 938 if (InterlockedCompareExchangePointer((void**)&This->pStream, stream, NULL)) 939 { 940 /* Some other thread set the stream first. */ 941 IStream_Release(stream); 942 hr = WINCODEC_ERR_WRONGSTATE; 943 } 944 } 945 946 return hr; 947 } 948 949 /****************************************** 950 * IWICStream_InitializeFromMemory 951 * 952 * Initializes the internal IStream object to retrieve its data from a memory chunk. 953 * 954 * PARAMS 955 * pbBuffer [I] pointer to the memory chunk 956 * cbBufferSize [I] number of bytes to use from the memory chunk 957 * 958 * RETURNS 959 * SUCCESS: S_OK 960 * FAILURE: E_INVALIDARG, if pbBuffer is NULL 961 * E_OUTOFMEMORY, if we run out of memory 962 * WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before 963 * 964 */ 965 static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface, 966 BYTE *pbBuffer, DWORD cbBufferSize) 967 { 968 IWICStreamImpl *This = impl_from_IWICStream(iface); 969 StreamOnMemory *pObject; 970 TRACE("(%p,%p)\n", iface, pbBuffer); 971 972 if (!pbBuffer) return E_INVALIDARG; 973 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 974 975 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory)); 976 if (!pObject) return E_OUTOFMEMORY; 977 978 pObject->IStream_iface.lpVtbl = &StreamOnMemory_Vtbl; 979 pObject->ref = 1; 980 pObject->pbMemory = pbBuffer; 981 pObject->dwMemsize = cbBufferSize; 982 pObject->dwCurPos = 0; 983 InitializeCriticalSection(&pObject->lock); 984 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnMemory.lock"); 985 986 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 987 { 988 /* Some other thread set the stream first. */ 989 IStream_Release(&pObject->IStream_iface); 990 return WINCODEC_ERR_WRONGSTATE; 991 } 992 993 return S_OK; 994 } 995 996 static HRESULT map_file(HANDLE file, HANDLE *map, void **mem, LARGE_INTEGER *size) 997 { 998 *map = NULL; 999 if (!GetFileSizeEx(file, size)) return HRESULT_FROM_WIN32(GetLastError()); 1000 if (size->u.HighPart) 1001 { 1002 WARN("file too large\n"); 1003 return E_FAIL; 1004 } 1005 if (!(*map = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, size->u.LowPart, NULL))) 1006 { 1007 return HRESULT_FROM_WIN32(GetLastError()); 1008 } 1009 if (!(*mem = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, size->u.LowPart))) 1010 { 1011 CloseHandle(*map); 1012 return HRESULT_FROM_WIN32(GetLastError()); 1013 } 1014 return S_OK; 1015 } 1016 1017 HRESULT stream_initialize_from_filehandle(IWICStream *iface, HANDLE file) 1018 { 1019 IWICStreamImpl *This = impl_from_IWICStream(iface); 1020 StreamOnFileHandle *pObject; 1021 IWICStream *stream = NULL; 1022 HANDLE map; 1023 void *mem; 1024 LARGE_INTEGER size; 1025 HRESULT hr; 1026 TRACE("(%p,%p)\n", iface, file); 1027 1028 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 1029 1030 hr = map_file(file, &map, &mem, &size); 1031 if (FAILED(hr)) return hr; 1032 1033 hr = StreamImpl_Create(&stream); 1034 if (FAILED(hr)) goto error; 1035 1036 hr = IWICStreamImpl_InitializeFromMemory(stream, mem, size.u.LowPart); 1037 if (FAILED(hr)) goto error; 1038 1039 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnFileHandle)); 1040 if (!pObject) 1041 { 1042 hr = E_OUTOFMEMORY; 1043 goto error; 1044 } 1045 pObject->IStream_iface.lpVtbl = &StreamOnFileHandle_Vtbl; 1046 pObject->ref = 1; 1047 pObject->map = map; 1048 pObject->mem = mem; 1049 pObject->stream = stream; 1050 1051 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 1052 { 1053 /* Some other thread set the stream first. */ 1054 IStream_Release(&pObject->IStream_iface); 1055 return WINCODEC_ERR_WRONGSTATE; 1056 } 1057 return S_OK; 1058 1059 error: 1060 if (stream) IWICStream_Release(stream); 1061 UnmapViewOfFile(mem); 1062 CloseHandle(map); 1063 return hr; 1064 } 1065 1066 static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface, 1067 IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize) 1068 { 1069 IWICStreamImpl *This = impl_from_IWICStream(iface); 1070 StreamOnStreamRange *pObject; 1071 TRACE("(%p,%p)\n", iface, pIStream); 1072 1073 if (!pIStream) return E_INVALIDARG; 1074 if (This->pStream) return WINCODEC_ERR_WRONGSTATE; 1075 1076 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnStreamRange)); 1077 if (!pObject) return E_OUTOFMEMORY; 1078 1079 pObject->IStream_iface.lpVtbl = &StreamOnStreamRange_Vtbl; 1080 pObject->ref = 1; 1081 IStream_AddRef(pIStream); 1082 pObject->stream = pIStream; 1083 pObject->pos.QuadPart = 0; 1084 pObject->offset = ulOffset; 1085 pObject->max_size = ulMaxSize; 1086 InitializeCriticalSection(&pObject->lock); 1087 pObject->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StreamOnStreamRange.lock"); 1088 1089 if (InterlockedCompareExchangePointer((void**)&This->pStream, pObject, NULL)) 1090 { 1091 /* Some other thread set the stream first. */ 1092 IStream_Release(&pObject->IStream_iface); 1093 return WINCODEC_ERR_WRONGSTATE; 1094 } 1095 1096 return S_OK; 1097 } 1098 1099 1100 static const IWICStreamVtbl WICStream_Vtbl = 1101 { 1102 /*** IUnknown methods ***/ 1103 IWICStreamImpl_QueryInterface, 1104 IWICStreamImpl_AddRef, 1105 IWICStreamImpl_Release, 1106 /*** ISequentialStream methods ***/ 1107 IWICStreamImpl_Read, 1108 IWICStreamImpl_Write, 1109 /*** IStream methods ***/ 1110 IWICStreamImpl_Seek, 1111 IWICStreamImpl_SetSize, 1112 IWICStreamImpl_CopyTo, 1113 IWICStreamImpl_Commit, 1114 IWICStreamImpl_Revert, 1115 IWICStreamImpl_LockRegion, 1116 IWICStreamImpl_UnlockRegion, 1117 IWICStreamImpl_Stat, 1118 IWICStreamImpl_Clone, 1119 /*** IWICStream methods ***/ 1120 IWICStreamImpl_InitializeFromIStream, 1121 IWICStreamImpl_InitializeFromFilename, 1122 IWICStreamImpl_InitializeFromMemory, 1123 IWICStreamImpl_InitializeFromIStreamRegion, 1124 }; 1125 1126 HRESULT StreamImpl_Create(IWICStream **stream) 1127 { 1128 IWICStreamImpl *pObject; 1129 1130 if( !stream ) return E_INVALIDARG; 1131 1132 pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl)); 1133 if( !pObject ) { 1134 *stream = NULL; 1135 return E_OUTOFMEMORY; 1136 } 1137 1138 pObject->IWICStream_iface.lpVtbl = &WICStream_Vtbl; 1139 pObject->ref = 1; 1140 pObject->pStream = NULL; 1141 1142 *stream = &pObject->IWICStream_iface; 1143 1144 return S_OK; 1145 } 1146