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
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,18 @@ jobs:
- name: Check Ninja
run: ninja --version

- name: Configure
run: cmake -S . -B build -G Ninja

- name: Setup MSVC toolchain on Windows
if: matrix.os == 'windows-latest'
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ runner.arch == 'ARM64' && 'arm64' || 'x64' }}

- name: Print make version and path
run: |
which make
make --version

- name: Run tests (debug build)
- name: Build and test against c2pa-rs 0.92.0 release
run: make test

- name: Run tests (debug build, with sanitizers)
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
cmake_minimum_required(VERSION 3.27)

# This is the current version of this C++ project
project(c2pa-c VERSION 0.26.19)
project(c2pa-c VERSION 0.27.0)

# Set the version of the c2pa_rs library used
set(C2PA_VERSION "0.91.10")
set(C2PA_VERSION "0.92.0")

set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
set(CMAKE_C_STANDARD 17)
Expand Down
28 changes: 11 additions & 17 deletions docs/context-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ c2pa::Reader reader(context, "image.jpg");
- **Improves code clarity**: `Builder(context, manifest)` shows configuration is being used

> [!NOTE]
> The deprecated `c2pa::load_settings(data, format)` still works but you should migrate to `Context`. **Never mix the two approaches**.
> See [Migrating from deprecated APIs](#migrating-from-deprecated-apis).
> Pass settings explicitly through a `Context`. For existing applications, see
> [Migrating from deprecated APIs](#migrating-from-deprecated-apis).

### Context lifecycle

Expand Down Expand Up @@ -883,13 +883,16 @@ c2pa::Context context(R"({

## Migrating from deprecated APIs

The SDK introduced Context-based APIs to replace constructors and functions that relied on thread-local state. The older APIs still compile but produce deprecation warnings. This section covers each deprecation that involves passing a `Context`, and explains the `Builder::sign` overloads.
The SDK introduced Context-based APIs to replace constructors and functions that relied on thread-local state. `load_settings` has been removed. The context-free `Reader` and `Builder` constructors still compile with deprecation warnings, but create a new default Context rather than reading thread-local settings. This section covers migration to explicit contexts and the `Builder::sign` overloads.

### Quick reference

| Deprecated API | Replacement |
| Removed API | Replacement |
|---|---|
| `load_settings(data, format)` | [`Context` constructors or `ContextBuilder`](#replacing-load_settings) |

| Deprecated API | Replacement |
|---|---|
| `Reader(format, stream)` | [`Reader(shared_ptr<IContextProvider>, format, stream)`](#adding-a-context-parameter-to-reader-and-builder) |
| `Reader(source_path)` | [`Reader(shared_ptr<IContextProvider>, source_path)`](#adding-a-context-parameter-to-reader-and-builder) |
| `Builder(manifest_json)` | [`Builder(shared_ptr<IContextProvider>, manifest_json)`](#adding-a-context-parameter-to-reader-and-builder) |
Expand All @@ -898,35 +901,26 @@ The SDK introduced Context-based APIs to replace constructors and functions that

### Replacing load_settings

`c2pa::load_settings(data, format)` sets thread-local settings that `Reader` and `Builder` pick up implicitly. Replace it with a `Context` that you pass explicitly.
The removed `c2pa::load_settings(data, format)` used to set thread-local settings that `Reader` and `Builder` picked up implicitly. Replace it with a `Context` that you pass explicitly.

| Aspect | load_settings (legacy) | Context |
|--------|------------------------|---------|
| Scope | Global / thread-local | Per Reader/Builder, passed explicitly |
| Multiple configs | Awkward (per-thread) | One context per configuration |
| Testing | Shared global state | Isolated contexts per test |

**Deprecated:**

```cpp
std::ifstream config_file("settings.json");
std::string config((std::istreambuf_iterator<char>(config_file)), std::istreambuf_iterator<char>());
c2pa::load_settings(config, "json");
c2pa::Reader reader("image/jpeg", stream); // uses thread-local settings
```

**With context API:**

```cpp
c2pa::Context context(settings_json_string); // or Context(Settings(...))
auto context = std::make_shared<c2pa::Context>(settings_json_string);
c2pa::Reader reader(context, "image/jpeg", stream);
```

If you still use `load_settings`, construct `Reader` or `Builder` **without** a context parameter to continue using the thread-local settings. Prefer passing a context for new code.
There is no thread-local settings fallback. Context-free constructors use default settings; pass a context whenever configuration matters.

### Adding a context parameter to Reader and Builder

The following constructors are deprecated because they rely on thread-local settings:
The following constructors are deprecated because they do not accept explicit configuration:

- `Reader(const std::string& format, std::istream& stream)`
- `Reader(const std::filesystem::path& source_path)`
Expand Down
38 changes: 25 additions & 13 deletions docs/embeddable-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ The embeddable signing API provides direct, fine-grained control over embedding
4. Sign the claim.
5. Patch the manifest in place.

## Migrating from the removed data-hashed APIs

The methods `data_hashed_placeholder(reserve_size, format)`
and `sign_data_hashed_embeddable(signer, data_hash, format, asset)` have been removed.
The supported workflow is:

1. Attach the signer to the Context before constructing the Builder.
2. Call `placeholder(format)` and embed the returned bytes in the asset.
3. Call `set_data_hash_exclusions()` with the embedded placeholder's byte offset and length.
4. Call `update_hash_from_stream(format, asset)` to hash the asset.
5. Call `sign_embeddable(format)` and overwrite the placeholder with its result.

The new workflow obtains the signature reserve size from the Context signer and
computes the hash from the supplied stream; it does not accept the old precomputed
DataHash JSON argument. Do not change the asset outside the excluded placeholder
region after hashing. `format_embeddable(format, data)` remains available for raw
manifest bytes and now uses the supported `c2pa_builder_compose_manifest` API.

## Why use the embeddable API

The standard `Builder::sign()` handles the full pipeline internally:
Expand All @@ -23,7 +41,7 @@ auto manifest_bytes = builder.sign(source_path, output_path, signer);
The standard approach works for most use cases. The embeddable API exists for situations where the application requires explicit control over embedding, for example:

- The application controls its own I/O pipeline. Video transcoders, streaming ingestion services, and other tools have their own asset-writing code. Transferring stream ownership to the SDK conflicts with that architecture.
- The asset is too large to buffer. The SDK's `sign()` may re-read large files. With the embeddable API, the application can hash chunks as it writes them and pass the results directly to the builder.
- The asset is too large to buffer. The embeddable API can hash an asset through a stream without requiring the entire asset in memory.
- The application needs in-place patching. When using the placeholder workflow, `sign_embeddable()` returns a signed manifest that is byte-for-byte the same size as the placeholder. The caller can then overwrite the placeholder region in the file without changing the overall file size or shifting any surrounding data.

## Concepts
Expand Down Expand Up @@ -78,9 +96,9 @@ To use `BoxHash` mode, enable `prefer_box_hash` in Builder settings. These forma

When `needs_placeholder()` returns `false`, the standard `Builder::sign()` flow is usually all you need. The embeddable API (`update_hash_from_stream()` + `sign_embeddable()`) is available for situations where you need finer control over the process:

- The application controls its own write pipeline (e.g., a video transcoder or streaming ingest service) and wants to hash the asset during its own write pass rather than having the SDK re-read the finished file.
- The application controls its own write pipeline (e.g., a video transcoder or streaming ingest service) and can provide a readable asset stream for the SDK to hash after writing.
- The application needs to receive the raw signed manifest bytes and decide where and how to append them as a new chunk, rather than letting the SDK write to a destination path.
- Using the SDK, the application produces the asset incrementally, so it can pass the stream to `update_hash_from_stream()` at the right moment, then call `sign_embeddable()` to get the manifest without a second full read.
- The application produces the asset incrementally and can pass the completed asset stream to `update_hash_from_stream()`, then call `sign_embeddable()` to obtain the manifest.

<!--
The `prefer_box_hash` setting can be provided in a JSON settings file:
Expand Down Expand Up @@ -189,17 +207,11 @@ These methods perform the signing workflow: placeholder creation, hashing, and s
| `Builder::update_hash_from_stream(format, stream)` | Reads the asset stream and computes the hard-binding hash. Automatically selects the appropriate path based on format: `BmffHash` for BMFF (skips manifest box), `BoxHash` for chunk-based formats (creates assertion if needed), or `DataHash` (skips exclusion ranges). Takes a `std::istream&`. |
| `Builder::sign_embeddable(format)` | Signs the manifest and returns bytes ready to embed. For placeholder workflows, it pads the output to match the placeholder size for in-place patching. For BoxHash workflows, the output is the actual signed manifest size (not padded), suitable for appending as a new chunk. |

### Deprecated methods

The c2pa-rs 0.92.0 removes C FFI functions behind some `Builder` methods. These methods will be removed when c2pa-c moves to c2pa-rs 0.92.0.

| Deprecated method | Replacement |
|-------------------|-------------|
| `data_hashed_placeholder(reserved_size, format)` | `needs_placeholder(format)`, then `placeholder(format)`. The reserve size comes from the signer on the Context. |
| `sign_data_hashed_embeddable(signer, data_hash, format, asset)` | `set_data_hash_exclusions(exclusions)`, `update_hash_from_stream(format, stream)`, then `sign_embeddable(format)`. The signer comes from the Context. |
| `format_embeddable(format, data)` | `sign_embeddable(format)`, which returns bytes already formatted for `format`. |
### Deprecated method

For the full replacement flow, see [Using the DataHash placeholder](#using-the-datahash-placeholder).
`Builder::format_embeddable(format, data)` remains available for formatting raw
manifest bytes. Prefer `sign_embeddable(format)`, which returns bytes already
formatted for embedding.

## Using the DataHash placeholder

Expand Down
12 changes: 3 additions & 9 deletions docs/intents.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ You can set the intent on a `Builder` instance by:
- [Using Context](#using-context)
- [Using `set_intent` on the `Builder`](#using-set_intent-on-builder)

Don't set intent using the deprecated `load_settings()` function. For existing code, see [Context and Settings - Migrating from deprecated APIs](context-settings.md#migrating-from-deprecated-apis).
For existing code, see [Context and Settings - Migrating from deprecated APIs](context-settings.md#migrating-from-deprecated-apis).

### Using Context

Expand Down Expand Up @@ -112,11 +112,7 @@ flowchart TD
Check --> |No| CheckCtx{Was a Context with
builder.intent provided?}
CheckCtx --> |Yes| UseCtx["Use Context intent"]
CheckCtx --> |No| CheckGlobal{Was load_settings called
with builder.intent?}
CheckGlobal --> |Yes| UseGlobal["Use global intent
(deprecated)"]
CheckGlobal --> |No| NoIntent["No intent set.
CheckCtx --> |No| NoIntent["No intent set.
Caller must define actions
manually in manifest JSON."]
```
Expand Down Expand Up @@ -171,8 +167,7 @@ The `Builder` intent controls what `Builder` does with the source stream (source
```mermaid
flowchart TD
Intent["Intent
(via Context, set_intent,
or load_settings)"] --> Q{Intent type?}
(via Context or set_intent)"] --> Q{Intent type?}
Q --> |CREATE| CreateFlow["No parent allowed
Source stream is new content"]
Q --> |EDIT or UPDATE| EditFlow{Was a parentOf ingredient
Expand Down Expand Up @@ -485,4 +480,3 @@ c2pa::Builder builder(context, R"({})");
builder.set_intent(Update);
builder.sign("signed_asset.jpg", "updated_asset.jpg", signer);
```

26 changes: 25 additions & 1 deletion docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Release notes

## 0.27.0 — breaking changes

11 November 2026

This release updates the native SDK to c2pa-rs **0.92.0** and requires a
minor version bump because it removes deprecated C++ APIs and changes their
behavior:

- `c2pa::load_settings` has been removed. Pass configuration through a
`Context`; context-free `Reader` and `Builder` constructors now use default
settings rather than thread-local settings.
- `Builder::data_hashed_placeholder` and `Builder::sign_data_hashed_embeddable`
have been removed. Configure a signer on the `Context` and use the
[embeddable signing workflow](embeddable-api.md#migrating-from-the-removed-data-hashed-apis).
The new workflow does not accept a precomputed DataHash JSON value.
- The C++ stream wrappers now share the owning `c2pa::C2paStream` base, which
supports polymorphic destruction. The global C API type `::C2paStream` is
opaque and is no longer their base. Code using a global `::C2paStream*` as a
wrapper base must use `c2pa::C2paStream*` instead. Use the wrapper's `c_stream`
member when passing a stream to C; the underlying C++ stream must outlive the
wrapper. Qualify the type when both the C and C++ names are in scope.

Applications using `C2PA_RS_PATH` or `C2PA_C_LIB_OVERRIDE` must update their
own native library to a compatible 0.92.0 build.

## 26 Oct 2026

The selected native SDK release is c2pa-rs **0.91.7**, including its eMudhra
Expand Down Expand Up @@ -31,4 +56,3 @@ Additionally, this release adds support for:
- Using `Builder` and `Reader` together to [selectively construct a manifest by filtering actions and ingredients](selective-manifests.md).

For answers to frequently asked questions about these features, see the [FAQs](faqs.md).

Loading
Loading