]> granicus.if.org Git - multimarkdown/commitdiff
CHANGED: Add mmd_convert_to_data functions; Refactor main.c so that EPUB and other...
authorFletcher T. Penney <fletcher@fletcherpenney.net>
Thu, 25 May 2017 00:55:22 +0000 (20:55 -0400)
committerFletcher T. Penney <fletcher@fletcherpenney.net>
Thu, 25 May 2017 00:55:22 +0000 (20:55 -0400)
CMakeLists.txt
Sources/libMultiMarkdown/epub.c
Sources/libMultiMarkdown/epub.h
Sources/libMultiMarkdown/include/libMultiMarkdown.h
Sources/libMultiMarkdown/mmd.c
Sources/libMultiMarkdown/zip.c [new file with mode: 0644]
Sources/libMultiMarkdown/zip.h [new file with mode: 0644]
Sources/multimarkdown/main.c

index 012d324844df266e42bb91b71582b5babcb30315..84b578f10fa282004a198c22056de60be6454d0d 100644 (file)
@@ -200,6 +200,7 @@ set(src_files
        Sources/libMultiMarkdown/transclude.c
        Sources/libMultiMarkdown/uuid.c
        Sources/libMultiMarkdown/writer.c
+       Sources/libMultiMarkdown/zip.c
 )
 
 # Primary header files, also for doxygen documentation
@@ -227,6 +228,7 @@ set(header_files
        Sources/libMultiMarkdown/uthash.h
        Sources/libMultiMarkdown/uuid.h
        Sources/libMultiMarkdown/writer.h
+       Sources/libMultiMarkdown/zip.h
 )
 
 set (scripts
index 6a0a3a892b245e1bbd72bed156feec6abe7518f3..1dc79a156c270457610f8f66f758febf4a0771c2 100644 (file)
 #include <curl/curl.h>
 #endif
 
-#include "d_string.h"
 #include "epub.h"
 #include "html.h"
 #include "i18n.h"
 #include "miniz.h"
-#include "mmd.h"
 #include "transclude.h"
 #include "uuid.h"
 #include "writer.h"
-
+#include "zip.h"
 
 #define print(x) d_string_append(out, x)
 #define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
@@ -295,7 +293,10 @@ char * epub_nav(mmd_engine * e, scratch_pad * scratch) {
 }
 
 
-bool add_asset_from_file(const char * filepath, asset * a, const char * destination, const char * directory) {
+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;
@@ -303,7 +304,7 @@ bool add_asset_from_file(const char * filepath, asset * a, const char * destinat
        DString * buffer = scan_file(path);
 
        if (buffer && buffer->currentStringLength > 0) {
-               status = mz_zip_add_mem_to_archive_file_in_place(filepath, destination, buffer->str, buffer->currentStringLength, NULL, 0, MZ_BEST_COMPRESSION);
+               status = mz_zip_writer_add_mem(pZip, destination, buffer->str, buffer->currentStringLength, MZ_BEST_COMPRESSION);
 
                d_string_free(buffer, true);
                result = true;
@@ -344,7 +345,7 @@ static size_t write_memory(void * contents, size_t size, size_t nmemb, void * us
 }
 
 // Add assets to zipfile using libcurl
-void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
+void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
        asset * a, * a_tmp;
 
        if (e->asset_hash){
@@ -375,12 +376,12 @@ void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
 
                        if (res != CURLE_OK) {
                                // Attempt to add asset from local file
-                               if (!add_asset_from_file(filepath, a, destination, directory)) {
+                               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_add_mem_to_archive_file_in_place(filepath, destination, chunk.memory, chunk.size, NULL, 0, MZ_BEST_COMPRESSION);
+                               status = mz_zip_writer_add_mem(pZip, destination, chunk.memory, chunk.size, MZ_BEST_COMPRESSION);
                        }
                }
        }
@@ -388,7 +389,7 @@ void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
 
 #else
 // Add local assets only (libcurl not available)
-void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
+void add_assets(mz_zip_archive * pZip, mmd_engine * e, const char * directory) {
        asset * a, * a_tmp;
 
        if (e->asset_hash){
@@ -403,7 +404,7 @@ void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
                        memcpy(&destination[13], a->asset_path, 36);
 
                        // Attempt to add asset from local file
-                       if (!add_asset_from_file(filepath, a, destination, directory)) {
+                       if (!add_asset_from_file(pZip, a, destination, directory)) {
                                fprintf(stderr, "Unable to store '%s' in EPUB\n", a->url);
                        }
                }
@@ -414,53 +415,76 @@ void add_assets(const char * filepath, mmd_engine * e, const char * directory) {
 
 // Use the miniz library to create a zip archive for the EPUB document
 void epub_write_wrapper(const char * filepath, const char * body, mmd_engine * e, const char * directory) {
+       FILE * output_stream;
+
+       DString * result = epub_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 * epub_create(const char * body, mmd_engine * e, const char * directory) {
+       DString * result = d_string_new("");
        scratch_pad * scratch = scratch_pad_new(e, FORMAT_EPUB);
+
        mz_bool status;
        char * data;
        size_t len;
 
-       // Delete existing file, if present
-       remove(filepath);
+       mz_zip_archive zip;
+       zip_new_archive(&zip);
 
        // Add mimetype
        data = epub_mimetype();
        len = strlen(data);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "mimetype", data, len, NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "mimetype", data, len, MZ_BEST_COMPRESSION);
        free(data);
 
        // Create directories
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "OEBPS/", NULL, 0, NULL, 0, MZ_BEST_COMPRESSION);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "META-INF/", NULL, 0, NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "OEBPS/", NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "META-INF/", NULL, 0, MZ_BEST_COMPRESSION);
 
        // Add container
        data = epub_container_xml();
        len = strlen(data);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "META-INF/container.xml", data, len, NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "META-INF/container.xml", data, len, MZ_BEST_COMPRESSION);
        free(data);
 
        // Add package
        data = epub_package_document(scratch);
        len = strlen(data);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "OEBPS/main.opf", data, len, NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "OEBPS/main.opf", data, len, MZ_BEST_COMPRESSION);
        free(data);
 
        // Add nav
        data = epub_nav(e, scratch);
        len = strlen(data);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "OEBPS/nav.xhtml", data, len, NULL, 0, MZ_BEST_COMPRESSION);
+       status = mz_zip_writer_add_mem(&zip, "OEBPS/nav.xhtml", data, len, MZ_BEST_COMPRESSION);
        free(data);
 
        // Add main document
        len = strlen(body);
-       status = mz_zip_add_mem_to_archive_file_in_place(filepath, "OEBPS/main.xhtml", body, len, NULL, 0, MZ_BEST_COMPRESSION);
-
+       status = mz_zip_writer_add_mem(&zip, "OEBPS/main.xhtml", body, len, MZ_BEST_COMPRESSION);
 
        // Add assets
-       add_assets(filepath, e, directory);
+       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));
 
+       return result;
+}
 
 
index e778297126da543b5c0c5e15333348102c8b835b..2f9e2e962abf0ea9f736d9c0a143f562f2b97cf7 100644 (file)
 #ifndef EPUB_MULTIMARKDOWN_H
 #define EPUB_MULTIMARKDOWN_H
 
