meshconvert updated to support long path names with Windows 10 (#102)

This commit is contained in:
Chuck Walbourn 2023-06-13 15:40:30 -07:00 коммит произвёл GitHub
Родитель 200f224737
Коммит 51f29f1688
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 100 добавлений и 78 удалений

Просмотреть файл

@ -210,6 +210,7 @@ if(BUILD_TOOLS AND WIN32)
add_executable(meshconvert
Meshconvert/Meshconvert.cpp
Meshconvert/Meshconvert.rc
Meshconvert/settings.manifest
Meshconvert/MeshOBJ.cpp
Meshconvert/Mesh.h
Meshconvert/Mesh.cpp

Просмотреть файл

@ -88,7 +88,7 @@ namespace
struct SConversion
{
wchar_t szSrc[MAX_PATH];
std::wstring szSrc;
};
struct SValue
@ -201,11 +201,11 @@ namespace
return 0;
}
void SearchForFiles(const wchar_t* path, std::list<SConversion>& files, bool recursive)
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,
ScopedFindHandle hFile(safe_handle(FindFirstFileExW(path.c_str(),
FindExInfoBasic, &findData,
FindExSearchNameMatch, nullptr,
FIND_FIRST_EX_LARGE_FETCH)));
@ -215,12 +215,8 @@ namespace
{
if (!(findData.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
{
wchar_t drive[_MAX_DRIVE] = {};
wchar_t dir[_MAX_DIR] = {};
_wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
SConversion conv = {};
_wmakepath_s(conv.szSrc, drive, dir, findData.cFileName, nullptr);
conv.szSrc = path.parent_path().append(findData.cFileName).native();
files.push_back(conv);
}
@ -232,15 +228,9 @@ namespace
// Process directories
if (recursive)
{
wchar_t searchDir[MAX_PATH] = {};
{
wchar_t drive[_MAX_DRIVE] = {};
wchar_t dir[_MAX_DIR] = {};
_wsplitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
_wmakepath_s(searchDir, drive, dir, L"*", nullptr);
}
auto searchDir = path.parent_path().append(L"*");
hFile.reset(safe_handle(FindFirstFileExW(searchDir,
hFile.reset(safe_handle(FindFirstFileExW(searchDir.c_str(),
FindExInfoBasic, &findData,
FindExSearchLimitToDirectories, nullptr,
FIND_FIRST_EX_LARGE_FETCH)));
@ -253,17 +243,7 @@ namespace
{
if (findData.cFileName[0] != L'.')
{
wchar_t subdir[MAX_PATH] = {};
{
wchar_t drive[_MAX_DRIVE] = {};
wchar_t dir[_MAX_DIR] = {};
wchar_t fname[_MAX_FNAME] = {};
wchar_t ext[_MAX_FNAME] = {};
_wsplitpath_s(path, drive, dir, fname, ext);
wcscat_s(dir, findData.cFileName);
_wmakepath_s(subdir, drive, dir, fname, ext);
}
auto subdir = path.parent_path().append(findData.cFileName).append(path.filename().c_str());
SearchForFiles(subdir, files, recursive);
}
@ -279,36 +259,38 @@ namespace
{
std::list<SConversion> flist;
std::set<std::wstring> excludes;
wchar_t fname[1024] = {};
auto fname = std::make_unique<wchar_t[]>(32768);
for (;;)
{
inFile >> fname;
inFile >> fname.get();
if (!inFile)
break;
if (*fname == L'#')
if (fname[0] == L'#')
{
// Comment
}
else if (*fname == L'-')
else if (fname[0] == L'-')
{
if (flist.empty())
{
wprintf(L"WARNING: Ignoring the line '%ls' in -flist\n", fname);
wprintf(L"WARNING: Ignoring the line '%ls' in -flist\n", fname.get());
}
else
{
std::filesystem::path path(fname + 1);
std::filesystem::path path(fname.get() + 1);
auto& npath = path.make_preferred();
if (wcspbrk(fname, L"?*") != nullptr)
if (wcspbrk(fname.get(), L"?*") != nullptr)
{
std::list<SConversion> removeFiles;
SearchForFiles(npath.c_str(), removeFiles, false);
SearchForFiles(npath, removeFiles, false);
for (auto& it : removeFiles)
{
_wcslwr_s(it.szSrc);
excludes.insert(it.szSrc);
std::wstring name = it.szSrc;
std::transform(name.begin(), name.end(), name.begin(), towlower);
excludes.insert(name);
}
}
else
@ -319,16 +301,16 @@ namespace
}
}
}
else if (wcspbrk(fname, L"?*") != nullptr)
else if (wcspbrk(fname.get(), L"?*") != nullptr)
{
std::filesystem::path path(fname);
SearchForFiles(path.make_preferred().c_str(), flist, false);
std::filesystem::path path(fname.get());
SearchForFiles(path.make_preferred(), flist, false);
}
else
{
SConversion conv = {};
std::filesystem::path path(fname);
wcscpy_s(conv.szSrc, path.make_preferred().c_str());
std::filesystem::path path(fname.get());
conv.szSrc = path.make_preferred().native();
flist.push_back(conv);
}
@ -388,7 +370,7 @@ namespace
wchar_t version[32] = {};
wchar_t appName[_MAX_PATH] = {};
if (GetModuleFileNameW(nullptr, appName, static_cast<DWORD>(std::size(appName))))
if (GetModuleFileNameW(nullptr, appName, _MAX_PATH))
{
const DWORD size = GetFileVersionInfoSizeW(appName, nullptr);
if (size > 0)
@ -533,7 +515,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
DXGI_FORMAT uvFormat = DXGI_FORMAT_R32G32_FLOAT;
DXGI_FORMAT colorFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
wchar_t szOutputFile[MAX_PATH] = {};
std::wstring outputFile;
// Set locale for output since GetErrorDesc can get localized strings.
std::locale::global(std::locale(""));
@ -643,7 +625,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
case OPT_OUTPUTFILE:
{
std::filesystem::path path(pValue);
wcscpy_s(szOutputFile, path.make_preferred().c_str());
outputFile = path.make_preferred().native();
}
break;
@ -754,7 +736,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{
const size_t count = conversion.size();
std::filesystem::path path(pArg);
SearchForFiles(path.make_preferred().c_str(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0);
SearchForFiles(path.make_preferred(), conversion, (dwOptions & (1 << OPT_RECURSIVE)) != 0);
if (conversion.size() <= count)
{
wprintf(L"No matching files found for %ls\n", pArg);
@ -765,7 +747,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
{
SConversion conv = {};
std::filesystem::path path(pArg);
wcscpy_s(conv.szSrc, path.make_preferred().c_str());
conv.szSrc = path.make_preferred().native();
conversion.push_back(conv);
}
}
@ -776,7 +758,7 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 0;
}
if (*szOutputFile && conversion.size() > 1)
if (!outputFile.empty() && conversion.size() > 1)
{
wprintf(L"Cannot use -o with multiple input files\n");
return 1;
@ -788,46 +770,45 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
// Process files
for (auto pConv = conversion.begin(); pConv != conversion.end(); ++pConv)
{
wchar_t ext[_MAX_EXT] = {};
wchar_t fname[_MAX_FNAME] = {};
_wsplitpath_s(pConv->szSrc, nullptr, 0, nullptr, 0, fname, _MAX_FNAME, ext, _MAX_EXT);
std::filesystem::path curpath(pConv->szSrc);
auto const ext = curpath.extension();
if (pConv != conversion.begin())
wprintf(L"\n");
wprintf(L"reading %ls", pConv->szSrc);
wprintf(L"reading %ls", curpath.c_str());
fflush(stdout);
std::unique_ptr<Mesh> inMesh;
std::vector<Mesh::Material> inMaterial;
HRESULT hr = E_NOTIMPL;
if (_wcsicmp(ext, L".vbo") == 0)
if (_wcsicmp(ext.c_str(), L".vbo") == 0)
{
hr = Mesh::CreateFromVBO(pConv->szSrc, inMesh);
hr = Mesh::CreateFromVBO(curpath.c_str(), inMesh);
}
else if (_wcsicmp(ext, L".sdkmesh") == 0)
else if (_wcsicmp(ext.c_str(), L".sdkmesh") == 0)
{
wprintf(L"\nERROR: Importing SDKMESH files not supported\n");
return 1;
}
else if (_wcsicmp(ext, L".cmo") == 0)
else if (_wcsicmp(ext.c_str(), L".cmo") == 0)
{
wprintf(L"\nERROR: Importing Visual Studio CMO files not supported\n");
return 1;
}
else if (_wcsicmp(ext, L".x") == 0)
else if (_wcsicmp(ext.c_str(), L".x") == 0)
{
wprintf(L"\nERROR: Legacy Microsoft X files not supported\n");
return 1;
}
else if (_wcsicmp(ext, L".fbx") == 0)
else if (_wcsicmp(ext.c_str(), L".fbx") == 0)
{
wprintf(L"\nERROR: Autodesk FBX files not supported\n");
return 1;
}
else
{
hr = LoadFromOBJ(pConv->szSrc, inMesh, inMaterial,
hr = LoadFromOBJ(curpath.c_str(), inMesh, inMaterial,
(dwOptions & (1 << OPT_CLOCKWISE)) ? false : true,
(dwOptions & (1 << OPT_NODDS)) ? false : true);
}
@ -1023,15 +1004,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wprintf(L" [ACMR %f, ATVR %f] ", acmr, atvr);
}
wchar_t outputPath[MAX_PATH] = {};
wchar_t outputExt[_MAX_EXT] = {};
if (*szOutputFile)
if (!outputFile.empty())
{
wcscpy_s(outputPath, szOutputFile);
_wsplitpath_s(szOutputFile, nullptr, 0, nullptr, 0, nullptr, 0, outputExt, _MAX_EXT);
std::filesystem::path npath(outputFile);
wcscpy_s(outputExt, npath.extension().c_str());
}
else
{
@ -1052,22 +1030,20 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
wcscpy_s(outputExt, L".sdkmesh");
}
wchar_t outFilename[_MAX_FNAME] = {};
wcscpy_s(outFilename, fname);
_wmakepath_s(outputPath, nullptr, nullptr, outFilename, outputExt);
outputFile.assign(curpath.stem());
outputFile.append(outputExt);
}
if (dwOptions & (1 << OPT_TOLOWER))
{
std::ignore = _wcslwr_s(outputPath);
std::transform(outputFile.begin(), outputFile.end(), outputFile.begin(), towlower);
}
if (~dwOptions & (1 << OPT_OVERWRITE))
{
if (GetFileAttributesW(outputPath) != INVALID_FILE_ATTRIBUTES)
if (GetFileAttributesW(outputFile.c_str()) != INVALID_FILE_ATTRIBUTES)
{
wprintf(L"\nERROR: Output file already exists, use -y to overwrite:\n'%ls'\n", outputPath);
wprintf(L"\nERROR: Output file already exists, use -y to overwrite:\n'%ls'\n", outputFile.c_str());
return 1;
}
}
@ -1086,12 +1062,12 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 1;
}
hr = inMesh->ExportToVBO(outputPath);
hr = inMesh->ExportToVBO(outputFile.c_str());
}
else if (!_wcsicmp(outputExt, L".sdkmesh"))
{
hr = inMesh->ExportToSDKMESH(
outputPath,
outputFile.c_str(),
inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data(),
(dwOptions & (1 << OPT_FORCE_32BIT_IB)) ? true : false,
(dwOptions & (1 << OPT_SDKMESH_V2)) ? true : false,
@ -1113,11 +1089,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
return 1;
}
hr = inMesh->ExportToCMO(outputPath, inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
hr = inMesh->ExportToCMO(outputFile.c_str(), inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
}
else if (!_wcsicmp(outputExt, L".obj") || !_wcsicmp(outputExt, L"._obj"))
{
hr = inMesh->ExportToOBJ(outputPath, inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
hr = inMesh->ExportToOBJ(outputFile.c_str(), inMaterial.size(), inMaterial.empty() ? nullptr : inMaterial.data());
}
else if (!_wcsicmp(outputExt, L".x"))
{
@ -1133,11 +1109,11 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
if (FAILED(hr))
{
wprintf(L"\nERROR: Failed write (%08X%ls):-> '%ls'\n",
static_cast<unsigned int>(hr), GetErrorDesc(hr), outputPath);
static_cast<unsigned int>(hr), GetErrorDesc(hr), outputFile.c_str());
return 1;
}
wprintf(L" %zu vertices, %zu faces written:\n'%ls'\n", nVerts, nFaces, outputPath);
wprintf(L" %zu vertices, %zu faces written:\n'%ls'\n", nVerts, nFaces, outputFile.c_str());
}
return 0;

Просмотреть файл

@ -295,6 +295,9 @@
<ItemGroup>
<ResourceCompile Include="Meshconvert.rc" />
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

Просмотреть файл

@ -29,5 +29,8 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest">
<Filter>Resource Files</Filter>
</Manifest>
</ItemGroup>
</Project>

Просмотреть файл

@ -425,6 +425,9 @@
<ItemGroup>
<ResourceCompile Include="Meshconvert.rc" />
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

Просмотреть файл

@ -29,5 +29,8 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest">
<Filter>Resource Files</Filter>
</Manifest>
</ItemGroup>
</Project>

Просмотреть файл

@ -301,6 +301,9 @@
<ItemGroup>
<ResourceCompile Include="Meshconvert.rc" />
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

Просмотреть файл

@ -29,5 +29,8 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest">
<Filter>Resource Files</Filter>
</Manifest>
</ItemGroup>
</Project>

Просмотреть файл

@ -431,6 +431,9 @@
<ItemGroup>
<ResourceCompile Include="Meshconvert.rc" />
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

Просмотреть файл

@ -29,5 +29,8 @@
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="settings.manifest">
<Filter>Resource Files</Filter>
</Manifest>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,21 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10 / Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>