Skip to content

Commit

Permalink
Update typedefs of C-style function pointers to std::function
Browse files Browse the repository at this point in the history
This allows for the callback to maintain their own state (without recourse
to globals).

In addition, added some incidental clean up:

  - URICallback, passed by pointer, is now asserted to be non-null before
    accessing.
  - FSCallbacks are validated when they are set (in debug builds).
  • Loading branch information
SeanCurtis-TRI committed Jun 6, 2024
1 parent f03fe26 commit e08df72
Showing 1 changed file with 59 additions and 43 deletions.
102 changes: 59 additions & 43 deletions tiny_gltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <limits>
#include <map>
#include <string>
#include <utility>
#include <vector>

// Auto-detect C++14 standard version
Expand Down Expand Up @@ -1263,17 +1265,18 @@ enum SectionCheck {
/// image URIs differently, for example. See
/// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#uris
///
typedef bool (*URIEncodeFunction)(const std::string &in_uri,
const std::string &object_type,
std::string *out_uri, void *user_data);
using URIEncodeFunction = std::function<bool(
const std::string & /* in_uri */, const std::string & /* object_type */,
std::string * /* out_uri */, void * /* user_data */)>;

///
/// URIDecodeFunction type. Signature for custom URI decoding of external
/// resources such as .bin and image files. Used by tinygltf when computing
/// filenames to write resources.
///
typedef bool (*URIDecodeFunction)(const std::string &in_uri,
std::string *out_uri, void *user_data);
using URIDecodeFunction =
std::function<bool(const std::string & /* in_uri */,
std::string * /* out_uri */, void * /* user_data */)>;

// Declaration of default uri decode function
bool URIDecode(const std::string &in_uri, std::string *out_uri,
Expand All @@ -1292,22 +1295,21 @@ struct URICallbacks {
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
std::string *, int, int,
const unsigned char *, int,
void *user_pointer);
using LoadImageDataFunction = std::function<bool(
Image * /* image */, const int /* image_idx */, std::string * /* err */,
std::string * /* warn */, int /* req_width */, int /* req_height */,
const unsigned char * /* bytes */, int /* size */, void * /*user_data */)>;

///
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
/// The out_uri parameter becomes the URI written to the gltf and may reference
/// a file or contain a data URI.
///
typedef bool (*WriteImageDataFunction)(const std::string *basepath,
const std::string *filename,
const Image *image, bool embedImages,
const URICallbacks *uri_cb,
std::string *out_uri,
void *user_pointer);
using WriteImageDataFunction = std::function<bool(
const std::string * /* basepath */, const std::string * /* filename */,
const Image *image, bool /* embedImages */,
const URICallbacks * /* uri_cb */, std::string * /* out_uri */,
void * /* user_pointer */)>;

#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
Expand All @@ -1324,35 +1326,36 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
#endif

///
/// FilExistsFunction type. Signature for custom filesystem callbacks.
/// FileExistsFunction type. Signature for custom filesystem callbacks.
///
typedef bool (*FileExistsFunction)(const std::string &abs_filename, void *);
using FileExistsFunction = std::function<bool(
const std::string & /* abs_filename */, void * /* user_data */)>;

///
/// ExpandFilePathFunction type. Signature for custom filesystem callbacks.
///
typedef std::string (*ExpandFilePathFunction)(const std::string &, void *);
using ExpandFilePathFunction =
std::function<std::string(const std::string &, void *)>;

///
/// ReadWholeFileFunction type. Signature for custom filesystem callbacks.
///
typedef bool (*ReadWholeFileFunction)(std::vector<unsigned char> *,
std::string *, const std::string &,
void *);
using ReadWholeFileFunction = std::function<bool(
std::vector<unsigned char> *, std::string *, const std::string &, void *)>;

///
/// WriteWholeFileFunction type. Signature for custom filesystem callbacks.
///
typedef bool (*WriteWholeFileFunction)(std::string *, const std::string &,
const std::vector<unsigned char> &,
void *);
using WriteWholeFileFunction =
std::function<bool(std::string *, const std::string &,
const std::vector<unsigned char> &, void *)>;

///
/// GetFileSizeFunction type. Signature for custom filesystem callbacks.
///
typedef bool (*GetFileSizeFunction)(size_t *filesize_out, std::string *err,
const std::string &abs_filename,
void *userdata);
using GetFileSizeFunction =
std::function<bool(size_t *filesize_out, std::string *err,
const std::string &abs_filename, void *userdata)>;

///
/// A structure containing all required filesystem callbacks and a pointer to
Expand Down Expand Up @@ -2571,7 +2574,7 @@ void TinyGLTF::SetParseStrictness(ParseStrictness strictness) {
}

void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
LoadImageData = func;
LoadImageData = std::move(func);
load_image_user_data_ = user_data;
user_image_loader_ = true;
}
Expand Down Expand Up @@ -2697,7 +2700,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
#endif

void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) {
WriteImageData = func;
WriteImageData = std::move(func);
write_image_user_data_ = user_data;
}

