From 9c778fe76a3e915e5d1e20a23118c2ebe4cb07f3 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sun, 5 May 2024 22:37:05 -0700 Subject: [PATCH 1/5] fix: validate the document name --- .gitignore | 4 +++- src/json2cpp.cpp | 30 ++++++++++++++++++++++++++++++ src/main.cpp | 4 +--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d2475db..00836f3 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ cmake-build-*/ $RECYCLE.BIN/ .TemporaryItems ehthumbs.db -Thumbs.db \ No newline at end of file +Thumbs.db + +.cache/ diff --git a/src/json2cpp.cpp b/src/json2cpp.cpp index 79e20cd..b27128f 100644 --- a/src/json2cpp.cpp +++ b/src/json2cpp.cpp @@ -24,6 +24,8 @@ SOFTWARE. #include "json2cpp.hpp" +#include +#include #include std::string compile(const nlohmann::json &value, std::size_t &obj_count, std::vector &lines) @@ -85,8 +87,35 @@ std::string compile(const nlohmann::json &value, std::size_t &obj_count, std::ve return "unhandled"; } + +/** + * @brief Checks if the given string is a valid C++ identifier. A valid C++ identifier is a string that starts with an + * alphabetic character and is followed by zero or more alphanumeric characters. + * + * @param name The string to check + * @return true if the string is a valid C++ identifier, false otherwise + */ +bool is_valid_identifier(const std::string_view name) +{ + // not empty + return !name.empty() + // starts with an alphabetic character + && std::isalpha(name.front()) != 0 + // and is followed by zero or more alphanumeric characters + && std::all_of(name.begin(), name.end(), [](const auto &chr) { return std::isalnum(chr) != 0; }); +} + +void assert_valid_identifier(const std::string_view document_name) +{ + if (!is_valid_identifier(document_name)) { + throw std::invalid_argument( + fmt::format("document_name '{}' must be a non-empty valid C++ identifier", document_name)); + } +} + compile_results compile(const std::string_view document_name, const nlohmann::json &json) { + assert_valid_identifier(document_name); std::size_t obj_count{ 0 }; @@ -162,6 +191,7 @@ void write_compilation([[maybe_unused]] std::string_view document_name, const compile_results &results, const std::filesystem::path &base_output) { + assert_valid_identifier(document_name); const auto append_extension = [](std::filesystem::path name, std::string_view ext) { return name += ext; }; diff --git a/src/main.cpp b/src/main.cpp index 12fc259..aadeb5e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,9 +23,7 @@ SOFTWARE. */ #include -#include -#include -#include +#include #include "json2cpp.hpp" #include From 96aa7107b0572dc874eb76b6c130969fa6132fce Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sun, 5 May 2024 22:52:57 -0700 Subject: [PATCH 2/5] fix: validate and report file loading errors --- src/json2cpp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/json2cpp.cpp b/src/json2cpp.cpp index b27128f..ab1dbf0 100644 --- a/src/json2cpp.cpp +++ b/src/json2cpp.cpp @@ -26,6 +26,7 @@ SOFTWARE. #include "json2cpp.hpp" #include #include +#include #include std::string compile(const nlohmann::json &value, std::size_t &obj_count, std::vector &lines) @@ -179,6 +180,7 @@ compile_results compile(const std::string_view document_name, const std::filesys spdlog::info("Loading file: '{}'", filename.string()); std::ifstream input(filename); + if (!input.is_open()) { throw std::runtime_error(fmt::format("Unable to open the input file name: {}", filename)); } nlohmann::json document; input >> document; From 678920e2b4f050e0ec59f2e7bc18fdc3de9cd86f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sun, 5 May 2024 23:05:47 -0700 Subject: [PATCH 3/5] docs: add documentation and help for the CLI --- README.md | 25 +++++++++++++++++++++++++ src/main.cpp | 11 ++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c70fa04..8a75a11 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,28 @@ Features See the [test](test) folder for examples for building resources, using the valijson adapter, constexpr usage of resources, and firewalled usage of resources. + +## CLI Usage + +The json2cpp CLI can be used to convert a JSON file into a C++ source file that can be compiled into your project. + +```shell +json2cpp version 0.0.1 +Usage: ./build/src/Debug/json2cpp [OPTIONS] [] [] [] + +Positionals: + TEXT The name of the document used in the generated C++ namespace and include guards + TEXT The input JSON file to compile + TEXT The base path for the output files. It will generate .cpp and .hpp + +Options: + -h,--help Print this help message and exit + --version Show version information + +``` + +For example, to compile a JSON file named `"./data/data.json"`: + +```shell +json2cpp "data" "./data.json" "./data_source" +``` diff --git a/src/main.cpp b/src/main.cpp index aadeb5e..2a47457 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,9 +41,14 @@ int main(int argc, const char **argv) bool show_version = false; app.add_flag("--version", show_version, "Show version information"); - app.add_option("", document_name); - app.add_option("", input_file_name); - app.add_option("", output_base_name); + app.add_option("", + document_name, + "The name of the document used in the generated C++ namespace and include guards"); + app.add_option("", input_file_name, "The input JSON file to compile"); + app.add_option("", + output_base_name, + "The base path for the output filesThe base path for the output files. It will generate .cpp " + "and .hpp"); CLI11_PARSE(app, argc, argv); compile_to(document_name, input_file_name, output_base_name); From aeae0ebfa30c8f04a8db22e35c358d9261f8a73a Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sun, 5 May 2024 23:06:11 -0700 Subject: [PATCH 4/5] fix: avoid empty output base name --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 2a47457..c2fdb50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,7 +37,7 @@ int main(int argc, const char **argv) std::string document_name; std::filesystem::path input_file_name; - std::filesystem::path output_base_name; + std::filesystem::path output_base_name = "out"; bool show_version = false; app.add_flag("--version", show_version, "Show version information"); From d3687dbe4b9aefa1bf7b818cd7314c2ac39dcdd2 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sun, 5 May 2024 23:07:53 -0700 Subject: [PATCH 5/5] fix: create the directory of the base_output's parent --- src/json2cpp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/json2cpp.cpp b/src/json2cpp.cpp index ab1dbf0..a43a9c9 100644 --- a/src/json2cpp.cpp +++ b/src/json2cpp.cpp @@ -197,6 +197,8 @@ void write_compilation([[maybe_unused]] std::string_view document_name, const auto append_extension = [](std::filesystem::path name, std::string_view ext) { return name += ext; }; + // Create the directory of the base_output's parent + std::filesystem::create_directories(base_output.parent_path()); const auto hpp_name = append_extension(base_output, ".hpp"); const auto cpp_name = append_extension(base_output, ".cpp");