From 51f29f1688abf35ebed15549b436e87fdc5a388e Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Tue, 13 Jun 2023 15:40:30 -0700 Subject: [PATCH] meshconvert updated to support long path names with Windows 10 (#102) --- CMakeLists.txt | 1 + Meshconvert/Meshconvert.cpp | 132 +++++++----------- Meshconvert/Meshconvert_Desktop_2019.vcxproj | 3 + .../Meshconvert_Desktop_2019.vcxproj.filters | 3 + .../Meshconvert_Desktop_2019_Win10.vcxproj | 3 + ...convert_Desktop_2019_Win10.vcxproj.filters | 3 + Meshconvert/Meshconvert_Desktop_2022.vcxproj | 3 + .../Meshconvert_Desktop_2022.vcxproj.filters | 3 + .../Meshconvert_Desktop_2022_Win10.vcxproj | 3 + ...convert_Desktop_2022_Win10.vcxproj.filters | 3 + Meshconvert/settings.manifest | 21 +++ 11 files changed, 100 insertions(+), 78 deletions(-) create mode 100644 Meshconvert/settings.manifest diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c64f42..d72c18f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Meshconvert/Meshconvert.cpp b/Meshconvert/Meshconvert.cpp index f1bd74c..7b10c54 100644 --- a/Meshconvert/Meshconvert.cpp +++ b/Meshconvert/Meshconvert.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& files, bool recursive) + void SearchForFiles(const std::filesystem::path& path, std::list& 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 flist; std::set excludes; - wchar_t fname[1024] = {}; + + auto fname = std::make_unique(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 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(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 inMesh; std::vector 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(hr), GetErrorDesc(hr), outputPath); + static_cast(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; diff --git a/Meshconvert/Meshconvert_Desktop_2019.vcxproj b/Meshconvert/Meshconvert_Desktop_2019.vcxproj index cb41d59..3f80802 100644 --- a/Meshconvert/Meshconvert_Desktop_2019.vcxproj +++ b/Meshconvert/Meshconvert_Desktop_2019.vcxproj @@ -295,6 +295,9 @@ + + + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2019.vcxproj.filters b/Meshconvert/Meshconvert_Desktop_2019.vcxproj.filters index 41f44e5..5fb4723 100644 --- a/Meshconvert/Meshconvert_Desktop_2019.vcxproj.filters +++ b/Meshconvert/Meshconvert_Desktop_2019.vcxproj.filters @@ -29,5 +29,8 @@ + + Resource Files + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj b/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj index 7fc1791..23aeccb 100644 --- a/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj +++ b/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj @@ -425,6 +425,9 @@ + + + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj.filters b/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj.filters index 41f44e5..5fb4723 100644 --- a/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj.filters +++ b/Meshconvert/Meshconvert_Desktop_2019_Win10.vcxproj.filters @@ -29,5 +29,8 @@ + + Resource Files + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2022.vcxproj b/Meshconvert/Meshconvert_Desktop_2022.vcxproj index 3228e4a..57d5b00 100644 --- a/Meshconvert/Meshconvert_Desktop_2022.vcxproj +++ b/Meshconvert/Meshconvert_Desktop_2022.vcxproj @@ -301,6 +301,9 @@ + + + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2022.vcxproj.filters b/Meshconvert/Meshconvert_Desktop_2022.vcxproj.filters index 41f44e5..5fb4723 100644 --- a/Meshconvert/Meshconvert_Desktop_2022.vcxproj.filters +++ b/Meshconvert/Meshconvert_Desktop_2022.vcxproj.filters @@ -29,5 +29,8 @@ + + Resource Files + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj b/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj index 3df8ece..436a888 100644 --- a/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj +++ b/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj @@ -431,6 +431,9 @@ + + + \ No newline at end of file diff --git a/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj.filters b/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj.filters index 41f44e5..5fb4723 100644 --- a/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj.filters +++ b/Meshconvert/Meshconvert_Desktop_2022_Win10.vcxproj.filters @@ -29,5 +29,8 @@ + + Resource Files + \ No newline at end of file diff --git a/Meshconvert/settings.manifest b/Meshconvert/settings.manifest new file mode 100644 index 0000000..544e45d --- /dev/null +++ b/Meshconvert/settings.manifest @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + true + + +