-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathemscripten_example.cpp
More file actions
168 lines (142 loc) · 5.82 KB
/
emscripten_example.cpp
File metadata and controls
168 lines (142 loc) · 5.82 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
// Example: Using c2pa C++ library in an Emscripten project
// Build: make emscripten-example
//
// HTTP resolver note: emscripten_fetch in SYNCHRONOUS mode is only available
// from a Web Worker, not the browser main thread. Under Node.js there is no
// such restriction.
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "c2pa.hpp"
#include <emscripten/fetch.h>
using namespace c2pa;
// ---------------------------------------------------------------------------
// Example 1: read from file path
// ---------------------------------------------------------------------------
static void read_from_file(const std::string& path) {
std::cout << "\n[1] Reading manifest from file: " << path << std::endl;
try {
Context ctx;
Reader reader(ctx, path);
std::cout << reader.json() << std::endl;
} catch (const C2paException& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// ---------------------------------------------------------------------------
// Example 2: read from an in-memory stream
// ---------------------------------------------------------------------------
static void read_from_stream(const std::vector<uint8_t>& data) {
std::cout << "\n[2] Reading manifest from memory stream" << std::endl;
try {
// Wrap the data in a std::istringstream so CppIStream can use it.
std::string str_data(reinterpret_cast<const char*>(data.data()), data.size());
std::istringstream iss(str_data, std::ios::binary);
Context ctx;
Reader reader(ctx, "image/jpeg", iss);
std::cout << reader.json() << std::endl;
std::cout << "Embedded: " << (reader.is_embedded() ? "yes" : "no") << std::endl;
} catch (const C2paException& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// ---------------------------------------------------------------------------
// Example 3: read with a custom HTTP resolver (emscripten_fetch)
// - Exercises remote manifest fetching, OCSP, timestamps, etc.
// - Must run from a Web Worker in the browser; no restriction under Node.js.
// ---------------------------------------------------------------------------
// Parse "Name: Value\n..." into a NULL-terminated char* array for
// emscripten_fetch_attr_t::requestHeaders.
struct ParsedHeaders {
std::vector<std::string> storage;
std::vector<const char*> ptrs;
};
static ParsedHeaders parse_headers(const std::string& raw) {
ParsedHeaders h;
std::istringstream ss(raw);
std::string line;
while (std::getline(ss, line)) {
if (line.empty()) continue;
auto colon = line.find(':');
if (colon == std::string::npos) continue;
h.storage.push_back(line.substr(0, colon));
h.storage.push_back(line.substr(colon + 2));
}
for (auto& s : h.storage) h.ptrs.push_back(s.c_str());
h.ptrs.push_back(nullptr);
return h;
}
static int emscripten_http_handler(
void* /*ctx*/, const C2paHttpRequest* req, C2paHttpResponse* resp)
{
emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS;
strncpy(attr.requestMethod, req->method, sizeof(attr.requestMethod) - 1);
attr.requestMethod[sizeof(attr.requestMethod) - 1] = '\0';
if (req->body && req->body_len > 0) {
attr.requestData = reinterpret_cast<const char*>(req->body);
attr.requestDataSize = req->body_len;
}
auto headers = parse_headers(req->headers ? req->headers : "");
if (headers.ptrs.size() > 1) attr.requestHeaders = headers.ptrs.data();
emscripten_fetch_t* fetch = emscripten_fetch(&attr, req->url);
if (!fetch) { c2pa_error_set_last("emscripten_fetch returned null"); return -1; }
resp->status = static_cast<int32_t>(fetch->status);
resp->body_len = static_cast<size_t>(fetch->numBytes);
if (resp->body_len > 0 && fetch->data) {
resp->body = static_cast<uint8_t*>(malloc(resp->body_len));
memcpy(resp->body, fetch->data, resp->body_len);
} else {
resp->body = nullptr;
resp->body_len = 0;
}
emscripten_fetch_close(fetch);
return 0;
}
static void read_with_http_resolver(const std::vector<uint8_t>& data) {
std::cout << "\n[3] Reading remote manifest with custom HTTP resolver" << std::endl;
try {
auto ctx = Context::ContextBuilder()
.with_http_resolver(nullptr, emscripten_http_handler)
.create_context();
std::string str_data(reinterpret_cast<const char*>(data.data()), data.size());
std::istringstream iss(str_data, std::ios::binary);
Reader reader(ctx, "image/jpeg", iss);
std::cout << reader.json() << std::endl;
} catch (const C2paException& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
// ---------------------------------------------------------------------------
int main(int argc, char* argv[]) {
std::cout << "=== C2PA Emscripten Example ===" << std::endl;
std::cout << "Version: " << version() << std::endl;
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <image.jpg>" << std::endl;
return 0;
}
const char* path = argv[1];
// Read file into memory once; reuse for stream-based examples.
std::vector<uint8_t> image_data;
{
std::ifstream f(path, std::ios::binary | std::ios::ate);
if (f) {
auto sz = f.tellg();
f.seekg(0);
image_data.resize(static_cast<size_t>(sz));
f.read(reinterpret_cast<char*>(image_data.data()), sz);
}
}
read_from_file(path);
if (!image_data.empty()) {
read_from_stream(image_data);
read_with_http_resolver(image_data);
}
std::cout << "\n=== Done ===" << std::endl;
return 0;
}