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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/README.md +7 -9
  4. data/Rakefile +33 -18
  5. data/ext/Makefile +261 -0
  6. data/ext/extconf.rb +23 -3
  7. data/ext/mmd/aho-corasick.c +596 -0
  8. data/ext/mmd/aho-corasick.h +120 -0
  9. data/ext/mmd/beamer.c +344 -0
  10. data/ext/mmd/beamer.h +72 -0
  11. data/ext/mmd/char.c +156 -0
  12. data/ext/mmd/char.h +111 -0
  13. data/ext/mmd/char_lookup.c +212 -0
  14. data/ext/mmd/critic_markup.c +330 -0
  15. data/ext/mmd/critic_markup.h +94 -0
  16. data/ext/mmd/d_string.c +402 -0
  17. data/ext/mmd/epub.c +563 -0
  18. data/ext/mmd/epub.h +69 -0
  19. data/ext/mmd/fodt.c +2288 -0
  20. data/ext/mmd/fodt.h +81 -0
  21. data/ext/mmd/html.c +2460 -0
  22. data/ext/mmd/html.h +81 -0
  23. data/ext/mmd/i18n.h +170 -0
  24. data/ext/mmd/include/d_string.h +182 -0
  25. data/ext/mmd/include/libMultiMarkdown.h +548 -0
  26. data/ext/mmd/include/token.h +233 -0
  27. data/ext/mmd/latex.c +2435 -0
  28. data/ext/mmd/latex.h +83 -0
  29. data/ext/mmd/lexer.c +3001 -0
  30. data/ext/mmd/lexer.h +75 -0
  31. data/ext/mmd/memoir.c +138 -0
  32. data/ext/mmd/memoir.h +67 -0
  33. data/ext/mmd/miniz.c +7557 -0
  34. data/ext/mmd/miniz.h +1328 -0
  35. data/ext/mmd/mmd.c +2798 -0
  36. data/ext/mmd/mmd.h +120 -0
  37. data/ext/mmd/object_pool.c +141 -0
  38. data/ext/mmd/object_pool.h +101 -0
  39. data/ext/mmd/opendocument-content.c +2071 -0
  40. data/ext/mmd/opendocument-content.h +135 -0
  41. data/ext/mmd/opendocument.c +981 -0
  42. data/ext/mmd/opendocument.h +118 -0
  43. data/ext/mmd/parser.c +1760 -0
  44. data/ext/mmd/parser.h +39 -0
  45. data/{MultiMarkdown-4 → ext/mmd}/rng.c +90 -49
  46. data/ext/mmd/scanners.c +77512 -0
  47. data/ext/mmd/scanners.h +101 -0
  48. data/ext/mmd/stack.c +142 -0
  49. data/ext/mmd/stack.h +113 -0
  50. data/ext/mmd/textbundle.c +455 -0
  51. data/ext/mmd/textbundle.h +115 -0
  52. data/ext/mmd/token.c +773 -0
  53. data/ext/mmd/token_pairs.c +263 -0
  54. data/ext/mmd/token_pairs.h +123 -0
  55. data/ext/mmd/transclude.c +549 -0
  56. data/ext/mmd/transclude.h +87 -0
  57. data/ext/mmd/uthash.h +1074 -0
  58. data/ext/mmd/uuid.c +154 -0
  59. data/ext/mmd/uuid.h +77 -0
  60. data/ext/mmd/version.h +111 -0
  61. data/ext/mmd/writer.c +2652 -0
  62. data/ext/mmd/writer.h +260 -0
  63. data/ext/mmd/zip.c +210 -0
  64. data/ext/mmd/zip.h +120 -0
  65. data/ext/{multi_markdown.c → ruby_multi_markdown.c} +87 -18
  66. data/lib/multi_markdown.bundle +0 -0
  67. data/lib/multi_markdown.rb +5 -8
  68. data/lib/multi_markdown/version.rb +1 -1
  69. data/rmultimarkdown.gemspec +2 -2
  70. data/test/{extensions_test.rb.rb → extensions_test.rb} +10 -54
  71. data/test/multi_markdown_test.rb +13 -0
  72. metadata +67 -47
  73. data/MultiMarkdown-4/GLibFacade.c +0 -310
  74. data/MultiMarkdown-4/GLibFacade.h +0 -100
  75. data/MultiMarkdown-4/beamer.c +0 -182
  76. data/MultiMarkdown-4/beamer.h +0 -11
  77. data/MultiMarkdown-4/critic.c +0 -111
  78. data/MultiMarkdown-4/critic.h +0 -15
  79. data/MultiMarkdown-4/glib.h +0 -11
  80. data/MultiMarkdown-4/html.c +0 -1117
  81. data/MultiMarkdown-4/html.h +0 -14
  82. data/MultiMarkdown-4/latex.c +0 -1217
  83. data/MultiMarkdown-4/latex.h +0 -16
  84. data/MultiMarkdown-4/libMultiMarkdown.h +0 -177
  85. data/MultiMarkdown-4/lyx.c +0 -2265
  86. data/MultiMarkdown-4/lyx.h +0 -37
  87. data/MultiMarkdown-4/lyxbeamer.c +0 -265
  88. data/MultiMarkdown-4/lyxbeamer.h +0 -11
  89. data/MultiMarkdown-4/memoir.c +0 -80
  90. data/MultiMarkdown-4/memoir.h +0 -10
  91. data/MultiMarkdown-4/multimarkdown.c +0 -518
  92. data/MultiMarkdown-4/odf.c +0 -1222
  93. data/MultiMarkdown-4/odf.h +0 -18
  94. data/MultiMarkdown-4/opml.c +0 -189
  95. data/MultiMarkdown-4/opml.h +0 -15
  96. data/MultiMarkdown-4/parse_utilities.c +0 -884
  97. data/MultiMarkdown-4/parser.c +0 -16656
  98. data/MultiMarkdown-4/parser.h +0 -188
  99. data/MultiMarkdown-4/rtf.c +0 -665
  100. data/MultiMarkdown-4/rtf.h +0 -17
  101. data/MultiMarkdown-4/strtok.c +0 -56
  102. data/MultiMarkdown-4/strtok.h +0 -9
  103. data/MultiMarkdown-4/text.c +0 -53
  104. data/MultiMarkdown-4/text.h +0 -11
  105. data/MultiMarkdown-4/toc.c +0 -142
  106. data/MultiMarkdown-4/toc.h +0 -15
  107. data/MultiMarkdown-4/transclude.c +0 -307
  108. data/MultiMarkdown-4/transclude.h +0 -28
  109. data/MultiMarkdown-4/writer.c +0 -731
  110. 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
+