FileIOHelper.cpp 33 KB

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