+#include "d_string.h"
 #include "mmd.h"
 
 void epub_write_wrapper(const char * root_path, const char * body, mmd_engine * e, const char * directory);
 
+DString * epub_create(const char * body, mmd_engine * e, const char * directory);
+
 
 #endif
index 236760c8386abebe40ffc5b65b441782de875d36..d74282c343c9798f7e974036a9272f07d5f18c5e 100644 (file)
 char * mmd_string_convert(const char * source, unsigned long extensions, short format, short language);
 
 
+/// Convert MMD text to specified format using DString as a container for block of data
+/// and length of that block.  Must be used for "complex" output formats such as EPUB.
+/// Returned DString * must be freed
+DString * mmd_string_convert_to_data(const char * source, unsigned long extensions, short format, short language, const char * directory);
+
+
 /// Convert MMD text and write results to specified file -- used for "complex" output formats requiring
 /// multiple documents (e.g. EPUB)
 void mmd_string_convert_to_file(const char * source, unsigned long extensions, short format, short language, const char * directory, const char * filepath);
@@ -124,6 +130,12 @@ char * mmd_string_metavalue_for_key(char * source, const char * key);
 char * mmd_d_string_convert(DString * source, unsigned long extensions, short format, short language);
 
 
+/// Convert MMD text to specified format using DString as a container for block of data
+/// and length of that block.  Must be used for "complex" output formats such as EPUB.
+/// Returned DString * must be freed
+DString * mmd_d_string_convert_to_data(DString * source, unsigned long extensions, short format, short language, const char * directory);
+
+
 /// Convert MMD text and write results to specified file -- used for "complex" output formats requiring
 /// multiple documents (e.g. EPUB)
 void mmd_d_string_convert_to_file(DString * source, unsigned long extensions, short format, short language, const char * directory, const char * filepath);
