c2pa-c
C++ API for c2pa-c library
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 <filesystem>
35#include <fstream>
36#include <iostream>
37#include <string>
38#include <vector>
39#include <optional>
40
41#include <c2pa.h>
42
43// NOOP for now, can use later to define static library
44#define C2PA_CPP_API
45
46namespace c2pa
47{
48 using namespace std;
49
50 typedef C2paSignerInfo SignerInfo;
51
52 /// C2paException class for C2pa errors.
53 /// This class is used to throw exceptions for errors encountered by the C2pa library via c2pa_error().
54 class C2PA_CPP_API C2paException : public exception
55 {
56 private:
57 string message;
58
59 public:
61
62 C2paException(string what);
63
64 virtual const char *what() const noexcept;
65 };
66
67 /// Returns the version of the C2pa library.
68 string C2PA_CPP_API version();
69
70 /// Loads C2PA settings from a string in a given format.
71 /// @param data the string to load.
72 /// @param format the mime format of the string.
73 /// @throws a C2pa::C2paException for errors encountered by the C2PA library.
74 void C2PA_CPP_API load_settings(const string& data, const string& format);
75
76 /// Reads a file and returns the manifest json as a C2pa::String.
77 /// @param source_path the path to the file to read.
78 /// @param data_dir the directory to store binary resources (optional).
79 /// @return a string containing the manifest json if a manifest was found.
80 /// @throws a C2pa::C2paException for errors encountered by the C2PA library.
81 optional<string> C2PA_CPP_API read_file(const std::filesystem::path &source_path, const optional<std::filesystem::path> data_dir = nullopt);
82
83 /// Reads a file and returns an ingredient JSON as a C2pa::String.
84 /// @param source_path the path to the file to read.
85 /// @param data_dir the directory to store binary resources.
86 /// @return a string containing the ingredient json.
87 /// @throws a C2pa::C2paException for errors encountered by the C2PA library.
88 std::string C2PA_CPP_API read_ingredient_file(const std::filesystem::path &source_path, const std::filesystem::path &data_dir);
89
90 /// Adds the manifest and signs a file.
91 /// @param source_path the path to the asset to be signed.
92 /// @param dest_path the path to write the signed file to.
93 /// @param manifest the manifest json to add to the file.
94 /// @param signer_info the signer info to use for signing.
95 /// @param data_dir the directory to store binary resources (optional).
96 /// @throws a C2pa::C2paException for errors encountered by the C2PA library.
97 void C2PA_CPP_API sign_file(const std::filesystem::path &source_path,
98 const std::filesystem::path &dest_path,
99 const char *manifest,
100 SignerInfo *signer_info,
101 const std::optional<std::filesystem::path> data_dir = std::nullopt);
102
103 /// @brief Istream Class wrapper for C2paStream.
104 /// @details This class is used to wrap an input stream for use with the C2PA library.
105 class C2PA_CPP_API CppIStream : public C2paStream
106 {
107 public:
108 C2paStream *c_stream;
109 template <typename IStream>
110 explicit CppIStream(IStream &istream) {
111 static_assert(std::is_base_of<std::istream, IStream>::value,
112 "Stream must be derived from std::istream");
113 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&istream), reader, seeker, writer, flusher);
114 }
115
116 CppIStream(const CppIStream &) = delete;
117 CppIStream &operator=(const CppIStream &) = delete;
118 CppIStream(CppIStream &&) = delete;
120
122
123 private:
124 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
125 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
126 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
127 static intptr_t flusher(StreamContext *context);
128
129 friend class Reader;
130 };
131
132 /// @brief Ostream Class wrapper for C2paStream.
133 /// @details This class is used to wrap an output stream for use with the C2PA library.
134 class C2PA_CPP_API CppOStream : public C2paStream
135 {
136 public:
137 C2paStream *c_stream;
138 template <typename OStream>
139 explicit CppOStream(OStream &ostream) {
140 static_assert(std::is_base_of<std::ostream, OStream>::value, "Stream must be derived from std::ostream");
141 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&ostream), reader, seeker, writer, flusher);
142 }
143
145
146 private:
147 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
148 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
149 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
150 static intptr_t flusher(StreamContext *context);
151 };
152
153 /// @brief IOStream Class wrapper for C2paStream.
154 /// @details This class is used to wrap an input/output stream for use with the C2PA library.
155 class C2PA_CPP_API CppIOStream : public C2paStream
156 {
157 public:
158 C2paStream *c_stream;
159 template <typename IOStream>
160 CppIOStream(IOStream &iostream) {
161 static_assert(std::is_base_of<std::iostream, IOStream>::value, "Stream must be derived from std::iostream");
162 c_stream = c2pa_create_stream(reinterpret_cast<StreamContext *>(&iostream), reader, seeker, writer, flusher);
163 }
165
166 private:
167 static intptr_t reader(StreamContext *context, uint8_t *buffer, intptr_t size);
168 static intptr_t writer(StreamContext *context, const uint8_t *buffer, intptr_t size);
169 static intptr_t seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence);
170 static intptr_t flusher(StreamContext *context);
171 };
172
173 /// @brief Reader class for reading a manifest.
174 /// @details This class is used to read and validate a manifest from a stream or file.
176 {
177 private:
178 C2paReader *c2pa_reader;
179 CppIStream *cpp_stream = nullptr;
180
181 public:
182 /// @brief Create a Reader from a stream.
183 /// @details The validation_status field in the json contains validation results.
184 /// @param format The mime format of the stream.
185 /// @param stream The input stream to read from.
186 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
187 Reader(const std::string &format, std::istream &stream);
188
189 /// @brief Create a Reader from a file path.
190 /// @param source_path the path to the file to read.
191 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
192 Reader(const std::filesystem::path &source_path);
194
195 /// @brief Returns if the reader was created from an embedded manifest.
196 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
197 [[nodiscard]] inline bool is_embedded() const {
198 return c2pa_reader_is_embedded(c2pa_reader);
199 }
200
201 /// @brief Returns the remote url of the manifest if this `Reader`
202 /// obtained the manifest remotely.
203 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
204 [[nodiscard]] std::optional<std::string> remote_url() const;
205
206 /// @brief Get the manifest as a json string.
207 /// @return The manifest as a json string.
208 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
209 string json();
210
211 /// @brief Get a resource from the reader and write it to a file.
212 /// @param uri The uri of the resource.
213 /// @param path The path to write the resource to.
214 /// @return The number of bytes written.
215 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
216 int64_t get_resource(const string &uri, const std::filesystem::path &path);
217
218 /// @brief Get a resource from the reader and write it to an output stream.
219 /// @param uri The uri of the resource.
220 /// @param stream The output stream to write the resource to.
221 /// @return The number of bytes written.
222 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
223 int64_t get_resource(const string &uri, std::ostream &stream);
224
225 /// @brief Get the raw C2paReader pointer.
226 /// @return The raw C2paReader pointer.
227 /// @note This is intended for internal API use and compatibility with C APIs.
228 C2paReader* get_api_internal_raw_reader() const { return c2pa_reader; }
229
230 /// @brief Returns a vector of mime types that the SDK is able to
231 /// read manifests from.
232 static std::vector<std::string> supported_mime_types();
233 };
234
235 /// @brief Signer Callback function type.
236 /// @param data the data to sign.
237 /// @return the signature as a vector of bytes.
238 /// @details This function type is used to create a callback function for signing.
239 using SignerFunc = std::vector<unsigned char>(const std::vector<unsigned char> &);
240
241 /// @brief Signer class for creating a signer.
242 /// @details This class is used to create a signer from a signing algorithm, certificate, and TSA URI.
244 {
245 private:
246 C2paSigner *signer;
247
248 public:
249 /// @brief Create a Signer from a callback function, signing algorithm, certificate, and TSA URI.
250 /// @param callback the callback function to use for signing.
251 /// @param alg The signing algorithm to use.
252 /// @param sign_cert The certificate to use for signing.
253 /// @param tsa_uri The TSA URI to use for time-stamping.
254 Signer(SignerFunc *callback, C2paSigningAlg alg, const string &sign_cert, const string &tsa_uri);
255
256 Signer(C2paSigner *signer) : signer(signer) {}
257
258 Signer(const string &alg, const string &sign_cert, const string &private_key, const optional<string> &tsa_uri = nullopt);
259
261
262 /// @brief Get the size to reserve for a signature for this signer.
263 /// @return Reserved size for the signature.
264 uintptr_t reserve_size();
265
266 /// @brief Get the C2paSigner
267 C2paSigner *c2pa_signer();
268 };
269
270 /// @brief Builder class for creating a manifest.
271 /// @details This class is used to create a manifest from a json string and add resources and ingredients to the manifest.
273 {
274 private:
275 C2paBuilder *builder;
276
277 public:
278 /// @brief Create a Builder from a manifest JSON string.
279 /// @param manifest_json The manifest JSON string.
280 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
281 Builder(const std::string &manifest_json);
282
284
285 /// @brief Get the underlying C2paBuilder pointer.
286 /// @return Pointer managed by this wrapper.
287 C2paBuilder *c2pa_builder();
288
289 /// @brief Set the no embed flag.
291
292 /// @brief Set the remote URL.
293 /// @param remote_url The remote URL to set.
294 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
295 void set_remote_url(const string &remote_url);
296
297 /// @brief Set the base path for loading resources from files.
298 /// Loads from memory if this is not set.
299 /// @param base_path The base path to set.
300 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
301 /// @deprecated This method is planned to be deprecated in a future release.
302 /// Usage should be limited and temporary. Use `add_resource` instead.
303 void set_base_path(const string &base_path);
304
305 /// @brief Add a resource to the builder.
306 /// @param uri The uri of the resource.
307 /// @param source The input stream to read the resource from.
308 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
309 void add_resource(const string &uri, istream &source);
310
311 /// @brief Add a resource to the builder.
312 /// @param uri The uri of the resource.
313 /// @param source_path The path to the resource file.
314 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
315 void add_resource(const string &uri, const std::filesystem::path &source_path);
316
317 /// @brief Add an ingredient to the builder.
318 /// @param ingredient_json Any fields of the ingredient you want to define.
319 /// @param format The format of the ingredient file.
320 /// @param source The input stream to read the ingredient from.
321 /// @throws C2pa::C2paException for errors encountered by the C2pa library.
322 void add_ingredient(const string &ingredient_json, const string &format, istream &source);
323
324 /// @brief Add an ingredient to the builder.
325 /// @param ingredient_json Any fields of the ingredient you want to define.
326 /// @param source_path The path to the ingredient file.
327 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
328 void add_ingredient(const string &ingredient_json, const std::filesystem::path &source_path);
329
330 /// @brief Add an action to the manifest the Builder is constructing.
331 /// @param action_json JSON string containing the action data.
332 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
333 void add_action(const string &action_json);
334
335 /// @brief Sign an input stream and write the signed data to an output stream.
336 /// @param format The format of the output stream.
337 /// @param source The input stream to sign.
338 /// @param dest The output stream to write the signed data to.
339 /// @param signer
340 /// @return A vector containing the signed manifest bytes.
341 /// @throws C2pa::C2paException for errors encountered by the C2PA library
342 /// @deprecated Use `sign(const string&, istream&, iostream&, Signer&)`
343 std::vector<unsigned char> sign(const string &format, istream &source, ostream &dest, Signer &signer);
344
345 /// @brief Sign an input stream and write the signed data to an output stream.
346 /// @param format The format of the output stream.
347 /// @param source The input stream to sign.
348 /// @param dest The in/output stream to write the signed data to.
349 /// @param signer
350 /// @return A vector containing the signed manifest bytes.
351 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
352 std::vector<unsigned char> sign(const string &format, istream &source, iostream &dest, Signer &signer);
353
354 /// @brief Sign a file and write the signed data to an output file.
355 /// @param source_path The path to the file to sign.
356 /// @param dest_path The path to write the signed file to.
357 /// @param signer A signer object to use when signing.
358 /// @return A vector containing the signed manifest bytes.
359 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
360 std::vector<unsigned char> sign(const std::filesystem::path &source_path, const std::filesystem::path &dest_path, Signer &signer);
361
362 /// @brief Create a Builder from an archive.
363 /// @param archive The input stream to read the archive from.
364 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
365 static Builder from_archive(istream &archive);
366
367 /// @brief Create a Builder from an archive
368 /// @param archive_path the path to the archive file
369 /// @throws C2pa::C2paException for errors encountered by the C2PA library
370 static Builder from_archive(const std::filesystem::path &archive_path);
371
372 /// @brief Write the builder to an archive stream.
373 /// @param dest The output stream to write the archive to.
374 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
375 void to_archive(ostream &dest);
376
377 /// @brief Write the builder to an archive file.
378 /// @param dest_path The path to write the archive file to.
379 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
380 void to_archive(const std::filesystem::path &dest_path);
381
382 /// @brief Create a hashed placeholder from the builder.
383 /// @param reserved_size The size required for a signature from the intended signer.
384 /// @param format The format of the mime type or extension of the asset.
385 /// @return A vector containing the hashed placeholder.
386 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
387 std::vector<unsigned char> data_hashed_placeholder(uintptr_t reserved_size, const string &format);
388
389 /// @brief Sign a Builder using the specified signer and data hash.
390 /// @param signer The signer to use for signing.
391 /// @param data_hash The data hash ranges to sign. This must contain hashes unless and asset is provided.
392 /// @param format The mime format for embedding into. Use "c2pa" for an unformatted result.
393 /// @param asset An optional asset to hash according to the data_hash information.
394 /// @return A vector containing the signed data.
395 /// @throws C2pa::C2paException for errors encountered by the C2PA library.
396 std::vector<unsigned char> sign_data_hashed_embeddable(Signer &signer, const string &data_hash, const string &format, istream *asset = nullptr);
397
398 /// @brief convert an unformatted manifest data to an embeddable format.
399 /// @param format The format for embedding into.
400 /// @param data An unformatted manifest data block from sign_data_hashed_embeddable using "c2pa" format.
401 /// @return A formatted copy of the data.
402 static std::vector<unsigned char> format_embeddable(const string &format, std::vector<unsigned char> &data);
403
404 /// @brief Returns a vector of mime types that the SDK is able to sign.
405 static std::vector<std::string> supported_mime_types();
406
407 private:
408 // Private constructor for Builder from an archive (todo: find a better way to handle this)
409 explicit Builder(istream &archive);
410 };
411}
412
413// Restore warnings
414#ifdef __GNUC__
415#pragma GCC diagnostic pop
416#endif
417
418#ifdef _MSC_VER
419#pragma warning(pop)
420#endif
421
422#endif // C2PA_H
#define C2PA_CPP_API
Definition c2pa.hpp:44
Builder class for creating a manifest.
Definition c2pa.hpp:273
void add_ingredient(const string &ingredient_json, const string &format, istream &source)
Add an ingredient to the builder.
Builder(const std::string &manifest_json)
Create a Builder from a manifest JSON string.
void set_remote_url(const string &remote_url)
Set the remote URL.
std::vector< unsigned char > sign(const std::filesystem::path &source_path, const std::filesystem::path &dest_path, Signer &signer)
Sign a file and write the signed data to an output file.
void to_archive(ostream &dest)
Write the builder to an archive stream.
void add_resource(const string &uri, const std::filesystem::path &source_path)
Add a resource to the builder.
void add_ingredient(const string &ingredient_json, const std::filesystem::path &source_path)
Add an ingredient to the builder.
void to_archive(const std::filesystem::path &dest_path)
Write the builder to an archive file.
void set_no_embed()
Set the no embed flag.
void add_action(const string &action_json)
Add an action to the manifest the Builder is constructing.
std::vector< unsigned char > sign(const string &format, istream &source, ostream &dest, Signer &signer)
Sign an input stream and write the signed data to an output stream.
static std::vector< unsigned char > format_embeddable(const string &format, std::vector< unsigned char > &data)
convert an unformatted manifest data to an embeddable format.
std::vector< unsigned char > sign_data_hashed_embeddable(Signer &signer, const string &data_hash, const string &format, istream *asset=nullptr)
Sign a Builder using the specified signer and data hash.
static Builder from_archive(const std::filesystem::path &archive_path)
Create a Builder from an archive.
std::vector< unsigned char > data_hashed_placeholder(uintptr_t reserved_size, const string &format)
Create a hashed placeholder from the builder.
C2paBuilder * c2pa_builder()
Get the underlying C2paBuilder pointer.
void add_resource(const string &uri, istream &source)
Add a resource to the builder.
std::vector< unsigned char > sign(const string &format, istream &source, iostream &dest, Signer &signer)
Sign an input stream and write the signed data to an output stream.
static std::vector< std::string > supported_mime_types()
Returns a vector of mime types that the SDK is able to sign.
static Builder from_archive(istream &archive)
Create a Builder from an archive.
void set_base_path(const string &base_path)
Set the base path for loading resources from files. Loads from memory if this is not set.
Definition c2pa.hpp:55
virtual const char * what() const noexcept
C2paException(string what)
IOStream Class wrapper for C2paStream.
Definition c2pa.hpp:156
C2paStream * c_stream
Definition c2pa.hpp:158
CppIOStream(IOStream &iostream)
Definition c2pa.hpp:160
Istream Class wrapper for C2paStream.
Definition c2pa.hpp:106
CppIStream & operator=(const CppIStream &)=delete
CppIStream(CppIStream &&)=delete
CppIStream & operator=(CppIStream &&)=delete
C2paStream * c_stream
Definition c2pa.hpp:108
CppIStream(IStream &istream)
Definition c2pa.hpp:110
CppIStream(const CppIStream &)=delete
Ostream Class wrapper for C2paStream.
Definition c2pa.hpp:135
CppOStream(OStream &ostream)
Definition c2pa.hpp:139
C2paStream * c_stream
Definition c2pa.hpp:137
Reader class for reading a manifest.
Definition c2pa.hpp:176
int64_t get_resource(const string &uri, const std::filesystem::path &path)
Get a resource from the reader and write it to a file.
bool is_embedded() const
Returns if the reader was created from an embedded manifest.
Definition c2pa.hpp:197
Reader(const std::string &format, std::istream &stream)
Create a Reader from a stream.
std::optional< std::string > remote_url() const
Returns the remote url of the manifest if this Reader obtained the manifest remotely.
int64_t get_resource(const string &uri, std::ostream &stream)
Get a resource from the reader and write it to an output stream.
string json()
Get the manifest as a json string.
Reader(const std::filesystem::path &source_path)
Create a Reader from a file path.
C2paReader * get_api_internal_raw_reader() const
Get the raw C2paReader pointer.
Definition c2pa.hpp:228
static std::vector< std::string > supported_mime_types()
Returns a vector of mime types that the SDK is able to read manifests from.
Signer class for creating a signer.
Definition c2pa.hpp:244
Signer(const string &alg, const string &sign_cert, const string &private_key, const optional< string > &tsa_uri=nullopt)
Signer(SignerFunc *callback, C2paSigningAlg alg, const string &sign_cert, const string &tsa_uri)
Create a Signer from a callback function, signing algorithm, certificate, and TSA URI.
uintptr_t reserve_size()
Get the size to reserve for a signature for this signer.
C2paSigner * c2pa_signer()
Get the C2paSigner.
Signer(C2paSigner *signer)
Definition c2pa.hpp:256
Definition c2pa.hpp:47
C2paSignerInfo SignerInfo
Definition c2pa.hpp:50
std::vector< unsigned char >(const std::vector< unsigned char > &) SignerFunc
Signer Callback function type.
Definition c2pa.hpp:239