]> granicus.if.org Git - multimarkdown/commitdiff
ADDED: Start working on textbundle output format
authorFletcher T. Penney <fletcher@fletcherpenney.net>
Sun, 2 Jul 2017 03:35:51 +0000 (23:35 -0400)
committerFletcher T. Penney <fletcher@fletcherpenney.net>
Sun, 2 Jul 2017 03:35:51 +0000 (23:35 -0400)
CMakeLists.txt
Sources/libMultiMarkdown/include/libMultiMarkdown.h
Sources/libMultiMarkdown/mmd.c
Sources/libMultiMarkdown/textbundle.c [new file with mode: 0644]
Sources/libMultiMarkdown/textbundle.h [new file with mode: 0644]
Sources/libMultiMarkdown/writer.c
Sources/multimarkdown/main.c

index c47e862792d29381669155c9271870bfbf13c686..c61406c3dc4606a4f68a50e2928cf195fa3e18a1 100644 (file)
@@ -195,6 +195,7 @@ set(src_files
        Sources/libMultiMarkdown/rng.c
        Sources/libMultiMarkdown/scanners.c
        Sources/libMultiMarkdown/stack.c
+       Sources/libMultiMarkdown/textbundle.c
        Sources/libMultiMarkdown/token.c
        Sources/libMultiMarkdown/token_pairs.c
        Sources/libMultiMarkdown/transclude.c
@@ -222,6 +223,7 @@ set(header_files
        Sources/libMultiMarkdown/object_pool.h
        Sources/libMultiMarkdown/scanners.h
        Sources/libMultiMarkdown/stack.h
+       Sources/libMultiMarkdown/textbundle.c
        Sources/libMultiMarkdown/include/token.h
        Sources/libMultiMarkdown/token_pairs.h
        Sources/libMultiMarkdown/transclude.h
index 1b9605fcc4cecfc2f2dffed3824783051fd8a41b..95778e0bc03ba140435521f96c266d519e8ae088 100644 (file)
@@ -480,6 +480,8 @@ enum output_format {
        FORMAT_MEMOIR,
        FORMAT_ODF,
        FORMAT_MMD,
+       FORMAT_TEXTBUNDLE,
+       FORMAT_TEXTBUNDLE_COMPRESSED,
 };
 
 
index 84db1727b50af13796852e0479e8a07e0934cc63..78f743c05289c2dca631209e8e2bea5b600f7ba7 100644 (file)
@@ -67,6 +67,7 @@
 #include "parser.h"
 #include "scanners.h"
 #include "stack.h"
+#include "textbundle.h"
 #include "token.h"
 #include "token_pairs.h"
 #include "writer.h"
@@ -2219,6 +2220,9 @@ void mmd_engine_convert_to_file(mmd_engine * e, short format, const char * direc
                case FORMAT_EPUB:
                        epub_write_wrapper(filepath, output->str, e, directory);
                        break;
+               case FORMAT_TEXTBUNDLE_COMPRESSED:
+                       textbundle_write_wrapper(filepath, output->str, e, directory);
+                       break;
                default:
                        // Basic formats just write to file
                        if (!(output_stream = fopen(filepath, "w"))) {
@@ -2274,6 +2278,11 @@ DString * mmd_engine_convert_to_data(mmd_engine * e, short format, const char *
                case FORMAT_EPUB:
                        result = epub_create(output->str, e, directory);
 
+                       d_string_free(output, true);
+                       break;
+               case FORMAT_TEXTBUNDLE_COMPRESSED:
+                       result = textbundle_create(output->str, e, directory);
+
                        d_string_free(output, true);
                        break;
                default:
diff --git a/Sources/libMultiMarkdown/textbundle.c b/Sources/libMultiMarkdown/textbundle.c
new file mode 100644 (file)
index 0000000..6c83805
--- /dev/null
@@ -0,0 +1,330 @@
+/**
+
+       MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file textbundle.c
+
+       @brief 
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the
+       text of the license.
+       
+       uthash library:
+               Copyright (c) 2005-2016, Troy D. Hanson
+       
+               Licensed under Revised BSD license
+       
+       miniz library:
+               Copyright 2013-2014 RAD Game Tools and Valve Software
+               Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+       
+               Licensed under the MIT license
+       
+       argtable3 library:
+               Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+               <sheitmann@users.sourceforge.net>
+               All rights reserved.
+       
+               Licensed under the Revised BSD License
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files (the
+       "Software"), to deal in the Software without restriction, including
+       without limitation the rights to use, copy, modify, merge, publish,
+       distribute, sublicense, and/or sell copies of the Software, and to
+       permit persons to whom the Software is furnished to do so, subject to
+       the following conditions:
+       
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+       CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+       TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+       SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+       
+       
+       ## Revised BSD License ##
+       
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+           * Redistributions of source code must retain the above copyright
+             notice, this list of conditions and the following disclaimer.
+           * Redistributions in binary form must reproduce the above
+             copyright notice, this list of conditions and the following
+             disclaimer in the documentation and/or other materials provided
+             with the distribution.
+           * Neither the name of the <organization> nor the
+             names of its contributors may be used to endorse or promote
+             products derived from this software without specific prior
+             written permission.
+       
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+       A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
+       HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+       EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+       PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR
+       PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+       LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+       NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+       
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef USE_CURL
+#include <curl/curl.h>
+#endif
+
+#include "textbundle.h"
+#include "html.h"
+#include "miniz.h"
+#include "transclude.h"
+#include "writer.h"
+#include "zip.h"
+
+
+char * textbundle_info_json(void) {
+       DString * info = d_string_new("");
+
+       d_string_append(info, "{\n");
+       d_string_append(info, "\t\"version\": 2,\n");
+       d_string_append(info, "\t\"type\": \"net.daringfireball.markdown\",\n");
+       d_string_append(info, "\t\"transient\": false,\n");
+       d_string_append(info, "\t\"creatorIdentifier\": \"net.multimarkdown\"\n");
+       d_string_append(info, "}");
+
+       char * result = info->str;
+       d_string_free(info, false);
+       return result;
+}
+
+
+static bool add_asset_from_file(mz_zip_archive * pZip, asset * a, const char * destination, const char * directory) {
+       if (!directory)
+               return false;
+       
+       char * path = path_from_dir_base(directory, a->url);
+       mz_bool status;
+       bool result = false;
+
+       DString * buffer = scan_file(path);
+
+       if (buffer && buffer->currentStringLength > 0) {
+               status = mz_zip_writer_add_mem(pZip, destination, buffer->str, buffer->currentStringLength, MZ_BEST_COMPRESSION);
+
+               if (!status) {
+                       fprintf(stderr, "Error adding asset '%s' to zip.\n", destination);
+               }
+
+               d_string_free(buffer, true);
+               result = true;
+       }
+
+       free(path);
+
+       return result;
+}
+
+
+#ifdef USE_CURL
+// Dynamic buffer for downloading files in memory
+// Based on https://curl.haxx.se/libcurl/c/getinmemory.html
+
+struct MemoryStruct {
+       char * memory;
+       size_t size;
+};
+
+
+static size_t write_memory(void * contents, size_t size, size_t nmemb, void * userp) {
+       size_t realsize = size * nmemb;
+       struct MemoryStruct * mem = (struct MemoryStruct *)userp;
+
+       mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+       if (mem->memory == NULL) {
+               // Out of memory
+               fprintf(stderr, "Out of memory\n");
+               return 0;
+       }
+
+       memcpy(&(mem->memory[mem->size]), contents, realsize);
+       mem->size += realsize;
+       mem->memory[mem->size] = 0;
+
+       return realsize;
+}
+
+// Add assets to zipfile using libcurl
+static void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
+       asset * a, * a_tmp;
+
+       if (e->asset_hash){
+               CURL * curl;
+               CURLcode res;
+               
+               struct MemoryStruct chunk;
+               chunk.memory = malloc(1);
+               chunk.size = 0;
+
+               char destination[100] = "assets/";
+               destination[49] = '\0';
+               
+               mz_bool status;
+
+               curl_global_init(CURL_GLOBAL_ALL);
+               curl = curl_easy_init();
+
+               curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory);
+               curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+               curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+
+               HASH_ITER(hh, e->asset_hash, a, a_tmp) {
+                       curl_easy_setopt(curl, CURLOPT_URL, a->url);
+                       res = curl_easy_perform(curl);
+
+                       memcpy(&destination[7], a->asset_path, 36);
+
+                       if (res != CURLE_OK) {
+                               // Attempt to add asset from local file
+                               if (!add_asset_from_file(pZip, a, destination, directory)) {
+                                       fprintf(stderr, "Unable to store '%s' in EPUB\n", a->url);
+                               }
+                       } else {
+                               // Store downloaded file in zip
+                               status = mz_zip_writer_add_mem(pZip, destination, chunk.memory, chunk.size, MZ_BEST_COMPRESSION);
+
+                               if (!status) {
+                                       fprintf(stderr, "Error adding asset '%s' to zip as '%s'.\n", a->asset_path, destination);
+                               }
+                       }
+               }
+       }
+}
+
+#else
+// Add local assets only (libcurl not available)
+static void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
+       asset * a, * a_tmp;
+
+       if (e->asset_hash){
+
+               char destination[100] = "assets/";
+               destination[49] = '\0';
+               
+               mz_bool status;
+
+               HASH_ITER(hh, e->asset_hash, a, a_tmp) {
+
+                       memcpy(&destination[13], a->asset_path, 36);
+
+                       // Attempt to add asset from local file
+                       if (!add_asset_from_file(pZip, a, destination, directory)) {
+                               fprintf(stderr, "Unable to store '%s' in EPUB\n", a->url);
+                       }
+               }
+       }
+}
+#endif
+
+
+// Use the miniz library to create a zip archive for the TEXTBUNDLE_COMPRESSED document
+void textbundle_write_wrapper(const char * filepath, const char * body, mmd_engine * e, const char * directory) {
+       FILE * output_stream;
+
+       DString * result = textbundle_create(body, e, directory);
+
+       if (!(output_stream = fopen(filepath, "w"))) {
+               // Failed to open file
+               perror(filepath);
+       } else {
+               fwrite(&(result->str), result->currentStringLength, 1, output_stream);
+               fclose(output_stream);
+       }
+
+       d_string_free(result, true);
+}
+
+
+DString * textbundle_create(const char * body, mmd_engine * e, const char * directory) {
+       DString * result = d_string_new("");
+       scratch_pad * scratch = scratch_pad_new(e, FORMAT_TEXTBUNDLE_COMPRESSED);
+
+       mz_bool status;
+       char * data;
+       size_t len;
+
+       mz_zip_archive zip;
+       zip_new_archive(&zip);
+
+
+       // Add info json
+       data = textbundle_info_json();
+       len = strlen(data);
+       status = mz_zip_writer_add_mem(&zip, "info.json", data, len, MZ_BEST_COMPRESSION);
+       free(data);
+       if (!status) {
+               fprintf(stderr, "Error adding JSON info to zip.\n");
+       }
+
+       // Create directories
+       status = mz_zip_writer_add_mem(&zip, "assets/", NULL, 0, MZ_BEST_COMPRESSION);
+       if (!status) {
+               fprintf(stderr, "Error adding assets directory to zip.\n");
+       }
+
+       // Add main document
+       len = strlen(body);
+       status = mz_zip_writer_add_mem(&zip, "text.html", body, len, MZ_BEST_COMPRESSION);
+       if (!status) {
+               fprintf(stderr, "Error adding content to zip.\n");
+       }
+
+       // Add assets
+       add_assets(&zip, e, directory);
+
+       scratch_pad_free(scratch);
+
+       // Finalize zip archive and extract data
+       free(result->str);
+
+       status = mz_zip_writer_finalize_heap_archive(&zip, (void **) &(result->str), &(result->currentStringLength));
+       if (!status) {
+               fprintf(stderr, "Error finalizing zip.\n");
+       }
+
+       return result;
+}
diff --git a/Sources/libMultiMarkdown/textbundle.h b/Sources/libMultiMarkdown/textbundle.h
new file mode 100644 (file)
index 0000000..7b7aa7e
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+
+       MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file textbundle.h
+
+       @brief 
+
+
+       @author Fletcher T. Penney
+       @bug    
+
+**/
+
+/*
+
+       Copyright © 2016 - 2017 Fletcher T. Penney.
+
+
+       The `MultiMarkdown 6` project is released under the MIT License..
+       
+       GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+       
+               https://github.com/fletcher/MultiMarkdown-4/
+       
+       MMD 4 is released under both the MIT License and GPL.
+       
+       
+       CuTest is released under the zlib/libpng license. See CuTest.c for the
+       text of the license.
+       
+       uthash library:
+               Copyright (c) 2005-2016, Troy D. Hanson
+       
+               Licensed under Revised BSD license
+       
+       miniz library:
+               Copyright 2013-2014 RAD Game Tools and Valve Software
+               Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+       
+               Licensed under the MIT license
+       
+       argtable3 library:
+               Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+               <sheitmann@users.sourceforge.net>
+               All rights reserved.
+       
+               Licensed under the Revised BSD License
+       
+       
+       ## The MIT License ##
+       
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files (the
+       "Software"), to deal in the Software without restriction, including
+       without limitation the rights to use, copy, modify, merge, publish,
+       distribute, sublicense, and/or sell copies of the Software, and to
+       permit persons to whom the Software is furnished to do so, subject to
+       the following conditions:
+       
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+       
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+       CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+       TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+       SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+       
+       
+       ## Revised BSD License ##
+       
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+           * Redistributions of source code must retain the above copyright
+             notice, this list of conditions and the following disclaimer.
+           * Redistributions in binary form must reproduce the above
+             copyright notice, this list of conditions and the following
+             disclaimer in the documentation and/or other materials provided
+             with the distribution.
+           * Neither the name of the <organization> nor the
+             names of its contributors may be used to endorse or promote
+             products derived from this software without specific prior
+             written permission.
+       
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+       "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+       LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+       A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
+       HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+       EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+       PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR
+       PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+       LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+       NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+       
+
+*/
+
+
+#ifndef TEXTBUNDLE_MULTIMARKDOWN_H
+#define TEXTBUNDLE_MULTIMARKDOWN_H
+
+#include "d_string.h"
+#include "mmd.h"
+
+void textbundle_write_wrapper(const char * root_path, const char * body, mmd_engine * e, const char * directory);
+
+DString * textbundle_create(const char * body, mmd_engine * e, const char * directory);
+
+#endif
index 4539eb50ebd132439cd25b66be72eabc183a4be7..9bb89088a99e258ff0d8caa629811bd74b59e51b 100644 (file)
@@ -1731,6 +1731,7 @@ void mmd_engine_export_token_tree(DString * out, mmd_engine * e, short format) {
 
                        break;
                case FORMAT_EPUB:
+               case FORMAT_TEXTBUNDLE_COMPRESSED:
                        mmd_start_complete_html(out, e->dstr->str, scratch);
                        scratch->store_assets = true;
 
index 1f943f336aa562a0eb2f77bc3900f32fbf953f41..667681dfefddccc524b2ea2db3122a61256829db 100644 (file)
@@ -153,7 +153,7 @@ int main(int argc, char** argv) {
 
                a_rem2                  = arg_rem("", ""),
 
-               a_format                = arg_str0("t", "to", "FORMAT", "convert to FORMAT, FORMAT = html|latex|beamer|memoir|mmd|odf|epub"),
+               a_format                = arg_str0("t", "to", "FORMAT", "convert to FORMAT, FORMAT = html|latex|beamer|memoir|mmd|odf|epub|bundle|bundlezip"),
                a_o                             = arg_file0("o", "output", "FILE", "send output to FILE"),
 
                a_rem3                  = arg_rem("",""),
@@ -280,6 +280,10 @@ int main(int argc, char** argv) {
                        format = FORMAT_ODF;
                else if (strcmp(a_format->sval[0], "epub") == 0)
                        format = FORMAT_EPUB;
+               else if (strcmp(a_format->sval[0], "bundle") == 0)
+                       format = FORMAT_TEXTBUNDLE;
+               else if (strcmp(a_format->sval[0], "bundlezip") == 0)
+                       format = FORMAT_TEXTBUNDLE_COMPRESSED;
                else {
                        // No valid format found
                        fprintf(stderr, "%s: Unknown output format '%s'\n", binname, a_format->sval[0]);
@@ -347,6 +351,12 @@ int main(int argc, char** argv) {
                                case FORMAT_EPUB:
                                        output_filename = filename_with_extension(a_file->filename[i], ".epub");
                                        break;
+                               case FORMAT_TEXTBUNDLE:
+                                       output_filename = filename_with_extension(a_file->filename[i], ".textbundle");
+                                       break;
+                               case FORMAT_TEXTBUNDLE_COMPRESSED:
+                                       output_filename = filename_with_extension(a_file->filename[i], ".textpack");
+                                       break;
                        }
 
                        // Perform transclusion(s)