@@ -205,6 +217,12 @@ char * mmd_engine_convert(mmd_engine * e, short format);
 void mmd_engine_convert_to_file(mmd_engine * e, short format, const char * directory, const char * filepath);
 
 
+/// Convert MMD text to specified format using DString as a container for block of data
+/// and length of that block.  Must be used for "complex" output formats such as EPUB.
+/// Returned DString * must be freed
+DString * mmd_engine_convert_to_data(mmd_engine * e, short format, const char * directory);
+
+
 /// Does the text have metadata?
 bool mmd_engine_has_metadata(mmd_engine * e, size_t * end);
 
index 902e64d5c685991ac9dc5f9836222f345d89388c..6eab95c280dc536a4d5669af2df47e65be1c8963 100644 (file)
@@ -2203,6 +2203,55 @@ void mmd_engine_convert_to_file(mmd_engine * e, short format, const char * direc
 }
 
 
+DString * mmd_string_convert_to_data(const char * source, unsigned long extensions, short format, short language, const char * directory) {
+       mmd_engine * e = mmd_engine_create_with_string(source, extensions);
+
+       mmd_engine_set_language(e, language);
+
+       DString * result = mmd_engine_convert_to_data(e, format, directory);
+
+       mmd_engine_free(e, true);
+
+       return result;
+}
+
+
+DString * mmd_d_string_convert_to_data(DString * source, unsigned long extensions, short format, short language, const char * directory) {
+       mmd_engine * e = mmd_engine_create_with_dstring(source, extensions);
+
+       mmd_engine_set_language(e, language);
+
+       DString * result =  mmd_engine_convert_to_data(e, format, directory);
+
+       mmd_engine_free(e, false);                      // The engine doesn't own the DString, so don't free it.
+
+       return result;
+}
+
+
+DString * mmd_engine_convert_to_data(mmd_engine * e, short format, const char * directory) {
+       DString * output = d_string_new("");
+       DString * result = NULL;
+
+       mmd_engine_parse_string(e);
+       
+       mmd_engine_export_token_tree(output, e, format);
+
+       switch (format) {
+               case FORMAT_EPUB:
+                       result = epub_create(output->str, e, directory);
+
+                       d_string_free(output, true);
+                       break;
+               default:
+                       result = output;
+                       break;
+       }
+
+       return result;
+}
+
+
 /// Return string containing engine version.
 char * mmd_version(void) {
        char * result;
diff --git a/Sources/libMultiMarkdown/zip.c b/Sources/libMultiMarkdown/zip.c
new file mode 100644 (file)
index 0000000..88cba3e
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+
+       MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file zip.c
+
+       @brief Common routines for zip-based file formats
+
+
+       @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 "miniz.h"
+#include "zip.h"
+
+
+void zip_new_archive(mz_zip_archive * pZip) {
+       memset(pZip, 0, sizeof(mz_zip_archive));
+
+       mz_bool status;
+
+       status = mz_zip_writer_init_heap(pZip, 0, 0);
+
+       if (!status) {
+               fprintf(stderr, "mz_zip_writer_init_heap() failed.\n");
+       }
+}
+
diff --git a/Sources/libMultiMarkdown/zip.h b/Sources/libMultiMarkdown/zip.h
new file mode 100644 (file)
index 0000000..64c3549
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+
+       MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+       @file zip.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 ZIP_MULTIMARKDOWN_H
+#define ZIP_MULTIMARKDOWN_H
+
+void zip_new_archive(mz_zip_archive * pZip);
+
+
+#endif
index b279c5cbdd76f4752807d7697f9b0504ec6b850c..0366efb7f2341d8ec4b4bef916de59af90a21b0d 100644 (file)
@@ -287,7 +287,8 @@ int main(int argc, char** argv) {
        }
 
        DString * buffer = NULL;
-       char * result = NULL;
+       DString * result = NULL;
+       char * char_result = NULL;
        FILE * output_stream;
        char * output_filename;
 
@@ -360,46 +361,40 @@ int main(int argc, char** argv) {
 #endif
                        if (a_meta->count > 0) {
                                // List metadata keys
-                               result = mmd_string_metadata_keys(buffer->str);
+                               char_result = mmd_string_metadata_keys(buffer->str);
 
-                               fputs(result, stdout);
+                               fputs(char_result, stdout);
 
-                               free(result);
+                               free(char_result);
                        } else if (a_extract->count > 0) {
                                // Extract metadata key
                                const char * query = a_extract->sval[0];
 
-                               result = mmd_string_metavalue_for_key(buffer->str, query);
+                               char_result = mmd_string_metavalue_for_key(buffer->str, query);
 
-                               fputs(result, stdout);
+                               fputs(char_result, stdout);
                                fputc('\n', stdout);
 
-                               free(result);
+                               free(char_result);
                        } else {
                                // Regular processing
 
-                               if (FORMAT_EPUB == format) {
-                                       mmd_d_string_convert_to_file(buffer, extensions, format, language, folder, output_filename);
-                                       result = NULL;
-                               } else if (FORMAT_MMD == format) {
-                                       result = buffer->str;
+                               if (FORMAT_MMD == format) {
+                                       result = buffer;
                                } else {
-                                       result = mmd_d_string_convert(buffer, extensions, format, language);
+                                       result = mmd_d_string_convert_to_data(buffer, extensions, format, language, folder);
                                }
 
-                               if (result) {
-                                       if (!(output_stream = fopen(output_filename, "w"))) {
-                                               // Failed to open file
-                                               perror(output_filename);
-                                       } else {
-                                               fputs(result, output_stream);
-                                               fputc('\n', output_stream);
-                                               fclose(output_stream);
-                                       }
+                               if (!(output_stream = fopen(output_filename, "w"))) {
+                                       // Failed to open file
+                                       perror(output_filename);
+                               } else {
+                                       fwrite(result->str, result->currentStringLength, 1, output_stream);
+                                       fclose(output_stream);
                                }
 
                                if (FORMAT_MMD != format) {
-                                       free(result);
+                                       d_string_free(result, true);
                                }
                        }
 
@@ -434,9 +429,14 @@ int main(int argc, char** argv) {
                        buffer = stdin_buffer();
                }
 
+               char * folder = NULL;
+
+               if (a_file->count == 1) {
+                       folder = dirname((char *) a_file->filename[0]);
+               }
+
                if ((extensions & EXT_TRANSCLUDE) && (a_file->count == 1)) {
                        // Perform transclusion(s)
-                       char * folder = dirname((char *) a_file->filename[0]);
 
                        mmd_transclude_source(buffer, folder, "", format, NULL, NULL);
 
@@ -454,28 +454,28 @@ int main(int argc, char** argv) {
 
                if (a_meta->count > 0) {
                        // List metadata keys
-                       result = mmd_string_metadata_keys(buffer->str);
+                       char_result = mmd_string_metadata_keys(buffer->str);
 
-                       fputs(result, stdout);
+                       fputs(char_result, stdout);
 
-                       free(result);
+                       free(char_result);
                } else if (a_extract->count > 0) {
                        // Extract metadata key
                        const char * query = a_extract->sval[0];
 
-                       result = mmd_string_metavalue_for_key(buffer->str, query);
+                       char_result = mmd_string_metavalue_for_key(buffer->str, query);
 
-                       fputs(result, stdout);
+                       fputs(char_result, stdout);
                        fputc('\n', stdout);
 
-                       free(result);
+                       free(char_result);
                } else {
                        // Regular processing
 
                        if (FORMAT_MMD == format) {
-                               result = buffer->str;
+                               result = buffer;
                        } else {
-                               result = mmd_d_string_convert(buffer, extensions, format, language);
+                               result = mmd_d_string_convert_to_data(buffer, extensions, format, language, folder);
                        }
 
                        // Where does output go?
@@ -491,14 +491,13 @@ int main(int argc, char** argv) {
                                goto exit;
                        }
 
-                       fputs(result, output_stream);
-                       fputc('\n', output_stream);
-                       
+                       fwrite(result->str, result->currentStringLength, 1, output_stream);                     
+
                        if (output_stream != stdout)
                                fclose(output_stream);
 
                        if (FORMAT_MMD != format) {
-                               free(result);
+                               d_string_free(result, true);
                        }
                }