c2pa-cpp
C++ API for the C2PA SDK
Loading...
Searching...
No Matches
c2pa.hpp
Go to the documentation of this file.
1// Copyright 2024 Adobe. All rights reserved.
2// This file is licensed to you under the Apache License,
3// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
4// or the MIT license (http://opensource.org/licenses/MIT),
5// at your option.
6// Unless required by applicable law or agreed to in writing,
7// this software is distributed on an "AS IS" BASIS, WITHOUT
8// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
9// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
10// specific language governing permissions and limitations under
11// each license.
12
13/// @file c2pa.hpp
14/// @brief C++ wrapper for the C2PA C library.
15/// @details This is used for creating and verifying C2PA manifests.
16/// This is an early version, and has not been fully tested.
17/// Thread safety is not guaranteed due to the use of errno and etc.
18
19#ifndef C2PA_H
20#define C2PA_H
21
22// Suppress unused function warning for GCC/Clang
23#ifdef __GNUC__
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wunused-function"
26#endif
27
28// Suppress unused function warning for MSVC
29#ifdef _MSC_VER
30#pragma warning(push)
31#pragma warning(disable : 4505)
32#endif
33
34#include <cerrno>
35#include <filesystem>
36#include <fstream>
37#include <functional>
38#include <istream>
39#include <ostream>
40#include <string>
41#include <vector>
42#include <optional>
43#include <memory>
44#include <utility>
45
46#include "c2pa.h"
47
48// NOOP for now, can use later to define static library
49#define C2PA_CPP_API
50
51namespace c2pa
52{
53 /// @typedef SignerInfo
54 /// @brief Type alias for C2paSignerInfo from the C API.
55 typedef C2paSignerInfo SignerInfo;
56
57 // Forward declarations for context types
58 class Settings;
59 class Context;
60 class IContextProvider;
61 class Signer;
62
63 /// @brief Result codes for C API operations (matches C API return convention).
64 enum class OperationResult : int {
65 Success = 0, ///< Operation succeeded
66 Error = -1 ///< Operation failed (check C2paException for details)
67 };
68
69 /// @brief Stream/FFI error codes (maps to errno values used by the C layer).
70 enum class StreamError : int {
71 InvalidArgument = EINVAL,
72 IoError = EIO,
73 NoBufferSpace = ENOBUFS
74 };
75
76 /// @brief Set errno from StreamError and return error sentinel.
77 /// @param e The StreamError value to convert to errno.
78 /// @return OperationResult::Error (-1) for use as C API error return.
79 inline int stream_error_return(StreamError e) noexcept {
80 errno = static_cast<int>(e);
81 return static_cast<int>(OperationResult::Error);
82 }
83
84 /// @brief Exception class for C2pa errors.
85 /// This class is used to throw exceptions for errors encountered by the C2pa library via c2pa_error().
86 class C2PA_CPP_API C2paException : public std::exception
87 {
88 public:
89 /// @brief Default constructor.
90 /// @details Creates an exception and retrieves the error message from the C2PA library.
92
93 /// @brief Construct an exception with a custom error message.
94 /// @param message The error message.
95 explicit C2paException(std::string message);
96
97 ~C2paException() override = default;
98
99 C2paException(const C2paException&) = default;
100
102
104
106
107 /// @brief Get the exception message.
108 /// @return Null-terminated error message string.
109 const char* what() const noexcept override;
110
111 private:
112 std::string message_;
113 };
114
115 /// @brief Interface for types that can provide C2PA context functionality.
116 /// @details This interface can be implemented by external libraries to provide
117 /// custom context implementations (e.g. AdobeContext wrappers).
118 /// Reader and Builder take the context by reference and use it only at
119 /// construction; the underlying implementation copies context state
120 /// into the reader/builder, so the context does not need to outlive them.
121 ///
122 /// @par Move semantics
123 /// Move construction and move assignment are defaulted. After move, the moved-from
124 /// object is left in a valid but unspecified state: is_valid() may be false and
125 /// c_context() may return nullptr. Implementations that own a C2paContext* (e.g. Context)
126 /// must set the source's handle to nullptr on move to avoid double-free; callers must
127 /// not use a moved-from provider without checking is_valid() first.
128 ///
129 /// @par Implementation Requirements for is_valid()
130 /// The is_valid() method exists to support implementations that may have:
131 /// - Optional or lazy context initialization
132 /// - Contexts that can be invalidated or moved
133 /// - A "no context" state as part of their lifecycle
134 ///
135 /// @par Why Both c_context() and is_valid()?
136 /// While c_context() can return nullptr, is_valid() provides:
137 /// 1. A boolean check without pointer inspection (yes/no answer for intialization)
138 /// 2. Forward compatibility for implementations with complex context lifecycles (lazy load)
139 ///
140 /// @par Impact on Reader and Builder
141 /// Reader and Builder constructors validate that a provider both exists and
142 /// is_valid() returns true before using c_context(). This ensures that:
143 /// - External implementations cannot be used in an uninitialized state
144 /// - A consistent validation pattern exists across all context-using classes
145 /// - Errors are caught early at construction time rather than during operations
146 ///
147 /// @par Standard Context Implementation
148 /// The built-in Context class always returns true from is_valid() after
149 /// successful construction, as it validates the context pointer in its constructor.
150 /// External implementations may have different invariants.
152 public:
153 virtual ~IContextProvider() noexcept = default;
154
155 /// @brief Get the underlying C2PA context pointer for FFI operations.
156 /// @return Pointer to C2paContext, or nullptr if not available.
157 /// @note Provider retains ownership; pointer valid for provider's lifetime.
158 [[nodiscard]] virtual C2paContext* c_context() const noexcept = 0;
159
160 /// @brief Check if this provider has a valid context.
161 /// @return true if context is available, false otherwise.
162 /// @note For standard Context objects, this always returns true after construction.
163 /// External implementations may return false to indicate uninitialized or
164 /// invalidated state. Reader and Builder constructors check this before use.
165 /// @warning Implementations must ensure is_valid() == true implies c_context() != nullptr.
166 [[nodiscard]] virtual bool is_valid() const noexcept = 0;
167
168 protected:
169 IContextProvider() = default;
170
172 IContextProvider& operator=(const IContextProvider&) = delete;
173 };
174
175 /// @brief (C2PA SDK) Settings configuration object for creating contexts.
176 /// @details Settings can be configured via JSON strings or programmatically
177 /// via set() and update() methods. Once passed to Context::ContextBuilder,
178 /// the settings are copied into the context and the Settings
179 /// object can be reused or discarded.
180 ///
181 /// @par Validity
182 /// Settings uses is_valid() to indicate whether the object holds a valid underlying
183 /// C settings handle. After move-from, is_valid() is false. set(), update(), and callers
184 /// passing this object to the C API must ensure is_valid() is true or check before use.
186 public:
187 /// @brief Create default settings.
189
190 /// @brief Create settings from a configuration string.
191 /// @param data Configuration data in JSON format.
192 /// @param format Format of the data ("json").
193 /// @throws C2paException if parsing fails.
194 Settings(const std::string& data, const std::string& format);
195
196 // Move semantics
197 Settings(Settings&&) noexcept;
198 Settings& operator=(Settings&&) noexcept;
199
200 // Non-copyable
201 Settings(const Settings&) = delete;
202 Settings& operator=(const Settings&) = delete;
203
204 ~Settings() noexcept;
205
206 /// @brief Check if this Settings object is valid (holds a C settings handle).
207 /// @return true if the object can be used (set, update, c_settings, or passed to Context/ContextBuilder).
208 /// @return false if moved-from (or otherwise invalid). Callers must check before use.
209 [[nodiscard]] bool is_valid() const noexcept;
210
211 /// @brief Set a single configuration value by path.
212 /// @param path Dot-separated path to the setting (e.g., "verify.verify_after_sign").
213 /// @param json_value JSON-encoded value to set.
214 /// @return Reference to this Settings for method chaining.
215 /// @throws C2paException if the path or value is invalid.
216 Settings& set(const std::string& path, const std::string& json_value);
217
218 /// @brief Merge configuration from a JSON string (latest configuration wins).
219 /// @param data Configuration data in JSON format.
220 /// @return Reference to this Settings for method chaining.
221 /// @throws C2paException if parsing fails, or if this object is invalid.
222 /// @note This is the recommended overload when configuration is JSON.
223 Settings& update(const std::string& data) { return update(data, "json"); }
224
225 /// @brief Merge configuration from a std::string (latest configuration wins).
226 /// @param data Configuration data in JSON or TOML format.
227 /// @param format Format of the data ("json" or "toml").
228 /// @return Reference to this Settings for method chaining.
229 /// @throws C2paException if parsing fails, or if this object is invalid.
230 Settings& update(const std::string& data, const std::string& format);
231
232 /// @brief Get the raw C FFI settings pointer.
233 /// @return Pointer to C2paSettings when is_valid() is true; nullptr when invalid.
234 /// @note Callers passing this to the C API should check is_valid() first and treat nullptr as invalid.
235 [[nodiscard]] C2paSettings* c_settings() const noexcept;
236
237 private:
238 C2paSettings* settings_ptr;
239 };
240
241 /// @brief Phase values reported to the ProgressCallbackFunc.
242 ///
243 /// @details A scoped C++ mirror of `C2paProgressPhase` from c2pa.h.
244 /// Values are verified at compile time to match the C enum, so any
245 /// future divergence in c2pa-rs will be caught as a build error.
246 ///
247 /// Phases emitted during a typical sign cycle (in order):
248 /// AddingIngredient → Thumbnail → Hashing → Signing → Embedding →
249 /// (if verify_after_sign) VerifyingManifest → VerifyingSignature →
250 /// VerifyingAssetHash → VerifyingIngredient
251 ///
252 /// Phases emitted during reading:
253 /// Reading → VerifyingManifest → VerifyingSignature →
254 /// VerifyingAssetHash → VerifyingIngredient
255 enum class ProgressPhase : uint8_t {
256 Reading = 0,
262 Thumbnail = 6,
263 Hashing = 7,
264 Signing = 8,
265 Embedding = 9,
267 Writing = 11,
268 FetchingOCSP = 12,
270 };
271
272 /// @brief Type alias for the progress callback passed to ContextBuilder::with_progress_callback().
273 ///
274 /// @details The callback is invoked at each major phase of signing and reading operations.
275 /// Returning false from the callback aborts the operation with an
276 /// OperationCancelled error (equivalent to calling Context::cancel()).
277 ///
278 /// @param phase Current operation phase.
279 /// @param step 1-based step index within the phase.
280 /// 0 = indeterminate (use as liveness signal); resets to 1 at each new phase.
281 /// @param total 0 = indeterminate; 1 = single-shot; >1 = determinate (step/total = fraction).
282 /// @return true to continue the operation, false to request cancellation.
283 ///
284 /// @note The callback must not throw. If it throws, the implementation catches the
285 /// exception and reports cancellation to the underlying library (same as returning
286 /// false); the original exception is not propagated. Prefer returning false or
287 /// using Context::cancel() instead of throwing.
288 ///
289 using ProgressCallbackFunc = std::function<bool(ProgressPhase phase, uint32_t step, uint32_t total)>;
290
291 /// @brief C2PA context implementing IContextProvider.
292 /// @details Context objects manage C2PA SDK configuration and state.
293 /// Contexts can be created via direct construction or the ContextBuilder:
294 ///
295 /// Direct construction:
296 /// @code
297 /// c2pa::Context ctx; // default
298 /// c2pa::Context ctx(settings); // from Settings
299 /// c2pa::Context ctx(json); // from JSON string
300 /// @endcode
301 ///
302 /// ContextBuilder (for multi-step configuration):
303 /// @code
304 /// auto ctx = c2pa::Context::ContextBuilder()
305 /// .with_settings(settings)
306 /// .with_json(json)
307 /// .create_context();
308 /// @endcode
309 ///
310 /// Builder and Reader take the context by reference (IContextProvider&).
311 /// The context object must outlive the Builder or Reader instance.
313 public:
314 /// @brief ContextBuilder for creating customized Context instances.
315 /// @details Provides a builder pattern for configuring contexts with multiple settings.
316 /// Note: create_context() consumes the builder.
317 /// @note For most use cases, prefer direct construction via the Context constructors.
318 /// The ContextBuilder is useful when you need to layer multiple configuration
319 /// sources (e.g. with_settings() followed by with_json()).
321 public:
323 ~ContextBuilder() noexcept;
324
325 // Move semantics
327 ContextBuilder& operator=(ContextBuilder&&) noexcept;
328
329 // Non-copyable
331 ContextBuilder& operator=(const ContextBuilder&) = delete;
332
333 /// @brief Check if the builder is in a valid state.
334 /// @return true if the builder can be used, false if moved from.
335 [[nodiscard]] bool is_valid() const noexcept;
336
337 /// @brief Configure with Settings object.
338 /// @param settings Settings to use (will be copied into the context). Must be valid (is_valid() true).
339 /// @return Reference to this ContextBuilder for method chaining.
340 /// @throws C2paException if settings are invalid or settings.is_valid() is false.
341 ContextBuilder& with_settings(const Settings& settings);
342
343 /// @brief Configure settings with JSON string.
344 /// @param json JSON configuration string.
345 /// @return Reference to this ContextBuilder for method chaining.
346 /// @throws C2paException if JSON is invalid.
347 ContextBuilder& with_json(const std::string& json);
348
349 /// @brief Configure settings from a JSON settings file.
350 /// @param settings_path Full path to the JSON settings file.
351 /// @return Reference to this ContextBuilder for method chaining.
352 /// @throws C2paException if file cannot be read or JSON is invalid.
353 ContextBuilder& with_json_settings_file(const std::filesystem::path& settings_path);
354
355 /// @brief Set a Signer on the context being built.
356 /// @details After this call the source Signer object is consumed and must
357 /// not be reused, as it becomes part to the context and tied to it.
358 /// If settings also contain a signer, the programmatic signer
359 /// set through this API will be used for signing.
360 /// @param signer Signer to put into the context.
361 /// @return Reference to this ContextBuilder for method chaining.
362 /// @throws C2paException if the builder or signer is invalid.
363 ContextBuilder& with_signer(Signer&& signer);
364
365 /// @brief Attach a progress callback to the context being built.
366 ///
367 /// @details The callback is invoked at each major phase of signing and
368 /// reading operations performed with the resulting context.
369 /// Return false from the callback to abort the current operation
370 /// with an OperationCancelled error.
371 ///
372 /// Phases emitted during a typical sign cycle (in order):
373 /// VerifyingIngredient → VerifyingManifest → VerifyingSignature →
374 /// VerifyingAssetHash → Thumbnail → Hashing → Signing → Embedding →
375 /// (if verify_after_sign) VerifyingManifest → … → VerifyingIngredient
376 ///
377 /// Phases emitted during reading:
378 /// Reading → VerifyingManifest → VerifyingSignature →
379 /// VerifyingAssetHash → VerifyingIngredient
380 ///
381 /// @param callback A callable matching ProgressCallbackFunc. The callback is
382 /// heap-allocated and owned by the resulting Context. Calling this method
383 /// more than once on the same builder replaces the previous callback.
384 /// The callable must not throw when invoked (see ProgressCallbackFunc).
385 /// @return Reference to this ContextBuilder for method chaining.
386 /// @throws C2paException if the builder is invalid or the C API call fails.
387 ///
388 ContextBuilder& with_progress_callback(ProgressCallbackFunc callback);
389
390 /// @brief Create a Context from the current builder configuration.
391 /// @return A new Context instance.
392 /// @throws C2paException if context creation fails.
393 /// @note This consumes the builder. After calling this, is_valid() returns false.
394 [[nodiscard]] Context create_context();
395
396 /// @brief Release ownership of the underlying C2paContextBuilder pointer.
397 /// After this call, the ContextBuilder no longer owns the pointer
398 /// and is_valid() returns false. The caller is responsible for managing
399 /// the lifetime of the returned pointer.
400 /// @return Pointer to the C2paContextBuilder object, or nullptr if moved from.
401 C2paContextBuilder* release() noexcept;
402
403 private:
404 C2paContextBuilder* context_builder;
405 std::unique_ptr<ProgressCallbackFunc> pending_callback_;
406 };
407
408 // Direct construction
409 /// @brief Create a Context with default settings.
410 /// @throws C2paException if context creation fails.
412
413 /// @brief Create a Context configured with a Settings object.
414 /// @param settings Settings configuration to apply. Must be valid (settings.is_valid() true).
415 /// @throws C2paException if settings are invalid, settings.is_valid() is false, or context creation fails.
416 explicit Context(const Settings& settings);
417
418 /// @brief Create a Context configured with a JSON string.
419 /// @param json JSON configuration string.
420 /// @throws C2paException if JSON is invalid or context creation fails.
421 explicit Context(const std::string& json);
422
423 /// @brief Create a Context with a Settings object and a Signer.
424 /// @param settings Settings configuration to apply.
425 /// @param signer Signer to move into the context. Consumed after this call.
426 /// The programmatic Signer from the signer parameter
427 /// takes priority over the Signer in settings, so use this API
428 /// when wanting to explicitly set a Signer (or override the Signer in settings).
429 /// @throws C2paException if settings or signer are invalid, or context creation fails.
430 Context(const Settings& settings, Signer&& signer);
431
432 // Non-copyable, moveable
433 Context(const Context&) = delete;
434 Context& operator=(const Context&) = delete;
435 Context(Context&&) noexcept;
436 Context& operator=(Context&&) noexcept;
437
438 ~Context() noexcept override;
439
440 // IContextProvider implementation
441 /// @brief Get the underlying C2PA context pointer.
442 /// @return C2paContext pointer when is_valid() is true; nullptr when moved-from (is_valid() false).
443 /// @note Callers must check is_valid() before using the result; do not pass nullptr to the C API.
444 [[nodiscard]] C2paContext* c_context() const noexcept override;
445
446 /// @brief Check if this Context has a valid context (validity check for context-like types).
447 /// @return true when the object holds a valid C context; false when moved-from.
448 /// @note After move, is_valid() is false and c_context() returns nullptr.
449 [[nodiscard]] bool is_valid() const noexcept override;
450
451 /// @brief Internal constructor from raw FFI pointer (prefer public constructors).
452 /// @param ctx Raw C2paContext pointer — Context takes ownership.
453 /// @throws C2paException if ctx is nullptr.
454 explicit Context(C2paContext* ctx);
455
456 /// @brief Request cancellation of any in-progress operation on this context.
457 ///
458 /// @details Safe to call from another thread while this Context remains valid
459 /// and is not being destroyed or moved concurrently with this call.
460 /// While a signing or reading operation is running on a valid Context,
461 /// the operation is aborted with an OperationCancelled error at the
462 /// next progress checkpoint. Has no effect if no operation is currently
463 /// in progress, or if this object is moved-from (is_valid() is false).
464 ///
465 void cancel() noexcept;
466
467 private:
468 C2paContext* context;
469
470 /// Heap-owned ProgressCallbackFunc; non-null only when set via
471 /// ContextBuilder::with_progress_callback(). Deleted in the destructor.
472 void* callback_owner_ = nullptr;
473 };
474
475 /// @brief Get the version of the C2PA library.
476 /// @return Version string.
477 std::string C2PA_CPP_API version();
478
479 /// @brief Load C2PA settings from a string in a given format.
480 /// @param data The configuration data to load.
481 /// @param format The mimetype of the string.
482 /// @throws C2paException for errors encountered by the C2PA library.
483 /// @deprecated Use Context constructors or Context::ContextBuilder instead for better thread safety.
484 [[deprecated("Use Context::from_json() or Context::from_settings() instead")]]
485 void C2PA_CPP_API load_settings(const std::string& data, const std::string& format);
486
487 /// @brief Read a file and return the manifest JSON.
488 /// @param source_path The path to the file to read.
489 /// @param data_dir Optional directory to store binary resources.
490 /// @return Optional string containing the manifest JSON if a manifest was found.
491 /// @throws C2paException for errors encountered by the C2PA library.
492 /// @deprecated Use Reader object instead.
493 [[deprecated("Use Reader object instead")]]
494 std::optional<std::string> C2PA_CPP_API read_file(const std::filesystem::path &source_path, const std::optional<std::filesystem::path> data_dir = std::nullopt);
495
496 /// @brief Read a file and return an ingredient JSON.
497 /// @param source_path The path to the file to read.
498 /// @param data_dir The directory to store binary resources.
499 /// @return String containing the ingredient JSON.
500 /// @throws C2paException for errors encountered by the C2PA library.
501 /// @deprecated Use Reader and Builder.add_ingredient instead.
502 [[deprecated("Use Reader and Builder.add_ingredient")]]
503 std::string C2PA_CPP_API read_ingredient_file(const std::filesystem::path &source_path, const std::filesystem::path &data_dir);
504
505 /// @brief Add a manifest and sign a file.
506 /// @param source_path The path to the asset to be signed.
507 /// @param dest_path The path to write the signed file to.
508 /// @param manifest The manifest JSON to add to the file.
509 /// @param signer_info The signer info to use for signing.
510 /// @param data_dir Optional directory to store binary resources.
511 /// @throws C2paException for errors encountered by the C2PA library.
512 /// @deprecated Use Builder.sign instead.
513 [[deprecated("Use Builder.sign instead")]]
514 void C2PA_CPP_API sign_file(const std::filesystem::path &source_path,
515 const std::filesystem::path &dest_path,
516 const char *manifest,
517 SignerInfo *signer_info,
518 const std::optional<std::filesystem::path> data_dir = std::nullopt);
519
520 /// @defgroup StreamWrappers Stream wrappers for C2PA C API
521 /// @brief C++ stream types that adapt stream types to C2paStream.
522 ///
523 /// The C2PA C API expects a C2paStream with four callbacks: reader, writer, seeker, flusher.
524 /// The contract for each callback is:
525 /// - reader(context, buffer, size): read up to size bytes into buffer; return bytes read, or -1 on error (set errno).
526 /// - writer(context, buffer, size): write size bytes from buffer; return bytes written, or -1 on error (set errno).
527 /// - seeker(context, offset, whence): seek to offset (whence = Start/Current/End); return new position or -1 (set errno).
528 /// - flusher(context): flush; return 0 on success, -1 on error (set errno).
529
530 /// @brief Input stream IStream wrapper for C2paStream.
531 /// @details This class is used to wrap an input stream for use with the C2PA library.
532 class C2PA_CPP_API CppIStream : public C2paStream
533 {
534 public:
535 /// @brief Pointer to the underlying C2paStream.
536 C2paStream *c_stream;
537
538 /// @brief Construct an input stream wrapper from a std::istream-derived object.
539 /// @tparam IStream Type derived from std::istream.
540 /// @param istream The input stream to wrap (must be open and valid).
541 /// @throws C2paException if stream wrapper creation fails.
542 template <typename IStream>
543 explicit CppIStream(IStream &istream) {
544 static_assert(std::is_base_of<std::istream, IStream>::value,
545 "Stream must be derived from std::istream");
546 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&istream), reader, seeker, writer, flusher);
547 if (c_stream == nullptr) {
548 throw C2paException("Failed to create input stream wrapper: is stream open and valid?");
549 }
550 }
551
552 CppIStream(const CppIStream &) = delete;
553
554 CppIStream &operator=(const CppIStream &) = delete;
555
556 CppIStream(CppIStream &&) = delete;
557
559
561
562 private:
563 /// @brief Reader callback implementation.
564 /// @param context Stream context pointer.
565 /// @param buffer Buffer to read into.
566 /// @param size Number of bytes to read.
567 /// @return Number of bytes read, or -1 on error (sets errno).
568 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
569
570 /// @brief Writer callback implementation (not used for input streams).
571 /// @param context Stream context pointer.
572 /// @param buffer Buffer to write from.
573 /// @param size Number of bytes to write.
574 /// @return -1 (always fails for input streams).
575 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
576
577 /// @brief Seeker callback implementation.
578 /// @param context Stream context pointer.
579 /// @param offset Offset to seek to.
580 /// @param whence Seek mode (Start/Current/End).
581 /// @return New stream position, or -1 on error (sets errno).
582 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
583
584 /// @brief Flusher callback implementation (no-op for input streams).
585 /// @param context Stream context pointer.
586 /// @return 0 on success.
587 static intptr_t flusher(StreamContext *context);
588
589 friend class Reader;
590 };
591
592 /// @brief Output stream OStream wrapper for C2paStream.
593 /// @details This class is used to wrap an output stream for use with the C2PA library.
594 class C2PA_CPP_API CppOStream : public C2paStream
595 {
596 public:
597 /// @brief Pointer to the underlying C2paStream.
598 C2paStream *c_stream;
599
600 /// @brief Construct an output stream wrapper from a std::ostream-derived object.
601 /// @tparam OStream Type derived from std::ostream.
602 /// @param ostream The output stream to wrap (must be open and valid).
603 /// @throws C2paException if stream wrapper creation fails.
604 template <typename OStream>
605 explicit CppOStream(OStream &ostream) {
606 static_assert(std::is_base_of<std::ostream, OStream>::value, "Stream must be derived from std::ostream");
607 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&ostream), reader, seeker, writer, flusher);
608 if (c_stream == nullptr) {
609 throw C2paException("Failed to create output stream wrapper: is stream open and valid?");
610 }
611 }
612
613 CppOStream(const CppOStream &) = delete;
614
615 CppOStream &operator=(const CppOStream &) = delete;
616
617 CppOStream(CppOStream &&) = delete;
618
620
622
623 private:
624 /// @brief Reader callback implementation (not used for output streams).
625 /// @param context Stream context pointer.
626 /// @param buffer Buffer to read into.
627 /// @param size Number of bytes to read.
628 /// @return -1 (always fails for output streams).
629 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
630
631 /// @brief Writer callback implementation.
632 /// @param context Stream context pointer.
633 /// @param buffer Buffer to write from.
634 /// @param size Number of bytes to write.
635 /// @return Number of bytes written, or -1 on error (sets errno).
636 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
637
638 /// @brief Seeker callback implementation.
639 /// @param context Stream context pointer.
640 /// @param offset Offset to seek to.
641 /// @param whence Seek mode (Start/Current/End).
642 /// @return New stream position, or -1 on error (sets errno).
643 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
644
645 /// @brief Flusher callback implementation.
646 /// @param context Stream context pointer.
647 /// @return 0 on success, -1 on error (sets errno).
648 static intptr_t flusher(StreamContext *context);
649 };
650
651 /// @brief IOStream Class wrapper for C2paStream.
652 /// @details This class is used to wrap an input/output stream for use with the C2PA library.
653 class C2PA_CPP_API CppIOStream : public C2paStream
654 {
655 public:
656 /// @brief Pointer to the underlying C2paStream.
657 C2paStream *c_stream;
658
659 /// @brief Construct an I/O stream wrapper from a std::iostream-derived object.
660 /// @tparam IOStream Type derived from std::iostream.
661 /// @param iostream The I/O stream to wrap (must be open and valid).
662 /// @throws C2paException if stream wrapper creation fails.
663 template <typename IOStream>
664 CppIOStream(IOStream &iostream) {
665 static_assert(std::is_base_of<std::iostream, IOStream>::value, "Stream must be derived from std::iostream");
666 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&iostream), reader, seeker, writer, flusher);
667 if (c_stream == nullptr) {
668 throw C2paException("Failed to create I/O stream wrapper: is stream open and valid?");
669 }
670 }
671
672 CppIOStream(const CppIOStream &) = delete;
673
675
677
679
681
682 private:
683 /// @brief Reader callback implementation.
684 /// @param context Stream context pointer.
685 /// @param buffer Buffer to read into.
686 /// @param size Number of bytes to read.
687 /// @return Number of bytes read, or -1 on error (sets errno).
688 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
689
690 /// @brief Writer callback implementation.
691 /// @param context Stream context pointer.
692 /// @param buffer Buffer to write from.
693 /// @param size Number of bytes to write.
694 /// @return Number of bytes written, or -1 on error (sets errno).
695 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
696
697 /// @brief Seeker callback implementation.
698 /// @param context Stream context pointer.
699 /// @param offset Offset to seek to.
700 /// @param whence Seek mode (Start/Current/End).
701 /// @return New stream position, or -1 on error (sets errno).
702 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
703
704 /// @brief Flusher callback implementation.
705 /// @param context Stream context pointer.
706 /// @return 0 on success, -1 on error (sets errno).
707 static intptr_t flusher(StreamContext *context);
708 };
709
710 /// @brief Reader class for reading a manifest.
711 /// @details This class is used to read and validate a manifest from a stream or file.
712 /// Resources are managed using RAII; member order ensures cpp_stream (which
713 /// holds a C stream pointing at the ifstream) is destroyed before owned_stream.
715 {
716 private:
717 C2paReader *c2pa_reader;
718 std::unique_ptr<std::ifstream> owned_stream; // Owns file stream when created from path
719 std::unique_ptr<CppIStream> cpp_stream; // Wraps stream for C API; destroyed before owned_stream
720
721 public:
722 /// @brief Create a Reader from a context and stream.
723 /// @param context Context provider; used at construction to configure settings.
724 /// @param format The mime format of the stream.
725 /// @param stream The input stream to read from.
726 /// @throws C2paException if context.is_valid() returns false,
727 /// or for other errors encountered by the C2PA library.
728 Reader(IContextProvider& context, const std::string &format, std::istream &stream);
729
730 /// @brief Create a Reader from a context and file path.
731 /// @param context Context provider; used at construction only to configure settings.
732 /// @param source_path The path to the file to read.
733 /// @throws C2paException if context.is_valid() returns false,
734 /// or for other errors encountered by the C2PA library.
735 /// @note Prefer using the streaming APIs if possible.
736 Reader(IContextProvider& context, const std::filesystem::path &source_path);
737
738 /// @brief Create a Reader from a stream (will use global settings if any loaded).
739 /// @details The validation_status field in the JSON contains validation results.
740 /// @param format The mime format of the stream.
741 /// @param stream The input stream to read from.
742 /// @throws C2paException for errors encountered by the C2PA library.
743 /// @deprecated Use Reader(IContextProvider& context, format, stream) instead.
744 [[deprecated("Use Reader(IContextProvider& context, format, stream) instead")]]
745 Reader(const std::string &format, std::istream &stream);
746
747 /// @brief Create a Reader from a file path (will use global settings if any loaded).
748 /// @param source_path The path to the file to read.
749 /// @throws C2paException for errors encountered by the C2PA library.
750 /// @deprecated Use Reader(IContextProvider& context, source_path) instead.
751 /// @note Prefer using the streaming APIs if possible.
752 [[deprecated("Use Reader(IContextProvider& context, source_path) instead")]]
753 Reader(const std::filesystem::path &source_path);
754
755 /// @brief Try to open a Reader from a context and file path when the asset may lack C2PA data.
756 /// @return A Reader if JUMBF (c2pa/manifest) data is present; std::nullopt if none.
757 /// @throws C2paException for errors other than a missing manifest (e.g. invalid asset).
758 /// @throws std::system_error if the file cannot be opened.
759 static std::optional<Reader> from_asset(IContextProvider& context, const std::filesystem::path &source_path);
760
761 /// @brief Try to create a Reader from a context and stream when the asset may lack C2PA data.
762 /// @return A Reader if JUMBF (c2pa/manifest) data is present; std::nullopt if none.
763 /// @throws C2paException for errors other than a missing manifest.
764 static std::optional<Reader> from_asset(IContextProvider& context, const std::string &format, std::istream &stream);
765
766 // Non-copyable
767 Reader(const Reader&) = delete;
768
769 Reader& operator=(const Reader&) = delete;
770
771 Reader(Reader&& other) noexcept
772 : c2pa_reader(std::exchange(other.c2pa_reader, nullptr)),
773 owned_stream(std::move(other.owned_stream)),
774 cpp_stream(std::move(other.cpp_stream)) {
775 }
776
777 Reader& operator=(Reader&& other) noexcept {
778 if (this != &other) {
779 c2pa_free(c2pa_reader);
780 c2pa_reader = std::exchange(other.c2pa_reader, nullptr);
781 owned_stream = std::move(other.owned_stream);
782 cpp_stream = std::move(other.cpp_stream);
783 }
784 return *this;
785 }
786
788
789 /// @brief Check if the reader was created from an embedded manifest.
790 /// @return true if the manifest was embedded in the asset, false if external.
791 /// @throws C2paException for errors encountered by the C2PA library.
792 [[nodiscard]] inline bool is_embedded() const {
793 return c2pa_reader_is_embedded(c2pa_reader);
794 }
795
796 /// @brief Returns the remote url of the manifest if this `Reader`
797 /// obtained the manifest remotely
798 /// @return Optional string containing the remote URL, or std::nullopt if manifest was embedded.
799 /// @throws C2paException for errors encountered by the C2PA library.
800 [[nodiscard]] std::optional<std::string> remote_url() const;
801
802 /// @brief Get the manifest as a JSON string.
803 /// @return The manifest as a JSON string.
804 /// @throws C2paException for errors encountered by the C2PA library.
805 std::string json() const;
806
807 /// @brief Get a resource from the reader and write it to a file.
808 /// @param uri The URI of the resource.
809 /// @param path The file path to write the resource to.
810 /// @return The number of bytes written.
811 /// @throws C2paException for errors encountered by the C2PA library.
812 /// @note Prefer using the streaming APIs if possible.
813 int64_t get_resource(const std::string &uri, const std::filesystem::path &path);
814
815 /// @brief Get a resource from the reader and write it to an output stream.
816 /// @param uri The URI of the resource.
817 /// @param stream The output stream to write the resource to.
818 /// @return The number of bytes written.
819 /// @throws C2paException for errors encountered by the C2PA library.
820 int64_t get_resource(const std::string &uri, std::ostream &stream);
821
822 /// @brief Get the raw C2paReader pointer.
823 /// @return The raw C2paReader pointer.
824 /// @note This is intended for internal API use and compatibility with C APIs.
825 C2paReader* get_api_internal_raw_reader() const { return c2pa_reader; }
826
827 /// @brief Get a list of mime types that the SDK can read manifests from.
828 /// @return Vector of supported MIME type strings.
829 static std::vector<std::string> supported_mime_types();
830 };
831
832 /// @brief Signer callback function type.
833 /// @details This function type is used to create a callback function for signing.
834 /// The callback receives data to sign and returns the signature.
835 /// @param data The data to sign.
836 /// @return The signature as a vector of bytes.
837 using SignerFunc = std::vector<unsigned char>(const std::vector<unsigned char> &);
838
839 /// @brief Signer class for creating a Signer
840 /// @details This class is used to create a signer from a signing algorithm, certificate, and TSA URI.
841 /// Supports both callback-based and direct signing methods.
843 {
845
846 private:
847 C2paSigner *signer;
848
849 /// @brief Transfers ownership of the underlying C2paSigner pointer out
850 /// of this wrapper, without freeing it.
851 /// @details Used by ContextBuilder::with_signer() to pass the raw pointer
852 /// to c2pa_context_builder_set_signer(), which takes ownership on
853 /// the Rust side via Box::from_raw. After this call the Signer
854 /// wrapper holds nullptr and its destructor is a no-op.
855 /// This is not the same as c2pa_signer_free(), which destroys
856 /// the signer. Similar to std::unique_ptr::release().
857 /// @return Raw C2paSigner pointer, or nullptr if already released.
858 C2paSigner* release() noexcept {
859 return std::exchange(signer, nullptr);
860 }
861
862 /// @brief Validate a TSA URI string.
863 /// @param tsa_uri The TSA URI to validate.
864 /// @return Validated C-string pointer.
865 static const char *validate_tsa_uri(const std::string &tsa_uri);
866
867 /// @brief Validate an optional TSA URI.
868 /// @param tsa_uri The optional TSA URI to validate.
869 /// @return Validated C-string pointer, or nullptr if nullopt.
870 static const char *validate_tsa_uri(const std::optional<std::string> &tsa_uri);
871
872 public:
873 /// @brief Create a Signer from a callback function.
874 /// @param callback The callback function to use for signing.
875 /// @param alg The signing algorithm to use (e.g., C2paSigningAlg::PS256).
876 /// @param sign_cert The signing certificate in PEM format.
877 /// @param tsa_uri The timestamp authority URI for time-stamping.
878 /// @throws C2paException if signer creation fails.
879 Signer(SignerFunc *callback, C2paSigningAlg alg, const std::string &sign_cert, const std::string &tsa_uri);
880
881 /// @brief Create a signer from a Signer pointer and take ownership of that pointer.
882 /// @param c_signer The C2paSigner pointer (must be non-null).
883 Signer(C2paSigner *c_signer) : signer(c_signer) {
884 if (!c_signer) {
885 throw C2paException("Signer can not be null");
886 }
887 }
888
889 /// @brief Create a Signer from signing credentials.
890 /// @param alg Signing algorithm name (e.g., "ps256", "es256").
891 /// @param sign_cert Signing certificate in PEM format.
892 /// @param private_key Private key in PEM format.
893 /// @param tsa_uri Optional timestamp authority URI.
894 /// @throws C2paException if signer creation fails.
895 Signer(const std::string &alg, const std::string &sign_cert, const std::string &private_key, const std::optional<std::string> &tsa_uri = std::nullopt);
896
897 Signer(const Signer&) = delete;
898
899 Signer& operator=(const Signer&) = delete;
900
901 /// @brief Move constructor.
902 /// @param other Signer to move from.
903 Signer(Signer&& other) noexcept : signer(std::exchange(other.signer, nullptr)) {
904 }
905
906 Signer& operator=(Signer&& other) noexcept {
907 if (this != &other) {
908 c2pa_free(signer);
909 signer = std::exchange(other.signer, nullptr);
910 }
911 return *this;
912 }
913
915
916 /// @brief Get the size to reserve for a signature for this Signer.
917 /// @return Reserved size for the signature in bytes.
918 uintptr_t reserve_size();
919
920 /// @brief Get the underlying C2paSigner pointer.
921 /// @return Pointer to the C2paSigner object.
922 C2paSigner *c2pa_signer() const noexcept;
923 };
924
925 /// @brief Builder class for creating a manifest.
926 /// @details This class is used to create a manifest from a json std::string and add resources and ingredients to the manifest.
928 {
929 private:
930 C2paBuilder *builder;
931
932 public:
933 /// @brief Create a Builder from a context with an empty manifest.
934 /// @param context Context provider; used at construction to configure settings.
935 /// @throws C2paException if context.is_valid() returns false,
936 /// or for other errors encountered by the C2PA library.
937 explicit Builder(IContextProvider& context);
938
939 /// @brief Create a Builder from a context and manifest JSON string.
940 /// @param context Context provider; used at construction to configure settings.
941 /// @param manifest_json The manifest JSON string.
942 /// @throws C2paException if context.is_valid() returns false,
943 /// or for other errors encountered by the C2PA library.
944 Builder(IContextProvider& context, const std::string &manifest_json);
945
946 /// @brief Create a Builder from a manifest JSON string (will use global settings if any loaded).
947 /// @param manifest_json The manifest JSON string.
948 /// @throws C2paException for errors encountered by the C2PA library.
949 /// @deprecated Use Builder(IContextProvider& context, manifest_json) instead.
950 [[deprecated("Use Builder(IContextProvider& context, manifest_json) instead")]]
951 Builder(const std::string &manifest_json);
952
953 /// @brief Create a Builder from a raw C FFI builder.
954 /// @param builder Raw C2paBuilder pointer to wrap.
955 /// @throws C2paException if builder is nullptr.
956 explicit Builder(C2paBuilder *builder);
957
958 Builder(const Builder&) = delete;
959
960 Builder& operator=(const Builder&) = delete;
961
962 Builder(Builder&& other) noexcept : builder(std::exchange(other.builder, nullptr)) {
963 }
964
965 Builder& operator=(Builder&& other) noexcept {
966 if (this != &other) {
967 c2pa_free(builder);
968 builder = std::exchange(other.builder, nullptr);
969 }
970 return *this;
971 }
972
974
975 /// @brief Get the underlying C2paBuilder pointer.
976 /// @return Pointer managed by this wrapper.
977 C2paBuilder *c2pa_builder() const noexcept;
978
979 /// @brief Set or update the manifest definition.
980 /// @param manifest_json The manifest JSON string.
981 /// @return Reference to this Builder for method chaining.
982 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
983 Builder& with_definition(const std::string &manifest_json);
984
985 /// @brief Set the no-embed flag to prevent embedding the manifest in the asset.
986 /// @details When set, the manifest will be stored externally rather than embedded.
987 void set_no_embed();
988
989 /// @brief Set the remote URL.
990 /// @param remote_url The remote URL to set.
991 /// @throws C2paException for errors encountered by the C2PA library.
992 void set_remote_url(const std::string &remote_url);
993
994 /// @brief Set the base path for loading resources from files.
995 /// @details When set, resources are loaded from files relative to this path.
996 /// If not set, resources are loaded from memory.
997 /// @param base_path The base directory path.
998 /// @throws C2paException for errors encountered by the C2PA library.
999 /// @deprecated This method is planned to be deprecated in a future release.
1000 /// Usage should be limited and temporary. Use add_resource instead.
1001 void set_base_path(const std::string &base_path);
1002
1003 /// @brief Add a resource to the builder from a stream.
1004 /// @param uri The URI identifier for the resource.
1005 /// @param source The input stream to read the resource from.
1006 /// @throws C2paException for errors encountered by the C2PA library.
1007 void add_resource(const std::string &uri, std::istream &source);
1008
1009 /// @brief Add a resource to the builder from a file.
1010 /// @param uri The URI identifier for the resource.
1011 /// @param source_path The path to the resource file.
1012 /// @throws C2paException for errors encountered by the C2PA library.
1013 /// @note Prefer using the streaming APIs if possible.
1014 void add_resource(const std::string &uri, const std::filesystem::path &source_path);
1015
1016 /// @brief Add an ingredient to the builder from a stream.
1017 /// @param ingredient_json Any fields of the ingredient you want to define.
1018 /// @param format The mime format of the ingredient.
1019 /// @param source The input stream to read the ingredient from.
1020 /// @throws C2paException for errors encountered by the C2PA library.
1021 void add_ingredient(const std::string &ingredient_json, const std::string &format, std::istream &source);
1022
1023 /// @brief Add an ingredient to the builder from a file.
1024 /// @param ingredient_json Any fields of the ingredient you want to define.
1025 /// @param source_path The path to the ingredient file.
1026 /// @throws C2paException for errors encountered by the C2PA library.
1027 /// @note Prefer using the streaming APIs if possible.
1028 void add_ingredient(const std::string &ingredient_json, const std::filesystem::path &source_path);
1029
1030 /// @brief Add an action to the manifest.
1031 /// @param action_json JSON string containing the action data.
1032 /// @throws C2paException for errors encountered by the C2PA library.
1033 void add_action(const std::string &action_json);
1034
1035 /// @brief Set the intent for this Builder, controlling what kind of manifest to create.
1036 /// @param intent The intent type: Create, Edit, or Update.
1037 /// @param digital_source_type Required for Create intent. Describes how the asset was produced.
1038 /// Defaults to Empty.
1039 /// @throws C2paException if the intent cannot be set.
1040 void set_intent(C2paBuilderIntent intent, C2paDigitalSourceType digital_source_type = Empty);
1041
1042 /// @brief Sign an input stream and write the signed data to an output stream.
1043 /// @param format The mime format of the output stream.
1044 /// @param source The input stream to sign.
1045 /// @param dest The output stream to write the signed data to.
1046 /// @param signer The Signer object to use for signing.
1047 /// @return A vector containing the signed manifest bytes.
1048 /// @throws C2paException for errors encountered by the C2PA library.
1049 /// @deprecated Use sign(const string&, std::istream&, std::iostream&, Signer&) instead.
1050 std::vector<unsigned char> sign(const std::string &format, std::istream &source, std::ostream &dest, Signer &signer);
1051
1052 /// @brief Sign an input stream and write the signed data to an I/O stream.
1053 /// @param format The mime format of the output.
1054 /// @param source The input stream to sign.
1055 /// @param dest The I/O stream to write the signed data to.
1056 /// @param signer The Signer object to use for signing.
1057 /// @return A vector containing the signed manifest bytes.
1058 /// @throws C2paException for errors encountered by the C2PA library.
1059 std::vector<unsigned char> sign(const std::string &format, std::istream &source, std::iostream &dest, Signer &signer);
1060
1061 /// @brief Sign a file and write the signed data to an output file.
1062 /// @param source_path The path to the file to sign.
1063 /// @param dest_path The path to write the signed file to.
1064 /// @param signer The signer object to use for signing.
1065 /// @return A vector containing the signed manifest bytes.
1066 /// @throws C2paException for errors encountered by the C2PA library.
1067 /// @note Prefer using the streaming APIs if possible.
1068 std::vector<unsigned char> sign(const std::filesystem::path &source_path, const std::filesystem::path &dest_path, Signer &signer);
1069
1070 /// @brief Sign using the signer from the Builder's Context.
1071 /// @details The Signer may have been set programmatically via
1072 /// ContextBuilder::with_signer(), or configured in settings JSON.
1073 /// If both programmatic and settings signers are present,
1074 /// the programmatic signer takes priority.
1075 /// @param format The mime format of the output.
1076 /// @param source The input stream to sign.
1077 /// @param dest The I/O stream to write the signed data to.
1078 /// @return A vector containing the signed manifest bytes.
1079 /// @throws C2paException if the context has no signer or on other errors.
1080 std::vector<unsigned char> sign(const std::string &format, std::istream &source, std::iostream &dest);
1081
1082 /// @brief Sign a file using the signer from the Builder's Context.
1083 /// @details The signer may have been set programmatically via
1084 /// ContextBuilder::with_signer(), or configured in settings JSON.
1085 /// If both programmatic and settings signers are present,
1086 /// the programmatic signer takes priority.
1087 /// @param source_path The path to the file to sign.
1088 /// @param dest_path The path to write the signed file to.
1089 /// @return A vector containing the signed manifest bytes.
1090 /// @throws C2paException if the context has no signer or on other errors.
1091 std::vector<unsigned char> sign(const std::filesystem::path &source_path, const std::filesystem::path &dest_path);
1092
1093 /// @brief Create a Builder from an archived Builder stream.
1094 /// @param archive The input stream to read the archive from.
1095 /// @return A new Builder instance loaded from the archive.
1096 /// @throws C2paException for errors encountered by the C2PA library.
1097 static Builder from_archive(std::istream &archive);
1098
1099 /// @brief Create a Builder from an archive.
1100 /// @param archive_path The path to the archive file.
1101 /// @return A new Builder instance loaded from the archive.
1102 /// @throws C2paException for errors encountered by the C2PA library.
1103 /// @note Prefer using the streaming APIs if possible.
1104 static Builder from_archive(const std::filesystem::path &archive_path);
1105
1106 /// @brief Load an archive into this builder.
1107 /// @details Replaces the current definition with the archived builder state.
1108 /// @param archive The input stream to read the archive from.
1109 /// @return Reference to this builder for method chaining.
1110 /// @throws C2paException for errors encountered by the C2PA library.
1111 /// @note This allows setting a context before loading the archive, preserving context settings.
1112 Builder& with_archive(std::istream &archive);
1113
1114 /// @brief Write the builder to an archive stream.
1115 /// @param dest The output stream to write the archive to.
1116 /// @throws C2paException for errors encountered by the C2PA library.
1117 void to_archive(std::ostream &dest);
1118
1119 /// @brief Write the builder to an archive file.
1120 /// @param dest_path The path to write the archive file to.
1121 /// @throws C2paException for errors encountered by the C2PA library.
1122 /// @note Prefer using the streaming APIs if possible.
1123 void to_archive(const std::filesystem::path &dest_path);
1124
1125 /// @brief Create a hashed placeholder from the builder.
1126 /// @param reserved_size The size required for a signature from the intended signer (in bytes).
1127 /// @param format The mime format or extension of the asset.
1128 /// @return A vector containing the hashed placeholder bytes.
1129 /// @throws C2paException for errors encountered by the C2PA library.
1130 std::vector<unsigned char> data_hashed_placeholder(uintptr_t reserved_size, const std::string &format);
1131
1132 /// @brief Sign a Builder using the specified signer and data hash.
1133 /// @param signer The signer to use for signing.
1134 /// @param data_hash The data hash ranges to sign (must contain hashes unless an asset is provided).
1135 /// @param format The mime format for embedding. Use "c2pa" for an unformatted result.
1136 /// @param asset Optional asset to hash according to the data_hash information.
1137 /// @return A vector containing the signed embeddable data.
1138 /// @throws C2paException for errors encountered by the C2PA library.
1139 std::vector<unsigned char> sign_data_hashed_embeddable(Signer &signer, const std::string &data_hash, const std::string &format, std::istream *asset = nullptr);
1140
1141 /// @brief Convert unformatted manifest data to an embeddable format.
1142 /// @param format The format for embedding.
1143 /// @param data Unformatted manifest data from sign_data_hashed_embeddable using "c2pa" format.
1144 /// @return A formatted copy of the data.
1145 static std::vector<unsigned char> format_embeddable(const std::string &format, std::vector<unsigned char> &data);
1146
1147 /// @brief Check if the given format requires a placeholder embedding step.
1148 /// @details Returns false for BoxHash-capable formats when prefer_box_hash is enabled in
1149 /// the context settings (no placeholder needed — hash covers the full asset).
1150 /// Always returns true for BMFF formats (MP4, etc.) regardless of settings.
1151 /// @param format The MIME type or extension of the asset (e.g. "image/jpeg", "video/mp4").
1152 /// @return true if placeholder() must be called and embedded before sign_embeddable(); false otherwise.
1153 /// @throws C2paException on error.
1154 bool needs_placeholder(const std::string &format);
1155
1156 /// @brief Create a composed placeholder manifest to embed in the asset.
1157 /// @details The signer (and its reserve size) are obtained from the Builder's Context.
1158 /// For BMFF assets, the placeholder includes a BmffHash assertion with
1159 /// default exclusions for the manifest UUID box.
1160 /// Returns empty bytes for formats that do not need a placeholder (BoxHash).
1161 /// The placeholder size is stored internally so sign_embeddable() returns bytes
1162 /// of exactly the same size, enabling in-place patching.
1163 /// @param format The MIME type or extension of the asset (e.g. "image/jpeg", "video/mp4").
1164 /// @return Composed placeholder bytes ready to embed into the asset.
1165 /// @throws C2paException on error.
1166 std::vector<unsigned char> placeholder(const std::string &format);
1167
1168 /// @brief Register the byte ranges where the placeholder was embedded (DataHash workflow).
1169 /// @details Call this after embedding the placeholder bytes into the asset and before
1170 /// update_hash_from_stream(). The exclusions replace the dummy ranges set by
1171 /// placeholder() so the asset hash covers all bytes except the manifest slot.
1172 /// Exclusions are (start, length) pairs in asset byte coordinates.
1173 /// @param exclusions Vector of (start, length) pairs describing the embedded placeholder region.
1174 /// @throws C2paException if no DataHash assertion exists or on other error.
1175 void set_data_hash_exclusions(const std::vector<std::pair<uint64_t, uint64_t>> &exclusions);
1176
1177 /// @brief Compute and store the asset hash by reading a stream.
1178 /// @details Automatically detects the hard binding type from the builder state:
1179 /// - DataHash: uses exclusion ranges already registered via set_data_hash_exclusions().
1180 /// - BmffHash: uses path-based exclusions from the BMFF assertion (UUID box, mdat).
1181 /// - BoxHash: hashes each format-specific box individually.
1182 /// Call set_data_hash_exclusions() before this for DataHash workflows.
1183 /// @param format The MIME type or extension of the asset (e.g. "image/jpeg", "video/mp4").
1184 /// @param stream The asset stream to hash. Must include the embedded placeholder bytes.
1185 /// @throws C2paException on error.
1186 void update_hash_from_stream(const std::string &format, std::istream &stream);
1187
1188 /// @brief Sign and return the final manifest bytes, ready for embedding.
1189 /// @details Operates in two modes:
1190 /// - Placeholder mode (after placeholder()): zero-pads the signed manifest to the
1191 /// pre-committed placeholder size, enabling in-place patching of the asset.
1192 /// - Direct mode (no placeholder): returns the actual signed manifest size.
1193 /// Requires a valid hard binding assertion (set via update_hash_from_stream()).
1194 /// The signer is obtained from the Builder's Context.
1195 /// @param format The MIME type or extension of the asset (e.g. "image/jpeg", "video/mp4").
1196 /// @return Signed manifest bytes ready to embed into the asset.
1197 /// @throws C2paException on error.
1198 std::vector<unsigned char> sign_embeddable(const std::string &format);
1199
1200 /// @brief Get a list of mime types that the Builder supports.
1201 /// @return Vector of supported MIME type strings.
1202 static std::vector<std::string> supported_mime_types();
1203
1204 private:
1205 explicit Builder(std::istream &archive);
1206 };
1207}
1208
1209// Restore warnings
1210#ifdef __GNUC__
1211#pragma GCC diagnostic pop
1212#endif
1213
1214#ifdef _MSC_VER
1215#pragma warning(pop)
1216#endif
1217
1218#endif // C2PA_H
#define C2PA_CPP_API
Definition c2pa.hpp:49
Builder class for creating a manifest.
Definition c2pa.hpp:928
Builder(const std::string &manifest_json)
Create a Builder from a manifest JSON string (will use global settings if any loaded).
Builder & operator=(const Builder &)=delete
Builder(Builder &&other) noexcept
Definition c2pa.hpp:962
Builder(C2paBuilder *builder)
Create a Builder from a raw C FFI builder.
Builder(const Builder &)=delete
C2paBuilder * c2pa_builder() const noexcept
Get the underlying C2paBuilder pointer.
Builder & operator=(Builder &&other) noexcept
Definition c2pa.hpp:965
Builder(IContextProvider &context)
Create a Builder from a context with an empty manifest.
Builder(IContextProvider &context, const std::string &manifest_json)
Create a Builder from a context and manifest JSON string.
Exception class for C2pa errors. This class is used to throw exceptions for errors encountered by the...
Definition c2pa.hpp:87
C2paException & operator=(C2paException &&)=default
~C2paException() override=default
C2paException(const C2paException &)=default
const char * what() const noexcept override
Get the exception message.
C2paException(std::string message)
Construct an exception with a custom error message.
C2paException & operator=(const C2paException &)=default
C2paException(C2paException &&)=default
C2paException()
Default constructor.
ContextBuilder for creating customized Context instances.
Definition c2pa.hpp:320
C2PA context implementing IContextProvider.
Definition c2pa.hpp:312
IOStream Class wrapper for C2paStream.
Definition c2pa.hpp:654
CppIOStream & operator=(const CppIOStream &)=delete
CppIOStream(const CppIOStream &)=delete
CppIOStream & operator=(CppIOStream &&)=delete
C2paStream * c_stream
Pointer to the underlying C2paStream.
Definition c2pa.hpp:657
CppIOStream(IOStream &iostream)
Construct an I/O stream wrapper from a std::iostream-derived object.
Definition c2pa.hpp:664
CppIOStream(CppIOStream &&)=delete
Input stream IStream wrapper for C2paStream.
Definition c2pa.hpp:533
CppIStream & operator=(const CppIStream &)=delete
CppIStream(CppIStream &&)=delete
CppIStream & operator=(CppIStream &&)=delete
C2paStream * c_stream
Pointer to the underlying C2paStream.
Definition c2pa.hpp:536
CppIStream(IStream &istream)
Construct an input stream wrapper from a std::istream-derived object.
Definition c2pa.hpp:543
CppIStream(const CppIStream &)=delete
Output stream OStream wrapper for C2paStream.
Definition c2pa.hpp:595
CppOStream(OStream &ostream)
Construct an output stream wrapper from a std::ostream-derived object.
Definition c2pa.hpp:605
CppOStream(CppOStream &&)=delete
CppOStream & operator=(CppOStream &&)=delete
C2paStream * c_stream
Pointer to the underlying C2paStream.
Definition c2pa.hpp:598
CppOStream & operator=(const CppOStream &)=delete
CppOStream(const CppOStream &)=delete
Interface for types that can provide C2PA context functionality.
Definition c2pa.hpp:151
virtual ~IContextProvider() noexcept=default
Reader class for reading a manifest.
Definition c2pa.hpp:715
bool is_embedded() const
Check if the reader was created from an embedded manifest.
Definition c2pa.hpp:792
std::string json() const
Get the manifest as a JSON string.
static std::optional< Reader > from_asset(IContextProvider &context, const std::string &format, std::istream &stream)
Try to create a Reader from a context and stream when the asset may lack C2PA data.
int64_t get_resource(const std::string &uri, const std::filesystem::path &path)
Get a resource from the reader and write it to a file.
Reader(const std::string &format, std::istream &stream)
Create a Reader from a stream (will use global settings if any loaded).
int64_t get_resource(const std::string &uri, std::ostream &stream)
Get a resource from the reader and write it to an output stream.
static std::optional< Reader > from_asset(IContextProvider &context, const std::filesystem::path &source_path)
Try to open a Reader from a context and file path when the asset may lack C2PA data.
Reader(Reader &&other) noexcept
Definition c2pa.hpp:771
Reader(const Reader &)=delete
Reader & operator=(const Reader &)=delete
std::optional< std::string > remote_url() const
Returns the remote url of the manifest if this Reader obtained the manifest remotely.
Reader(IContextProvider &context, const std::string &format, std::istream &stream)
Create a Reader from a context and stream.
Reader & operator=(Reader &&other) noexcept
Definition c2pa.hpp:777
Reader(const std::filesystem::path &source_path)
Create a Reader from a file path (will use global settings if any loaded).
C2paReader * get_api_internal_raw_reader() const
Get the raw C2paReader pointer.
Definition c2pa.hpp:825
Reader(IContextProvider &context, const std::filesystem::path &source_path)
Create a Reader from a context and file path.
static std::vector< std::string > supported_mime_types()
Get a list of mime types that the SDK can read manifests from.
(C2PA SDK) Settings configuration object for creating contexts.
Definition c2pa.hpp:185
Settings & update(const std::string &data)
Merge configuration from a JSON string (latest configuration wins).
Definition c2pa.hpp:223
C2paSettings * c_settings() const noexcept
Get the raw C FFI settings pointer.
Settings(const std::string &data, const std::string &format)
Create settings from a configuration string.
Settings()
Create default settings.
Settings(Settings &&) noexcept
Settings & update(const std::string &data, const std::string &format)
Merge configuration from a std::string (latest configuration wins).
Signer class for creating a Signer.
Definition c2pa.hpp:843
Signer & operator=(Signer &&other) noexcept
Definition c2pa.hpp:906
uintptr_t reserve_size()
Get the size to reserve for a signature for this Signer.
C2paSigner * c2pa_signer() const noexcept
Get the underlying C2paSigner pointer.
Signer(SignerFunc *callback, C2paSigningAlg alg, const std::string &sign_cert, const std::string &tsa_uri)
Create a Signer from a callback function.
Signer(C2paSigner *c_signer)
Create a signer from a Signer pointer and take ownership of that pointer.
Definition c2pa.hpp:883
Signer & operator=(const Signer &)=delete
Signer(Signer &&other) noexcept
Move constructor.
Definition c2pa.hpp:903
Signer(const Signer &)=delete
Signer(const std::string &alg, const std::string &sign_cert, const std::string &private_key, const std::optional< std::string > &tsa_uri=std::nullopt)
Create a Signer from signing credentials.
Definition c2pa.hpp:52
OperationResult
Result codes for C API operations (matches C API return convention).
Definition c2pa.hpp:64
@ Success
Operation succeeded.
@ Error
Operation failed (check C2paException for details)
ProgressPhase
Phase values reported to the ProgressCallbackFunc.
Definition c2pa.hpp:255
std::function< bool(ProgressPhase phase, uint32_t step, uint32_t total)> ProgressCallbackFunc
Type alias for the progress callback passed to ContextBuilder::with_progress_callback().
Definition c2pa.hpp:289
int stream_error_return(StreamError e) noexcept
Set errno from StreamError and return error sentinel.
Definition c2pa.hpp:79
C2paSignerInfo SignerInfo
Type alias for C2paSignerInfo from the C API.
Definition c2pa.hpp:55
StreamError
Stream/FFI error codes (maps to errno values used by the C layer).
Definition c2pa.hpp:70
std::vector< unsigned char >(const std::vector< unsigned char > &) SignerFunc
Signer callback function type.
Definition c2pa.hpp:837