Expand Down Expand Up @@ -2775,6 +2778,7 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
} else {
// Throw error?
}
assert(uri_cb != nullptr);
if (uri_cb->encode) {
if (!uri_cb->encode(*filename, "image", out_uri, uri_cb->user_data)) {
return false;
Expand All @@ -2791,11 +2795,19 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
void TinyGLTF::SetURICallbacks(URICallbacks callbacks) {
assert(callbacks.decode);
if (callbacks.decode) {
uri_cb = callbacks;
uri_cb = std::move(callbacks);
}
}

void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) {
// If callbacks are defined at all, they must all be defined.
assert(callbacks.FileExists != nullptr);
assert(callbacks.ExpandFilePath != nullptr);
assert(callbacks.ReadWholeFile != nullptr);
assert(callbacks.WriteWholeFile != nullptr);
assert(callbacks.GetFileSizeInBytes != nullptr);
fs = std::move(callbacks);
}

#ifdef _WIN32
static inline std::wstring UTF8ToWchar(const std::string &str) {
Expand Down Expand Up @@ -3200,12 +3212,13 @@ static std::string MimeToExt(const std::string &mimeType) {
static bool UpdateImageObject(const Image &image, std::string &baseDir,
int index, bool embedImages,
const URICallbacks *uri_cb,
WriteImageDataFunction *WriteImageData,
const WriteImageDataFunction& WriteImageData,
void *user_data, std::string *out_uri) {
std::string filename;
std::string ext;
// If image has uri, use it as a filename
if (image.uri.size()) {
assert(uri_cb != nullptr);
std::string decoded_uri;
if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) {
// A decode failure results in a failure to write the gltf.
Expand All @@ -3230,9 +3243,9 @@ static bool UpdateImageObject(const Image &image, std::string &baseDir,
// image data does not exist, this is not considered a failure and the
// original uri should be maintained.
bool imageWritten = false;
if (*WriteImageData != nullptr && !filename.empty() && !image.image.empty()) {
imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages,
uri_cb, out_uri, user_data);
if (WriteImageData != nullptr && !filename.empty() && !image.image.empty()) {
imageWritten = WriteImageData(&baseDir, &filename, &image, embedImages,
uri_cb, out_uri, user_data);
if (!imageWritten) {
return false;
}
Expand Down Expand Up @@ -4214,7 +4227,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
bool store_original_json_for_extras_and_extensions,
const std::string &basedir, const size_t max_file_size,
FsCallbacks *fs, const URICallbacks *uri_cb,
LoadImageDataFunction *LoadImageData = nullptr,
const LoadImageDataFunction& LoadImageData = nullptr,
void *load_image_user_data = nullptr) {
// A glTF image must either reference a bufferView or an image uri

Expand Down Expand Up @@ -4310,6 +4323,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
return true;
#else
std::string decoded_uri;
assert(uri_cb != nullptr);
if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) {
if (warn) {
(*warn) += "Failed to decode 'uri' for image[" +
Expand Down Expand Up @@ -4345,14 +4359,14 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
#endif
}

if (*LoadImageData == nullptr) {
if (LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
return false;
}
return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
return LoadImageData(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
}

static bool ParseTexture(Texture *texture, std::string *err,
Expand Down Expand Up @@ -4490,6 +4504,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
} else {
// External .bin file.
std::string decoded_uri;
assert(uri_cb != nullptr);
if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
return false;
}
Expand Down Expand Up @@ -4540,6 +4555,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
} else {
// Assume external .bin file.
std::string decoded_uri;
assert(uri_cb != nullptr);
if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
return false;
}
Expand Down Expand Up @@ -6341,7 +6357,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
if (!ParseImage(&image, idx, err, warn, o,
store_original_json_for_extras_and_extensions_, base_dir,
max_external_file_size_, &fs, &uri_cb,
&this->LoadImageData, load_image_user_data)) {
this->LoadImageData, load_image_user_data)) {
return false;
}

Expand Down Expand Up @@ -6370,7 +6386,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
}
const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];

if (*LoadImageData == nullptr) {
if (LoadImageData == nullptr) {
if (err) {
(*err) += "No LoadImageData callback specified.\n";
}
Expand Down Expand Up @@ -8513,7 +8529,7 @@ bool TinyGLTF::WriteGltfSceneToStream(const Model *model, std::ostream &stream,
// we
std::string uri;
if (!UpdateImageObject(model->images[i], dummystring, int(i), true,
&uri_cb, &this->WriteImageData,
&uri_cb, this->WriteImageData,
this->write_image_user_data_, &uri)) {
return false;
}
Expand Down Expand Up @@ -8621,7 +8637,7 @@ bool TinyGLTF::WriteGltfSceneToFile(const Model *model,

std::string uri;
if (!UpdateImageObject(model->images[i], baseDir, int(i), embedImages,
&uri_cb, &this->WriteImageData,
&uri_cb, this->WriteImageData,
this->write_image_user_data_, &uri)) {
return false;
}
Expand Down

0 comments on commit e08df72

Please sign in to comment.