c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

commit 4356a1bc85404610cdb00d9a80a7f354e0c962b8
parent 573bc19b17cc0482e9408a1bf7187b53a46ea8ec
Author: nick <nick.libraries@gmail.com>
Date:   Tue, 18 Jun 2024 09:54:15 -0400

Add iterators over manifests and resources in unstable API (#482)

* Add `Reader::iter_manifests` + `ResourceSource::iter_resources` + pub `ResourceStore`

* Move iter_resources to Manifest
Diffstat:
Msdk/src/lib.rs | 2+-
Msdk/src/manifest.rs | 10+++++++++-
Asdk/src/manifest2.rs | 1+
Msdk/src/reader.rs | 5+++++
Msdk/src/resource_store.rs | 25++++++++++++++++++++++++-
5 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs @@ -129,7 +129,7 @@ pub use manifest_store::ManifestStore; pub use manifest_store_report::ManifestStoreReport; #[cfg(feature = "unstable_api")] pub use reader::Reader; -pub use resource_store::ResourceRef; +pub use resource_store::{ResourceRef, ResourceStore}; pub use signer::{AsyncSigner, RemoteSigner, Signer}; pub use signing_alg::SigningAlg; pub use utils::mime::format_from_path; diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs @@ -34,7 +34,7 @@ use crate::{ ingredient::Ingredient, jumbf, manifest_assertion::ManifestAssertion, - resource_store::{skip_serializing_resources, ResourceRef, ResourceStore}, + resource_store::{mime_from_uri, skip_serializing_resources, ResourceRef, ResourceStore}, salt::DefaultSalt, store::Store, AsyncSigner, ClaimGeneratorInfo, HashRange, ManifestAssertionKind, RemoteSigner, Signer, @@ -451,6 +451,14 @@ impl Manifest { self.signature_info.to_owned().and_then(|sig| sig.time) } + /// Returns an iterator over [`ResourceRef`][ResourceRef]s. + pub fn iter_resources(&self) -> impl Iterator<Item = ResourceRef> + '_ { + self.resources + .resources() + .keys() + .map(|uri| ResourceRef::new(mime_from_uri(uri), uri.to_owned())) + } + /// Return an immutable reference to the manifest resources pub fn resources(&self) -> &ResourceStore { &self.resources diff --git a/sdk/src/manifest2.rs b/sdk/src/manifest2.rs @@ -0,0 +1 @@ + diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs @@ -186,6 +186,11 @@ impl Reader { self.manifest_store.active_label() } + /// Returns an iterator over [`Manifest`][Manifest]s. + pub fn iter_manifests(&self) -> impl Iterator<Item = &Manifest> + '_ { + self.manifest_store.manifests().values() + } + /// Return a [`Manifest`] for a given label if it exists. /// # Arguments /// * `label` - The label of the requested [`Manifest`] diff --git a/sdk/src/resource_store.rs b/sdk/src/resource_store.rs @@ -28,7 +28,13 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "unstable_api")] use crate::asset_io::CAIRead; -use crate::{assertions::AssetType, claim::Claim, hashed_uri::HashedUri, Error, Result}; +use crate::{ + assertions::{labels, AssetType}, + claim::Claim, + hashed_uri::HashedUri, + jumbf::labels::assertion_label_from_uri, + Error, Result, +}; /// Function that is used by serde to determine whether or not we should serialize /// resources based on the `serialize_resources` flag. @@ -93,6 +99,8 @@ impl From<HashedUri> for UriOrResource { #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] #[cfg_attr(feature = "json_schema", derive(JsonSchema))] /// A reference to a resource to be used in JSON serialization. +/// +/// The underlying data can be read as a stream via [`Reader::resource_to_stream`][crate::Reader::resource_to_stream]. pub struct ResourceRef { /// The mime type of the referenced resource. pub format: String, @@ -361,6 +369,7 @@ impl Default for ResourceStore { #[cfg(feature = "unstable_api")] pub trait ResourceResolver { + /// Read the data in a [`ResourceRef`][ResourceRef] via a stream. fn open(&self, reference: &ResourceRef) -> Result<Box<dyn CAIRead>>; } @@ -373,6 +382,20 @@ impl ResourceResolver for ResourceStore { } } +pub fn mime_from_uri(uri: &str) -> String { + if let Some(label) = assertion_label_from_uri(uri) { + if label.starts_with(labels::THUMBNAIL) { + // https://c2pa.org/specifications/specifications/1.0/specs/C2PA_Specification.html#_thumbnail + if let Some(ext) = label.rsplit('.').next() { + return format!("image/{ext}"); + } + } + } + + // Unknown binary data. + String::from("application/octet-stream") +} + #[cfg(test)] #[cfg(feature = "openssl_sign")] mod tests {