Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ This will automatically fetch, build, and link the `c2pa_cpp` library and its de

### Example usage

See the [`examples/`](examples/) directory for sample applications that demonstrate how to use the library in practice.
See the [`examples/`](examples/) directory for sample applications that demonstrate how to use the library in practice.

## Development

This project has been tested on macOS and should also work on common Linux distributions.

You must install the [Ninja](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages) build system to run the unit tests.

### Building using pre-build C FFI libraries
### Building using pre-built C FFI libraries

Building the library holding the C++ SDK requires [GNU make](https://www.gnu.org/software/make/), which is installed on most macOS systems.

Expand All @@ -72,7 +72,7 @@ Results are saved in the `build` directory.

This project can also be built entirely from source (without pre-built library download), with the pre-requisite that you will also need [c2pa-rs](https://github.com/contentauth/c2pa-rs) on the local machine, as well as the [Rust toolchain](https://rust-lang.org/tools/install/).

To build in this case, the build scripts need to be able to locate the `c2pa-rs` sources as well as the librari this builds for linking. This is done by setting environment variables in the terminal where the builds will run.
To build in this case, the build scripts need to be able to locate the `c2pa-rs` sources as well as the library this builds for linking. This is done by setting environment variables in the terminal where the builds will run.

```sh
# Enable local c2pa-rs build
Expand All @@ -81,7 +81,7 @@ export C2PA_BUILD_FROM_SOURCE=ON
# If local build is enabled, set this environment variable to contain the path to c2pa-rs sources
export C2PA_RS_PATH=path_to_c2pa_rs_sources

# Since this is going to build Rust code, the build sysstem need to locate cargo, the tool to build RUst code
# Since this is going to build Rust code, the build system needs to locate cargo, the tool to build Rust code
# Add Rust cargo to PATH if not already there
export PATH="$HOME/.cargo/bin:$PATH"

Expand Down
66 changes: 14 additions & 52 deletions include/c2pa.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,6 @@ namespace c2pa
constexpr const char* BinaryArchive = "application/c2pa";
}

/// @brief Enum for settings/configuration format
enum class ConfigFormat {
JSON,
TOML
};

/// @brief Helper to convert enum to string format
/// @param format ConfigFormat enum value
/// @return Format as string, defaults to json
inline const char* config_format_to_string(ConfigFormat format) noexcept {
switch(format) {
case ConfigFormat::JSON: return "json";
case ConfigFormat::TOML: return "toml";
default: return "json";
}
}

/// C2paException class for C2pa errors.
/// This class is used to throw exceptions for errors encountered by the C2pa library via c2pa_error().
class C2PA_CPP_API C2paException : public std::exception
Expand Down Expand Up @@ -157,7 +140,7 @@ namespace c2pa
};

/// @brief (C2PA SDK) Settings configuration object for creating contexts.
/// @details Settings can be configured via JSON/TOML strings or programmatically
/// @details Settings can be configured via JSON strings or programmatically
/// via set() and update() methods. Once passed to Context::ContextBuilder,
/// the settings are copied into the context and the Settings
/// object can be reused or discarded.
Expand All @@ -167,18 +150,11 @@ namespace c2pa
Settings();

/// @brief Create settings from a configuration string.
/// @param data Configuration data in JSON or TOML format.
/// @param format Format of the data ("json" or "toml").
/// @param data Configuration data in JSON format.
/// @param format Format of the data ("json").
/// @throws C2paException if parsing fails.
Settings(const std::string& data, const std::string& format);

/// @brief Create settings from a configuration string.
/// @param data Configuration data in ConfigFormat format.
/// @param format Format of the data from `ConfigFormat` enum.
/// @throws C2paException if parsing fails.
Settings(const std::string& data, ConfigFormat format)
: Settings(data, config_format_to_string(format)) {}

// Move semantics
Settings(Settings&&) noexcept;
Settings& operator=(Settings&&) noexcept;
Expand All @@ -196,21 +172,19 @@ namespace c2pa
/// @throws C2paException if the path or value is invalid.
Settings& set(const std::string& path, const std::string& json_value);

/// @brief Merge configuration from a std::string (latest configuration wins).
/// @param data Configuration data in JSON or TOML format.
/// @param format Format of the data ("json" or "toml").
/// @brief Merge configuration from a JSON string (latest configuration wins).
/// @param data Configuration data in JSON format.
/// @return Reference to this Settings for method chaining.
/// @throws C2paException if parsing fails.
Settings& update(const std::string& data, const std::string& format);
/// @note This is the recommended overload when configuration is JSON.
Settings& update(const std::string& data) { return update(data, "json"); }

/// @brief Merge configuration from a std::string (latest configuration wins).
/// @param data Configuration data in ConfigFormat format.
/// @param format Format of the data as `ConfigFormat` enum.
/// @param data Configuration data in JSON or TOML format.
/// @param format Format of the data ("json" or "toml").
/// @return Reference to this Settings for method chaining.
/// @throws C2paException if parsing fails.
Settings& update(const std::string& data, ConfigFormat format) {
return update(data, config_format_to_string(format));
}
Settings& update(const std::string& data, const std::string& format);

/// @brief Get the raw C FFI settings pointer.
/// @return Pointer to C2paSettings, or nullptr if not initialized.
Expand Down Expand Up @@ -259,12 +233,6 @@ namespace c2pa
/// @throws C2paException if builder is invalid or JSON is invalid.
ContextBuilder& with_json(const std::string& json);

/// @brief Configure settings with TOML string.
/// @param toml TOML configuration string.
/// @return Reference to this ContextBuilder for method chaining.
/// @throws C2paException if builder is invalid or TOML is invalid.
ContextBuilder& with_toml(const std::string& toml);

/// @brief Create the immutable Context (consuming build operation).
/// @return Shared pointer to the new Context.
/// @throws C2paException if context creation fails or builder is invalid.
Expand All @@ -287,12 +255,6 @@ namespace c2pa
/// @throws C2paException if JSON is invalid or context creation fails.
[[nodiscard]] static std::shared_ptr<IContextProvider> from_json(const std::string& json);

/// @brief Create a Context from TOML configuration (settings).
/// @param toml TOML configuration string.
/// @return Shared pointer to the new Context.
/// @throws C2paException if TOML is invalid or context creation fails.
[[nodiscard]] static std::shared_ptr<IContextProvider> from_toml(const std::string& toml);

// Non-copyable, non-moveable
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
Expand Down Expand Up @@ -321,8 +283,8 @@ namespace c2pa
/// @param data the std::string to load.
/// @param format the mime format of the string.
/// @throws a C2pa::C2paException for errors encountered by the C2PA library.
/// @deprecated Use Context::from_json() or Context::from_toml() instead for better thread safety.
[[deprecated("Use Context pattern instead, Context::from_json() or Context::from_toml() instead")]]
/// @deprecated Use Context::from_json() or Context::ContextBuilder().with_json().create_context() instead for better thread safety.
[[deprecated("Use Context pattern instead, Context::from_json() or Context::ContextBuilder().with_json().create_context() instead")]]
void C2PA_CPP_API load_settings(const std::string& data, const std::string& format);

/// Reads a file and returns the manifest json as a C2pa::String.
Expand Down Expand Up @@ -752,14 +714,14 @@ namespace c2pa
/// @param ingredient_json Any fields of the ingredient you want to define (e.g. title, relationship).
/// @param archive The input stream to read the archive from.
/// @throws C2pa::C2paException for errors encountered by the C2PA library.
void add_ingredient_from_binary_archive(const std::string &ingredient_json, std::istream &archive);
void from_ingredient_archive(const std::string &ingredient_json, std::istream &archive);

/// @brief Add an archive (working store) as an ingredient to the builder.
/// @param ingredient_json Any fields of the ingredient you want to define (e.g. title, relationship).
/// @param archive_path The path to the archive file.
/// @throws C2pa::C2paException for errors encountered by the C2PA library.
/// @note Prefer using the streaming APIs if possible
void add_ingredient_from_binary_archive(const std::string &ingredient_json, const std::filesystem::path &archive_path);
void from_ingredient_archive(const std::string &ingredient_json, const std::filesystem::path &archive_path);

/// @brief Add an action to the manifest the Builder is constructing.
/// @param action_json JSON std::string containing the action data.
Expand Down
21 changes: 5 additions & 16 deletions src/c2pa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ inline std::string extract_file_extension(const std::filesystem::path &path) noe
return ext.empty() ? "" : ext.substr(1);
}

/// @brief Only call C API free when pointer is non-null (FFI can panic on null).
/// @brief Only call C API free when pointer is non-null.
inline void safe_c2pa_free(void* p) {
if (p != nullptr)
c2pa_free(p);
Expand Down Expand Up @@ -411,10 +411,6 @@ inline std::vector<unsigned char> to_byte_vector(const unsigned char* data, int6
return ContextBuilder().with_json(json).create_context();
}

std::shared_ptr<IContextProvider> Context::from_toml(const std::string& toml) {
return ContextBuilder().with_toml(toml).create_context();
}

// Context::ContextBuilder

Context::ContextBuilder::ContextBuilder() : context_builder(c2pa_context_builder_new()) {
Expand Down Expand Up @@ -461,14 +457,7 @@ inline std::vector<unsigned char> to_byte_vector(const unsigned char* data, int6
if (!is_valid()) {
throw C2paException("ContextBuilder is invalid (already consumed)");
}
return with_settings(Settings(json, ConfigFormat::JSON));
}

Context::ContextBuilder& Context::ContextBuilder::with_toml(const std::string& toml) {
if (!is_valid()) {
throw C2paException("ContextBuilder is invalid (already consumed)");
}
return with_settings(Settings(toml, ConfigFormat::TOML));
return with_settings(Settings(json, "json"));
}

std::shared_ptr<IContextProvider> Context::ContextBuilder::create_context() {
Expand Down Expand Up @@ -975,15 +964,15 @@ inline std::vector<unsigned char> to_byte_vector(const unsigned char* data, int6
add_ingredient(ingredient_json, format.c_str(), *stream);
}

void Builder::add_ingredient_from_binary_archive(const std::string &ingredient_json, std::istream &archive)
void Builder::from_ingredient_archive(const std::string &ingredient_json, std::istream &archive)
{
add_ingredient(ingredient_json, C2paMimeType::BinaryArchive, archive);
}

void Builder::add_ingredient_from_binary_archive(const std::string &ingredient_json, const std::filesystem::path &archive_path)
void Builder::from_ingredient_archive(const std::string &ingredient_json, const std::filesystem::path &archive_path)
{
auto stream = detail::open_file_binary<std::ifstream>(archive_path);
add_ingredient_from_binary_archive(ingredient_json, *stream);
from_ingredient_archive(ingredient_json, *stream);
}

void Builder::add_action(const std::string &action_json)
Expand Down
Loading