зеркало из https://github.com/microsoft/DirectXTK.git
Refactor command-line tools to use shared header (#481)
This commit is contained in:
Родитель
fc904593c1
Коммит
78d1a3eb89
|
@ -367,6 +367,7 @@ if(BUILD_TOOLS AND WIN32)
|
|||
xwbtool/xwbtool.cpp
|
||||
xwbtool/xwbtool.rc
|
||||
xwbtool/settings.manifest
|
||||
xwbtool/CmdLineHelpers.h
|
||||
Audio/WAVFileReader.cpp
|
||||
Audio/WAVFileReader.h)
|
||||
target_compile_features(xwbtool PRIVATE cxx_std_17)
|
||||
|
@ -381,6 +382,10 @@ if(directxmath_FOUND)
|
|||
endforeach()
|
||||
endif()
|
||||
|
||||
if(TOOL_EXES)
|
||||
message(STATUS "Building tools: ${TOOL_EXES}")
|
||||
endif()
|
||||
|
||||
# Model uses dynamic_cast, so we need /GR (Enable RTTI)
|
||||
if(MSVC)
|
||||
foreach(t IN LISTS TOOL_EXES ITEMS ${PROJECT_NAME})
|
||||
|
@ -428,6 +433,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
|||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
if(ENABLE_CODE_ANALYSIS)
|
||||
message(STATUS "Building with Code Analysis (PREFIX)")
|
||||
foreach(t IN LISTS TOOL_EXES ITEMS ${PROJECT_NAME})
|
||||
target_compile_options(${t} PRIVATE /analyze /WX)
|
||||
endforeach()
|
||||
|
|
|
@ -294,7 +294,9 @@
|
|||
{ "name": "x64-Debug-ICX" , "description": "Intel oneAPI Compiler (Debug) for Windows 8", "inherits": [ "base", "x64", "Debug", "IntelLLVM" ] },
|
||||
{ "name": "x64-Release-ICX" , "description": "Intel oneAPI Compiler (Release) for Windows 8", "inherits": [ "base", "x64", "Release", "IntelLLVM" ] },
|
||||
|
||||
{ "name": "x64-Fuzzing" , "description": "MSVC for x64 (Release) with ASan", "inherits": [ "base", "x64", "Release", "MSVC", "Win10", "Fuzzing" ] }
|
||||
{ "name": "x64-Fuzzing" , "description": "MSVC for x64 (Release) with ASan", "inherits": [ "base", "x64", "Release", "MSVC", "Win10", "Fuzzing" ] },
|
||||
{ "name": "x64-Analyze" , "description": "MSVC for x64 (Debug) for Windows 8 using /analyze", "inherits": [ "base", "x64", "Debug", "MSVC" ], "cacheVariables": { "ENABLE_CODE_ANALYSIS": true } },
|
||||
{ "name": "x64-Analyze-Win10" , "description": "MSVC for x64 (Debug) for Windows 10 using /analyze", "inherits": [ "base", "x64", "Debug", "MSVC", "Win10" ], "cacheVariables": { "ENABLE_CODE_ANALYSIS": true } }
|
||||
],
|
||||
"testPresets": [
|
||||
{ "name": "x64-Debug" , "configurePreset": "x64-Debug" },
|
||||
|
|
|
@ -0,0 +1,375 @@
|
|||
//--------------------------------------------------------------------------------------
|
||||
// File: CmdLineHelpers.h
|
||||
//
|
||||
// Command-line tool shared functions
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
#error Requires C++17 (and /Zc:__cplusplus with MSVC)
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cwchar>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#ifndef TOOL_VERSION
|
||||
#error Define TOOL_VERSION before including this header
|
||||
#endif
|
||||
|
||||
|
||||
namespace Helpers
|
||||
{
|
||||
struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
struct find_closer { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
|
||||
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
|
||||
|
||||
#ifdef _PREFAST_
|
||||
#pragma prefast(disable : 26018, "Only used with static internal arrays")
|
||||
#endif
|
||||
|
||||
struct SConversion
|
||||
{
|
||||
std::wstring szSrc;
|
||||
std::wstring szFolder;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SValue
|
||||
{
|
||||
const wchar_t* name;
|
||||
T value;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T LookupByName(const wchar_t _In_z_ *pName, const SValue<T> *pArray)
|
||||
{
|
||||
while (pArray->name)
|
||||
{
|
||||
if (!_wcsicmp(pName, pArray->name))
|
||||
return pArray->value;
|
||||
|
||||
pArray++;
|
||||
}
|
||||
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const wchar_t* LookupByValue(T value, const SValue<T> *pArray)
|
||||
{
|
||||
while (pArray->name)
|
||||
{
|
||||
if (value == pArray->value)
|
||||
return pArray->name;
|
||||
|
||||
pArray++;
|
||||
}
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
void PrintFormat(DXGI_FORMAT Format, const SValue<DXGI_FORMAT>* pFormatList)
|
||||
{
|
||||
for (auto pFormat = pFormatList; pFormat->name; pFormat++)
|
||||
{
|
||||
if (pFormat->value == Format)
|
||||
{
|
||||
wprintf(L"%ls", pFormat->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wprintf(L"*UNKNOWN*");
|
||||
}
|
||||
|
||||
void PrintFormat(DXGI_FORMAT Format, const SValue<DXGI_FORMAT>* pFormatList1, const SValue<DXGI_FORMAT>* pFormatList2)
|
||||
{
|
||||
for (auto pFormat = pFormatList1; pFormat->name; pFormat++)
|
||||
{
|
||||
if (pFormat->value == Format)
|
||||
{
|
||||
wprintf(L"%ls", pFormat->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto pFormat = pFormatList2; pFormat->name; pFormat++)
|
||||
{
|
||||
if (pFormat->value == Format)
|
||||
{
|
||||
wprintf(L"%ls", pFormat->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wprintf(L"*UNKNOWN*");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PrintList(size_t cch, const SValue<T> *pValue)
|
||||
{
|
||||
while (pValue->name)
|
||||
{
|
||||
const size_t cchName = wcslen(pValue->name);
|
||||
|
||||
if (cch + cchName + 2 >= 80)
|
||||
{
|
||||
wprintf(L"\n ");
|
||||
cch = 6;
|
||||
}
|
||||
|
||||
wprintf(L"%ls ", pValue->name);
|
||||
cch += cchName + 2;
|
||||
pValue++;
|
||||
}
|
||||
|
||||
wprintf(L"\n");
|
||||
}
|
||||
|
||||
void PrintLogo(bool versionOnly, _In_z_ const wchar_t* name, _In_z_ const wchar_t* desc)
|
||||
{
|
||||
wchar_t version[32] = {};
|
||||
|
||||
wchar_t appName[_MAX_PATH] = {};
|
||||
if (GetModuleFileNameW(nullptr, appName, _MAX_PATH))
|
||||
{
|
||||
const DWORD size = GetFileVersionInfoSizeW(appName, nullptr);
|
||||
if (size > 0)
|
||||
{
|
||||
auto verInfo = std::make_unique<uint8_t[]>(size);
|
||||
if (GetFileVersionInfoW(appName, 0, size, verInfo.get()))
|
||||
{
|
||||
LPVOID lpstr = nullptr;
|
||||
UINT strLen = 0;
|
||||
if (VerQueryValueW(verInfo.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", &lpstr, &strLen))
|
||||
{
|
||||
wcsncpy_s(version, reinterpret_cast<const wchar_t*>(lpstr), strLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!*version || wcscmp(version, L"1.0.0.0") == 0)
|
||||
{
|
||||
swprintf_s(version, L"%03d (library)", TOOL_VERSION);
|
||||
}
|
||||
|
||||
if (versionOnly)
|
||||
{
|
||||
wprintf(L"%ls version %ls\n", name, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"%ls Version %ls\n", desc, version);
|
||||
wprintf(L"Copyright (C) Microsoft Corp.\n");
|
||||
#ifdef _DEBUG
|
||||
wprintf(L"*** Debug build ***\n");
|
||||
#endif
|
||||
wprintf(L"\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SearchForFiles(const std::filesystem::path& path, std::list<SConversion>& files, bool recursive, _In_opt_z_ const wchar_t* folder)
|
||||
{
|
||||
// Process files
|
||||
WIN32_FIND_DATAW findData = {};
|
||||
ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path.c_str(),
|
||||
FindExInfoBasic, &findData,
|
||||
FindExSearchNameMatch, nullptr,
|
||||
FIND_FIRST_EX_LARGE_FETCH)));
|
||||
if (hFile)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
|
||||
{
|
||||
SConversion conv = {};
|
||||
conv.szSrc = path.parent_path().append(findData.cFileName).native();
|
||||
if (folder)
|
||||
{
|
||||
conv.szFolder = folder;
|
||||
}
|
||||
files.push_back(conv);
|
||||
}
|
||||
|
||||
if (!FindNextFileW(hFile.get(), &findData))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process directories
|
||||
if (recursive)
|
||||
{
|
||||
auto searchDir = path.parent_path().append(L"*");
|
||||
|
||||
hFile.reset(safe_handle(FindFirstFileExW(searchDir.c_str(),
|
||||
FindExInfoBasic, &findData,
|
||||
FindExSearchLimitToDirectories, nullptr,
|
||||
FIND_FIRST_EX_LARGE_FETCH)));
|
||||
if (!hFile)
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (findData.cFileName[0] != L'.')
|
||||
{
|
||||
auto subfolder = (folder)
|
||||
? (std::wstring(folder) + std::wstring(findData.cFileName) + std::filesystem::path::preferred_separator)
|
||||
: (std::wstring(findData.cFileName) + std::filesystem::path::preferred_separator);
|
||||
|
||||
auto subdir = path.parent_path().append(findData.cFileName).append(path.filename().c_str());
|
||||
|
||||
SearchForFiles(subdir, files, recursive, subfolder.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!FindNextFileW(hFile.get(), &findData))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessFileList(std::wifstream& inFile, std::list<SConversion>& files)
|
||||
{
|
||||
std::list<SConversion> flist;
|
||||
std::set<std::wstring> excludes;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::wstring fname;
|
||||
std::getline(inFile, fname);
|
||||
if (!inFile)
|
||||
break;
|
||||
|
||||
if (fname[0] == L'#')
|
||||
{
|
||||
// Comment
|
||||
}
|
||||
else if (fname[0] == L'-')
|
||||
{
|
||||
if (flist.empty())
|
||||
{
|
||||
wprintf(L"WARNING: Ignoring the line '%ls' in -flist\n", fname.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::filesystem::path path(fname.c_str() + 1);
|
||||
auto& npath = path.make_preferred();
|
||||
if (wcspbrk(fname.c_str(), L"?*") != nullptr)
|
||||
{
|
||||
std::list<SConversion> removeFiles;
|
||||
SearchForFiles(npath, removeFiles, false, nullptr);
|
||||
|
||||
for (auto& it : removeFiles)
|
||||
{
|
||||
std::wstring name = it.szSrc;
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
excludes.insert(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring name = npath.c_str();
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
excludes.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wcspbrk(fname.c_str(), L"?*") != nullptr)
|
||||
{
|
||||
std::filesystem::path path(fname.c_str());
|
||||
SearchForFiles(path.make_preferred(), flist, false, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
SConversion conv = {};
|
||||
std::filesystem::path path(fname.c_str());
|
||||
conv.szSrc = path.make_preferred().native();
|
||||
flist.push_back(conv);
|
||||
}
|
||||
}
|
||||
|
||||
inFile.close();
|
||||
|
||||
if (!excludes.empty())
|
||||
{
|
||||
// Remove any excluded files
|
||||
for (auto it = flist.begin(); it != flist.end();)
|
||||
{
|
||||
std::wstring name = it->szSrc;
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
auto item = it;
|
||||
++it;
|
||||
if (excludes.find(name) != excludes.end())
|
||||
{
|
||||
flist.erase(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flist.empty())
|
||||
{
|
||||
wprintf(L"WARNING: No file names found in -flist\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
files.splice(files.end(), flist);
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t* GetErrorDesc(HRESULT hr)
|
||||
{
|
||||
static wchar_t desc[1024] = {};
|
||||
|
||||
LPWSTR errorText = nullptr;
|
||||
|
||||
const DWORD result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
nullptr, static_cast<DWORD>(hr),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&errorText), 0, nullptr);
|
||||
|
||||
*desc = 0;
|
||||
|
||||
if (result > 0 && errorText)
|
||||
{
|
||||
swprintf_s(desc, L": %ls", errorText);
|
||||
|
||||
size_t len = wcslen(desc);
|
||||
if (len >= 1)
|
||||
{
|
||||
desc[len - 1] = 0;
|
||||
}
|
||||
|
||||
if (errorText)
|
||||
LocalFree(errorText);
|
||||
|
||||
for(wchar_t* ptr = desc; *ptr != 0; ++ptr)
|
||||
{
|
||||
if (*ptr == L'\r' || *ptr == L'\n')
|
||||
{
|
||||
*ptr = L' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@
|
|||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dxgiformat.h>
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
#error Requires C++17 (and /Zc:__cplusplus with MSVC)
|
||||
|
@ -57,6 +58,11 @@
|
|||
|
||||
#include "WAVFileReader.h"
|
||||
|
||||
#define TOOL_VERSION 0
|
||||
#include "CmdLineHelpers.h"
|
||||
|
||||
using namespace Helpers;
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning(disable : 161)
|
||||
// warning #161: unrecognized #pragma
|
||||
|
@ -112,16 +118,6 @@ static_assert(sizeof(XMA2WAVEFORMATEX) == 52, "Mismatch of XMA2 type");
|
|||
|
||||
namespace
|
||||
{
|
||||
struct handle_closer { void operator()(HANDLE h) { if (h) CloseHandle(h); } };
|
||||
|
||||
using ScopedHandle = std::unique_ptr<void, handle_closer>;
|
||||
|
||||
inline HANDLE safe_handle(HANDLE h) { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
|
||||
|
||||
struct find_closer { void operator()(HANDLE h) { assert(h != INVALID_HANDLE_VALUE); if (h) FindClose(h); } };
|
||||
|
||||
using ScopedFindHandle = std::unique_ptr<void, find_closer>;
|
||||
|
||||
#define BLOCKALIGNPAD(a, b) \
|
||||
((((a) + ((b) - 1)) / (b)) * (b))
|
||||
|
||||
|
@ -784,65 +780,53 @@ namespace
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
const wchar_t* g_ToolName = L"xwbtool";
|
||||
const wchar_t* g_Description = L"Microsoft (R) XACT-style Wave Bank Tool [DirectXTK]";
|
||||
|
||||
enum OPTIONS : uint32_t
|
||||
{
|
||||
OPT_RECURSIVE = 1,
|
||||
OPT_STREAMING,
|
||||
OPT_ADVANCED_FORMAT,
|
||||
OPT_OUTPUTFILE,
|
||||
OPT_OUTPUTHEADER,
|
||||
OPT_TOLOWER,
|
||||
OPT_OVERWRITE,
|
||||
OPT_COMPACT,
|
||||
OPT_NOCOMPACT,
|
||||
OPT_FRIENDLY_NAMES,
|
||||
OPT_NOLOGO,
|
||||
OPT_FILELIST,
|
||||
OPT_MAX
|
||||
};
|
||||
enum OPTIONS : uint32_t
|
||||
{
|
||||
OPT_RECURSIVE = 1,
|
||||
OPT_STREAMING,
|
||||
OPT_ADVANCED_FORMAT,
|
||||
OPT_OUTPUTFILE,
|
||||
OPT_OUTPUTHEADER,
|
||||
OPT_TOLOWER,
|
||||
OPT_OVERWRITE,
|
||||
OPT_COMPACT,
|
||||
OPT_NOCOMPACT,
|
||||
OPT_FRIENDLY_NAMES,
|
||||
OPT_NOLOGO,
|
||||
OPT_FILELIST,
|
||||
OPT_MAX
|
||||
};
|
||||
|
||||
static_assert(OPT_MAX <= 32, "dwOptions is a unsigned int bitfield");
|
||||
static_assert(OPT_MAX <= 32, "dwOptions is a unsigned int bitfield");
|
||||
|
||||
struct SConversion
|
||||
{
|
||||
std::wstring szSrc;
|
||||
};
|
||||
struct WaveFile
|
||||
{
|
||||
DirectX::WAVData data;
|
||||
size_t conv;
|
||||
MINIWAVEFORMAT miniFmt;
|
||||
std::unique_ptr<uint8_t[]> waveData;
|
||||
|
||||
struct SValue
|
||||
{
|
||||
const wchar_t* name;
|
||||
uint32_t value;
|
||||
};
|
||||
WaveFile() noexcept :
|
||||
data{},
|
||||
conv(0),
|
||||
miniFmt{}
|
||||
{}
|
||||
|
||||
struct WaveFile
|
||||
{
|
||||
DirectX::WAVData data;
|
||||
size_t conv;
|
||||
MINIWAVEFORMAT miniFmt;
|
||||
std::unique_ptr<uint8_t[]> waveData;
|
||||
WaveFile(WaveFile&) = delete;
|
||||
WaveFile& operator= (WaveFile&) = delete;
|
||||
|
||||
WaveFile() noexcept :
|
||||
data{},
|
||||
conv(0),
|
||||
miniFmt{}
|
||||
{}
|
||||
WaveFile(WaveFile&&) = default;
|
||||
WaveFile& operator= (WaveFile&&) = default;
|
||||
};
|
||||
|
||||
WaveFile(WaveFile&) = delete;
|
||||
WaveFile& operator= (WaveFile&) = delete;
|
||||
|
||||
WaveFile(WaveFile&&) = default;
|
||||
WaveFile& operator= (WaveFile&&) = default;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void FileNameToIdentifier(_Inout_updates_all_(count) wchar_t* str, size_t count)
|
||||
{
|
||||
size_t j = 0;
|
||||
|
@ -854,240 +838,35 @@ namespace
|
|||
*c = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const SValue g_pOptions[] =
|
||||
{
|
||||
{ L"r", OPT_RECURSIVE },
|
||||
{ L"s", OPT_STREAMING },
|
||||
{ L"af", OPT_ADVANCED_FORMAT },
|
||||
{ L"o", OPT_OUTPUTFILE },
|
||||
{ L"l", OPT_TOLOWER },
|
||||
{ L"h", OPT_OUTPUTHEADER },
|
||||
{ L"y", OPT_OVERWRITE },
|
||||
{ L"c", OPT_COMPACT },
|
||||
{ L"nc", OPT_NOCOMPACT },
|
||||
{ L"f", OPT_FRIENDLY_NAMES },
|
||||
{ L"nologo", OPT_NOLOGO },
|
||||
{ L"flist", OPT_FILELIST },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef _PREFAST_
|
||||
#pragma prefast(disable : 26018, "Only used with static internal arrays")
|
||||
#endif
|
||||
|
||||
uint32_t LookupByName(const wchar_t *pName, const SValue *pArray)
|
||||
const SValue<uint32_t> g_pOptions[] =
|
||||
{
|
||||
while (pArray->name)
|
||||
{
|
||||
if (!_wcsicmp(pName, pArray->name))
|
||||
return pArray->value;
|
||||
{ L"r", OPT_RECURSIVE },
|
||||
{ L"s", OPT_STREAMING },
|
||||
{ L"af", OPT_ADVANCED_FORMAT },
|
||||
{ L"o", OPT_OUTPUTFILE },
|
||||
{ L"l", OPT_TOLOWER },
|
||||
{ L"h", OPT_OUTPUTHEADER },
|
||||
{ L"y", OPT_OVERWRITE },
|
||||
{ L"c", OPT_COMPACT },
|
||||
{ L"nc", OPT_NOCOMPACT },
|
||||
{ L"f", OPT_FRIENDLY_NAMES },
|
||||
{ L"nologo", OPT_NOLOGO },
|
||||
{ L"flist", OPT_FILELIST },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
pArray++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SearchForFiles(const std::filesystem::path& path, std::list<SConversion>& files, bool recursive)
|
||||
{
|
||||
// Process files
|
||||
WIN32_FIND_DATAW findData = {};
|
||||
ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path.c_str(),
|
||||
FindExInfoBasic, &findData,
|
||||
FindExSearchNameMatch, nullptr,
|
||||
FIND_FIRST_EX_LARGE_FETCH)));
|
||||
if (hFile)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
|
||||
{
|
||||
SConversion conv = {};
|
||||
conv.szSrc = path.parent_path().append(findData.cFileName).native();
|
||||
files.push_back(conv);
|
||||
}
|
||||
|
||||
if (!FindNextFileW(hFile.get(), &findData))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Process directories
|
||||
if (recursive)
|
||||
{
|
||||
auto searchDir = path.parent_path().append(L"*");
|
||||
|
||||
hFile.reset(safe_handle(FindFirstFileExW(searchDir.c_str(),
|
||||
FindExInfoBasic, &findData,
|
||||
FindExSearchLimitToDirectories, nullptr,
|
||||
FIND_FIRST_EX_LARGE_FETCH)));
|
||||
if (!hFile)
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if (findData.cFileName[0] != L'.')
|
||||
{
|
||||
auto subdir = path.parent_path().append(findData.cFileName).append(path.filename().c_str());
|
||||
|
||||
SearchForFiles(subdir, files, recursive);
|
||||
}
|
||||
}
|
||||
|
||||
if (!FindNextFileW(hFile.get(), &findData))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessFileList(std::wifstream& inFile, std::list<SConversion>& files)
|
||||
{
|
||||
std::list<SConversion> flist;
|
||||
std::set<std::wstring> excludes;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::wstring fname;
|
||||
std::getline(inFile, fname);
|
||||
if (!inFile)
|
||||
break;
|
||||
|
||||
if (fname[0] == L'#')
|
||||
{
|
||||
// Comment
|
||||
}
|
||||
else if (fname[0] == L'-')
|
||||
{
|
||||
if (flist.empty())
|
||||
{
|
||||
wprintf(L"WARNING: Ignoring the line '%ls' in -flist\n", fname.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::filesystem::path path(fname.c_str() + 1);
|
||||
auto& npath = path.make_preferred();
|
||||
if (wcspbrk(fname.c_str(), L"?*") != nullptr)
|
||||
{
|
||||
std::list<SConversion> removeFiles;
|
||||
SearchForFiles(npath, removeFiles, false);
|
||||
|
||||
for (auto& it : removeFiles)
|
||||
{
|
||||
std::wstring name = it.szSrc;
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
excludes.insert(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring name = npath.c_str();
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
excludes.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wcspbrk(fname.c_str(), L"?*") != nullptr)
|
||||
{
|
||||
std::filesystem::path path(fname.c_str());
|
||||
SearchForFiles(path.make_preferred(), flist, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SConversion conv = {};
|
||||
std::filesystem::path path(fname.c_str());
|
||||
conv.szSrc = path.make_preferred().native();
|
||||
flist.push_back(conv);
|
||||
}
|
||||
}
|
||||
|
||||
inFile.close();
|
||||
|
||||
if (!excludes.empty())
|
||||
{
|
||||
// Remove any excluded files
|
||||
for (auto it = flist.begin(); it != flist.end();)
|
||||
{
|
||||
std::wstring name = it->szSrc;
|
||||
std::transform(name.begin(), name.end(), name.begin(), towlower);
|
||||
auto item = it;
|
||||
++it;
|
||||
if (excludes.find(name) != excludes.end())
|
||||
{
|
||||
flist.erase(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flist.empty())
|
||||
{
|
||||
wprintf(L"WARNING: No file names found in -flist\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
files.splice(files.end(), flist);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintLogo(bool versionOnly)
|
||||
{
|
||||
wchar_t version[32] = {};
|
||||
|
||||
wchar_t appName[_MAX_PATH] = {};
|
||||
if (GetModuleFileNameW(nullptr, appName, _MAX_PATH))
|
||||
{
|
||||
DWORD size = GetFileVersionInfoSizeW(appName, nullptr);
|
||||
if (size > 0)
|
||||
{
|
||||
auto verInfo = std::make_unique<uint8_t[]>(size);
|
||||
if (GetFileVersionInfoW(appName, 0, size, verInfo.get()))
|
||||
{
|
||||
LPVOID lpstr = nullptr;
|
||||
UINT strLen = 0;
|
||||
if (VerQueryValueW(verInfo.get(), L"\\StringFileInfo\\040904B0\\ProductVersion", &lpstr, &strLen))
|
||||
{
|
||||
wcsncpy_s(version, reinterpret_cast<const wchar_t*>(lpstr), strLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!*version)
|
||||
{
|
||||
wcscpy_s(version, L"MISSING");
|
||||
}
|
||||
|
||||
if (versionOnly)
|
||||
{
|
||||
wprintf(L"xwbtool version %ls\n", version);
|
||||
}
|
||||
else
|
||||
{
|
||||
wprintf(L"Microsoft (R) XACT-style Wave Bank Tool [DirectXTK] Version %ls\n", version);
|
||||
wprintf(L"Copyright (C) Microsoft Corp.\n");
|
||||
#ifdef _DEBUG
|
||||
wprintf(L"*** Debug build ***\n");
|
||||
#endif
|
||||
wprintf(L"\n");
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrintUsage()
|
||||
{
|
||||
PrintLogo(false);
|
||||
PrintLogo(false, g_ToolName, g_Description);
|
||||
|
||||
static const wchar_t* const s_usage =
|
||||
L"Usage: xwbtool <options> [--] <wav-files>\n"
|
||||
|
@ -1112,44 +891,6 @@ namespace
|
|||
wprintf(L"%ls", s_usage);
|
||||
}
|
||||
|
||||
const wchar_t* GetErrorDesc(HRESULT hr)
|
||||
{
|
||||
static wchar_t desc[1024] = {};
|
||||
|
||||
LPWSTR errorText = nullptr;
|
||||
|
||||
DWORD result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
nullptr, static_cast<DWORD>(hr),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&errorText), 0, nullptr);
|
||||
|
||||
*desc = 0;
|
||||
|
||||
if (result > 0 && errorText)
|
||||
{
|
||||
swprintf_s(desc, L": %ls", errorText);
|
||||
|
||||
size_t len = wcslen(desc);
|
||||
if (len >= 2)
|
||||
{
|
||||
desc[len - 2] = 0;
|
||||
desc[len - 1] = 0;
|
||||
}
|
||||
|
||||
if (errorText)
|
||||
LocalFree(errorText);
|
||||
|
||||
for (wchar_t* ptr = desc; *ptr != 0; ++ptr)
|
||||
{
|
||||
if (*ptr == L'\r' || *ptr == L'\n')
|
||||
{
|
||||
*ptr = L' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
const char* GetFormatTagName(WORD wFormatTag)
|
||||
{
|
||||
switch (wFormatTag)
|
||||
|
@ -1242,7 +983,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
|||
}
|
||||
else if (!_wcsicmp(pArg, L"--version"))
|
||||
{
|
||||
PrintLogo(true);
|
||||
PrintLogo(true, g_ToolName, g_Description);
|
||||
return 0;
|
||||
}
|
||||
else if (!_wcsicmp(pArg, L"--help"))
|
||||
|
@ -1365,7 +1106,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
|||
{
|
||||
size_t count = conversion.size();
|
||||
std::filesystem::path path(pArg);
|
||||
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0);
|
||||
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0, nullptr);
|
||||
if (conversion.size() <= count)
|
||||
{
|
||||
wprintf(L"No matching files found for %ls\n", pArg);
|
||||
|
@ -1389,7 +1130,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
|||
}
|
||||
|
||||
if (~dwOptions & (1 << OPT_NOLOGO))
|
||||
PrintLogo(false);
|
||||
PrintLogo(false, g_ToolName, g_Description);
|
||||
|
||||
// Determine output file name
|
||||
if (outputFile.empty())
|
||||
|
|
|
@ -256,6 +256,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Audio\WAVFileReader.h" />
|
||||
<ClInclude Include="CmdLineHelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="xwbtool.rc" />
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Audio\WAVFileReader.h" />
|
||||
<ClInclude Include="CmdLineHelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Resource Files">
|
||||
|
|
|
@ -256,6 +256,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Audio\WAVFileReader.h" />
|
||||
<ClInclude Include="CmdLineHelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="xwbtool.rc" />
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Audio\WAVFileReader.h" />
|
||||
<ClInclude Include="CmdLineHelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Resource Files">
|
||||
|
|
Загрузка…
Ссылка в новой задаче