FileIOHelper.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // FileIOHelper.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // TODO: consider including an empty blob singleton (possibly UTF-8/16 too). //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/Support/Global.h"
  12. #include "dxc/Support/WinIncludes.h"
  13. #include "dxc/Support/microcom.h"
  14. #include "dxc/Support/Unicode.h"
  15. #include "dxc/Support/FileIOHelper.h"
  16. #include "dxc/Support/WinFunctions.h"
  17. #include "dxc/dxcapi.h"
  18. #include <algorithm>
  19. #include <memory>
  20. #ifdef _WIN32
  21. #include <intsafe.h>
  22. #endif
  23. #define CP_UTF16 1200
  24. struct HeapMalloc : public IMalloc {
  25. public:
  26. ULONG STDMETHODCALLTYPE AddRef() override { return 1; }
  27. ULONG STDMETHODCALLTYPE Release() override { return 1; }
  28. STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) override {
  29. return DoBasicQueryInterface<IMalloc>(this, iid, ppvObject);
  30. }
  31. virtual void *STDMETHODCALLTYPE Alloc (
  32. /* [annotation][in] */
  33. _In_ SIZE_T cb) override {
  34. return HeapAlloc(GetProcessHeap(), 0, cb);
  35. }
  36. virtual void *STDMETHODCALLTYPE Realloc (
  37. /* [annotation][in] */
  38. _In_opt_ void *pv,
  39. /* [annotation][in] */
  40. _In_ SIZE_T cb) override
  41. {
  42. return HeapReAlloc(GetProcessHeap(), 0, pv, cb);
  43. }
  44. virtual void STDMETHODCALLTYPE Free (
  45. /* [annotation][in] */
  46. _In_opt_ void *pv) override
  47. {
  48. HeapFree(GetProcessHeap(), 0, pv);
  49. }
  50. virtual SIZE_T STDMETHODCALLTYPE GetSize(
  51. /* [annotation][in] */
  52. _In_opt_ _Post_writable_byte_size_(return) void *pv)
  53. {
  54. return HeapSize(GetProcessHeap(), 0, pv);
  55. }
  56. virtual int STDMETHODCALLTYPE DidAlloc(
  57. /* [annotation][in] */
  58. _In_opt_ void *pv)
  59. {
  60. return -1; // don't know
  61. }
  62. virtual void STDMETHODCALLTYPE HeapMinimize(void) {}
  63. };
  64. static HeapMalloc g_HeapMalloc;
  65. namespace hlsl {
  66. IMalloc *GetGlobalHeapMalloc() throw() {
  67. return &g_HeapMalloc;
  68. }
  69. _Use_decl_annotations_
  70. void ReadBinaryFile(IMalloc *pMalloc, LPCWSTR pFileName, void **ppData,
  71. DWORD *pDataSize) {
  72. HANDLE hFile = CreateFileW(pFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  73. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  74. if (hFile == INVALID_HANDLE_VALUE) {
  75. IFT(HRESULT_FROM_WIN32(GetLastError()));
  76. }
  77. CHandle h(hFile);
  78. LARGE_INTEGER FileSize;
  79. if (!GetFileSizeEx(hFile, &FileSize)) {
  80. IFT(HRESULT_FROM_WIN32(GetLastError()));
  81. }
  82. if (FileSize.u.HighPart != 0) {
  83. throw(hlsl::Exception(DXC_E_INPUT_FILE_TOO_LARGE, "input file is too large"));
  84. }
  85. char *pData = (char *)pMalloc->Alloc(FileSize.u.LowPart);
  86. if (!pData) {
  87. throw std::bad_alloc();
  88. }
  89. DWORD BytesRead;
  90. if (!ReadFile(hFile, pData, FileSize.u.LowPart, &BytesRead, nullptr)) {
  91. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  92. pMalloc->Free(pData);
  93. throw ::hlsl::Exception(hr);
  94. }
  95. DXASSERT(FileSize.u.LowPart == BytesRead, "ReadFile operation failed");
  96. *ppData = pData;
  97. *pDataSize = FileSize.u.LowPart;
  98. }
  99. _Use_decl_annotations_
  100. void ReadBinaryFile(LPCWSTR pFileName, void **ppData, DWORD *pDataSize) {
  101. return ReadBinaryFile(GetGlobalHeapMalloc(), pFileName, ppData, pDataSize);
  102. }
  103. _Use_decl_annotations_
  104. void WriteBinaryFile(LPCWSTR pFileName, const void *pData, DWORD DataSize) {
  105. HANDLE hFile = CreateFileW(pFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  106. if(hFile == INVALID_HANDLE_VALUE) {
  107. IFT(HRESULT_FROM_WIN32(GetLastError()));
  108. }
  109. CHandle h(hFile);
  110. DWORD BytesWritten;
  111. if(!WriteFile(hFile, pData, DataSize, &BytesWritten, nullptr)) {
  112. IFT(HRESULT_FROM_WIN32(GetLastError()));
  113. }
  114. DXASSERT(DataSize == BytesWritten, "WriteFile operation failed");
  115. }
  116. _Use_decl_annotations_
  117. UINT32 DxcCodePageFromBytes(const char *bytes, size_t byteLen) throw() {
  118. UINT32 codePage;
  119. if (byteLen >= 4) {
  120. // Now try to use the BOM to check for Unicode encodings
  121. char bom[4] = { bytes[0], bytes[1], bytes[2], bytes[3] };
  122. if (strncmp(bom, "\xef\xbb\xbf", 3) == 0) {
  123. codePage = CP_UTF8;
  124. }
  125. else if (strncmp(bom, "\xff\xfe**", 2) == 0) {
  126. codePage = 1200; //UTF-16 LE
  127. }
  128. else if (strncmp(bom, "\xfe\xff**", 2) == 0) {
  129. codePage = 1201; //UTF-16 BE
  130. }
  131. else if (strncmp(bom, "\xff\xfe\x00\x00", 4) == 0) {
  132. codePage = 12000; //UTF-32 LE
  133. }
  134. else if (strncmp(bom, "\x00\x00\xfe\xff", 4) == 0) {
  135. codePage = 12001; //UTF-32 BE
  136. }
  137. else {
  138. codePage = CP_ACP;
  139. }
  140. }
  141. else {
  142. codePage = CP_ACP;
  143. }
  144. return codePage;
  145. }
  146. class InternalDxcBlobEncoding : public IDxcBlobEncoding {
  147. private:
  148. DXC_MICROCOM_TM_REF_FIELDS() // an underlying m_pMalloc that owns this
  149. LPCVOID m_Buffer = nullptr;
  150. IUnknown* m_Owner = nullptr; // IMalloc when MallocFree is true, owning the buffer
  151. SIZE_T m_BufferSize;
  152. unsigned m_EncodingKnown : 1;
  153. unsigned m_MallocFree : 1;
  154. UINT32 m_CodePage;
  155. public:
  156. DXC_MICROCOM_ADDREF_IMPL(m_dwRef)
  157. ULONG STDMETHODCALLTYPE Release() override {
  158. // Because blobs are also used by tests and utilities, we avoid using TLS.
  159. ULONG result = (ULONG)--m_dwRef;
  160. if (result == 0) {
  161. CComPtr<IMalloc> pTmp(m_pMalloc);
  162. this->~InternalDxcBlobEncoding();
  163. pTmp->Free(this);
  164. }
  165. return result;
  166. }
  167. DXC_MICROCOM_TM_CTOR(InternalDxcBlobEncoding)
  168. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  169. return DoBasicQueryInterface<IDxcBlob, IDxcBlobEncoding>(this, iid, ppvObject);
  170. }
  171. ~InternalDxcBlobEncoding() {
  172. if (m_MallocFree) {
  173. ((IMalloc *)m_Owner)->Free((void *)m_Buffer);
  174. }
  175. if (m_Owner != nullptr) {
  176. m_Owner->Release();
  177. }
  178. }
  179. static HRESULT
  180. CreateFromHeap(LPCVOID buffer, SIZE_T bufferSize, bool encodingKnown,
  181. UINT32 codePage,
  182. _COM_Outptr_ InternalDxcBlobEncoding **ppEncoding) {
  183. return CreateFromMalloc(buffer, DxcGetThreadMallocNoRef(), bufferSize,
  184. encodingKnown, codePage, ppEncoding);
  185. }
  186. static HRESULT
  187. CreateFromBlob(_In_ IDxcBlob *pBlob, _In_ IMalloc *pMalloc, bool encodingKnown, UINT32 codePage,
  188. _COM_Outptr_ InternalDxcBlobEncoding **pEncoding) {
  189. *pEncoding = InternalDxcBlobEncoding::Alloc(pMalloc);
  190. if (*pEncoding == nullptr) {
  191. return E_OUTOFMEMORY;
  192. }
  193. pBlob->AddRef();
  194. (*pEncoding)->m_Owner = pBlob;
  195. (*pEncoding)->m_Buffer = pBlob->GetBufferPointer();
  196. (*pEncoding)->m_BufferSize = pBlob->GetBufferSize();
  197. (*pEncoding)->m_EncodingKnown = encodingKnown;
  198. (*pEncoding)->m_MallocFree = 0;
  199. (*pEncoding)->m_CodePage = codePage;
  200. (*pEncoding)->AddRef();
  201. return S_OK;
  202. }
  203. static HRESULT
  204. CreateFromMalloc(LPCVOID buffer, IMalloc *pIMalloc, SIZE_T bufferSize, bool encodingKnown,
  205. UINT32 codePage, _COM_Outptr_ InternalDxcBlobEncoding **pEncoding) {
  206. *pEncoding = InternalDxcBlobEncoding::Alloc(pIMalloc);
  207. if (*pEncoding == nullptr) {
  208. *pEncoding = nullptr;
  209. return E_OUTOFMEMORY;
  210. }
  211. pIMalloc->AddRef();
  212. (*pEncoding)->m_Owner = pIMalloc;
  213. (*pEncoding)->m_Buffer = buffer;
  214. (*pEncoding)->m_BufferSize = bufferSize;
  215. (*pEncoding)->m_EncodingKnown = encodingKnown;
  216. (*pEncoding)->m_MallocFree = 1;
  217. (*pEncoding)->m_CodePage = codePage;
  218. (*pEncoding)->AddRef();
  219. return S_OK;
  220. }
  221. void AdjustPtrAndSize(unsigned offset, unsigned size) {
  222. DXASSERT(offset < m_BufferSize, "else caller will overflow");
  223. DXASSERT(offset + size <= m_BufferSize, "else caller will overflow");
  224. m_Buffer = (const uint8_t*)m_Buffer + offset;
  225. m_BufferSize = size;
  226. }
  227. virtual LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override {
  228. return (LPVOID)m_Buffer;
  229. }
  230. virtual SIZE_T STDMETHODCALLTYPE GetBufferSize(void) override {
  231. return m_BufferSize;
  232. }
  233. virtual HRESULT STDMETHODCALLTYPE GetEncoding(_Out_ BOOL *pKnown, _Out_ UINT32 *pCodePage) override {
  234. *pKnown = m_EncodingKnown ? TRUE : FALSE;
  235. *pCodePage = m_CodePage;
  236. return S_OK;
  237. }
  238. // Relatively dangerous API. This means the buffer should be pinned for as
  239. // long as this object is alive.
  240. void ClearFreeFlag() { m_MallocFree = 0; }
  241. };
  242. static HRESULT CodePageBufferToUtf16(UINT32 codePage, LPCVOID bufferPointer,
  243. SIZE_T bufferSize,
  244. CDxcMallocHeapPtr<WCHAR> &utf16NewCopy,
  245. _Out_ UINT32 *pConvertedCharCount) {
  246. *pConvertedCharCount = 0;
  247. // If the buffer is empty, don't dereference bufferPointer at all.
  248. // Keep the null terminator post-condition.
  249. if (bufferSize == 0) {
  250. if (!utf16NewCopy.Allocate(1))
  251. return E_OUTOFMEMORY;
  252. utf16NewCopy.m_pData[0] = L'\0';
  253. DXASSERT(*pConvertedCharCount == 0, "else didn't init properly");
  254. return S_OK;
  255. }
  256. // Calculate the length of the buffer in wchar_t elements.
  257. int numToConvertUTF16 =
  258. MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, (LPCSTR)bufferPointer,
  259. bufferSize, nullptr, 0);
  260. if (numToConvertUTF16 == 0)
  261. return HRESULT_FROM_WIN32(GetLastError());
  262. // Add an extra character to make this more developer-friendly.
  263. unsigned buffSizeUTF16;
  264. IFR(Int32ToUInt32(numToConvertUTF16, &buffSizeUTF16));
  265. IFR(UInt32Add(buffSizeUTF16, 1, &buffSizeUTF16));
  266. IFR(UInt32Mult(buffSizeUTF16, sizeof(WCHAR), &buffSizeUTF16));
  267. utf16NewCopy.AllocateBytes(buffSizeUTF16);
  268. IFROOM(utf16NewCopy.m_pData);
  269. int numActuallyConvertedUTF16 =
  270. MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, (LPCSTR)bufferPointer,
  271. bufferSize, utf16NewCopy, buffSizeUTF16);
  272. if (numActuallyConvertedUTF16 == 0)
  273. return HRESULT_FROM_WIN32(GetLastError());
  274. ((LPWSTR)utf16NewCopy)[numActuallyConvertedUTF16] = L'\0';
  275. *pConvertedCharCount = numActuallyConvertedUTF16;
  276. return S_OK;
  277. }
  278. _Use_decl_annotations_
  279. HRESULT DxcCreateBlobFromBlob(
  280. IDxcBlob *pBlob, UINT32 offset, UINT32 length, IDxcBlob **ppResult) throw() {
  281. if (pBlob == nullptr || ppResult == nullptr) {
  282. return E_POINTER;
  283. }
  284. *ppResult = nullptr;
  285. SIZE_T blobSize = pBlob->GetBufferSize();
  286. if (offset > blobSize)
  287. return E_INVALIDARG;
  288. UINT32 end;
  289. IFR(UInt32Add(offset, length, &end));
  290. BOOL encodingKnown = FALSE;
  291. UINT32 codePage = CP_ACP;
  292. CComPtr<IDxcBlobEncoding> pBlobEncoding;
  293. if (SUCCEEDED(pBlob->QueryInterface(&pBlobEncoding))) {
  294. IFR(pBlobEncoding->GetEncoding(&encodingKnown, &codePage));
  295. }
  296. CComPtr<InternalDxcBlobEncoding> pCreated;
  297. IFR(InternalDxcBlobEncoding::CreateFromBlob(pBlob, DxcGetThreadMallocNoRef(), encodingKnown, codePage,
  298. &pCreated));
  299. pCreated->AdjustPtrAndSize(offset, length);
  300. *ppResult = pCreated.Detach();
  301. return S_OK;
  302. }
  303. _Use_decl_annotations_
  304. HRESULT
  305. DxcCreateBlobOnHeap(LPCVOID pData, UINT32 size, IDxcBlob **ppResult) throw() {
  306. if (pData == nullptr || ppResult == nullptr) {
  307. return E_POINTER;
  308. }
  309. *ppResult = nullptr;
  310. CComPtr<InternalDxcBlobEncoding> blob;
  311. IFR(InternalDxcBlobEncoding::CreateFromHeap(pData, size, false, 0, &blob));
  312. *ppResult = blob.Detach();
  313. return S_OK;
  314. }
  315. _Use_decl_annotations_
  316. HRESULT
  317. DxcCreateBlobOnHeapCopy(_In_bytecount_(size) LPCVOID pData, UINT32 size,
  318. _COM_Outptr_ IDxcBlob **ppResult) throw() {
  319. if (pData == nullptr || ppResult == nullptr) {
  320. return E_POINTER;
  321. }
  322. *ppResult = nullptr;
  323. CComHeapPtr<char> heapCopy;
  324. if (!heapCopy.AllocateBytes(size)) {
  325. return E_OUTOFMEMORY;
  326. }
  327. memcpy(heapCopy.m_pData, pData, size);
  328. CComPtr<InternalDxcBlobEncoding> blob;
  329. IFR(InternalDxcBlobEncoding::CreateFromHeap(heapCopy.m_pData, size, false, 0, &blob));
  330. heapCopy.Detach();
  331. *ppResult = blob.Detach();
  332. return S_OK;
  333. }
  334. _Use_decl_annotations_
  335. HRESULT
  336. DxcCreateBlobFromFile(IMalloc *pMalloc, LPCWSTR pFileName, UINT32 *pCodePage,
  337. IDxcBlobEncoding **ppBlobEncoding) throw() {
  338. if (pFileName == nullptr || ppBlobEncoding == nullptr) {
  339. return E_POINTER;
  340. }
  341. LPVOID pData;
  342. DWORD dataSize;
  343. *ppBlobEncoding = nullptr;
  344. try {
  345. ReadBinaryFile(pMalloc, pFileName, &pData, &dataSize);
  346. }
  347. CATCH_CPP_RETURN_HRESULT();
  348. bool known = (pCodePage != nullptr);
  349. UINT32 codePage = (pCodePage != nullptr) ? *pCodePage : 0;
  350. InternalDxcBlobEncoding *internalEncoding;
  351. HRESULT hr = InternalDxcBlobEncoding::CreateFromMalloc(
  352. pData, pMalloc, dataSize, known, codePage, &internalEncoding);
  353. if (SUCCEEDED(hr)) {
  354. *ppBlobEncoding = internalEncoding;
  355. }
  356. else {
  357. pMalloc->Free(pData);
  358. }
  359. return hr;
  360. }
  361. _Use_decl_annotations_
  362. HRESULT DxcCreateBlobFromFile(LPCWSTR pFileName, UINT32 *pCodePage,
  363. IDxcBlobEncoding **ppBlobEncoding) throw() {
  364. CComPtr<IMalloc> pMalloc;
  365. IFR(CoGetMalloc(1, &pMalloc));
  366. return DxcCreateBlobFromFile(pMalloc, pFileName, pCodePage, ppBlobEncoding);
  367. }
  368. _Use_decl_annotations_
  369. HRESULT
  370. DxcCreateBlobWithEncodingSet(IMalloc *pMalloc, IDxcBlob *pBlob, UINT32 codePage,
  371. IDxcBlobEncoding **ppBlobEncoding) throw() {
  372. DXASSERT_NOMSG(pMalloc != nullptr);
  373. DXASSERT_NOMSG(pBlob != nullptr);
  374. DXASSERT_NOMSG(ppBlobEncoding != nullptr);
  375. *ppBlobEncoding = nullptr;
  376. InternalDxcBlobEncoding *internalEncoding;
  377. HRESULT hr = InternalDxcBlobEncoding::CreateFromBlob(
  378. pBlob, pMalloc, true, codePage, &internalEncoding);
  379. if (SUCCEEDED(hr)) {
  380. *ppBlobEncoding = internalEncoding;
  381. }
  382. return hr;
  383. }
  384. _Use_decl_annotations_
  385. HRESULT
  386. DxcCreateBlobWithEncodingSet(IDxcBlob *pBlob, UINT32 codePage,
  387. IDxcBlobEncoding **ppBlobEncoding) throw() {
  388. return DxcCreateBlobWithEncodingSet(DxcGetThreadMallocNoRef(), pBlob,
  389. codePage, ppBlobEncoding);
  390. }
  391. _Use_decl_annotations_
  392. HRESULT DxcCreateBlobWithEncodingFromPinned(LPCVOID pText, UINT32 size,
  393. UINT32 codePage,
  394. IDxcBlobEncoding **pBlobEncoding) throw() {
  395. *pBlobEncoding = nullptr;
  396. InternalDxcBlobEncoding *internalEncoding;
  397. HRESULT hr = InternalDxcBlobEncoding::CreateFromHeap(
  398. pText, size, true, codePage, &internalEncoding);
  399. if (SUCCEEDED(hr)) {
  400. internalEncoding->ClearFreeFlag();
  401. *pBlobEncoding = internalEncoding;
  402. }
  403. return hr;
  404. }
  405. _Use_decl_annotations_
  406. HRESULT
  407. DxcCreateBlobWithEncodingFromStream(IStream *pStream, bool newInstanceAlways,
  408. UINT32 codePage,
  409. IDxcBlobEncoding **ppBlobEncoding) throw() {
  410. *ppBlobEncoding = nullptr;
  411. if (pStream == nullptr) {
  412. return S_OK;
  413. }
  414. // Try to reuse the existing stream.
  415. if (!newInstanceAlways) {
  416. CComPtr<IDxcBlobEncoding> blobEncoding;
  417. if (SUCCEEDED(pStream->QueryInterface(&blobEncoding))) {
  418. *ppBlobEncoding = blobEncoding.Detach();
  419. return S_OK;
  420. }
  421. }
  422. // Layer over the blob if possible.
  423. CComPtr<IDxcBlob> blob;
  424. if (SUCCEEDED(pStream->QueryInterface(&blob))) {
  425. return DxcCreateBlobWithEncodingSet(blob, codePage, ppBlobEncoding);
  426. }
  427. // Create a copy of contents, last resort.
  428. // TODO: implement when we find this codepath internally
  429. return E_NOTIMPL;
  430. }
  431. _Use_decl_annotations_
  432. HRESULT
  433. DxcCreateBlobWithEncodingOnHeap(LPCVOID pText, UINT32 size, UINT32 codePage,
  434. IDxcBlobEncoding **pBlobEncoding) throw() {
  435. *pBlobEncoding = nullptr;
  436. InternalDxcBlobEncoding *internalEncoding;
  437. HRESULT hr = InternalDxcBlobEncoding::CreateFromHeap(
  438. pText, size, true, codePage, &internalEncoding);
  439. if (SUCCEEDED(hr)) {
  440. *pBlobEncoding = internalEncoding;
  441. }
  442. return hr;
  443. }
  444. _Use_decl_annotations_
  445. HRESULT
  446. DxcCreateBlobWithEncodingOnHeapCopy(LPCVOID pText, UINT32 size, UINT32 codePage,
  447. IDxcBlobEncoding **pBlobEncoding) throw() {
  448. *pBlobEncoding = nullptr;
  449. CDxcMallocHeapPtr<char> heapCopy(DxcGetThreadMallocNoRef());
  450. if (!heapCopy.Allocate(size)) {
  451. return E_OUTOFMEMORY;
  452. }
  453. memcpy(heapCopy.m_pData, pText, size);
  454. InternalDxcBlobEncoding* internalEncoding;
  455. HRESULT hr = InternalDxcBlobEncoding::CreateFromHeap(heapCopy.m_pData, size, true, codePage, &internalEncoding);
  456. if (SUCCEEDED(hr)) {
  457. *pBlobEncoding = internalEncoding;
  458. heapCopy.Detach();
  459. }
  460. return hr;
  461. }
  462. _Use_decl_annotations_
  463. HRESULT
  464. DxcCreateBlobWithEncodingOnMalloc(LPCVOID pText, IMalloc *pIMalloc, UINT32 size, UINT32 codePage,
  465. IDxcBlobEncoding **pBlobEncoding) throw() {
  466. *pBlobEncoding = nullptr;
  467. InternalDxcBlobEncoding* internalEncoding;
  468. HRESULT hr = InternalDxcBlobEncoding::CreateFromMalloc(pText, pIMalloc, size, true, codePage, &internalEncoding);
  469. if (SUCCEEDED(hr)) {
  470. *pBlobEncoding = internalEncoding;
  471. }
  472. return hr;
  473. }
  474. _Use_decl_annotations_
  475. HRESULT
  476. DxcCreateBlobWithEncodingOnMallocCopy(IMalloc *pIMalloc, LPCVOID pText, UINT32 size, UINT32 codePage,
  477. IDxcBlobEncoding **ppBlobEncoding) throw() {
  478. *ppBlobEncoding = nullptr;
  479. void *pData = pIMalloc->Alloc(size);
  480. if (pData == nullptr)
  481. return E_OUTOFMEMORY;
  482. memcpy(pData, pText, size);
  483. HRESULT hr = DxcCreateBlobWithEncodingOnMalloc(pData, pIMalloc, size, codePage, ppBlobEncoding);
  484. if (FAILED(hr)) {
  485. pIMalloc->Free(pData);
  486. return hr;
  487. }
  488. return S_OK;
  489. }
  490. _Use_decl_annotations_
  491. HRESULT DxcGetBlobAsUtf8(IDxcBlob *pBlob, IDxcBlobEncoding **pBlobEncoding) throw() {
  492. *pBlobEncoding = nullptr;
  493. HRESULT hr;
  494. CComPtr<IDxcBlobEncoding> pSourceBlob;
  495. UINT32 codePage = CP_ACP;
  496. BOOL known = FALSE;
  497. if (SUCCEEDED(pBlob->QueryInterface(&pSourceBlob))) {
  498. hr = pSourceBlob->GetEncoding(&known, &codePage);
  499. if (FAILED(hr)) {
  500. return hr;
  501. }
  502. // If it's known to be CP_UTF8, there is nothing else to be done.
  503. if (known && codePage == CP_UTF8) {
  504. *pBlobEncoding = pSourceBlob.Detach();
  505. return S_OK;
  506. }
  507. }
  508. else {
  509. known = FALSE;
  510. }
  511. SIZE_T blobLen = pBlob->GetBufferSize();
  512. if (!known && blobLen > 0) {
  513. codePage = DxcCodePageFromBytes((const char *)pBlob->GetBufferPointer(), blobLen);
  514. }
  515. if (codePage == CP_UTF8 || blobLen == 0) {
  516. // Reuse the underlying blob but create an object with the encoding known.
  517. // Empty blobs are encoding-agnostic, so we can consider them UTF-8 and avoid useless conversion.
  518. InternalDxcBlobEncoding* internalEncoding;
  519. hr = InternalDxcBlobEncoding::CreateFromBlob(pBlob, DxcGetThreadMallocNoRef(), true, CP_UTF8, &internalEncoding);
  520. if (SUCCEEDED(hr)) {
  521. *pBlobEncoding = internalEncoding;
  522. }
  523. return hr;
  524. }
  525. // Convert and create a blob that owns the encoding.
  526. // Any UTF-16 output must be converted to UTF-16 first, then
  527. // back to the target code page.
  528. CDxcMallocHeapPtr<WCHAR> utf16NewCopy(DxcGetThreadMallocNoRef());
  529. const wchar_t* utf16Chars = nullptr;
  530. UINT32 utf16CharCount;
  531. if (codePage == CP_UTF16) {
  532. utf16Chars = (const wchar_t*)pBlob->GetBufferPointer();
  533. utf16CharCount = blobLen / sizeof(wchar_t);
  534. }
  535. else {
  536. hr = CodePageBufferToUtf16(codePage, pBlob->GetBufferPointer(), blobLen,
  537. utf16NewCopy, &utf16CharCount);
  538. if (FAILED(hr)) {
  539. return hr;
  540. }
  541. utf16Chars = utf16NewCopy;
  542. }
  543. const UINT32 targetCodePage = CP_UTF8;
  544. CDxcTMHeapPtr<char> finalNewCopy;
  545. int numToConvertFinal = WideCharToMultiByte(
  546. targetCodePage, 0, utf16Chars, utf16CharCount,
  547. finalNewCopy, 0, NULL, NULL);
  548. if (numToConvertFinal == 0)
  549. return HRESULT_FROM_WIN32(GetLastError());
  550. unsigned buffSizeFinal;
  551. IFR(Int32ToUInt32(numToConvertFinal, &buffSizeFinal));
  552. IFR(UInt32Add(buffSizeFinal, 1, &buffSizeFinal));
  553. finalNewCopy.AllocateBytes(buffSizeFinal);
  554. IFROOM(finalNewCopy.m_pData);
  555. int numActuallyConvertedFinal = WideCharToMultiByte(
  556. targetCodePage, 0, utf16Chars, utf16CharCount,
  557. finalNewCopy, buffSizeFinal, NULL, NULL);
  558. if (numActuallyConvertedFinal == 0)
  559. return HRESULT_FROM_WIN32(GetLastError());
  560. ((LPSTR)finalNewCopy)[numActuallyConvertedFinal] = '\0';
  561. InternalDxcBlobEncoding* internalEncoding;
  562. hr = InternalDxcBlobEncoding::CreateFromMalloc(finalNewCopy.m_pData,
  563. DxcGetThreadMallocNoRef(),
  564. numActuallyConvertedFinal, true, targetCodePage, &internalEncoding);
  565. if (SUCCEEDED(hr)) {
  566. *pBlobEncoding = internalEncoding;
  567. finalNewCopy.Detach();
  568. }
  569. return hr;
  570. }
  571. HRESULT
  572. DxcGetBlobAsUtf8NullTerm(_In_ IDxcBlob *pBlob,
  573. _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) throw() {
  574. *ppBlobEncoding = nullptr;
  575. HRESULT hr;
  576. CComPtr<IDxcBlobEncoding> pSourceBlob;
  577. unsigned blobSize = pBlob->GetBufferSize();
  578. // Check whether we already have a null-terminated UTF-8 blob.
  579. if (SUCCEEDED(pBlob->QueryInterface(&pSourceBlob))) {
  580. UINT32 codePage = CP_ACP;
  581. BOOL known = FALSE;
  582. hr = pSourceBlob->GetEncoding(&known, &codePage);
  583. if (FAILED(hr)) {
  584. return hr;
  585. }
  586. if (known && codePage == CP_UTF8) {
  587. char *pChars = (char *)pBlob->GetBufferPointer();
  588. if (blobSize > 0) {
  589. if (pChars[blobSize - 1] == '\0') {
  590. *ppBlobEncoding = pSourceBlob.Detach();
  591. return S_OK;
  592. }
  593. }
  594. // We have a non-null-terminated UTF-8 stream. Copy to a new location.
  595. CDxcTMHeapPtr<char> pCopy;
  596. if (!pCopy.Allocate(blobSize + 1))
  597. return E_OUTOFMEMORY;
  598. memcpy(pCopy.m_pData, pChars, blobSize);
  599. pCopy.m_pData[blobSize] = '\0';
  600. IFR(DxcCreateBlobWithEncodingOnMalloc(
  601. pCopy.m_pData, DxcGetThreadMallocNoRef(), blobSize + 1, CP_UTF8,
  602. ppBlobEncoding));
  603. pCopy.Detach();
  604. return S_OK;
  605. }
  606. }
  607. // Perform the conversion, which typically adds a new null terminator,
  608. // but run this again just in case.
  609. CComPtr<IDxcBlobEncoding> pConverted;
  610. IFR(DxcGetBlobAsUtf8(pBlob, &pConverted));
  611. return DxcGetBlobAsUtf8NullTerm(pConverted, ppBlobEncoding);
  612. }
  613. _Use_decl_annotations_
  614. HRESULT DxcGetBlobAsUtf16(IDxcBlob *pBlob, IMalloc *pMalloc, IDxcBlobEncoding **pBlobEncoding) throw() {
  615. *pBlobEncoding = nullptr;
  616. HRESULT hr;
  617. CComPtr<IDxcBlobEncoding> pSourceBlob;
  618. UINT32 codePage = CP_ACP;
  619. BOOL known = FALSE;
  620. if (SUCCEEDED(pBlob->QueryInterface(&pSourceBlob))) {
  621. hr = pSourceBlob->GetEncoding(&known, &codePage);
  622. if (FAILED(hr)) {
  623. return hr;
  624. }
  625. // If it's known to be CP_UTF8, there is nothing else to be done.
  626. if (known && codePage == CP_UTF16) {
  627. *pBlobEncoding = pSourceBlob.Detach();
  628. return S_OK;
  629. }
  630. }
  631. else {
  632. known = FALSE;
  633. }
  634. SIZE_T blobLen = pBlob->GetBufferSize();
  635. if (!known) {
  636. codePage = DxcCodePageFromBytes((char *)pBlob->GetBufferPointer(), blobLen);
  637. }
  638. // Reuse the underlying blob but create an object with the encoding known.
  639. if (codePage == CP_UTF16) {
  640. InternalDxcBlobEncoding* internalEncoding;
  641. hr = InternalDxcBlobEncoding::CreateFromBlob(pBlob, pMalloc, true, CP_UTF16, &internalEncoding);
  642. if (SUCCEEDED(hr)) {
  643. *pBlobEncoding = internalEncoding;
  644. }
  645. return hr;
  646. }
  647. // Convert and create a blob that owns the encoding.
  648. CDxcMallocHeapPtr<WCHAR> utf16NewCopy(pMalloc);
  649. UINT32 utf16CharCount;
  650. hr = CodePageBufferToUtf16(codePage, pBlob->GetBufferPointer(), blobLen,
  651. utf16NewCopy, &utf16CharCount);
  652. if (FAILED(hr)) {
  653. return hr;
  654. }
  655. InternalDxcBlobEncoding* internalEncoding;
  656. hr = InternalDxcBlobEncoding::CreateFromMalloc(
  657. utf16NewCopy.m_pData, pMalloc,
  658. utf16CharCount * sizeof(WCHAR), true, CP_UTF16, &internalEncoding);
  659. if (SUCCEEDED(hr)) {
  660. *pBlobEncoding = internalEncoding;
  661. utf16NewCopy.Detach();
  662. }
  663. return hr;
  664. }
  665. bool IsBlobNullOrEmpty(_In_opt_ IDxcBlob *pBlob) throw() {
  666. return pBlob == nullptr || pBlob->GetBufferSize() == 0;
  667. }
  668. ///////////////////////////////////////////////////////////////////////////////
  669. // Stream implementations.
  670. class MemoryStream : public AbstractMemoryStream, public IDxcBlob {
  671. private:
  672. DXC_MICROCOM_TM_REF_FIELDS()
  673. LPBYTE m_pMemory = nullptr;
  674. ULONG m_offset = 0;
  675. ULONG m_size = 0;
  676. ULONG m_allocSize = 0;
  677. public:
  678. DXC_MICROCOM_ADDREF_IMPL(m_dwRef)
  679. ULONG STDMETHODCALLTYPE Release() override {
  680. // Because memory streams are also used by tests and utilities,
  681. // we avoid using TLS.
  682. ULONG result = (ULONG)--m_dwRef;
  683. if (result == 0) {
  684. CComPtr<IMalloc> pTmp(m_pMalloc);
  685. this->~MemoryStream();
  686. pTmp->Free(this);
  687. }
  688. return result;
  689. }
  690. DXC_MICROCOM_TM_CTOR(MemoryStream)
  691. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  692. return DoBasicQueryInterface<IStream, ISequentialStream, IDxcBlob>(this, iid, ppvObject);
  693. }
  694. ~MemoryStream() {
  695. Reset();
  696. }
  697. HRESULT Grow(ULONG targetSize) {
  698. if (targetSize < m_allocSize * 2) {
  699. targetSize = m_allocSize * 2;
  700. }
  701. return Reserve(targetSize);
  702. }
  703. void Reset() {
  704. if (m_pMemory != nullptr) {
  705. m_pMalloc->Free(m_pMemory);
  706. }
  707. m_pMemory = nullptr;
  708. m_offset = 0;
  709. m_size = 0;
  710. m_allocSize = 0;
  711. }
  712. // AbstractMemoryStream implementation.
  713. LPBYTE GetPtr() throw() override {
  714. return m_pMemory;
  715. }
  716. ULONG GetPtrSize() throw() override {
  717. return m_size;
  718. }
  719. LPBYTE Detach() throw() override {
  720. LPBYTE result = m_pMemory;
  721. m_pMemory = nullptr;
  722. Reset();
  723. return result;
  724. }
  725. UINT64 GetPosition() throw() override {
  726. return m_offset;
  727. }
  728. HRESULT Reserve(ULONG targetSize) throw() override {
  729. if (m_pMemory == nullptr) {
  730. m_pMemory = (LPBYTE)m_pMalloc->Alloc(targetSize);
  731. if (m_pMemory == nullptr) {
  732. return E_OUTOFMEMORY;
  733. }
  734. }
  735. else {
  736. void* newPtr = m_pMalloc->Realloc(m_pMemory, targetSize);
  737. if (newPtr == nullptr) {
  738. return E_OUTOFMEMORY;
  739. }
  740. m_pMemory = (LPBYTE)newPtr;
  741. }
  742. m_allocSize = targetSize;
  743. return S_OK;
  744. }
  745. // IDxcBlob implementation. Requires no further writes.
  746. LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override {
  747. return m_pMemory;
  748. }
  749. SIZE_T STDMETHODCALLTYPE GetBufferSize(void) override {
  750. return m_size;
  751. }
  752. // ISequentialStream implementation.
  753. HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) override {
  754. if (!pv || !pcbRead) return E_POINTER;
  755. // If we seeked past the end, read nothing.
  756. if (m_offset > m_size) {
  757. *pcbRead = 0;
  758. return S_FALSE;
  759. }
  760. ULONG cbLeft = m_size - m_offset;
  761. *pcbRead = std::min(cb, cbLeft);
  762. memcpy(pv, m_pMemory + m_offset, *pcbRead);
  763. m_offset += *pcbRead;
  764. return (*pcbRead == cb) ? S_OK : S_FALSE;
  765. }
  766. HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) override {
  767. if (!pv || !pcbWritten) return E_POINTER;
  768. if (cb + m_offset > m_allocSize) {
  769. HRESULT hr = Grow(cb + m_offset);
  770. if (FAILED(hr)) return hr;
  771. // Implicitly extend as needed with zeroes.
  772. if (m_offset > m_size) {
  773. memset(m_pMemory + m_size, 0, m_offset - m_size);
  774. }
  775. }
  776. *pcbWritten = cb;
  777. memcpy(m_pMemory + m_offset, pv, cb);
  778. m_offset += cb;
  779. m_size = std::max(m_size, m_offset);
  780. return S_OK;
  781. }
  782. // IStream implementation.
  783. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  784. if (val.u.HighPart != 0) {
  785. return E_OUTOFMEMORY;
  786. }
  787. if (val.u.LowPart > m_allocSize) {
  788. return Grow(m_allocSize);
  789. }
  790. if (val.u.LowPart < m_size) {
  791. m_size = val.u.LowPart;
  792. m_offset = std::min(m_offset, m_size);
  793. }
  794. else if (val.u.LowPart > m_size) {
  795. memset(m_pMemory + m_size, 0, val.u.LowPart - m_size);
  796. m_size = val.u.LowPart;
  797. }
  798. return S_OK;
  799. }
  800. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  801. ULARGE_INTEGER *,
  802. ULARGE_INTEGER *) override {
  803. return E_NOTIMPL;
  804. }
  805. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  806. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  807. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  808. ULARGE_INTEGER, DWORD) override {
  809. return E_NOTIMPL;
  810. }
  811. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  812. ULARGE_INTEGER, DWORD) override {
  813. return E_NOTIMPL;
  814. }
  815. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  816. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  817. DWORD dwOrigin,
  818. ULARGE_INTEGER *lpNewFilePointer) override {
  819. if (lpNewFilePointer != nullptr) {
  820. lpNewFilePointer->QuadPart = 0;
  821. }
  822. if (liDistanceToMove.u.HighPart != 0) {
  823. return E_FAIL;
  824. }
  825. ULONG targetOffset;
  826. switch (dwOrigin) {
  827. case STREAM_SEEK_SET:
  828. targetOffset = liDistanceToMove.u.LowPart;
  829. break;
  830. case STREAM_SEEK_CUR:
  831. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  832. break;
  833. case STREAM_SEEK_END:
  834. targetOffset = liDistanceToMove.u.LowPart + m_size;
  835. break;
  836. default:
  837. return STG_E_INVALIDFUNCTION;
  838. }
  839. m_offset = targetOffset;
  840. if (lpNewFilePointer != nullptr) {
  841. lpNewFilePointer->u.LowPart = targetOffset;
  842. }
  843. return S_OK;
  844. }
  845. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  846. DWORD grfStatFlag) override {
  847. if (pStatstg == nullptr) {
  848. return E_POINTER;
  849. }
  850. ZeroMemory(pStatstg, sizeof(*pStatstg));
  851. pStatstg->type = STGTY_STREAM;
  852. pStatstg->cbSize.u.LowPart = m_size;
  853. return S_OK;
  854. }
  855. };
  856. class ReadOnlyBlobStream : public IStream {
  857. private:
  858. DXC_MICROCOM_TM_REF_FIELDS()
  859. CComPtr<IDxcBlob> m_pSource;
  860. LPBYTE m_pMemory;
  861. ULONG m_offset;
  862. ULONG m_size;
  863. public:
  864. DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
  865. DXC_MICROCOM_TM_CTOR(ReadOnlyBlobStream)
  866. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  867. return DoBasicQueryInterface<IStream, ISequentialStream>(this, iid, ppvObject);
  868. }
  869. void Init(IDxcBlob *pSource) {
  870. m_pSource = pSource;
  871. m_offset = 0;
  872. m_size = m_pSource->GetBufferSize();
  873. m_pMemory = (LPBYTE)m_pSource->GetBufferPointer();
  874. }
  875. // ISequentialStream implementation.
  876. HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb,
  877. ULONG *pcbRead) override {
  878. if (!pv || !pcbRead)
  879. return E_POINTER;
  880. ULONG cbLeft = m_size - m_offset;
  881. *pcbRead = std::min(cb, cbLeft);
  882. memcpy(pv, m_pMemory + m_offset, *pcbRead);
  883. m_offset += *pcbRead;
  884. return (*pcbRead == cb) ? S_OK : S_FALSE;
  885. }
  886. HRESULT STDMETHODCALLTYPE Write(void const *, ULONG, ULONG *) override {
  887. return STG_E_ACCESSDENIED;
  888. }
  889. // IStream implementation.
  890. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  891. return STG_E_ACCESSDENIED;
  892. }
  893. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  894. ULARGE_INTEGER *,
  895. ULARGE_INTEGER *) override {
  896. return E_NOTIMPL;
  897. }
  898. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  899. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  900. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  901. ULARGE_INTEGER, DWORD) override {
  902. return E_NOTIMPL;
  903. }
  904. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  905. ULARGE_INTEGER, DWORD) override {
  906. return E_NOTIMPL;
  907. }
  908. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  909. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  910. DWORD dwOrigin,
  911. ULARGE_INTEGER *lpNewFilePointer) override {
  912. if (lpNewFilePointer != nullptr) {
  913. lpNewFilePointer->QuadPart = 0;
  914. }
  915. if (liDistanceToMove.u.HighPart != 0) {
  916. return E_FAIL;
  917. }
  918. ULONG targetOffset;
  919. switch (dwOrigin) {
  920. case STREAM_SEEK_SET:
  921. targetOffset = liDistanceToMove.u.LowPart;
  922. break;
  923. case STREAM_SEEK_CUR:
  924. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  925. break;
  926. case STREAM_SEEK_END:
  927. targetOffset = liDistanceToMove.u.LowPart + m_size;
  928. break;
  929. default:
  930. return STG_E_INVALIDFUNCTION;
  931. }
  932. // Do not implicility extend.
  933. if (targetOffset > m_size) {
  934. return E_FAIL;
  935. }
  936. m_offset = targetOffset;
  937. if (lpNewFilePointer != nullptr) {
  938. lpNewFilePointer->u.LowPart = targetOffset;
  939. }
  940. return S_OK;
  941. }
  942. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  943. DWORD grfStatFlag) override {
  944. if (pStatstg == nullptr) {
  945. return E_POINTER;
  946. }
  947. ZeroMemory(pStatstg, sizeof(*pStatstg));
  948. pStatstg->type = STGTY_STREAM;
  949. pStatstg->cbSize.u.LowPart = m_size;
  950. return S_OK;
  951. }
  952. };
  953. HRESULT CreateMemoryStream(_In_ IMalloc *pMalloc, _COM_Outptr_ AbstractMemoryStream** ppResult) throw() {
  954. if (pMalloc == nullptr || ppResult == nullptr) {
  955. return E_POINTER;
  956. }
  957. CComPtr<MemoryStream> stream = MemoryStream::Alloc(pMalloc);
  958. *ppResult = stream.Detach();
  959. return (*ppResult == nullptr) ? E_OUTOFMEMORY : S_OK;
  960. }
  961. HRESULT CreateReadOnlyBlobStream(_In_ IDxcBlob *pSource, _COM_Outptr_ IStream** ppResult) throw() {
  962. if (pSource == nullptr || ppResult == nullptr) {
  963. return E_POINTER;
  964. }
  965. CComPtr<ReadOnlyBlobStream> stream = ReadOnlyBlobStream::Alloc(DxcGetThreadMallocNoRef());
  966. if (stream.p) {
  967. stream->Init(pSource);
  968. }
  969. *ppResult = stream.Detach();
  970. return (*ppResult == nullptr) ? E_OUTOFMEMORY : S_OK;
  971. }
  972. } // namespace hlsl