-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathc2pa_reader.cpp
More file actions
183 lines (156 loc) · 6.68 KB
/
c2pa_reader.cpp
File metadata and controls
183 lines (156 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright 2024 Adobe. All rights reserved.
// This file is licensed to you under the Apache License,
// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.
// Unless required by applicable law or agreed to in writing,
// this software is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
// implied. See the LICENSE-MIT and LICENSE-APACHE files for the
// specific language governing permissions and limitations under
// each license.
/// @file c2pa_reader.cpp
/// @brief Reader class implementation.
#include <system_error>
#include "c2pa.hpp"
#include "c2pa_internal.hpp"
namespace {
template <typename F>
std::optional<c2pa::Reader> reader_from_asset_impl(F&& construct_reader) {
try {
return construct_reader();
} catch (const c2pa::C2paException& e) {
if (c2pa::detail::error_indicates_manifest_not_found(e.what())) {
return std::nullopt;
}
throw;
}
}
} // namespace
namespace c2pa
{
/// Reader class for reading manifests
Reader::Reader(IContextProvider& context, const std::string &format, std::istream &stream)
: c2pa_reader(nullptr)
{
if (!context.is_valid()) {
throw C2paException("Invalid Context provider IContextProvider");
}
c2pa_reader = c2pa_reader_from_context(context.c_context());
if (c2pa_reader == nullptr) {
throw C2paException("Failed to create reader from context");
}
callback_guard_ = context.callback_guard();
cpp_stream = std::make_unique<CppIStream>(stream);
// Update reader with stream.
// Note: c2pa_reader_with_stream always consumes the reader pointer,
// so the original pointer is invalid after this call regardless of success/error.
C2paReader* updated = c2pa_reader_with_stream(c2pa_reader, format.c_str(), cpp_stream->c_stream);
c2pa_reader = nullptr;
if (updated == nullptr) {
throw C2paException();
}
c2pa_reader = updated;
}
Reader::Reader(IContextProvider& context, const std::filesystem::path &source_path)
: c2pa_reader(nullptr)
{
if (!context.is_valid()) {
throw C2paException("Invalid Context provider IContextProvider");
}
c2pa_reader = c2pa_reader_from_context(context.c_context());
if (c2pa_reader == nullptr) {
throw C2paException("Failed to create reader from context");
}
callback_guard_ = context.callback_guard();
// Create owned stream that will live as long as the Reader
owned_stream = std::make_unique<std::ifstream>(source_path, std::ios::binary);
if (!owned_stream->is_open()) {
c2pa_free(c2pa_reader);
throw std::system_error(errno, std::system_category(), "Failed to open file: " + source_path.string());
}
std::string extension = detail::extract_file_extension(source_path);
// CppIStream stores reference to owned_stream, which lives as long as Reader
cpp_stream = std::make_unique<CppIStream>(*owned_stream);
// Note: c2pa_reader_with_stream always consumes the reader pointer.
C2paReader* updated = c2pa_reader_with_stream(c2pa_reader, extension.c_str(), cpp_stream->c_stream);
c2pa_reader = nullptr;
if (updated == nullptr) {
throw C2paException();
}
c2pa_reader = updated;
}
Reader::Reader(const std::string &format, std::istream &stream)
{
cpp_stream = std::make_unique<CppIStream>(stream);
c2pa_reader = c2pa_reader_from_stream(format.c_str(), cpp_stream->c_stream);
if (c2pa_reader == nullptr)
{
throw C2paException();
}
}
Reader::Reader(const std::filesystem::path &source_path)
{
// Create owned stream that will live as long as the Reader
owned_stream = std::make_unique<std::ifstream>(source_path, std::ios::binary);
if (!owned_stream->is_open()) {
throw std::system_error(errno, std::system_category(), "Failed to open file: " + source_path.string());
}
std::string extension = detail::extract_file_extension(source_path);
// CppIStream stores reference to owned_stream, which lives as long as Reader
cpp_stream = std::make_unique<CppIStream>(*owned_stream);
c2pa_reader = c2pa_reader_from_stream(extension.c_str(), cpp_stream->c_stream);
if (c2pa_reader == nullptr)
{
throw C2paException();
}
}
Reader::~Reader()
{
c2pa_free(c2pa_reader);
// cpp_stream and owned_stream are cleaned up by unique_ptr
}
std::string Reader::json() const
{
return detail::c_string_to_string(c2pa_reader_json(c2pa_reader));
}
[[nodiscard]] std::optional<std::string> Reader::remote_url() const {
auto url = c2pa_reader_remote_url(c2pa_reader);
if (url == nullptr) { return std::nullopt; }
std::string url_str(url);
// The C2PA library returns a `const char*` that needs to be released.
// The underlying `char*` is mutable; however, to indicate the value
// shouldn't be modified, it's returned as a const char*.
//
// TODO: Revisit after determining how we want c2pa-rs to handle
// strings that shouldn't be modified by our bindings.
c2pa_free(url);
return url_str;
}
int64_t Reader::get_resource(const std::string &uri, const std::filesystem::path &path)
{
auto file_stream = detail::open_file_binary<std::ofstream>(path);
return get_resource(uri.c_str(), *file_stream);
}
int64_t Reader::get_resource(const std::string &uri, std::ostream &stream)
{
CppOStream output_stream(stream);
int64_t result = c2pa_reader_resource_to_stream(c2pa_reader, uri.c_str(), output_stream.c_stream);
if (result < 0)
{
throw C2paException();
}
return result;
}
std::vector<std::string> Reader::supported_mime_types() {
uintptr_t count = 0;
auto ptr = c2pa_reader_supported_mime_types(&count);
return detail::c_mime_types_to_vector(ptr, count);
}
std::optional<Reader> Reader::from_asset(IContextProvider& context, const std::filesystem::path& source_path) {
return reader_from_asset_impl([&]() { return Reader(context, source_path); });
}
std::optional<Reader> Reader::from_asset(IContextProvider& context, const std::string& format, std::istream& stream) {
return reader_from_asset_impl([&]() { return Reader(context, format, stream); });
}
} // namespace c2pa