| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
* pdfmake_attach.c — File attachments and embedded files. |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* §7.11.3 File Specification Dictionaries |
|
5
|
|
|
|
|
|
|
* §7.11.4 Embedded File Streams |
|
6
|
|
|
|
|
|
|
* §14.13 Embedded Files |
|
7
|
|
|
|
|
|
|
*/ |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#include "pdfmake_attach.h" |
|
10
|
|
|
|
|
|
|
#include "pdfmake_arena.h" |
|
11
|
|
|
|
|
|
|
#include "pdfmake_filter.h" |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
#include |
|
14
|
|
|
|
|
|
|
#include |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
/* ── MIME type guessing from filename extension ─────────── */ |
|
17
|
|
|
|
|
|
|
|
|
18
|
1
|
|
|
|
|
|
static const char *_guess_mime(const char *filename) { |
|
19
|
1
|
|
|
|
|
|
const char *dot = strrchr(filename, '.'); |
|
20
|
1
|
50
|
|
|
|
|
if (!dot) return "application/octet-stream"; |
|
21
|
1
|
|
|
|
|
|
dot++; |
|
22
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "pdf") == 0) return "application/pdf"; |
|
23
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "txt") == 0) return "text/plain"; |
|
24
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "html") == 0) return "text/html"; |
|
25
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "htm") == 0) return "text/html"; |
|
26
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "xml") == 0) return "application/xml"; |
|
27
|
1
|
50
|
|
|
|
|
if (strcasecmp(dot, "json") == 0) return "application/json"; |
|
28
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "csv") == 0) return "text/csv"; |
|
29
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "jpg") == 0) return "image/jpeg"; |
|
30
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "jpeg") == 0) return "image/jpeg"; |
|
31
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "png") == 0) return "image/png"; |
|
32
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "gif") == 0) return "image/gif"; |
|
33
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "svg") == 0) return "image/svg+xml"; |
|
34
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "zip") == 0) return "application/zip"; |
|
35
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "xlsx") == 0) return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; |
|
36
|
0
|
0
|
|
|
|
|
if (strcasecmp(dot, "docx") == 0) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; |
|
37
|
0
|
|
|
|
|
|
return "application/octet-stream"; |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
/* ── Create ────────────────────────────────────────────── */ |
|
41
|
|
|
|
|
|
|
|
|
42
|
25
|
|
|
|
|
|
pdfmake_attachment_t *pdfmake_doc_attach( |
|
43
|
|
|
|
|
|
|
pdfmake_doc_t *doc, |
|
44
|
|
|
|
|
|
|
const char *name, |
|
45
|
|
|
|
|
|
|
const char *filename, |
|
46
|
|
|
|
|
|
|
const uint8_t *data, size_t len, |
|
47
|
|
|
|
|
|
|
const char *mime_type, |
|
48
|
|
|
|
|
|
|
const char *description) |
|
49
|
|
|
|
|
|
|
{ |
|
50
|
|
|
|
|
|
|
size_t new_cap; |
|
51
|
|
|
|
|
|
|
void **new_arr; |
|
52
|
|
|
|
|
|
|
pdfmake_attachment_t *att; |
|
53
|
|
|
|
|
|
|
|
|
54
|
25
|
50
|
|
|
|
|
if (!doc || !name || !data) return NULL; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
|
56
|
25
|
100
|
|
|
|
|
if (doc->attach_count >= doc->attach_cap) { |
|
57
|
10
|
100
|
|
|
|
|
new_cap = doc->attach_cap == 0 ? 4 : doc->attach_cap * 2; |
|
58
|
10
|
|
|
|
|
|
new_arr = realloc(doc->attachments, new_cap * sizeof(void *)); |
|
59
|
10
|
50
|
|
|
|
|
if (!new_arr) return NULL; |
|
60
|
10
|
|
|
|
|
|
doc->attachments = new_arr; |
|
61
|
10
|
|
|
|
|
|
doc->attach_cap = new_cap; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
25
|
|
|
|
|
|
att = calloc(1, sizeof(pdfmake_attachment_t)); |
|
65
|
25
|
50
|
|
|
|
|
if (!att) return NULL; |
|
66
|
|
|
|
|
|
|
|
|
67
|
25
|
|
|
|
|
|
strncpy(att->name, name, sizeof(att->name) - 1); |
|
68
|
25
|
100
|
|
|
|
|
strncpy(att->filename, filename ? filename : name, sizeof(att->filename) - 1); |
|
69
|
|
|
|
|
|
|
|
|
70
|
25
|
100
|
|
|
|
|
if (mime_type) { |
|
71
|
24
|
|
|
|
|
|
strncpy(att->mime_type, mime_type, sizeof(att->mime_type) - 1); |
|
72
|
|
|
|
|
|
|
} else { |
|
73
|
1
|
|
|
|
|
|
strncpy(att->mime_type, _guess_mime(att->filename), sizeof(att->mime_type) - 1); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
25
|
100
|
|
|
|
|
if (description) { |
|
77
|
3
|
|
|
|
|
|
strncpy(att->description, description, sizeof(att->description) - 1); |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
25
|
|
|
|
|
|
att->data = malloc(len); |
|
81
|
25
|
50
|
|
|
|
|
if (!att->data) { free(att); return NULL; } |
|
82
|
25
|
|
|
|
|
|
memcpy(att->data, data, len); |
|
83
|
25
|
|
|
|
|
|
att->data_len = len; |
|
84
|
|
|
|
|
|
|
|
|
85
|
25
|
|
|
|
|
|
doc->attachments[doc->attach_count++] = att; |
|
86
|
25
|
|
|
|
|
|
return att; |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
|
pdfmake_attachment_t *pdfmake_doc_attach_file( |
|
90
|
|
|
|
|
|
|
pdfmake_doc_t *doc, |
|
91
|
|
|
|
|
|
|
const char *name, |
|
92
|
|
|
|
|
|
|
const char *path) |
|
93
|
|
|
|
|
|
|
{ |
|
94
|
|
|
|
|
|
|
FILE *fp; |
|
95
|
|
|
|
|
|
|
long file_len; |
|
96
|
|
|
|
|
|
|
uint8_t *buf; |
|
97
|
|
|
|
|
|
|
size_t nread; |
|
98
|
|
|
|
|
|
|
const char *slash; |
|
99
|
|
|
|
|
|
|
const char *bslash; |
|
100
|
|
|
|
|
|
|
const char *fname; |
|
101
|
|
|
|
|
|
|
pdfmake_attachment_t *att; |
|
102
|
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
|
if (!doc || !name || !path) return NULL; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
fp = fopen(path, "rb"); |
|
106
|
0
|
0
|
|
|
|
|
if (!fp) return NULL; |
|
107
|
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
fseek(fp, 0, SEEK_END); |
|
109
|
0
|
|
|
|
|
|
file_len = ftell(fp); |
|
110
|
0
|
0
|
|
|
|
|
if (file_len < 0) { fclose(fp); return NULL; } |
|
111
|
0
|
|
|
|
|
|
rewind(fp); |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
buf = malloc((size_t)file_len); |
|
114
|
0
|
0
|
|
|
|
|
if (!buf) { fclose(fp); return NULL; } |
|
115
|
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
nread = fread(buf, 1, (size_t)file_len, fp); |
|
117
|
0
|
|
|
|
|
|
fclose(fp); |
|
118
|
|
|
|
|
|
|
|
|
119
|
0
|
0
|
|
|
|
|
if ((long)nread != file_len) { free(buf); return NULL; } |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
/* Extract filename from path */ |
|
122
|
0
|
|
|
|
|
|
slash = strrchr(path, '/'); |
|
123
|
0
|
|
|
|
|
|
bslash = strrchr(path, '\\'); |
|
124
|
0
|
|
|
|
|
|
fname = path; |
|
125
|
0
|
0
|
|
|
|
|
if (slash && slash > fname) fname = slash + 1; |
|
|
|
0
|
|
|
|
|
|
|
126
|
0
|
0
|
|
|
|
|
if (bslash && bslash > fname) fname = bslash + 1; |
|
|
|
0
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
|
att = pdfmake_doc_attach(doc, name, fname, |
|
129
|
|
|
|
|
|
|
buf, (size_t)file_len, NULL, NULL); |
|
130
|
0
|
|
|
|
|
|
free(buf); |
|
131
|
0
|
|
|
|
|
|
return att; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
/* ── Query ─────────────────────────────────────────────── */ |
|
135
|
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
size_t pdfmake_doc_attachment_count(pdfmake_doc_t *doc) { |
|
137
|
0
|
0
|
|
|
|
|
return doc ? doc->attach_count : 0; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
pdfmake_attachment_t *pdfmake_doc_attachment_at(pdfmake_doc_t *doc, size_t idx) { |
|
141
|
0
|
0
|
|
|
|
|
if (!doc || idx >= doc->attach_count) return NULL; |
|
|
|
0
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
return (pdfmake_attachment_t *)doc->attachments[idx]; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
pdfmake_attachment_t *pdfmake_doc_attachment_by_name(pdfmake_doc_t *doc, const char *name) { |
|
146
|
|
|
|
|
|
|
size_t i; |
|
147
|
|
|
|
|
|
|
pdfmake_attachment_t *att; |
|
148
|
|
|
|
|
|
|
|
|
149
|
0
|
0
|
|
|
|
|
if (!doc || !name) return NULL; |
|
|
|
0
|
|
|
|
|
|
|
150
|
0
|
0
|
|
|
|
|
for (i = 0; i < doc->attach_count; i++) { |
|
151
|
0
|
|
|
|
|
|
att = (pdfmake_attachment_t *)doc->attachments[i]; |
|
152
|
0
|
0
|
|
|
|
|
if (strcmp(att->name, name) == 0) return att; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
0
|
|
|
|
|
|
return NULL; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
/* ── Properties ────────────────────────────────────────── */ |
|
158
|
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
const char *pdfmake_attachment_name(pdfmake_attachment_t *att) { |
|
160
|
0
|
0
|
|
|
|
|
return att ? att->name : NULL; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
0
|
|
|
|
|
|
const char *pdfmake_attachment_filename(pdfmake_attachment_t *att) { |
|
163
|
0
|
0
|
|
|
|
|
return att ? att->filename : NULL; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
0
|
|
|
|
|
|
const char *pdfmake_attachment_mime_type(pdfmake_attachment_t *att) { |
|
166
|
0
|
0
|
|
|
|
|
return att ? att->mime_type : NULL; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
0
|
|
|
|
|
|
size_t pdfmake_attachment_size(pdfmake_attachment_t *att) { |
|
169
|
0
|
0
|
|
|
|
|
return att ? att->data_len : 0; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
/* ── Extract ───────────────────────────────────────────── */ |
|
173
|
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
const uint8_t *pdfmake_attachment_data(pdfmake_attachment_t *att, size_t *out_len) { |
|
175
|
0
|
0
|
|
|
|
|
if (!att) { if (out_len) *out_len = 0; return NULL; } |
|
|
|
0
|
|
|
|
|
|
|
176
|
0
|
0
|
|
|
|
|
if (out_len) *out_len = att->data_len; |
|
177
|
0
|
|
|
|
|
|
return att->data; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
0
|
|
|
|
|
|
pdfmake_err_t pdfmake_attachment_extract_to_file(pdfmake_attachment_t *att, const char *path) { |
|
181
|
|
|
|
|
|
|
FILE *fp; |
|
182
|
|
|
|
|
|
|
size_t written; |
|
183
|
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
|
if (!att || !path || !att->data) return PDFMAKE_EINVAL; |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
fp = fopen(path, "wb"); |
|
186
|
0
|
0
|
|
|
|
|
if (!fp) return PDFMAKE_EINVAL; |
|
187
|
0
|
|
|
|
|
|
written = fwrite(att->data, 1, att->data_len, fp); |
|
188
|
0
|
|
|
|
|
|
fclose(fp); |
|
189
|
0
|
0
|
|
|
|
|
return (written == att->data_len) ? PDFMAKE_OK : PDFMAKE_EINVAL; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
/* ── Write ─────────────────────────────────────────────── */ |
|
193
|
|
|
|
|
|
|
|
|
194
|
4
|
|
|
|
|
|
uint32_t pdfmake_attachment_write(pdfmake_attachment_t *att, pdfmake_doc_t *doc) { |
|
195
|
|
|
|
|
|
|
pdfmake_arena_t *arena; |
|
196
|
|
|
|
|
|
|
uint32_t k; |
|
197
|
|
|
|
|
|
|
pdfmake_buf_t compressed; |
|
198
|
|
|
|
|
|
|
pdfmake_flate_params_t params; |
|
199
|
|
|
|
|
|
|
int use_flate; |
|
200
|
|
|
|
|
|
|
pdfmake_obj_t ef_stream; |
|
201
|
|
|
|
|
|
|
pdfmake_obj_t ef_dict_obj; |
|
202
|
|
|
|
|
|
|
char encoded[256]; |
|
203
|
|
|
|
|
|
|
size_t ei; |
|
204
|
|
|
|
|
|
|
size_t i; |
|
205
|
|
|
|
|
|
|
pdfmake_obj_t ef_params; |
|
206
|
|
|
|
|
|
|
pdfmake_obj_t fs; |
|
207
|
|
|
|
|
|
|
pdfmake_obj_t ef_dict; |
|
208
|
|
|
|
|
|
|
pdfmake_obj_t ef_ref; |
|
209
|
|
|
|
|
|
|
|
|
210
|
4
|
50
|
|
|
|
|
if (!att || !doc || !att->data) return 0; |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
211
|
4
|
50
|
|
|
|
|
if (att->fs_obj_num) return att->fs_obj_num; |
|
212
|
|
|
|
|
|
|
|
|
213
|
4
|
|
|
|
|
|
arena = pdfmake_doc_arena(doc); |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
/* Compress data with FlateDecode */ |
|
216
|
4
|
|
|
|
|
|
pdfmake_buf_init(&compressed); |
|
217
|
4
|
|
|
|
|
|
memset(¶ms, 0, sizeof(params)); |
|
218
|
4
|
|
|
|
|
|
params.predictor = 1; |
|
219
|
4
|
|
|
|
|
|
use_flate = (pdfmake_flate_encode(att->data, att->data_len, ¶ms, &compressed) == PDFMAKE_OK); |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
/* Create embedded file stream */ |
|
222
|
4
|
|
|
|
|
|
ef_stream = pdfmake_stream_new(arena); |
|
223
|
4
|
50
|
|
|
|
|
if (ef_stream.kind != PDFMAKE_STREAM) { |
|
224
|
0
|
|
|
|
|
|
pdfmake_buf_free(&compressed); |
|
225
|
0
|
|
|
|
|
|
return 0; |
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
4
|
50
|
|
|
|
|
if (use_flate && compressed.len < att->data_len) { |
|
|
|
50
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
pdfmake_stream_set_data(arena, &ef_stream, compressed.data, compressed.len); |
|
230
|
|
|
|
|
|
|
} else { |
|
231
|
4
|
|
|
|
|
|
pdfmake_stream_set_data(arena, &ef_stream, att->data, att->data_len); |
|
232
|
4
|
|
|
|
|
|
use_flate = 0; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
/* Set stream dict entries */ |
|
236
|
4
|
|
|
|
|
|
ef_dict_obj.kind = PDFMAKE_DICT; |
|
237
|
4
|
|
|
|
|
|
ef_dict_obj.as.dict = pdfmake_stream_dict(&ef_stream); |
|
238
|
|
|
|
|
|
|
|
|
239
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Type", 4); |
|
240
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict_obj, k, pdfmake_name_cstr(arena, "EmbeddedFile")); |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
/* MIME subtype: encode / as #2F per PDF spec */ |
|
243
|
4
|
50
|
|
|
|
|
if (att->mime_type[0]) { |
|
244
|
4
|
|
|
|
|
|
ei = 0; |
|
245
|
50
|
100
|
|
|
|
|
for (i = 0; att->mime_type[i] && ei < sizeof(encoded) - 4; i++) { |
|
|
|
50
|
|
|
|
|
|
|
246
|
46
|
100
|
|
|
|
|
if (att->mime_type[i] == '/') { |
|
247
|
4
|
|
|
|
|
|
encoded[ei++] = '#'; encoded[ei++] = '2'; encoded[ei++] = 'F'; |
|
248
|
|
|
|
|
|
|
} else { |
|
249
|
42
|
|
|
|
|
|
encoded[ei++] = att->mime_type[i]; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
} |
|
252
|
4
|
|
|
|
|
|
encoded[ei] = '\0'; |
|
253
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Subtype", 7); |
|
254
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict_obj, k, pdfmake_name(arena, encoded, ei)); |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
4
|
50
|
|
|
|
|
if (use_flate) { |
|
258
|
0
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Filter", 6); |
|
259
|
0
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict_obj, k, pdfmake_name_cstr(arena, "FlateDecode")); |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
/* Params */ |
|
263
|
4
|
|
|
|
|
|
ef_params = pdfmake_dict_new(arena); |
|
264
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Size", 4); |
|
265
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_params, k, pdfmake_int((int64_t)att->data_len)); |
|
266
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Params", 6); |
|
267
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict_obj, k, ef_params); |
|
268
|
|
|
|
|
|
|
|
|
269
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Length", 6); |
|
270
|
8
|
50
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict_obj, k, |
|
271
|
4
|
|
|
|
|
|
pdfmake_int((int64_t)(use_flate ? compressed.len : att->data_len))); |
|
272
|
|
|
|
|
|
|
|
|
273
|
4
|
|
|
|
|
|
att->ef_obj_num = pdfmake_doc_add(doc, ef_stream); |
|
274
|
4
|
|
|
|
|
|
pdfmake_buf_free(&compressed); |
|
275
|
4
|
50
|
|
|
|
|
if (att->ef_obj_num == 0) return 0; |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
/* Create Filespec dictionary */ |
|
278
|
4
|
|
|
|
|
|
fs = pdfmake_dict_new(arena); |
|
279
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Type", 4); |
|
280
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, pdfmake_name_cstr(arena, "Filespec")); |
|
281
|
|
|
|
|
|
|
|
|
282
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "F", 1); |
|
283
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, pdfmake_str_cstr(arena, att->filename)); |
|
284
|
|
|
|
|
|
|
|
|
285
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "UF", 2); |
|
286
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, pdfmake_str_cstr(arena, att->filename)); |
|
287
|
|
|
|
|
|
|
|
|
288
|
4
|
100
|
|
|
|
|
if (att->description[0]) { |
|
289
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Desc", 4); |
|
290
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, pdfmake_str_cstr(arena, att->description)); |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
/* /EF << /F ref /UF ref >> */ |
|
294
|
4
|
|
|
|
|
|
ef_dict = pdfmake_dict_new(arena); |
|
295
|
4
|
|
|
|
|
|
ef_ref = pdfmake_ref(att->ef_obj_num, 0); |
|
296
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "F", 1); |
|
297
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict, k, ef_ref); |
|
298
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "UF", 2); |
|
299
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_dict, k, ef_ref); |
|
300
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "EF", 2); |
|
301
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, ef_dict); |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
/* AFRelationship */ |
|
304
|
4
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "AFRelationship", 14); |
|
305
|
4
|
|
|
|
|
|
pdfmake_dict_set(arena, &fs, k, pdfmake_name_cstr(arena, "Data")); |
|
306
|
|
|
|
|
|
|
|
|
307
|
4
|
|
|
|
|
|
att->fs_obj_num = pdfmake_doc_add(doc, fs); |
|
308
|
4
|
|
|
|
|
|
return att->fs_obj_num; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
/* ── Write /Names/EmbeddedFiles into catalog ───────────── */ |
|
312
|
|
|
|
|
|
|
|
|
313
|
3
|
|
|
|
|
|
pdfmake_err_t pdfmake_doc_write_attachments(pdfmake_doc_t *doc) { |
|
314
|
|
|
|
|
|
|
pdfmake_arena_t *arena; |
|
315
|
|
|
|
|
|
|
uint32_t k; |
|
316
|
|
|
|
|
|
|
size_t i; |
|
317
|
|
|
|
|
|
|
pdfmake_attachment_t *att; |
|
318
|
|
|
|
|
|
|
pdfmake_obj_t names_arr; |
|
319
|
|
|
|
|
|
|
pdfmake_obj_t ef_tree; |
|
320
|
|
|
|
|
|
|
pdfmake_obj_t names_dict; |
|
321
|
|
|
|
|
|
|
pdfmake_obj_t *catalog; |
|
322
|
|
|
|
|
|
|
|
|
323
|
3
|
50
|
|
|
|
|
if (!doc || doc->attach_count == 0) return PDFMAKE_OK; |
|
|
|
50
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
|
325
|
3
|
|
|
|
|
|
arena = pdfmake_doc_arena(doc); |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
/* Ensure all attachments are written */ |
|
328
|
7
|
100
|
|
|
|
|
for (i = 0; i < doc->attach_count; i++) { |
|
329
|
4
|
|
|
|
|
|
att = (pdfmake_attachment_t *)doc->attachments[i]; |
|
330
|
4
|
50
|
|
|
|
|
if (!att->fs_obj_num) { |
|
331
|
4
|
50
|
|
|
|
|
if (pdfmake_attachment_write(att, doc) == 0) |
|
332
|
0
|
|
|
|
|
|
return PDFMAKE_ENOMEM; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
} |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
/* Build /Names array: [(name1) ref1 (name2) ref2 ...] */ |
|
337
|
3
|
|
|
|
|
|
names_arr = pdfmake_array_new(arena); |
|
338
|
7
|
100
|
|
|
|
|
for (i = 0; i < doc->attach_count; i++) { |
|
339
|
4
|
|
|
|
|
|
att = (pdfmake_attachment_t *)doc->attachments[i]; |
|
340
|
4
|
|
|
|
|
|
pdfmake_array_push(arena, &names_arr, |
|
341
|
4
|
|
|
|
|
|
pdfmake_str_cstr(arena, att->name)); |
|
342
|
4
|
|
|
|
|
|
pdfmake_array_push(arena, &names_arr, |
|
343
|
|
|
|
|
|
|
pdfmake_ref(att->fs_obj_num, 0)); |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
/* /EmbeddedFiles << /Names [...] >> */ |
|
347
|
3
|
|
|
|
|
|
ef_tree = pdfmake_dict_new(arena); |
|
348
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Names", 5); |
|
349
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &ef_tree, k, names_arr); |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
/* /Names << /EmbeddedFiles ... >> */ |
|
352
|
3
|
|
|
|
|
|
names_dict = pdfmake_dict_new(arena); |
|
353
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "EmbeddedFiles", 13); |
|
354
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, &names_dict, k, ef_tree); |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
/* Add to catalog */ |
|
357
|
3
|
|
|
|
|
|
catalog = pdfmake_doc_get(doc, doc->root_num); |
|
358
|
3
|
50
|
|
|
|
|
if (!catalog || catalog->kind != PDFMAKE_DICT) return PDFMAKE_EINVAL; |
|
|
|
50
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
|
360
|
3
|
|
|
|
|
|
k = pdfmake_arena_intern_name(arena, "Names", 5); |
|
361
|
3
|
|
|
|
|
|
pdfmake_dict_set(arena, catalog, k, names_dict); |
|
362
|
|
|
|
|
|
|
|
|
363
|
3
|
|
|
|
|
|
return PDFMAKE_OK; |
|
364
|
|
|
|
|
|
|
} |