FileIOHelper.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  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) override {
  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() throw() {
  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.u.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.u.LowPart);
  89. if (!pData) {
  90. throw std::bad_alloc();
  91. }
  92. DWORD BytesRead;
  93. if (!ReadFile(hFile, pData, FileSize.u.LowPart, &BytesRead, nullptr)) {
  94. HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  95. pMalloc->Free(pData);
  96. throw ::hlsl::Exception(hr);
  97. }
  98. DXASSERT(FileSize.u.LowPart == BytesRead, "ReadFile operation failed");
  99. *ppData = pData;
  100. *pDataSize = FileSize.u.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) throw() {
  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() override {
  161. // Because blobs are also used by tests and utilities, we avoid using TLS.
  162. ULONG result = (ULONG)llvm::sys::AtomicDecrement(&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) override {
  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) override {
  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, (LPCSTR)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, (LPCSTR)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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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) throw() {
  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((const 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. const wchar_t* utf16Chars = nullptr;
  532. UINT32 utf16CharCount;
  533. if (codePage == CP_UTF16) {
  534. utf16Chars = (const 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) throw() {
  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) throw() {
  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() override {
  682. // Because memory streams are also used by tests and utilities,
  683. // we avoid using TLS.
  684. ULONG result = (ULONG)llvm::sys::AtomicDecrement(&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) override {
  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. LPBYTE GetPtr() throw() override {
  716. return m_pMemory;
  717. }
  718. ULONG GetPtrSize() throw() override {
  719. return m_size;
  720. }
  721. LPBYTE Detach() throw() override {
  722. LPBYTE result = m_pMemory;
  723. m_pMemory = nullptr;
  724. Reset();
  725. return result;
  726. }
  727. UINT64 GetPosition() throw() override {
  728. return m_offset;
  729. }
  730. HRESULT Reserve(ULONG targetSize) throw() override {
  731. if (m_pMemory == nullptr) {
  732. m_pMemory = (LPBYTE)m_pMalloc->Alloc(targetSize);
  733. if (m_pMemory == nullptr) {
  734. return E_OUTOFMEMORY;
  735. }
  736. }
  737. else {
  738. void* newPtr = m_pMalloc->Realloc(m_pMemory, targetSize);
  739. if (newPtr == nullptr) {
  740. return E_OUTOFMEMORY;
  741. }
  742. m_pMemory = (LPBYTE)newPtr;
  743. }
  744. m_allocSize = targetSize;
  745. return S_OK;
  746. }
  747. // IDxcBlob implementation. Requires no further writes.
  748. LPVOID STDMETHODCALLTYPE GetBufferPointer(void) override {
  749. return m_pMemory;
  750. }
  751. SIZE_T STDMETHODCALLTYPE GetBufferSize(void) override {
  752. return m_size;
  753. }
  754. // ISequentialStream implementation.
  755. HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) override {
  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. HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) override {
  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. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  786. if (val.u.HighPart != 0) {
  787. return E_OUTOFMEMORY;
  788. }
  789. if (val.u.LowPart > m_allocSize) {
  790. return Grow(m_allocSize);
  791. }
  792. if (val.u.LowPart < m_size) {
  793. m_size = val.u.LowPart;
  794. m_offset = std::min(m_offset, m_size);
  795. }
  796. else if (val.u.LowPart > m_size) {
  797. memset(m_pMemory + m_size, 0, val.u.LowPart - m_size);
  798. m_size = val.u.LowPart;
  799. }
  800. return S_OK;
  801. }
  802. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  803. ULARGE_INTEGER *,
  804. ULARGE_INTEGER *) override {
  805. return E_NOTIMPL;
  806. }
  807. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  808. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  809. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  810. ULARGE_INTEGER, DWORD) override {
  811. return E_NOTIMPL;
  812. }
  813. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  814. ULARGE_INTEGER, DWORD) override {
  815. return E_NOTIMPL;
  816. }
  817. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  818. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  819. DWORD dwOrigin,
  820. ULARGE_INTEGER *lpNewFilePointer) override {
  821. if (lpNewFilePointer != nullptr) {
  822. lpNewFilePointer->QuadPart = 0;
  823. }
  824. if (liDistanceToMove.u.HighPart != 0) {
  825. return E_FAIL;
  826. }
  827. ULONG targetOffset;
  828. switch (dwOrigin) {
  829. case STREAM_SEEK_SET:
  830. targetOffset = liDistanceToMove.u.LowPart;
  831. break;
  832. case STREAM_SEEK_CUR:
  833. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  834. break;
  835. case STREAM_SEEK_END:
  836. targetOffset = liDistanceToMove.u.LowPart + m_size;
  837. break;
  838. default:
  839. return STG_E_INVALIDFUNCTION;
  840. }
  841. m_offset = targetOffset;
  842. if (lpNewFilePointer != nullptr) {
  843. lpNewFilePointer->u.LowPart = targetOffset;
  844. }
  845. return S_OK;
  846. }
  847. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  848. DWORD grfStatFlag) override {
  849. if (pStatstg == nullptr) {
  850. return E_POINTER;
  851. }
  852. ZeroMemory(pStatstg, sizeof(*pStatstg));
  853. pStatstg->type = STGTY_STREAM;
  854. pStatstg->cbSize.u.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) override {
  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. HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb,
  879. ULONG *pcbRead) override {
  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. HRESULT STDMETHODCALLTYPE Write(void const *, ULONG, ULONG *) override {
  889. return STG_E_ACCESSDENIED;
  890. }
  891. // IStream implementation.
  892. HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER val) override {
  893. return STG_E_ACCESSDENIED;
  894. }
  895. HRESULT STDMETHODCALLTYPE CopyTo(IStream *, ULARGE_INTEGER,
  896. ULARGE_INTEGER *,
  897. ULARGE_INTEGER *) override {
  898. return E_NOTIMPL;
  899. }
  900. HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
  901. HRESULT STDMETHODCALLTYPE Revert(void) override { return E_NOTIMPL; }
  902. HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
  903. ULARGE_INTEGER, DWORD) override {
  904. return E_NOTIMPL;
  905. }
  906. HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
  907. ULARGE_INTEGER, DWORD) override {
  908. return E_NOTIMPL;
  909. }
  910. HRESULT STDMETHODCALLTYPE Clone(IStream **) override { return E_NOTIMPL; }
  911. HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
  912. DWORD dwOrigin,
  913. ULARGE_INTEGER *lpNewFilePointer) override {
  914. if (lpNewFilePointer != nullptr) {
  915. lpNewFilePointer->QuadPart = 0;
  916. }
  917. if (liDistanceToMove.u.HighPart != 0) {
  918. return E_FAIL;
  919. }
  920. ULONG targetOffset;
  921. switch (dwOrigin) {
  922. case STREAM_SEEK_SET:
  923. targetOffset = liDistanceToMove.u.LowPart;
  924. break;
  925. case STREAM_SEEK_CUR:
  926. targetOffset = liDistanceToMove.u.LowPart + m_offset;
  927. break;
  928. case STREAM_SEEK_END:
  929. targetOffset = liDistanceToMove.u.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->u.LowPart = targetOffset;
  941. }
  942. return S_OK;
  943. }
  944. HRESULT STDMETHODCALLTYPE Stat(STATSTG *pStatstg,
  945. DWORD grfStatFlag) override {
  946. if (pStatstg == nullptr) {
  947. return E_POINTER;
  948. }
  949. ZeroMemory(pStatstg, sizeof(*pStatstg));
  950. pStatstg->type = STGTY_STREAM;
  951. pStatstg->cbSize.u.LowPart = m_size;
  952. return S_OK;
  953. }
  954. };
  955. HRESULT CreateMemoryStream(_In_ IMalloc *pMalloc, _COM_Outptr_ AbstractMemoryStream** ppResult) throw() {
  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) throw() {
  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