Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
828ab4d
fix: WIP
tmathern Feb 4, 2026
53c6c88
fix: All my debug
tmathern Feb 4, 2026
f776418
fix: Debug in progress
tmathern Feb 4, 2026
5a98e86
feat: Refactor (#138)
tmathern Feb 4, 2026
4b01fc0
fix: More refactors (#139)
tmathern Feb 4, 2026
68c9ac1
fix: Refactooooor
Feb 4, 2026
25de5c7
fix: Refactooooor
Feb 4, 2026
13aa333
fix: Refactooooor
Feb 4, 2026
800d8f0
fix: Refactooooor
Feb 4, 2026
d55abe7
fix: Refactooooor
Feb 4, 2026
77a4db4
fix: Refactooooor
Feb 4, 2026
afccb02
fix: Refactooooor
Feb 4, 2026
b27cf8c
fix: Refactooooor for build
Feb 4, 2026
f07cab4
fix: Fix WIndows build
Feb 4, 2026
e0c4816
fix: Cleaning up
Feb 4, 2026
5719024
fix: Add TODOs
Feb 4, 2026
c2cccef
ci: Merge commit
tmathern Feb 4, 2026
8e4c72e
fix: Update naming, clean up STL
tmathern Feb 4, 2026
713bff6
fix: WIP - fix stream handling for files
tmathern Feb 4, 2026
c77c671
fix: Tests
tmathern Feb 4, 2026
d1f32b4
fix: Write test for toml and json settings
tmathern Feb 4, 2026
5c336e9
fix: Add tests for settings combinations
tmathern Feb 4, 2026
93296e9
fix: Verify trust
tmathern Feb 4, 2026
b117f36
fix: Verify trust
tmathern Feb 4, 2026
5e8ba8c
fix: Reader with trust
tmathern Feb 4, 2026
6cd6615
fix: Clean up list
tmathern Feb 4, 2026
114eefb
fix: Update config
Feb 5, 2026
eaddf0a
fix: Format
Feb 5, 2026
7d39543
fix: Format
Feb 5, 2026
51e3f03
fix: Docs
Feb 5, 2026
e1b2341
fix: Docs
Feb 5, 2026
b1dbdc6
fix: Docs
Feb 5, 2026
a376b46
fix: Docs
Feb 5, 2026
54a8862
fix: Docs
Feb 5, 2026
abf3c46
fix: Docs
Feb 5, 2026
28c1bc6
fix: TODO dev notes
Feb 5, 2026
54a5f32
fix: CLean before rebuild
tmathern Feb 5, 2026
2800a63
fix: Refactorings once more
tmathern Feb 5, 2026
0c28883
fix: Refactorings
tmathern Feb 5, 2026
8f8e4bf
fix: Refactor streams
tmathern Feb 5, 2026
f4f9928
fix: Streams refacotr
tmathern Feb 5, 2026
3948cff
fix: Refactor
tmathern Feb 5, 2026
2c9ccf1
fix: Docs
tmathern Feb 5, 2026
c8cbf9c
fix: Improvements in progress
Feb 6, 2026
97e2d80
Merge branch 'vNext' into mathern/contexts-in-api
tmathern Feb 6, 2026
372deab
fix: Add ASAN, UBSAN
Feb 6, 2026
def9b59
fix: Set up sanitizers
Feb 6, 2026
3a1cc8a
fix: Texts
Feb 6, 2026
e493c71
fix: Update workflow
Feb 6, 2026
9993a98
fix: Update workflow
Feb 6, 2026
b9ea5bd
fix: Update workflow
Feb 6, 2026
6f76890
fix: Reactivate a test
Feb 6, 2026
736beb5
fix: reduce string copies, or try to
Feb 6, 2026
1b6092c
ci: Revert "fix: reduce string copies, or try to"
Feb 6, 2026
67a174c
fix: tests moved
Feb 6, 2026
adab0f2
fix: Text utils
Feb 6, 2026
18d9e17
fix: The refactoring axe is coming out
Feb 6, 2026
f1e8067
fix: THe Ubuntu leaks
Feb 6, 2026
1b9e379
fix: Bump to use the right c2pa-rs version
tmathern Feb 6, 2026
e9fb14b
fix: Last leak
tmathern Feb 6, 2026
8cfd82b
fix: Mem
tmathern Feb 6, 2026
9396e97
fix: Known leak that is not a leak
tmathern Feb 6, 2026
20366f3
fix: Clarify suppressor
tmathern Feb 6, 2026
139cfbf
fix: Clarify suppressor
tmathern Feb 6, 2026
f7b7568
fix: Add test coverage
Feb 7, 2026
9411f56
fix: Add test coverage for context
Feb 7, 2026
4c4a427
fix: Add coverage
Feb 7, 2026
e7ed22f
fix: A few more tests
tmathern Feb 7, 2026
e4eedcd
fix: Comment on test
tmathern Feb 7, 2026
ead5c87
fix: Reorg the tests
Feb 7, 2026
4baf9d0
fix: Reorg the tests
Feb 7, 2026
ac6e904
fix: Consistency
Feb 7, 2026
aa6a1ac
fix: Consistency
Feb 7, 2026
d0d44bd
fix: load archive
Feb 7, 2026
24ad845
fix: Intermediate signing
Feb 7, 2026
e0c28e3
fix: Multi ingredients
Feb 7, 2026
954a1d4
fix: CLean up
tmathern Feb 9, 2026
5349c7f
fix: Increased test-coveragae on #137 + minor bugfixes (#143)
tmathern Feb 9, 2026
83e6516
Merge branch 'vNext' into mathern/contexts-in-api
tmathern Feb 9, 2026
1ac05d7
fix: CLean up tests
tmathern Feb 10, 2026
a4b7b91
fix: Extract ingredeints from archives
tmathern Feb 10, 2026
2d4611b
fix: Extract ingredeints from archives 2
tmathern Feb 10, 2026
19b3e5f
fix: Add a test
tmathern Feb 10, 2026
d243e67
fix: Builder variations
tmathern Feb 10, 2026
a16d0b7
fix: Variations in resources handling
tmathern Feb 10, 2026
8be426a
fix: Remove the very ugly string based test
Feb 10, 2026
92ae444
fix: Refactor
Feb 10, 2026
7d777b1
fix: Refactor
Feb 10, 2026
7c732a8
fix: Cleanup 2
Feb 10, 2026
e415b68
fix: Reorg
Feb 10, 2026
449000a
fix: The TODOs are gone
Feb 10, 2026
c4f20a3
fix: FInish examples clean up
Feb 10, 2026
1683955
fix: Refactor bytes handling (#144)
tmathern Feb 10, 2026
4e3652e
fix: Settings reference link
tmathern Feb 10, 2026
2e321f1
fix: Review comments 1: toml go away! (#145)
tmathern Feb 10, 2026
d4ba8f8
fix: Review comments step 2 (#146)
tmathern Feb 10, 2026
3711f51
fix: Rely more on Rust for pointer clean up
tmathern Feb 10, 2026
bf28742
fix: Update coverage and simplify API (#147)
tmathern Feb 10, 2026
e667ce6
fix: Simplify CMakeList (#148)
tmathern Feb 10, 2026
f93b713
fix: Update docs
tmathern Feb 10, 2026
eee518f
fix: Refactor
tmathern Feb 10, 2026
62922fe
fix: Shorten docs
tmathern Feb 10, 2026
f43345c
fix: Update
tmathern Feb 10, 2026
f05b042
fix: Refactored once more and clarified docs
tmathern Feb 10, 2026
c667174
fix: Context verify move
tmathern Feb 10, 2026
35b7063
fix: Remove usunsed move
Feb 11, 2026
3427abd
fix: Refactor tests
Feb 11, 2026
8bb2562
fix: One more cleanup
Feb 11, 2026
4ab6953
fix: Remove the API I said I would
Feb 11, 2026
93fd169
fix: More clean up
Feb 11, 2026
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
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,10 @@ jobs:
run: |
which make
make --version
- name: Run tests

- name: Run tests (debug build)
run: make test

- name: Run tests (debug build, with sanitizers)
if: runner.os != 'Windows'
run: make test-san
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/build
/include/c2pa.h
/target

_deps
# CMake files
Expand All @@ -16,4 +16,4 @@ CMakeLists.txt.user
.vscode
# Mac OS X files
.DS_Store
.idea
.idea
60 changes: 59 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ set(C2PA_VERSION "0.75.19")

set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3")

if(MSVC)
Expand All @@ -46,6 +46,64 @@ else()
add_compile_options(-Wall -Wextra -Werror)
endif()

# Sanitizers (for debug/verification builds)
option(ENABLE_SANITIZERS "Enable AddressSanitizer, UndefinedBehaviorSanitizer, and LeakSanitizer" OFF)
option(ENABLE_MSAN "Enable MemorySanitizer (mutually exclusive with ASAN)" OFF)

if(ENABLE_SANITIZERS AND ENABLE_MSAN)
message(FATAL_ERROR "ENABLE_SANITIZERS and ENABLE_MSAN are mutually exclusive - choose one")
endif()

if(ENABLE_SANITIZERS)
if(MSVC)
message(WARNING "Sanitizers are not supported with MSVC in this configuration")
elseif(WIN32)
# MinGW on Windows doesn't have sanitizer libraries available
message(WARNING "Sanitizers are not available on Windows with MinGW - skipping sanitizer build")
else()
# AddressSanitizer, UndefinedBehaviorSanitizer, and LeakSanitizer for GCC/Clang
# Note: LeakSanitizer is not supported on macOS (both x86_64 and ARM64)
# On Linux, LeakSanitizer is integrated with AddressSanitizer
if(APPLE)
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer -g)
add_link_options(-fsanitize=address,undefined)
message(STATUS "Sanitizers enabled on macOS: ASAN and UBSAN (LSan not supported on macOS)")
else()
add_compile_options(-fsanitize=address,undefined,leak -fno-omit-frame-pointer -g)
add_link_options(-fsanitize=address,undefined,leak)
message(STATUS "Sanitizers enabled: ASAN, UBSAN, and LSan")
endif()
# Allow macro redefinition for _FORTIFY_SOURCE which conflicts with sanitizers
add_compile_options(-Wno-macro-redefined)
endif()
endif()

if(ENABLE_MSAN)
if(NOT MSVC)
# MemorySanitizer for detecting uninitialized memory reads
# WARNING: Requires all dependencies to be built with MSan
add_compile_options(-fsanitize=memory -fno-omit-frame-pointer -g)
add_compile_options(-Wno-macro-redefined)
add_link_options(-fsanitize=memory)
message(STATUS "MemorySanitizer enabled (MSan)")
else()
message(WARNING "MemorySanitizer is not supported with MSVC")
endif()
endif()

# Code coverage instrumentation
option(ENABLE_COVERAGE "Enable code coverage instrumentation" OFF)

if(ENABLE_COVERAGE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
add_compile_options(--coverage -fprofile-arcs -ftest-coverage)
add_link_options(--coverage)
message(STATUS "Code coverage enabled")
else()
message(WARNING "Code coverage is only supported with GCC or Clang")
endif()
endif()

enable_testing()

ADD_SUBDIRECTORY(src)
Expand Down
99 changes: 89 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,112 @@ BUILD_DIR = build
DEBUG_BUILD_DIR = build/debug
RELEASE_BUILD_DIR = build/release

# CMake options (can be overridden via environment)
CMAKE_OPTS :=
ifdef C2PA_BUILD_FROM_SOURCE
CMAKE_OPTS += -DC2PA_BUILD_FROM_SOURCE=$(C2PA_BUILD_FROM_SOURCE)
endif
ifdef C2PA_RS_PATH
CMAKE_OPTS += -DC2PA_RS_PATH=$(C2PA_RS_PATH)
endif

# Default target
all: test examples
all: clean test examples

clean:
rm -rf $(BUILD_DIR)

# Debug build
debug:
cmake -S . -B $(DEBUG_BUILD_DIR) -G "Ninja" -DCMAKE_BUILD_TYPE=Debug
cmake -S . -B $(DEBUG_BUILD_DIR) -G "Ninja" -DCMAKE_BUILD_TYPE=Debug $(CMAKE_OPTS)
cmake --build $(DEBUG_BUILD_DIR)

# Release build
release:
cmake -S . -B $(RELEASE_BUILD_DIR) -G "Ninja" -DCMAKE_BUILD_TYPE=Release
cmake -S . -B $(RELEASE_BUILD_DIR) -G "Ninja" -DCMAKE_BUILD_TYPE=Release $(CMAKE_OPTS)
cmake --build $(RELEASE_BUILD_DIR)

# Legacy cmake target (uses release build)
cmake: release

# Test targets
test: debug
test: clean debug
cd $(DEBUG_BUILD_DIR) && ctest --output-on-failure

test-release: release
test-release: clean release
cd $(RELEASE_BUILD_DIR) && ctest --output-on-failure

# Test with sanitizers (ASAN + UBSAN)
test-san: clean
cmake -S . -B $(DEBUG_BUILD_DIR) -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DENABLE_SANITIZERS=ON $(CMAKE_OPTS)
cmake --build $(DEBUG_BUILD_DIR)
cd $(DEBUG_BUILD_DIR) && ctest --output-on-failure

# Run only the C test (test.c)
test-c: clean release
@echo "Running C test only..."
ifeq ($(OS),Darwin)
DYLD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$DYLD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/ctest
else
LD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$LD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/ctest
endif

# Run only the C++ tests
test-cpp: clean release
@echo "Running C++ tests only..."
ifeq ($(OS),Darwin)
DYLD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$DYLD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/c2pa_c_tests
else
LD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$LD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/c2pa_c_tests
endif

# Run a single test by fully qualified name
# Like this: make run-single-test TEST=BuilderTest.MergingBuildersThenSignMerged
run-single-test: release
@if [ -z "$(TEST)" ]; then echo "Usage: make run-single-test TEST=SuiteName.TestName"; exit 1; fi
@echo "Running single test: $(TEST)"
ifeq ($(OS),Darwin)
DYLD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$DYLD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/c2pa_c_tests --gtest_filter="$(TEST)"
else
LD_LIBRARY_PATH=$(RELEASE_BUILD_DIR)/tests:$$LD_LIBRARY_PATH ./$(RELEASE_BUILD_DIR)/tests/c2pa_c_tests --gtest_filter="$(TEST)"
endif

# Test with coverage reporting
# THis verifies necessary tooling for coverage check is also installed
test-coverage: clean
cmake -S . -B build/coverage -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON $(CMAKE_OPTS)
cmake --build build/coverage
cd build/coverage && ctest --output-on-failure
@echo ""
@echo "Generating coverage report..."
@lcov --capture --directory build/coverage --output-file build/coverage/coverage.info \
--ignore-errors mismatch,inconsistent,unsupported,format 2>&1 \
| grep -v "WARNING:" || { echo "Error: lcov capture failed"; exit 1; }
@lcov --remove build/coverage/coverage.info \
'/usr/*' '*/googletest/*' '*/json-src/*' '*/c2pa_prebuilt-src/*' '*/tests/*' \
--output-file build/coverage/coverage_filtered.info \
--ignore-errors unused,mismatch,inconsistent,format 2>&1 \
| grep -v "WARNING:" || { echo "Error: lcov filter failed"; exit 1; }
@echo ""
@echo "=== Coverage Summary ==="
@lcov --summary build/coverage/coverage_filtered.info \
--ignore-errors inconsistent,format 2>&1 \
| grep -E "(lines|functions|branches)" || true
@echo "========================"
@echo ""
@if command -v genhtml > /dev/null 2>&1; then \
genhtml build/coverage/coverage_filtered.info --output-directory build/coverage/html \
--ignore-errors inconsistent,corrupt,unsupported,format,category 2>&1 \
| grep -v "WARNING:" || true; \
if [ -f build/coverage/html/index.html ]; then \
echo "HTML report: build/coverage/html/index.html"; \
else \
echo "Warning: HTML report was not generated (genhtml may have failed)"; \
fi; \
else \
echo "Note: genhtml not found, skipping HTML report (install lcov for HTML reports)"; \
fi

# Demo targets
demo: release
cmake --build $(RELEASE_BUILD_DIR) --target demo
Expand All @@ -39,12 +122,8 @@ training: release

examples: training demo

clean:
rm -rf $(BUILD_DIR)

.PHONY: all debug release cmake test test-release demo training examples clean
.PHONY: all debug release cmake test test-release test-san test-c test-cpp test-coverage demo training examples clean

# Build C API docs with Doxygen
docs:
./scripts/generate_api_docs.sh

55 changes: 39 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ Although this library works for plain C applications, the documentation assumes

For the best experience, read the docs on the [CAI Open Source SDK documentation website](https://opensource.contentauthenticity.org/docs/c2pa-c). If you want to view the documentation in GitHub, see:
- [Using the C++ library](docs/usage.md)
- [Supported formats](https://github.com/contentauth/c2pa-rs/blob/crandmck/reorg-docs/docs/supported-formats.md)
- [Supported formats](https://github.com/contentauth/c2pa-rs/blob/main/docs/supported-formats.md)

</div>
</div>

## Using c2pa_cpp
## Using c2pa_cpp

The recommended way to use this library in your own CMake project is with [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):

Expand All @@ -34,45 +34,70 @@ add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE c2pa_cpp)
```

This will automatically fetch, build, and link the `c2pa_cpp` library and its dependencies.
This will automatically fetch, build, and link the `c2pa_cpp` library and its dependencies.

> **Note:**
> **Note:**
> This project uses pre-built dynamic libraries from the [c2pa-rs](https://github.com/contentauth/c2pa-rs) repository. It should select the correct library for your platform. If your platform is not supported, you can build your own library using the c2pa_rs repo.

### 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.

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-built C FFI libraries

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

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

Enter this command to build the C library:
Enter this command to build the SDK:

```
make release
```

This will download the [pre-build libraries published with c2pa releases](https://github.com/contentauth/c2pa-rs/releases), build and link the C++ code.

The Makefile has a number of other targets; for example:
- `unit-tests` to run C++ unit tests
- `test` to run unit tests
- `examples` to build and run the C++ examples.
- `all` to run everything.
- `all` to build and run everything.

Results are saved in the `build` directory.

### Building using local sources

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 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
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 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"

# macOs: Set built library path for running tests
export DYLD_LIBRARY_PATH="$(pwd)/build/release/tests:$DYLD_LIBRARY_PATH"

# Linux: Set built library path for running tests
export LD_LIBRARY_PATH="$(pwd)/build/release/tests:$LD_LIBRARY_PATH"
```

### Testing

Build the [unit tests](https://github.com/contentauth/c2pa-c/tree/main/tests) by entering this `make` command:

```
make unit-test
make test
```

### Building API documentation
Expand All @@ -81,7 +106,7 @@ API documentation generated by Doxygen is automatically built on each PR.

To generate API docs locally, these are the main files:

- Configuration file: `c2pa-c/Doxyfile`
- Configuration file: `c2pa-c/Doxyfile`
- Script: `c2pa-c/scripts/generate_api_docs.sh`
- Output directory: `docs/_build/html`

Expand Down Expand Up @@ -111,5 +136,3 @@ Note that some components and dependent crates are licensed under different term
### Contributions and feedback

We welcome contributions to this project. For information on contributing, providing feedback, and about ongoing work, see [Contributing](https://github.com/contentauth/c2pa-c/blob/main/CONTRIBUTING.md).


13 changes: 13 additions & 0 deletions ci-cd/lsan_suppressions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# LeakSanitizer suppression file for c2pa-c tests.
#
# On first use Tokio allocates process-global singleton state (signal handler
# registry, thread-local handles via OnceLock/Lazy) that is intentionally never
# freed. The allocation is bounded, does not grow, and is reclaimed by the OS on process exit.
#
# Observed on Ubuntu 22.04 aarch64 where LSan classifies the allocation as a
# "direct leak" rather than "still reachable".
#
# Similar if not same as https://github.com/tokio-rs/tokio/issues/4756
# Happens only on some Linxues as it depends on the OS/glibc version too it seems!
#
leak:libc2pa_c
Loading