rmultimarkdown 4.7.1.1 → 6.2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +2 -2
- data/README.md +7 -9
- data/Rakefile +33 -18
- data/ext/Makefile +261 -0
- data/ext/extconf.rb +23 -3
- data/ext/mmd/aho-corasick.c +596 -0
- data/ext/mmd/aho-corasick.h +120 -0
- data/ext/mmd/beamer.c +344 -0
- data/ext/mmd/beamer.h +72 -0
- data/ext/mmd/char.c +156 -0
- data/ext/mmd/char.h +111 -0
- data/ext/mmd/char_lookup.c +212 -0
- data/ext/mmd/critic_markup.c +330 -0
- data/ext/mmd/critic_markup.h +94 -0
- data/ext/mmd/d_string.c +402 -0
- data/ext/mmd/epub.c +563 -0
- data/ext/mmd/epub.h +69 -0
- data/ext/mmd/fodt.c +2288 -0
- data/ext/mmd/fodt.h +81 -0
- data/ext/mmd/html.c +2460 -0
- data/ext/mmd/html.h +81 -0
- data/ext/mmd/i18n.h +170 -0
- data/ext/mmd/include/d_string.h +182 -0
- data/ext/mmd/include/libMultiMarkdown.h +548 -0
- data/ext/mmd/include/token.h +233 -0
- data/ext/mmd/latex.c +2435 -0
- data/ext/mmd/latex.h +83 -0
- data/ext/mmd/lexer.c +3001 -0
- data/ext/mmd/lexer.h +75 -0
- data/ext/mmd/memoir.c +138 -0
- data/ext/mmd/memoir.h +67 -0
- data/ext/mmd/miniz.c +7557 -0
- data/ext/mmd/miniz.h +1328 -0
- data/ext/mmd/mmd.c +2798 -0
- data/ext/mmd/mmd.h +120 -0
- data/ext/mmd/object_pool.c +141 -0
- data/ext/mmd/object_pool.h +101 -0
- data/ext/mmd/opendocument-content.c +2071 -0
- data/ext/mmd/opendocument-content.h +135 -0
- data/ext/mmd/opendocument.c +981 -0
- data/ext/mmd/opendocument.h +118 -0
- data/ext/mmd/parser.c +1760 -0
- data/ext/mmd/parser.h +39 -0
- data/{MultiMarkdown-4 → ext/mmd}/rng.c +90 -49
- data/ext/mmd/scanners.c +77512 -0
- data/ext/mmd/scanners.h +101 -0
- data/ext/mmd/stack.c +142 -0
- data/ext/mmd/stack.h +113 -0
- data/ext/mmd/textbundle.c +455 -0
- data/ext/mmd/textbundle.h +115 -0
- data/ext/mmd/token.c +773 -0
- data/ext/mmd/token_pairs.c +263 -0
- data/ext/mmd/token_pairs.h +123 -0
- data/ext/mmd/transclude.c +549 -0
- data/ext/mmd/transclude.h +87 -0
- data/ext/mmd/uthash.h +1074 -0
- data/ext/mmd/uuid.c +154 -0
- data/ext/mmd/uuid.h +77 -0
- data/ext/mmd/version.h +111 -0
- data/ext/mmd/writer.c +2652 -0
- data/ext/mmd/writer.h +260 -0
- data/ext/mmd/zip.c +210 -0
- data/ext/mmd/zip.h +120 -0
- data/ext/{multi_markdown.c → ruby_multi_markdown.c} +87 -18
- data/lib/multi_markdown.bundle +0 -0
- data/lib/multi_markdown.rb +5 -8
- data/lib/multi_markdown/version.rb +1 -1
- data/rmultimarkdown.gemspec +2 -2
- data/test/{extensions_test.rb.rb → extensions_test.rb} +10 -54
- data/test/multi_markdown_test.rb +13 -0
- metadata +67 -47
- data/MultiMarkdown-4/GLibFacade.c +0 -310
- data/MultiMarkdown-4/GLibFacade.h +0 -100
- data/MultiMarkdown-4/beamer.c +0 -182
- data/MultiMarkdown-4/beamer.h +0 -11
- data/MultiMarkdown-4/critic.c +0 -111
- data/MultiMarkdown-4/critic.h +0 -15
- data/MultiMarkdown-4/glib.h +0 -11
- data/MultiMarkdown-4/html.c +0 -1117
- data/MultiMarkdown-4/html.h +0 -14
- data/MultiMarkdown-4/latex.c +0 -1217
- data/MultiMarkdown-4/latex.h +0 -16
- data/MultiMarkdown-4/libMultiMarkdown.h +0 -177
- data/MultiMarkdown-4/lyx.c +0 -2265
- data/MultiMarkdown-4/lyx.h +0 -37
- data/MultiMarkdown-4/lyxbeamer.c +0 -265
- data/MultiMarkdown-4/lyxbeamer.h +0 -11
- data/MultiMarkdown-4/memoir.c +0 -80
- data/MultiMarkdown-4/memoir.h +0 -10
- data/MultiMarkdown-4/multimarkdown.c +0 -518
- data/MultiMarkdown-4/odf.c +0 -1222
- data/MultiMarkdown-4/odf.h +0 -18
- data/MultiMarkdown-4/opml.c +0 -189
- data/MultiMarkdown-4/opml.h +0 -15
- data/MultiMarkdown-4/parse_utilities.c +0 -884
- data/MultiMarkdown-4/parser.c +0 -16656
- data/MultiMarkdown-4/parser.h +0 -188
- data/MultiMarkdown-4/rtf.c +0 -665
- data/MultiMarkdown-4/rtf.h +0 -17
- data/MultiMarkdown-4/strtok.c +0 -56
- data/MultiMarkdown-4/strtok.h +0 -9
- data/MultiMarkdown-4/text.c +0 -53
- data/MultiMarkdown-4/text.h +0 -11
- data/MultiMarkdown-4/toc.c +0 -142
- data/MultiMarkdown-4/toc.h +0 -15
- data/MultiMarkdown-4/transclude.c +0 -307
- data/MultiMarkdown-4/transclude.h +0 -28
- data/MultiMarkdown-4/writer.c +0 -731
- data/MultiMarkdown-4/writer.h +0 -38
data/ext/mmd/epub.c
ADDED
@@ -0,0 +1,563 @@
|
|
1
|
+
/**
|
2
|
+
|
3
|
+
MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
4
|
+
|
5
|
+
@file epub.c
|
6
|
+
|
7
|
+
@brief
|
8
|
+
|
9
|
+
|
10
|
+
@author Fletcher T. Penney
|
11
|
+
@bug
|
12
|
+
|
13
|
+
**/
|
14
|
+
|
15
|
+
/*
|
16
|
+
|
17
|
+
Copyright © 2016 - 2017 Fletcher T. Penney.
|
18
|
+
|
19
|
+
|
20
|
+
The `MultiMarkdown 6` project is released under the MIT License..
|
21
|
+
|
22
|
+
GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
|
23
|
+
|
24
|
+
https://github.com/fletcher/MultiMarkdown-4/
|
25
|
+
|
26
|
+
MMD 4 is released under both the MIT License and GPL.
|
27
|
+
|
28
|
+
|
29
|
+
CuTest is released under the zlib/libpng license. See CuTest.c for the
|
30
|
+
text of the license.
|
31
|
+
|
32
|
+
|
33
|
+
## The MIT License ##
|
34
|
+
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
36
|
+
a copy of this software and associated documentation files (the
|
37
|
+
"Software"), to deal in the Software without restriction, including
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
41
|
+
the following conditions:
|
42
|
+
|
43
|
+
The above copyright notice and this permission notice shall be
|
44
|
+
included in all copies or substantial portions of the Software.
|
45
|
+
|
46
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
47
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
49
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
50
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
51
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
52
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
53
|
+
|
54
|
+
|
55
|
+
*/
|
56
|
+
|
57
|
+
#include <stdio.h>
|
58
|
+
#include <stdlib.h>
|
59
|
+
#include <sys/stat.h>
|
60
|
+
|
61
|
+
#ifdef USE_CURL
|
62
|
+
#include <curl/curl.h>
|
63
|
+
#endif
|
64
|
+
|
65
|
+
#include "epub.h"
|
66
|
+
#include "html.h"
|
67
|
+
#include "i18n.h"
|
68
|
+
#include "miniz.h"
|
69
|
+
#include "transclude.h"
|
70
|
+
#include "uuid.h"
|
71
|
+
#include "writer.h"
|
72
|
+
#include "zip.h"
|
73
|
+
|
74
|
+
#define print(x) d_string_append(out, x)
|
75
|
+
#define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
|
76
|
+
#define print_char(x) d_string_append_c(out, x)
|
77
|
+
#define printf(...) d_string_append_printf(out, __VA_ARGS__)
|
78
|
+
#define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len)
|
79
|
+
#define print_localized(x) mmd_print_localized_char_html(out, x, scratch)
|
80
|
+
|
81
|
+
|
82
|
+
/// strdup() not available on all platforms
|
83
|
+
static char * my_strdup(const char * source) {
|
84
|
+
if (source == NULL) {
|
85
|
+
return NULL;
|
86
|
+
}
|
87
|
+
|
88
|
+
char * result = malloc(strlen(source) + 1);
|
89
|
+
|
90
|
+
if (result) {
|
91
|
+
strcpy(result, source);
|
92
|
+
}
|
93
|
+
|
94
|
+
return result;
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
char * epub_mimetype(void) {
|
99
|
+
return my_strdup("application/epub+zip");
|
100
|
+
}
|
101
|
+
|
102
|
+
|
103
|
+
char * epub_container_xml(void) {
|
104
|
+
DString * container = d_string_new("");
|
105
|
+
|
106
|
+
d_string_append(container, "<?xml version=\"1.0\"?>\n");
|
107
|
+
d_string_append(container, "<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n");
|
108
|
+
d_string_append(container, "<rootfiles>\n");
|
109
|
+
d_string_append(container, "<rootfile full-path=\"OEBPS/main.opf\" media-type=\"application/oebps-package+xml\" />\n");
|
110
|
+
d_string_append(container, "</rootfiles>\n");
|
111
|
+
d_string_append(container, "</container>\n");
|
112
|
+
|
113
|
+
char * result = container->str;
|
114
|
+
d_string_free(container, false);
|
115
|
+
return result;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
char * epub_package_document(scratch_pad * scratch) {
|
120
|
+
DString * out = d_string_new("");
|
121
|
+
|
122
|
+
meta * m;
|
123
|
+
|
124
|
+
d_string_append(out, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n");
|
125
|
+
d_string_append(out, "<package xmlns=\"http://www.idpf.org/2007/opf\" version=\"3.0\" unique-identifier=\"pub-id\">\n");
|
126
|
+
|
127
|
+
|
128
|
+
// Metadata
|
129
|
+
d_string_append(out, "<metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n");
|
130
|
+
|
131
|
+
// Identifier
|
132
|
+
HASH_FIND_STR(scratch->meta_hash, "uuid", m);
|
133
|
+
|
134
|
+
if (m) {
|
135
|
+
print_const("<dc:identifier id=\"pub-id\">urn:uuid:");
|
136
|
+
mmd_print_string_html(out, m->value, false);
|
137
|
+
print_const("</dc:identifier>\n");
|
138
|
+
} else {
|
139
|
+
print_const("<dc:identifier id=\"pub-id\">urn:uuid:");
|
140
|
+
|
141
|
+
char * id = uuid_new();
|
142
|
+
print(id);
|
143
|
+
print_const("</dc:identifier>\n");
|
144
|
+
free(id);
|
145
|
+
}
|
146
|
+
|
147
|
+
// Title
|
148
|
+
HASH_FIND_STR(scratch->meta_hash, "title", m);
|
149
|
+
|
150
|
+
if (m) {
|
151
|
+
print_const("<dc:title>");
|
152
|
+
mmd_print_string_html(out, m->value, false);
|
153
|
+
print_const("</dc:title>\n");
|
154
|
+
} else {
|
155
|
+
print_const("<dc:title>Untitled</dc:title>\n");
|
156
|
+
}
|
157
|
+
|
158
|
+
// Author
|
159
|
+
HASH_FIND_STR(scratch->meta_hash, "author", m);
|
160
|
+
|
161
|
+
if (m) {
|
162
|
+
print_const("<dc:creator>");
|
163
|
+
mmd_print_string_html(out, m->value, false);
|
164
|
+
print_const("</dc:creator>\n");
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
// Language
|
169
|
+
HASH_FIND_STR(scratch->meta_hash, "language", m);
|
170
|
+
|
171
|
+
if (m) {
|
172
|
+
print_const("<dc:language>");
|
173
|
+
mmd_print_string_html(out, m->value, false);
|
174
|
+
print_const("</dc:language>\n");
|
175
|
+
} else {
|
176
|
+
switch (scratch->language) {
|
177
|
+
case LC_ES:
|
178
|
+
print_const("<dc:language>es</dc:language>\n");
|
179
|
+
break;
|
180
|
+
|
181
|
+
case LC_DE:
|
182
|
+
print_const("<dc:language>de</dc:language>\n");
|
183
|
+
break;
|
184
|
+
|
185
|
+
case LC_FR:
|
186
|
+
print_const("<dc:language>fr</dc:language>\n");
|
187
|
+
break;
|
188
|
+
|
189
|
+
case LC_NL:
|
190
|
+
print_const("<dc:language>nl</dc:language>\n");
|
191
|
+
break;
|
192
|
+
|
193
|
+
case LC_SV:
|
194
|
+
print_const("<dc:language>sv</dc:language>\n");
|
195
|
+
break;
|
196
|
+
|
197
|
+
default:
|
198
|
+
print_const("<dc:language>en</dc:language>\n");
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
// Date
|
203
|
+
HASH_FIND_STR(scratch->meta_hash, "date", m);
|
204
|
+
|
205
|
+
if (m) {
|
206
|
+
print_const("<meta property=\"dcterms:modified\">");
|
207
|
+
mmd_print_string_html(out, m->value, false);
|
208
|
+
print_const("</meta>\n");
|
209
|
+
} else {
|
210
|
+
time_t t = time(NULL);
|
211
|
+
struct tm * today = localtime(&t);
|
212
|
+
|
213
|
+
d_string_append_printf(out, "<meta property=\"dcterms:modified\">%d-%02d-%02d</meta>\n",
|
214
|
+
today->tm_year + 1900, today->tm_mon + 1, today->tm_mday);
|
215
|
+
}
|
216
|
+
|
217
|
+
d_string_append(out, "</metadata>\n");
|
218
|
+
|
219
|
+
|
220
|
+
// Manifest
|
221
|
+
d_string_append(out, "<manifest>\n");
|
222
|
+
d_string_append(out, "<item id=\"nav\" href=\"nav.xhtml\" properties=\"nav\" media-type=\"application/xhtml+xml\"/>\n");
|
223
|
+
d_string_append(out, "<item id=\"main\" href=\"main.xhtml\" media-type=\"application/xhtml+xml\"/>\n");
|
224
|
+
d_string_append(out, "</manifest>\n");
|
225
|
+
|
226
|
+
// Spine
|
227
|
+
d_string_append(out, "<spine>\n");
|
228
|
+
d_string_append(out, "<itemref idref=\"main\"/>");
|
229
|
+
d_string_append(out, "</spine>\n");
|
230
|
+
|
231
|
+
d_string_append(out, "</package>\n");
|
232
|
+
|
233
|
+
char * result = out->str;
|
234
|
+
d_string_free(out, false);
|
235
|
+
return result;
|
236
|
+
}
|
237
|
+
|
238
|
+
|
239
|
+
void epub_export_nav_entry(DString * out, const char * source, scratch_pad * scratch, size_t * counter, short level) {
|
240
|
+
token * entry, * next;
|
241
|
+
short entry_level, next_level;
|
242
|
+
char * temp_char;
|
243
|
+
|
244
|
+
print_const("\n<ol>\n");
|
245
|
+
|
246
|
+
// Iterate over tokens
|
247
|
+
while (*counter < scratch->header_stack->size) {
|
248
|
+
// Get token for header
|
249
|
+
entry = stack_peek_index(scratch->header_stack, *counter);
|
250
|
+
entry_level = raw_level_for_header(entry);
|
251
|
+
|
252
|
+
if (entry_level >= level) {
|
253
|
+
// This entry is a direct descendant of the parent
|
254
|
+
temp_char = label_from_header(source, entry);
|
255
|
+
printf("<li><a href=\"main.xhtml#%s\">", temp_char);
|
256
|
+
mmd_export_token_tree_html(out, source, entry->child, scratch);
|
257
|
+
print_const("</a>");
|
258
|
+
|
259
|
+
if (*counter < scratch->header_stack->size - 1) {
|
260
|
+
next = stack_peek_index(scratch->header_stack, *counter + 1);
|
261
|
+
next_level = next->type - BLOCK_H1 + 1;
|
262
|
+
|
263
|
+
if (next_level > entry_level) {
|
264
|
+
// This entry has children
|
265
|
+
(*counter)++;
|
266
|
+
epub_export_nav_entry(out, source, scratch, counter, entry_level + 1);
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
270
|
+
print_const("</li>\n");
|
271
|
+
free(temp_char);
|
272
|
+
} else if (entry_level < level ) {
|
273
|
+
// If entry < level, exit this level
|
274
|
+
// Decrement counter first, so that we can test it again later
|
275
|
+
(*counter)--;
|
276
|
+
break;
|
277
|
+
}
|
278
|
+
|
279
|
+
// Increment counter
|
280
|
+
(*counter)++;
|
281
|
+
}
|
282
|
+
|
283
|
+
print_const("</ol>\n");
|
284
|
+
}
|
285
|
+
|
286
|
+
|
287
|
+
void epub_export_nav(DString * out, mmd_engine * e, scratch_pad * scratch) {
|
288
|
+
size_t counter = 0;
|
289
|
+
|
290
|
+
|
291
|
+
epub_export_nav_entry(out, e->dstr->str, scratch, &counter, 0);
|
292
|
+
}
|
293
|
+
|
294
|
+
|
295
|
+
char * epub_nav(mmd_engine * e, scratch_pad * scratch) {
|
296
|
+
meta * temp;
|
297
|
+
|
298
|
+
DString * out = d_string_new("");
|
299
|
+
|
300
|
+
d_string_append(out, "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n");
|
301
|
+
|
302
|
+
d_string_append(out, "<head>\n<title>");
|
303
|
+
HASH_FIND_STR(scratch->meta_hash, "title", temp);
|
304
|
+
|
305
|
+
if (temp) {
|
306
|
+
mmd_print_string_html(out, temp->value, false);
|
307
|
+
} else {
|
308
|
+
print_const("Untitled");
|
309
|
+
}
|
310
|
+
|
311
|
+
print_const("</title>\n</head>\n");
|
312
|
+
|
313
|
+
print_const("<body>\n<nav epub:type=\"toc\">\n");
|
314
|
+
print_const("<h2>Table of Contents</h2>\n");
|
315
|
+
|
316
|
+
epub_export_nav(out, e, scratch);
|
317
|
+
|
318
|
+
print_const("</nav>\n</body>\n</html>\n");
|
319
|
+
|
320
|
+
char * result = out->str;
|
321
|
+
d_string_free(out, false);
|
322
|
+
return result;
|
323
|
+
}
|
324
|
+
|
325
|
+
|
326
|
+
static bool add_asset_from_file(mz_zip_archive * pZip, asset * a, const char * destination, const char * directory) {
|
327
|
+
if (!directory) {
|
328
|
+
return false;
|
329
|
+
}
|
330
|
+
|
331
|
+
char * path = path_from_dir_base(directory, a->url);
|
332
|
+
mz_bool status;
|
333
|
+
bool result = false;
|
334
|
+
|
335
|
+
DString * buffer = scan_file(path);
|
336
|
+
|
337
|
+
if (buffer && buffer->currentStringLength > 0) {
|
338
|
+
status = mz_zip_writer_add_mem(pZip, destination, buffer->str, buffer->currentStringLength, MZ_BEST_COMPRESSION);
|
339
|
+
|
340
|
+
if (!status) {
|
341
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
342
|
+
}
|
343
|
+
|
344
|
+
d_string_free(buffer, true);
|
345
|
+
result = true;
|
346
|
+
}
|
347
|
+
|
348
|
+
free(path);
|
349
|
+
|
350
|
+
return result;
|
351
|
+
}
|
352
|
+
|
353
|
+
|
354
|
+
#ifdef USE_CURL
|
355
|
+
// Dynamic buffer for downloading files in memory
|
356
|
+
// Based on https://curl.haxx.se/libcurl/c/getinmemory.html
|
357
|
+
|
358
|
+
struct MemoryStruct {
|
359
|
+
char * memory;
|
360
|
+
size_t size;
|
361
|
+
};
|
362
|
+
|
363
|
+
|
364
|
+
static size_t write_memory(void * contents, size_t size, size_t nmemb, void * userp) {
|
365
|
+
size_t realsize = size * nmemb;
|
366
|
+
struct MemoryStruct * mem = (struct MemoryStruct *)userp;
|
367
|
+
|
368
|
+
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
369
|
+
|
370
|
+
if (mem->memory == NULL) {
|
371
|
+
// Out of memory
|
372
|
+
fprintf(stderr, "Out of memory\n");
|
373
|
+
return 0;
|
374
|
+
}
|
375
|
+
|
376
|
+
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
377
|
+
mem->size += realsize;
|
378
|
+
mem->memory[mem->size] = 0;
|
379
|
+
|
380
|
+
return realsize;
|
381
|
+
}
|
382
|
+
|
383
|
+
// Add assets to zipfile using libcurl
|
384
|
+
static void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
|
385
|
+
asset * a, * a_tmp;
|
386
|
+
|
387
|
+
if (e->asset_hash) {
|
388
|
+
CURL * curl;
|
389
|
+
CURLcode res;
|
390
|
+
|
391
|
+
struct MemoryStruct chunk;
|
392
|
+
chunk.memory = malloc(1);
|
393
|
+
chunk.size = 0;
|
394
|
+
|
395
|
+
char destination[100] = "OEBPS/assets/";
|
396
|
+
destination[49] = '\0';
|
397
|
+
|
398
|
+
mz_bool status;
|
399
|
+
|
400
|
+
curl_global_init(CURL_GLOBAL_ALL);
|
401
|
+
curl = curl_easy_init();
|
402
|
+
|
403
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory);
|
404
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
|
405
|
+
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
406
|
+
|
407
|
+
HASH_ITER(hh, e->asset_hash, a, a_tmp) {
|
408
|
+
curl_easy_setopt(curl, CURLOPT_URL, a->url);
|
409
|
+
res = curl_easy_perform(curl);
|
410
|
+
|
411
|
+
memcpy(&destination[13], a->asset_path, 36);
|
412
|
+
|
413
|
+
if (res != CURLE_OK) {
|
414
|
+
// Attempt to add asset from local file
|
415
|
+
if (!add_asset_from_file(pZip, a, destination, directory)) {
|
416
|
+
fprintf(stderr, "Unable to store '%s' in EPUB\n", a->url);
|
417
|
+
}
|
418
|
+
} else {
|
419
|
+
// Store downloaded file in zip
|
420
|
+
status = mz_zip_writer_add_mem(pZip, destination, chunk.memory, chunk.size, MZ_BEST_COMPRESSION);
|
421
|
+
|
422
|
+
if (!status) {
|
423
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
424
|
+
}
|
425
|
+
}
|
426
|
+
}
|
427
|
+
}
|
428
|
+
}
|
429
|
+
|
430
|
+
#else
|
431
|
+
// Add local assets only (libcurl not available)
|
432
|
+
static void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
|
433
|
+
asset * a, * a_tmp;
|
434
|
+
|
435
|
+
if (e->asset_hash) {
|
436
|
+
|
437
|
+
char destination[100] = "OEBPS/assets/";
|
438
|
+
destination[49] = '\0';
|
439
|
+
|
440
|
+
mz_bool status;
|
441
|
+
|
442
|
+
HASH_ITER(hh, e->asset_hash, a, a_tmp) {
|
443
|
+
|
444
|
+
memcpy(&destination[13], a->asset_path, 36);
|
445
|
+
|
446
|
+
// Attempt to add asset from local file
|
447
|
+
if (!add_asset_from_file(pZip, a, destination, directory)) {
|
448
|
+
fprintf(stderr, "Unable to store '%s' in EPUB\n", a->url);
|
449
|
+
}
|
450
|
+
}
|
451
|
+
}
|
452
|
+
}
|
453
|
+
#endif
|
454
|
+
|
455
|
+
|
456
|
+
// Use the miniz library to create a zip archive for the EPUB document
|
457
|
+
void epub_write_wrapper(const char * filepath, const char * body, mmd_engine * e, const char * directory) {
|
458
|
+
FILE * output_stream;
|
459
|
+
|
460
|
+
DString * result = epub_create(body, e, directory);
|
461
|
+
|
462
|
+
if (!(output_stream = fopen(filepath, "w"))) {
|
463
|
+
// Failed to open file
|
464
|
+
perror(filepath);
|
465
|
+
} else {
|
466
|
+
fwrite(&(result->str), result->currentStringLength, 1, output_stream);
|
467
|
+
fclose(output_stream);
|
468
|
+
}
|
469
|
+
|
470
|
+
d_string_free(result, true);
|
471
|
+
}
|
472
|
+
|
473
|
+
|
474
|
+
DString * epub_create(const char * body, mmd_engine * e, const char * directory) {
|
475
|
+
DString * result = d_string_new("");
|
476
|
+
scratch_pad * scratch = scratch_pad_new(e, FORMAT_EPUB);
|
477
|
+
|
478
|
+
mz_bool status;
|
479
|
+
char * data;
|
480
|
+
size_t len;
|
481
|
+
|
482
|
+
mz_zip_archive zip;
|
483
|
+
zip_new_archive(&zip);
|
484
|
+
|
485
|
+
// Add mimetype
|
486
|
+
data = epub_mimetype();
|
487
|
+
len = strlen(data);
|
488
|
+
status = mz_zip_writer_add_mem(&zip, "mimetype", data, len, MZ_BEST_COMPRESSION);
|
489
|
+
free(data);
|
490
|
+
|
491
|
+
if (!status) {
|
492
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
493
|
+
}
|
494
|
+
|
495
|
+
// Create directories
|
496
|
+
status = mz_zip_writer_add_mem(&zip, "OEBPS/", NULL, 0, MZ_NO_COMPRESSION);
|
497
|
+
|
498
|
+
if (!status) {
|
499
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
500
|
+
}
|
501
|
+
|
502
|
+
status = mz_zip_writer_add_mem(&zip, "META-INF/", NULL, 0, MZ_NO_COMPRESSION);
|
503
|
+
|
504
|
+
if (!status) {
|
505
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
506
|
+
}
|
507
|
+
|
508
|
+
// Add container
|
509
|
+
data = epub_container_xml();
|
510
|
+
len = strlen(data);
|
511
|
+
status = mz_zip_writer_add_mem(&zip, "META-INF/container.xml", data, len, MZ_BEST_COMPRESSION);
|
512
|
+
free(data);
|
513
|
+
|
514
|
+
if (!status) {
|
515
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
516
|
+
}
|
517
|
+
|
518
|
+
// Add package
|
519
|
+
data = epub_package_document(scratch);
|
520
|
+
len = strlen(data);
|
521
|
+
status = mz_zip_writer_add_mem(&zip, "OEBPS/main.opf", data, len, MZ_BEST_COMPRESSION);
|
522
|
+
free(data);
|
523
|
+
|
524
|
+
if (!status) {
|
525
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
526
|
+
}
|
527
|
+
|
528
|
+
// Add nav
|
529
|
+
data = epub_nav(e, scratch);
|
530
|
+
len = strlen(data);
|
531
|
+
status = mz_zip_writer_add_mem(&zip, "OEBPS/nav.xhtml", data, len, MZ_BEST_COMPRESSION);
|
532
|
+
free(data);
|
533
|
+
|
534
|
+
if (!status) {
|
535
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
536
|
+
}
|
537
|
+
|
538
|
+
// Add main document
|
539
|
+
len = strlen(body);
|
540
|
+
status = mz_zip_writer_add_mem(&zip, "OEBPS/main.xhtml", body, len, MZ_BEST_COMPRESSION);
|
541
|
+
|
542
|
+
if (!status) {
|
543
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
544
|
+
}
|
545
|
+
|
546
|
+
// Add assets
|
547
|
+
add_assets(&zip, e, directory);
|
548
|
+
|
549
|
+
scratch_pad_free(scratch);
|
550
|
+
|
551
|
+
// Finalize zip archive and extract data
|
552
|
+
free(result->str);
|
553
|
+
|
554
|
+
status = mz_zip_writer_finalize_heap_archive(&zip, (void **) & (result->str), (size_t *) & (result->currentStringLength));
|
555
|
+
|
556
|
+
if (!status) {
|
557
|
+
fprintf(stderr, "Error adding asset to zip.\n");
|
558
|
+
}
|
559
|
+
|
560
|
+
return result;
|
561
|
+
}
|
562
|
+
|
563
|
+
|