c2pa-cpp
C++ API for the C2PA SDK
Loading...
Searching...
No Matches
c2pa_internal.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_internal.hpp
14/// @brief Internal implementation details shared across c2pa_cpp source files.
15/// @details This header is private to the library implementation and not installed,
16/// as it is used to share code inside c2pa_cpp SDK.
17
18#ifndef C2PA_INTERNAL_HPP
19#define C2PA_INTERNAL_HPP
20
21#include <cstring>
22#include <fstream>
23#include <filesystem>
24#include <string>
25#include <vector>
26#include <memory>
27
28#include "c2pa.h"
29#include "c2pa.hpp"
30
31namespace c2pa {
32namespace detail {
33
34/// @brief True if the C2PA error message indicates no JUMBF / manifest in the asset (ManifestNotFound).
35inline bool error_indicates_manifest_not_found(const char* message) noexcept {
36 return message != nullptr && std::strstr(message, "ManifestNotFound") != nullptr;
37}
38
39/// @brief Converts a C array of C strings to a std::vector of std::string.
40/// @param mime_types Pointer to an array of C strings (const char*).
41/// @param count Number of elements in the array.
42/// @return A std::vector containing the strings from the input array.
43/// @details This function takes ownership of the input array and frees it
44/// using c2pa_free_string_array().
45inline std::vector<std::string> c_mime_types_to_vector(const char* const* mime_types, uintptr_t count) {
46 std::vector<std::string> result;
47 if (mime_types == nullptr) { return result; }
48
49 result.reserve(count);
50 for(uintptr_t i = 0; i < count; i++) {
51 result.emplace_back(mime_types[i]);
52 }
53
54 c2pa_free_string_array(mime_types, count);
55 return result;
56}
57
58/// Maps C2PA seek mode to std::ios seek direction.
59constexpr std::ios_base::seekdir whence_to_seekdir(C2paSeekMode whence) noexcept {
60 switch (whence) {
61 case C2paSeekMode::Start: return std::ios_base::beg;
62 case C2paSeekMode::Current: return std::ios_base::cur;
63 case C2paSeekMode::End: return std::ios_base::end;
64 default: return std::ios_base::beg;
65 }
66}
67
68/// Check if stream is in valid state for I/O operations
69template<typename Stream>
70inline bool is_stream_usable(Stream* s) noexcept {
71 return s && !s->bad();
72}
73
74/// Traits (templated): how to seek and get position for a given stream type.
75template<typename Stream>
77
78template<>
79struct StreamSeekTraits<std::istream> {
80 static void seek(std::istream* s, intptr_t offset, std::ios_base::seekdir dir) {
81 s->seekg(offset, dir);
82 }
83 static int64_t tell(std::istream* s) {
84 return static_cast<int64_t>(s->tellg());
85 }
86};
87
88template<>
89struct StreamSeekTraits<std::ostream> {
90 static void seek(std::ostream* s, intptr_t offset, std::ios_base::seekdir dir) {
91 s->seekp(offset, dir);
92 }
93 static int64_t tell(std::ostream* s) {
94 return static_cast<int64_t>(s->tellp());
95 }
96};
97
98template<>
99struct StreamSeekTraits<std::iostream> {
100 static void seek(std::iostream* s, intptr_t offset, std::ios_base::seekdir dir) {
101 s->seekg(offset, dir);
102 s->seekp(offset, dir);
103 }
104 static int64_t tell(std::iostream* s) {
105 return static_cast<int64_t>(s->tellp());
106 }
107};
108
109/// Seeker impl.
110template<typename Stream>
111intptr_t stream_seeker(StreamContext* context, intptr_t offset, C2paSeekMode whence) {
112 auto* stream = reinterpret_cast<Stream*>(context);
113 if (!is_stream_usable(stream)) {
115 }
116 const std::ios_base::seekdir dir = whence_to_seekdir(whence);
117 stream->clear();
118 StreamSeekTraits<Stream>::seek(stream, offset, dir);
119 if (stream->fail()) {
121 }
122 if (stream->bad()) {
124 }
125 const int64_t pos = StreamSeekTraits<Stream>::tell(stream);
126 if (pos < 0) {
128 }
129 return static_cast<intptr_t>(pos);
130}
131
132/// Reader impl.
133template<typename Stream>
134intptr_t stream_reader(StreamContext* context, uint8_t* buffer, intptr_t size) {
135 if (!context || !buffer) {
137 }
138 if (size < 0) {
140 }
141 if (size == 0) {
142 return 0;
143 }
144 auto* stream = reinterpret_cast<Stream*>(context);
145 if (!is_stream_usable(stream)) {
147 }
148 stream->read(reinterpret_cast<char*>(buffer), size);
149 if (stream->fail()) {
150 if (!stream->eof()) {
152 }
153 }
154 if (stream->bad()) {
156 }
157 return static_cast<intptr_t>(stream->gcount());
158}
159
160/// Get stream from context, used by writer and flusher.
161template<typename Stream, typename Op>
162intptr_t stream_op(StreamContext* context, Op op) {
163 auto* stream = reinterpret_cast<Stream*>(context);
164 if (!is_stream_usable(stream)) {
166 }
167 const intptr_t result = op(stream);
168 if (stream->fail()) {
170 }
171 if (stream->bad()) {
173 }
174 return result;
175}
176
177/// Writer impl.
178template<typename Stream>
179intptr_t stream_writer(StreamContext* context, const uint8_t* buffer, intptr_t size) {
180 return stream_op<Stream>(context, [buffer, size](Stream* s) {
181 s->write(reinterpret_cast<const char*>(buffer), size);
182 return size;
183 });
184}
185
186/// Flusher impl.
187template<typename Stream>
189 return stream_op<Stream>(context, [](Stream* s) {
190 s->flush();
191 return 0;
192 });
193}
194
195/// @brief Open a binary file stream with error handling
196/// @tparam StreamType std::ifstream or std::ofstream
197/// @param path Path to the file
198/// @return Unique pointer to opened stream
199template<typename StreamType>
200inline std::unique_ptr<StreamType> open_file_binary(const std::filesystem::path &path)
201{
202 auto stream = std::make_unique<StreamType>(
203 path,
204 std::ios_base::binary
205 );
206 if (!stream->is_open()) {
207 throw C2paException("Failed to open file: " + path.string());
208 }
209 return stream;
210}
211
212/// @brief Extract file extension without the leading dot
213/// @param path Filesystem path
214/// @return Extension string (e.g., "jpg" not ".jpg")
215inline std::string extract_file_extension(const std::filesystem::path &path) noexcept {
216 auto ext = path.extension().string();
217 return ext.empty() ? "" : ext.substr(1);
218}
219
220/// @brief Convert C string result to C++ string with cleanup
221/// @param c_result Raw C string from C API
222/// @return C++ string (throws if null)
223template<typename T>
224inline std::string c_string_to_string(T* c_result) {
225 if (c_result == nullptr) {
226 throw C2paException();
227 }
228 std::string str(c_result);
230 return str;
231}
232
233/// @brief Convert C byte array result to C++ vector
234/// @param data Raw byte array from C API
235/// @param size Size of the byte array (result from C API call)
236/// @return Vector containing the bytes (throws if null or negative size)
237/// @details This helper extracts the pattern of checking C API results,
238/// copying to a vector, and freeing the C-allocated memory.
239/// The C API contract is: if result < 0 or data == nullptr, the operation failed.
240inline std::vector<unsigned char> to_byte_vector(const unsigned char* data, int64_t size) {
241 if (size < 0 || data == nullptr) {
242 c2pa_free(data); // May be null or allocated, c2pa_free handles both
243 throw C2paException();
244 }
245
246 auto result = std::vector<unsigned char>(data, data + size);
248 return result;
249}
250
251} // namespace detail
252} // namespace c2pa
253
254#endif // C2PA_INTERNAL_HPP
C++ wrapper for the C2PA C library.
Exception class for C2pa errors. This class is used to throw exceptions for errors encountered by the...
Definition c2pa.hpp:87
std::vector< std::string > c_mime_types_to_vector(const char *const *mime_types, uintptr_t count)
Converts a C array of C strings to a std::vector of std::string.
Definition c2pa_internal.hpp:45
intptr_t stream_writer(StreamContext *context, const uint8_t *buffer, intptr_t size)
Writer impl.
Definition c2pa_internal.hpp:179
intptr_t stream_op(StreamContext *context, Op op)
Get stream from context, used by writer and flusher.
Definition c2pa_internal.hpp:162
std::string extract_file_extension(const std::filesystem::path &path) noexcept
Extract file extension without the leading dot.
Definition c2pa_internal.hpp:215
bool error_indicates_manifest_not_found(const char *message) noexcept
True if the C2PA error message indicates no JUMBF / manifest in the asset (ManifestNotFound).
Definition c2pa_internal.hpp:35
intptr_t stream_flusher(StreamContext *context)
Flusher impl.
Definition c2pa_internal.hpp:188
constexpr std::ios_base::seekdir whence_to_seekdir(C2paSeekMode whence) noexcept
Maps C2PA seek mode to std::ios seek direction.
Definition c2pa_internal.hpp:59
bool is_stream_usable(Stream *s) noexcept
Check if stream is in valid state for I/O operations.
Definition c2pa_internal.hpp:70
std::vector< unsigned char > to_byte_vector(const unsigned char *data, int64_t size)
Convert C byte array result to C++ vector.
Definition c2pa_internal.hpp:240
intptr_t stream_reader(StreamContext *context, uint8_t *buffer, intptr_t size)
Reader impl.
Definition c2pa_internal.hpp:134
std::string c_string_to_string(T *c_result)
Convert C string result to C++ string with cleanup.
Definition c2pa_internal.hpp:224
intptr_t stream_seeker(StreamContext *context, intptr_t offset, C2paSeekMode whence)
Seeker impl.
Definition c2pa_internal.hpp:111
std::unique_ptr< StreamType > open_file_binary(const std::filesystem::path &path)
Open a binary file stream with error handling.
Definition c2pa_internal.hpp:200
Definition c2pa.hpp:52
int stream_error_return(StreamError e) noexcept
Set errno from StreamError and return error sentinel.
Definition c2pa.hpp:79
static void seek(std::iostream *s, intptr_t offset, std::ios_base::seekdir dir)
Definition c2pa_internal.hpp:100
static int64_t tell(std::iostream *s)
Definition c2pa_internal.hpp:104
static int64_t tell(std::istream *s)
Definition c2pa_internal.hpp:83
static void seek(std::istream *s, intptr_t offset, std::ios_base::seekdir dir)
Definition c2pa_internal.hpp:80
static void seek(std::ostream *s, intptr_t offset, std::ios_base::seekdir dir)
Definition c2pa_internal.hpp:90
static int64_t tell(std::ostream *s)
Definition c2pa_internal.hpp:93
Traits (templated): how to seek and get position for a given stream type.
Definition c2pa_internal.hpp:76