blob: 62485d3c4f0cf8c58bb65d822ed073db32ad8747 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// dxcapi.use.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides support for DXC API users. //
// //
///////////////////////////////////////////////////////////////////////////////
#include "dxc/Support/WinIncludes.h"
#include "dxc/Support/dxcapi.use.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/Unicode.h"
#include "dxc/Support/FileIOHelper.h"
#include "dxc/Support/WinFunctions.h"
namespace dxc {
#ifdef _WIN32
static void TrimEOL(_Inout_z_ char *pMsg) {
char *pEnd = pMsg + strlen(pMsg);
--pEnd;
while (pEnd > pMsg && (*pEnd == '\r' || *pEnd == '\n')) {
--pEnd;
}
pEnd[1] = '\0';
}
static std::string GetWin32ErrorMessage(DWORD err) {
char formattedMsg[200];
DWORD formattedMsgLen =
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, err, 0, formattedMsg, _countof(formattedMsg), 0);
if (formattedMsg > 0 && formattedMsgLen < _countof(formattedMsg)) {
TrimEOL(formattedMsg);
return std::string(formattedMsg);
}
return std::string();
}
#else
static std::string GetWin32ErrorMessage(DWORD err) {
// Since we use errno for handling messages, we use strerror to get the error
// message.
return std::string(std::strerror(err));
}
#endif // _WIN32
void IFT_Data(HRESULT hr, LPCWSTR data) {
if (SUCCEEDED(hr)) return;
CW2A pData(data, CP_UTF8);
std::string errMsg;
if (HRESULT_IS_WIN32ERR(hr)) {
DWORD err = HRESULT_AS_WIN32ERR(hr);
errMsg.append(GetWin32ErrorMessage(err));
if (data != nullptr) {
errMsg.append(" ", 1);
}
}
if (data != nullptr) {
errMsg.append(pData);
}
throw ::hlsl::Exception(hr, errMsg);
}
void EnsureEnabled(DxcDllSupport &dxcSupport) {
if (!dxcSupport.IsEnabled()) {
IFT(dxcSupport.Initialize());
}
}
void ReadFileIntoBlob(DxcDllSupport &dxcSupport, _In_ LPCWSTR pFileName,
_COM_Outptr_ IDxcBlobEncoding **ppBlobEncoding) {
CComPtr<IDxcLibrary> library;
IFT(dxcSupport.CreateInstance(CLSID_DxcLibrary, &library));
IFT_Data(library->CreateBlobFromFile(pFileName, nullptr, ppBlobEncoding),
pFileName);
}
void WriteOperationErrorsToConsole(_In_ IDxcOperationResult *pResult,
bool outputWarnings) {
HRESULT status;
IFT(pResult->GetStatus(&status));
if (FAILED(status) || outputWarnings) {
CComPtr<IDxcBlobEncoding> pErrors;
IFT(pResult->GetErrorBuffer(&pErrors));
if (pErrors.p != nullptr) {
WriteBlobToConsole(pErrors, STD_ERROR_HANDLE);
}
}
}
void WriteOperationResultToConsole(_In_ IDxcOperationResult *pRewriteResult,
bool outputWarnings) {
WriteOperationErrorsToConsole(pRewriteResult, outputWarnings);
CComPtr<IDxcBlob> pBlob;
IFT(pRewriteResult->GetResult(&pBlob));
WriteBlobToConsole(pBlob, STD_OUTPUT_HANDLE);
}
static void WriteUtf16NullTermToConsole(_In_opt_count_(charCount) const wchar_t *pText,
DWORD streamType) {
if (pText == nullptr) {
return;
}
bool lossy; // Note: even if there was loss, print anyway
std::string consoleMessage;
Unicode::UTF16ToConsoleString(pText, &consoleMessage, &lossy);
if (streamType == STD_OUTPUT_HANDLE) {
fprintf(stdout, "%s\n", consoleMessage.c_str());
}
else if (streamType == STD_ERROR_HANDLE) {
fprintf(stderr, "%s\n", consoleMessage.c_str());
}
else {
throw hlsl::Exception(E_INVALIDARG);
}
}
static HRESULT BlobToUtf8IfText(_In_opt_ IDxcBlob *pBlob, IDxcBlobUtf8 **ppBlobUtf8) {
CComPtr<IDxcBlobEncoding> pBlobEncoding;
if (SUCCEEDED(pBlob->QueryInterface(&pBlobEncoding))) {
BOOL known;
UINT32 cp = 0;
IFT(pBlobEncoding->GetEncoding(&known, &cp));
if (known) {
return hlsl::DxcGetBlobAsUtf8(pBlob, nullptr, ppBlobUtf8);
}
}
return S_OK;
}
static HRESULT BlobToUtf16IfText(_In_opt_ IDxcBlob *pBlob, IDxcBlobUtf16 **ppBlobUtf16) {
CComPtr<IDxcBlobEncoding> pBlobEncoding;
if (SUCCEEDED(pBlob->QueryInterface(&pBlobEncoding))) {
BOOL known;
UINT32 cp = 0;
IFT(pBlobEncoding->GetEncoding(&known, &cp));
if (known) {
return hlsl::DxcGetBlobAsUtf16(pBlob, nullptr, ppBlobUtf16);
}
}
return S_OK;
}
void WriteBlobToConsole(_In_opt_ IDxcBlob *pBlob, DWORD streamType) {
if (pBlob == nullptr) {
return;
}
// Try to get as UTF-16 or UTF-8
BOOL known;
UINT32 cp = 0;
CComPtr<IDxcBlobEncoding> pBlobEncoding;
IFT(pBlob->QueryInterface(&pBlobEncoding));
IFT(pBlobEncoding->GetEncoding(&known, &cp));
if (cp == DXC_CP_UTF16) {
CComPtr<IDxcBlobUtf16> pUtf16;
IFT(hlsl::DxcGetBlobAsUtf16(pBlob, nullptr, &pUtf16));
WriteUtf16NullTermToConsole(pUtf16->GetStringPointer(), streamType);
} else if (cp == CP_UTF8) {
CComPtr<IDxcBlobUtf8> pUtf8;
IFT(hlsl::DxcGetBlobAsUtf8(pBlob, nullptr, &pUtf8));
WriteUtf8ToConsoleSizeT(pUtf8->GetStringPointer(), pUtf8->GetStringLength(), streamType);
}
}
void WriteBlobToFile(_In_opt_ IDxcBlob *pBlob, _In_ LPCWSTR pFileName, _In_ UINT32 textCodePage) {
if (pBlob == nullptr) {
return;
}
CHandle file(CreateFileW(pFileName, GENERIC_WRITE, FILE_SHARE_READ, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr));
if (file == INVALID_HANDLE_VALUE) {
IFT_Data(HRESULT_FROM_WIN32(GetLastError()), pFileName);
}
WriteBlobToHandle(pBlob, file, pFileName, textCodePage);
}
void WriteBlobToHandle(_In_opt_ IDxcBlob *pBlob, _In_ HANDLE hFile, _In_opt_ LPCWSTR pFileName, _In_ UINT32 textCodePage) {
if (pBlob == nullptr) {
return;
}
LPCVOID pPtr = pBlob->GetBufferPointer();
SIZE_T size = pBlob->GetBufferSize();
std::string BOM;
CComPtr<IDxcBlobUtf8> pBlobUtf8;
CComPtr<IDxcBlobUtf16> pBlobUtf16;
if (textCodePage == DXC_CP_UTF8) {
IFT_Data(BlobToUtf8IfText(pBlob, &pBlobUtf8), pFileName);
if (pBlobUtf8) {
pPtr = pBlobUtf8->GetStringPointer();
size = pBlobUtf8->GetStringLength();
// TBD: Should we write UTF-8 BOM?
//BOM = "\xef\xbb\xbf"; // UTF-8
}
} else if (textCodePage == DXC_CP_UTF16) {
IFT_Data(BlobToUtf16IfText(pBlob, &pBlobUtf16), pFileName);
if (pBlobUtf16) {
pPtr = pBlobUtf16->GetStringPointer();
size = pBlobUtf16->GetStringLength() * sizeof(wchar_t);
BOM = "\xff\xfe"; // UTF-16 LE
}
}
IFT_Data(size > (SIZE_T)UINT32_MAX ? E_OUTOFMEMORY : S_OK , pFileName);
DWORD written;
if (!BOM.empty()) {
if (FALSE == WriteFile(hFile, BOM.data(), BOM.length(), &written, nullptr)) {
IFT_Data(HRESULT_FROM_WIN32(GetLastError()), pFileName);
}
}
if (FALSE == WriteFile(hFile, pPtr, (DWORD)size, &written, nullptr)) {
IFT_Data(HRESULT_FROM_WIN32(GetLastError()), pFileName);
}
}
void WriteUtf8ToConsole(_In_opt_count_(charCount) const char *pText,
int charCount, DWORD streamType) {
if (charCount == 0 || pText == nullptr) {
return;
}
std::string resultToPrint;
wchar_t *utf16Message = nullptr;
size_t utf16MessageLen;
Unicode::UTF8BufferToUTF16Buffer(pText, charCount, &utf16Message,
&utf16MessageLen);
WriteUtf16NullTermToConsole(utf16Message, streamType);
delete[] utf16Message;
}
void WriteUtf8ToConsoleSizeT(_In_opt_count_(charCount) const char *pText,
size_t charCount, DWORD streamType) {
if (charCount == 0) {
return;
}
int charCountInt = 0;
IFT(SizeTToInt(charCount, &charCountInt));
WriteUtf8ToConsole(pText, charCountInt, streamType);
}
} // namespace dxc