FileIOHelper.cpp 33 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/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) {
  516. // Reuse the underlying blob but create an object with the encoding known.
  517. InternalDxcBlobEncoding* internalEncoding;
  518. hr = InternalDxcBlobEncoding::CreateFromBlob(pBlob, DxcGetThreadMallocNoRef(), true, CP_UTF8, &internalEncoding);
  519. if (SUCCEEDED(hr)) {
  520. *pBlobEncoding = internalEncoding;
  521. }
  522. return hr;
  523. }
  524. // Convert and create a blob that owns the encoding.
  525. // Any UTF-16 output must be converted to UTF-16 first, then
  526. // back to the target code page.
  527. CDxcMallocHeapPtr<WCHAR> utf16NewCopy(DxcGetThreadMallocNoRef());
  528. const wchar_t* utf16Chars = nullptr;
  529. UINT32 utf16CharCount;
  530. if (codePage == CP_UTF16) {
  531. utf16Chars = (const wchar_t*)pBlob->GetBufferPointer();
  532. utf16CharCount = blobLen / sizeof(wchar_t);
  533. }
  534. else {
  535. hr = CodePageBufferToUtf16(codePage, pBlob->GetBufferPointer(), blobLen,
  536. utf16NewCopy, &utf16CharCount);
  537. if (FAILED(hr)) {
  538. return hr;
  539. }
  540. utf16Chars = utf16NewCopy;
  541. }
  542. const UINT32 targetCodePage = CP_UTF8;
  543. CDxcTMHeapPtr<char> finalNewCopy;
  544. int numToConvertFinal = WideCharToMultiByte(
  545. targetCodePage, 0, utf16Chars, utf16CharCount,
  546. finalNewCopy, 0, NULL, NULL);
  547. if (numToConvertFinal == 0)
  548. return HRESULT_FROM_WIN32(GetLastError());
  549. unsigned buffSizeFinal;
  550. IFR(Int32ToUInt32(numToConvertFinal, &buffSizeFinal));
  551. IFR(UInt32Add(buffSizeFinal, 1, &buffSizeFinal));
  552. finalNewCopy.AllocateBytes(buffSizeFinal);
  553. IFROOM(finalNewCopy.m_pData);
  554. int numActuallyConvertedFinal = WideCharToMultiByte(
  555. targetCodePage, 0, utf16Chars, utf16CharCount,
  556. finalNewCopy, buffSizeFinal, NULL, NULL);
  557. if (numActuallyConvertedFinal == 0)
  558. return HRESULT_FROM_WIN32(GetLastError());
  559. ((LPSTR)finalNewCopy)[numActuallyConvertedFinal] = '\0';
  560. InternalDxcBlobEncoding* internalEncoding;
  561. hr = InternalDxcBlobEncoding::CreateFromMalloc(finalNewCopy.m_pData,
  562. DxcGetThreadMallocNoRef(),
  563. numActuallyConvertedFinal, true, targetCodePage, &internalEncoding);
  564. if (SUCCEEDED(hr)) {
  565. *pBlobEncoding = internalEncoding;
  566. finalNewCopy.Detach();
  567. }
  568. return hr;
  569. }
  570. HRESULT
  571. DxcGetBlobAsUtf8NullTerm(_In_ IDxcBlob *pBlob,
  572. _COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) throw() {
  573. *ppBlobEncoding = nullptr;
  574. HRESULT hr;
  575. CComPtr<IDxcBlobEncoding> pSourceBlob;
  576. unsigned blobSize = pBlob->GetBufferSize();
  577. // Check whether we already have a null-terminated UTF-8 blob.
  578. if (SUCCEEDED(pBlob->QueryInterface(&pSourceBlob))) {
  579. UINT32 codePage = CP_ACP;
  580. BOOL known = FALSE;
  581. hr = pSourceBlob->GetEncoding(&known, &codePage);
  582. if (FAILED(hr)) {
  583. return hr;
  584. }
  585. if (known && codePage == CP_UTF8) {
  586. char *pChars = (char *)pBlob->GetBufferPointer();
  587. if (blobSize > 0) {
  588. if (pChars[blobSize - 1] == '\0') {
  589. *ppBlobEncoding = pSourceBlob.Detach();
  590. return S_OK;
  591. }
  592. }
  593. // We have a non-null-terminated UTF-8 stream. Copy to a new location.
  594. CDxcTMHeapPtr<char> pCopy;
  595. if (!pCopy.Allocate(blobSize + 1))
  596. return E_OUTOFMEMORY;
  597. memcpy(pCopy.m_pData, pChars, blobSize);
  598. pCopy.m_pData[blobSize] = '\0';
  599. IFR(DxcCreateBlobWithEncodingOnMalloc(
  600. pCopy.m_pData, DxcGetThreadMallocNoRef(), blobSize + 1, CP_UTF8,
  601. ppBlobEncoding));
  602. pCopy.Detach();
  603. return S_OK;
  604. }
  605. }
  606. // Perform the conversion, which typically adds a new null terminator,
  607. // but run this again just in case.
  608. CComPtr<IDxcBlobEncoding> pConverted;
  609. IFR(DxcGetBlobAsUtf8(pBlob, &pConverted));
  610. return DxcGetBlobAsUtf8NullTerm(pConverted, ppBlobEncoding);
  611. }
  612. _Use_decl_annotations_
  613. HRESULT DxcGetBlobAsUtf16(IDxcBlob *pBlob, IMalloc *pMalloc, IDxcBlobEncoding **pBlobEncoding) throw() {
  614. *pBlobEncoding = nullptr;
  615. HRESULT hr;
  616. CComPtr<IDxcBlobEncoding> pSourceBlob;
  617. UINT32 codePage = CP_ACP;
  618. BOOL known = FALSE;
  619. if (SUCCEEDED(pBlob->QueryInterface(&pSourceBlob))) {
  620. hr = pSourceBlob->GetEncoding(&known, &codePage);
  621. if (FAILED(hr)) {
  622. return hr;
  623. }
  624. // If it's known to be CP_UTF8, there is nothing else to be done.
  625. if (known && codePage == CP_UTF16) {
  626. *pBlobEncoding = pSourceBlob.Detach();
  627. return S_OK;
  628. }
  629. }
  630. else {
  631. known = FALSE;
  632. }
  633. SIZE_T blobLen = pBlob->GetBufferSize();
  634. if (!known) {
  635. codePage = DxcCodePageFromBytes((char *)pBlob->GetBufferPointer(), blobLen);
  636. }
  637. // Reuse the underlying blob but create an object with the encoding known.
  638. if (codePage == CP_UTF16) {
  639. InternalDxcBlobEncoding* internalEncoding;
  640. hr = InternalDxcBlobEncoding::CreateFromBlob(pBlob, pMalloc, true, CP_UTF16, &internalEncoding);
  641. if (SUCCEEDED(hr)) {
  642. *pBlobEncoding = internalEncoding;
  643. }
  644. return hr;
  645. }
  646. // Convert and create a blob that owns the encoding.
  647. CDxcMallocHeapPtr<WCHAR> utf16NewCopy(pMalloc);
  648. UINT32 utf16CharCount;
  649. hr = CodePageBufferToUtf16(codePage, pBlob->GetBufferPointer(), blobLen,
  650. utf16NewCopy, &utf16CharCount);
  651. if (FAILED(hr)) {
  652. return hr;
  653. }
  654. InternalDxcBlobEncoding* internalEncoding;
  655. hr = InternalDxcBlobEncoding::CreateFromMalloc(
  656. utf16NewCopy.m_pData, pMalloc,
  657. utf16CharCount * sizeof(WCHAR), true, CP_UTF16, &internalEncoding);
  658. if (SUCCEEDED(hr)) {
  659. *pBlobEncoding = internalEncoding;
  660. utf16NewCopy.Detach();
  661. }
  662. return hr;
  663. }
  664. bool IsBlobNullOrEmpty(_In_opt_ IDxcBlob *pBlob) throw() {
  665. return pBlob == nullptr || pBlob->GetBufferSize() == 0;
  666. }
  667. ///////////////////////////////////////////////////////////////////////////////
  668. // Stream implementations.
  669. class MemoryStream : public AbstractMemoryStream, public IDxcBlob {
  670. private:
  671. DXC_MICROCOM_TM_REF_FIELDS()
  672. LPBYTE m_pMemory = nullptr;
  673. ULONG m_offset = 0;
  674. ULONG m_size = 0;
  675. ULONG m_allocSize = 0;
  676. public:
  677. DXC_MICROCOM_ADDREF_IMPL(m_dwRef)
  678. ULONG STDMETHODCALLTYPE Release() override {
  679. // Because memory streams are also used by tests and utilities,
  680. // we avoid using TLS.
  681. ULONG result = (ULONG)--m_dwRef;
  682. if (result == 0) {
  683. CComPtr<IMalloc> pTmp(m_pMalloc);
  684. this->~MemoryStream();
  685. pTmp->Free(this);
  686. }
  687. return result;
  688. }
  689. DXC_MICROCOM_TM_CTOR(MemoryStream)
  690. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  691. return DoBasicQueryInterface<IStream, ISequentialStream, IDxcBlob>(this, iid, ppvObject);
  692. }
  693. ~MemoryStream() {
  694. Reset();
  695. }
  696. HRESULT Grow(ULONG targetSize) {
  697. if (targetSize < m_allocSize * 2) {
  698. targetSize = m_allocSize * 2;
  699. }
  700. return Reserve(targetSize);
  701. }
  702. void Reset() {
  703. if (m_pMemory != nullptr) {
  704. m_pMalloc->Free(m_pMemory);
  705. }
  706. m_pMemory = nullptr;
  707. m_offset = 0;
  708. m_size = 0;
  709. m_allocSize = 0;
  710. }
  711. // AbstractMemoryStream implementation.
  712. LPBYTE GetPtr() throw() override {
  713. return m_pMemory;
  714. }
  715. ULONG GetPtrSize() throw() override {
  716. return m_size;
  717. }
  718. LPBYTE Detach() throw() override {
  719. LPBYTE result = m_pMemory;
  720. m_pMemory = nullptr;
  721. Reset();
  722. return result;
  723. }
  724. UINT64 GetPosition() throw() override {
  725. return m_offset;
  726. }
  727. HRESULT Reserve(ULONG targetSize) throw() override {
  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. LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override {
  746. return m_pMemory;
  747. }
  748. SIZE_T STDMETHODCALLTYPE GetBufferSize(void) override {
  749. return m_size;
  750. }
  751. // ISequentialStream implementation.
  752. HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) override {
  753. if (!pv || !pcbRead) return E_POINTER;
  754. // If we seeked past the end, read nothing.
  755. if (m_offset > m_size) {
  756. *pcbRead = 0;
  757. return S_FALSE;
  758. }
  759. ULONG cbLeft = m_size - m_offset;
  760. *pcbRead = std::min(cb, cbLeft);
  761. memcpy(pv, m_pMemory + m_offset, *pcbRead);
  762. m_offset += *pcbRead;
  763. return (*pcbRead == cb) ? S_OK : S_FALSE;
  764. }
  765. HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) override {
  766. if (!pv || !pcbWritten) return E_POINTER;
  767. if (cb + m_offset > m_allocSize) {
  768. HRESULT hr = Grow(cb + m_offset);
  769. if (FAILED(hr)) return hr;
  770. // Implicitly extend as needed with zeroes.
  771. if (m_offset > m_size) {
  772. memset(m_pMemory + m_size, 0, m_offset - m_size);
  773. }
  774. }
  775. *pcbWritten = cb;
  776. memcpy(m_pMemory + m_offset, pv, cb);
  777. m_offset += cb;
  778. m_size = std::max(m_size, m_offset);
  779. return S_OK;
  780. }
  781. // IStream implementation.
  782. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  783. if (val.u.HighPart != 0) {
  784. return E_OUTOFMEMORY;
  785. }
  786. if (val.u.LowPart > m_allocSize) {
  787. return Grow(m_allocSize);
  788. }
  789. if (val.u.LowPart < m_size) {
  790. m_size = val.u.LowPart;
  791. m_offset = std::min(m_offset, m_size);
  792. }
  793. else if (val.u.LowPart > m_size) {
  794. memset(m_pMemory + m_size, 0, val.u.LowPart - m_size);
  795. m_size = val.u.LowPart;
  796. }
  797. return S_OK;
  798. }
  799. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  800. ULARGE_INTEGER *,
  801. ULARGE_INTEGER *) override {
  802. return E_NOTIMPL;
  803. }
  804. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  805. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  806. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  807. ULARGE_INTEGER, DWORD) override {
  808. return E_NOTIMPL;
  809. }
  810. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  811. ULARGE_INTEGER, DWORD) override {
  812. return E_NOTIMPL;
  813. }
  814. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  815. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  816. DWORD dwOrigin,
  817. ULARGE_INTEGER *lpNewFilePointer) override {
  818. if (lpNewFilePointer != nullptr) {
  819. lpNewFilePointer->QuadPart = 0;
  820. }
  821. if (liDistanceToMove.u.HighPart != 0) {
  822. return E_FAIL;
  823. }
  824. ULONG targetOffset;
  825. switch (dwOrigin) {
  826. case STREAM_SEEK_SET:
  827. targetOffset = liDistanceToMove.u.LowPart;
  828. break;
  829. case STREAM_SEEK_CUR:
  830. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  831. break;
  832. case STREAM_SEEK_END:
  833. targetOffset = liDistanceToMove.u.LowPart + m_size;
  834. break;
  835. default:
  836. return STG_E_INVALIDFUNCTION;
  837. }
  838. m_offset = targetOffset;
  839. if (lpNewFilePointer != nullptr) {
  840. lpNewFilePointer->u.LowPart = targetOffset;
  841. }
  842. return S_OK;
  843. }
  844. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  845. DWORD grfStatFlag) override {
  846. if (pStatstg == nullptr) {
  847. return E_POINTER;
  848. }
  849. ZeroMemory(pStatstg, sizeof(*pStatstg));
  850. pStatstg->type = STGTY_STREAM;
  851. pStatstg->cbSize.u.LowPart = m_size;
  852. return S_OK;
  853. }
  854. };
  855. class ReadOnlyBlobStream : public IStream {
  856. private:
  857. DXC_MICROCOM_TM_REF_FIELDS()
  858. CComPtr<IDxcBlob> m_pSource;
  859. LPBYTE m_pMemory;
  860. ULONG m_offset;
  861. ULONG m_size;
  862. public:
  863. DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
  864. DXC_MICROCOM_TM_CTOR(ReadOnlyBlobStream)
  865. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  866. return DoBasicQueryInterface<IStream, ISequentialStream>(this, iid, ppvObject);
  867. }
  868. void Init(IDxcBlob *pSource) {
  869. m_pSource = pSource;
  870. m_offset = 0;
  871. m_size = m_pSource->GetBufferSize();
  872. m_pMemory = (LPBYTE)m_pSource->GetBufferPointer();
  873. }
  874. // ISequentialStream implementation.
  875. HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb,
  876. ULONG *pcbRead) override {
  877. if (!pv || !pcbRead)
  878. return E_POINTER;
  879. ULONG cbLeft = m_size - m_offset;
  880. *pcbRead = std::min(cb, cbLeft);
  881. memcpy(pv, m_pMemory + m_offset, *pcbRead);
  882. m_offset += *pcbRead;
  883. return (*pcbRead == cb) ? S_OK : S_FALSE;
  884. }
  885. HRESULT STDMETHODCALLTYPE Write(void const *, ULONG, ULONG *) override {
  886. return STG_E_ACCESSDENIED;
  887. }
  888. // IStream implementation.
  889. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  890. return STG_E_ACCESSDENIED;
  891. }
  892. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  893. ULARGE_INTEGER *,
  894. ULARGE_INTEGER *) override {
  895. return E_NOTIMPL;
  896. }
  897. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  898. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  899. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  900. ULARGE_INTEGER, DWORD) override {
  901. return E_NOTIMPL;
  902. }
  903. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  904. ULARGE_INTEGER, DWORD) override {
  905. return E_NOTIMPL;
  906. }
  907. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  908. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  909. DWORD dwOrigin,
  910. ULARGE_INTEGER *lpNewFilePointer) override {
  911. if (lpNewFilePointer != nullptr) {
  912. lpNewFilePointer->QuadPart = 0;
  913. }
  914. if (liDistanceToMove.u.HighPart != 0) {
  915. return E_FAIL;
  916. }
  917. ULONG targetOffset;
  918. switch (dwOrigin) {
  919. case STREAM_SEEK_SET:
  920. targetOffset = liDistanceToMove.u.LowPart;
  921. break;
  922. case STREAM_SEEK_CUR:
  923. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  924. break;
  925. case STREAM_SEEK_END:
  926. targetOffset = liDistanceToMove.u.LowPart + m_size;
  927. break;
  928. default:
  929. return STG_E_INVALIDFUNCTION;
  930. }
  931. // Do not implicility extend.
  932. if (targetOffset > m_size) {
  933. return E_FAIL;
  934. }
  935. m_offset = targetOffset;
  936. if (lpNewFilePointer != nullptr) {
  937. lpNewFilePointer->u.LowPart = targetOffset;
  938. }
  939. return S_OK;
  940. }
  941. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  942. DWORD grfStatFlag) override {
  943. if (pStatstg == nullptr) {
  944. return E_POINTER;
  945. }
  946. ZeroMemory(pStatstg, sizeof(*pStatstg));
  947. pStatstg->type = STGTY_STREAM;
  948. pStatstg->cbSize.u.LowPart = m_size;
  949. return S_OK;
  950. }
  951. };
  952. HRESULT CreateMemoryStream(_In_ IMalloc *pMalloc, _COM_Outptr_ AbstractMemoryStream** ppResult) throw() {
  953. if (pMalloc == nullptr || ppResult == nullptr) {
  954. return E_POINTER;
  955. }
  956. CComPtr<MemoryStream> stream = MemoryStream::Alloc(pMalloc);
  957. *ppResult = stream.Detach();
  958. return (*ppResult == nullptr) ? E_OUTOFMEMORY : S_OK;
  959. }
  960. HRESULT CreateReadOnlyBlobStream(_In_ IDxcBlob *pSource, _COM_Outptr_ IStream** ppResult) throw() {
  961. if (pSource == nullptr || ppResult == nullptr) {
  962. return E_POINTER;
  963. }
  964. CComPtr<ReadOnlyBlobStream> stream = ReadOnlyBlobStream::Alloc(DxcGetThreadMallocNoRef());
  965. if (stream.p) {
  966. stream->Init(pSource);
  967. }
  968. *ppResult = stream.Detach();
  969. return (*ppResult == nullptr) ? E_OUTOFMEMORY : S_OK;
  970. }
  971. } // namespace hlsl