FileIOHelper.cpp 32 KB

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