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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 3.27)
project(c2pa-c VERSION 0.13.0)

# Set the version of the c2pa_rs library used
set(C2PA_VERSION "0.75.19")
set(C2PA_VERSION "0.75.21")

set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
set(CMAKE_C_STANDARD 17)
Expand Down
225 changes: 0 additions & 225 deletions tests/embeddable.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,231 +402,6 @@ TEST_F(EmbeddableTest, ContextSettingsPropagation) {
EXPECT_GT(manifest.size(), 0) << "Context propagated successfully through workflow";
}

// Using archives with embedding
TEST_F(EmbeddableTest, ArchiveRoundTripWithContextAJpg) {
auto manifest_json = c2pa_test::read_text_file(c2pa_test::get_fixture_path("training.json"));
auto signer = c2pa_test::create_test_signer();

// Create context with custom settings (thumbnails disabled)
auto context = c2pa::Context(R"({
"builder": {
"thumbnail": {
"enabled": false
}
}
})");

// Create initial builder and get baseline placeholder size
auto builder1 = c2pa::Builder(context, manifest_json);
auto placeholder1 = builder1.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");
size_t original_size = placeholder1.size();

// Save to archive
auto archive_path = get_temp_path("archive_a.c2pa");
std::ofstream archive_stream(archive_path, std::ios::binary);
builder1.to_archive(archive_stream);
archive_stream.close();

// Load from archive using same context
auto builder2 = c2pa::Builder(context);
std::ifstream load_stream(archive_path, std::ios::binary);
builder2.with_archive(load_stream);
load_stream.close();

// Get placeholder from restored builder
auto placeholder2 = builder2.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");

// Verify settings preserved by checking placeholder size matches
EXPECT_EQ(placeholder2.size(), original_size)
<< "Settings should be preserved through archive round-trip";
}

// Using archives with embedding with asset having content credentials
TEST_F(EmbeddableTest, ArchiveRoundTripWithContextCJpg) {
auto manifest_json = c2pa_test::read_text_file(c2pa_test::get_fixture_path("training.json"));
auto signer = c2pa_test::create_test_signer();
auto source_asset = c2pa_test::get_fixture_path("C.jpg");

auto context = c2pa::Context(R"({
"builder": {
"thumbnail": {
"enabled": false
}
}
})");

auto builder1 = c2pa::Builder(context, manifest_json);

auto archive_path = get_temp_path("archive_c.c2pa");
std::ofstream archive_stream(archive_path, std::ios::binary);
builder1.to_archive(archive_stream);
archive_stream.close();

auto builder2 = c2pa::Builder(context);
std::ifstream load_stream(archive_path, std::ios::binary);
builder2.with_archive(load_stream);
load_stream.close();

auto placeholder = builder2.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");

size_t embed_offset = 20;
std::string data_hash = R"({
"exclusions": [{
"start": )" + std::to_string(embed_offset) + R"(,
"length": )" + std::to_string(placeholder.size()) + R"(
}],
"name": "jumbf manifest",
"alg": "sha256",
"hash": "",
"pad": " "
})";

std::ifstream asset_stream(source_asset, std::ios::binary);
auto signed_manifest = builder2.sign_data_hashed_embeddable(
signer, data_hash, "image/jpeg", &asset_stream);
asset_stream.close();

// Verify the signed manifest has the expected size
EXPECT_EQ(signed_manifest.size(), placeholder.size())
<< "Settings preserved through archive round-trip";
}

// Using with ingredients
TEST_F(EmbeddableTest, ArchiveWithIngredientAJpg) {
auto signer = c2pa_test::create_test_signer();
auto ingredient_path = c2pa_test::get_fixture_path("A.jpg");

// Create manifest with ingredient
std::string manifest_with_ingredient = R"({
"claim_generator": "test_app/1.0",
"assertions": [
{
"label": "c2pa.actions",
"data": {
"actions": [
{
"action": "c2pa.created"
}
]
}
}
],
"ingredients": [
{
"title": "A.jpg",
"relationship": "parentOf"
}
]
})";

auto context = c2pa::Context(R"({
"builder": {
"thumbnail": {
"enabled": false
}
}
})");

auto builder1 = c2pa::Builder(context, manifest_with_ingredient);

// Add ingredient using the proper API
std::string ingredient_json = R"({"title": "A.jpg"})";
builder1.add_ingredient(ingredient_json, ingredient_path);

// Get baseline placeholder size
auto placeholder1 = builder1.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");
size_t original_size = placeholder1.size();

// Archive and restore
auto archive_path = get_temp_path("archive_with_ingredient_a.c2pa");
std::ofstream archive_stream(archive_path, std::ios::binary);
builder1.to_archive(archive_stream);
archive_stream.close();

auto builder2 = c2pa::Builder(context);
std::ifstream load_stream(archive_path, std::ios::binary);
builder2.with_archive(load_stream);
load_stream.close();

// Get placeholder from restored builder
auto placeholder2 = builder2.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");

// Verify the ingredient survived the round-trip (size should match since ingredients are included)
EXPECT_EQ(placeholder2.size(), original_size)
<< "Ingredient should be preserved through archive round-trip";
}

// Using with ingredients with asset having content credentials
TEST_F(EmbeddableTest, ArchiveWithIngredientCJpg) {
auto signer = c2pa_test::create_test_signer();
auto ingredient_path = c2pa_test::get_fixture_path("C.jpg");

std::string manifest_with_ingredient = R"({
"claim_generator": "test_app/1.0",
"assertions": [
{
"label": "c2pa.actions",
"data": {
"actions": [
{
"action": "c2pa.created"
}
]
}
}
],
"ingredients": [
{
"title": "C.jpg",
"relationship": "parentOf"
}
]
})";

auto context = c2pa::Context(R"({
"builder": {
"thumbnail": {
"enabled": false
}
}
})");

auto builder1 = c2pa::Builder(context, manifest_with_ingredient);
std::string ingredient_json = R"({"title": "C.jpg"})";
builder1.add_ingredient(ingredient_json, ingredient_path);

// Archive round-trip
auto archive_path = get_temp_path("archive_with_ingredient_c.c2pa");
std::ofstream archive_stream(archive_path, std::ios::binary);
builder1.to_archive(archive_stream);
archive_stream.close();

auto builder2 = c2pa::Builder(context);
std::ifstream load_stream(archive_path, std::ios::binary);
builder2.with_archive(load_stream);
load_stream.close();

// Verify we can create placeholders and sign after round-trip
auto placeholder2 = builder2.data_hashed_placeholder(signer.reserve_size(), "image/jpeg");
EXPECT_GT(placeholder2.size(), 0) << "Should be able to create placeholder after archive round-trip";

// Verify we can sign
std::string data_hash = R"({
"exclusions": [{
"start": 20,
"length": )" + std::to_string(placeholder2.size()) + R"(
}],
"name": "jumbf manifest",
"alg": "sha256",
"hash": "gWZNEOMHQNiULfA/tO5HD2awOwYMA3tnfUPApIr9csk=",
"pad": " "
})";

auto manifest = builder2.sign_data_hashed_embeddable(
signer, data_hash, "image/jpeg", nullptr);
EXPECT_GT(manifest.size(), 0) << "Should be able to sign after archive round-trip";
}

// Verify different formats
TEST_F(EmbeddableTest, MultipleFormats) {
auto manifest_json = c2pa_test::read_text_file(c2pa_test::get_fixture_path("training.json"));
Expand Down