Detailed changes
@@ -3,10 +3,6 @@
#include <stddef.h>
-// wrap_base64 wraps base64-encoded data at 76 characters per line with \r\n
-// separators, as required by MIME (RFC 2045). The caller must free the returned
-// pointer with free().
-// Returns NULL if allocation fails.
char* wrap_base64(const char* data, size_t len, size_t* out_len);
#endif
@@ -1,33 +1,6 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#include "entity.h"
#include <string.h>
-
-/* Generated by scripts/build_enity_map.py. */
static const ENTITY ENTITY_MAP[] = {
{ "Æ", { 198, 0 } },
{ "&", { 38, 0 } },
@@ -2156,7 +2129,6 @@ static const ENTITY ENTITY_MAP[] = {
{ "‌", { 8204, 0 } }
};
-
typedef struct ENTITY_KEY_tag ENTITY_KEY;
struct ENTITY_KEY_tag {
const char* name;
@@ -1,36 +1,8 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#ifndef MD4C_ENTITY_H
#define MD4C_ENTITY_H
#include <stdlib.h>
-
-/* Most entities are formed by single Unicode codepoint, few by two codepoints.
- * Single-codepoint entities have codepoints[1] set to zero. */
typedef struct ENTITY_tag ENTITY;
struct ENTITY_tag {
const char* name;
@@ -39,5 +11,4 @@ struct ENTITY_tag {
const ENTITY* entity_lookup(const char* name, size_t name_size);
-
-#endif /* MD4C_ENTITY_H */
+#endif
@@ -3,25 +3,22 @@
#include <stddef.h>
-// Element types found during HTML parsing.
enum {
- HELEM_TEXT = 0, // Plain text segment
- HELEM_H1 = 1, // <h1> text
- HELEM_H2 = 2, // <h2> text
- HELEM_LINK = 3, // <a href="...">text</a>
- HELEM_IMAGE = 4, // <img src="..." alt="...">
- HELEM_BLOCKQUOTE = 5, // <blockquote> content (with optional cite/prev)
+ HELEM_TEXT = 0,
+ HELEM_H1 = 1,
+ HELEM_H2 = 2,
+ HELEM_LINK = 3,
+ HELEM_IMAGE = 4,
+ HELEM_BLOCKQUOTE = 5,
};
-// HTMLElement represents a parsed element from the HTML document.
typedef struct {
int type;
- char* text; // Text content (h1/h2 text, link text, blockquote content)
- char* attr1; // href for links, src for images, cite for blockquotes
- char* attr2; // alt for images, prev_text for blockquotes (On...wrote:)
+ char* text;
+ char* attr1;
+ char* attr2;
} HTMLElement;
-// HTMLConvertResult holds the output of html_to_elements.
typedef struct {
HTMLElement* elements;
int count;
@@ -29,13 +26,8 @@ typedef struct {
int ok;
} HTMLConvertResult;
-// html_to_elements parses an HTML string and returns an array of structured
-// elements. The caller processes these elements to apply terminal styling.
-// style/script content is stripped. Block elements get proper spacing.
-// Returns a result with ok=1 on success. Caller must free with free_html_result.
HTMLConvertResult html_to_elements(const char* html, size_t len);
-// free_html_result frees all memory in an HTMLConvertResult.
void free_html_result(HTMLConvertResult* r);
#endif
@@ -3,26 +3,18 @@
#include <stddef.h>
-// ImageResult holds the output of decode_to_png.
typedef struct {
- unsigned char* png_data; // PNG-encoded bytes (caller must free)
- size_t png_len; // Length of png_data
- int width; // Image width in pixels
- int height; // Image height in pixels
- int ok; // 1 on success, 0 on failure
+ unsigned char* png_data;
+ size_t png_len;
+ int width;
+ int height;
+ int ok;
} ImageResult;
-// decode_to_png takes raw image bytes (JPEG, PNG, BMP, GIF, etc.),
-// decodes them, and re-encodes as PNG. Supports any format that
-// stb_image can decode.
ImageResult decode_to_png(const unsigned char* data, size_t len);
-// free_image_result frees the PNG data inside an ImageResult.
void free_image_result(ImageResult* r);
-// image_dimensions returns only the width and height of an image without
-// fully decoding pixel data. Faster than decode_to_png when you only need
-// dimensions. Returns 1 on success, 0 on failure.
int image_dimensions(const unsigned char* data, size_t len, int* width, int* height);
#endif
@@ -1,37 +1,11 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#include <stdio.h>
#include <string.h>
#include "md4c-html.h"
#include "entity.h"
-
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L
- /* C89/90 or old compilers in general may not understand "inline". */
+
#if defined __GNUC__
#define inline __inline__
#elif defined _MSC_VER
@@ -45,8 +19,6 @@
#define snprintf _snprintf
#endif
-
-
typedef struct MD_HTML_tag MD_HTML;
struct MD_HTML_tag {
void (*process_output)(const MD_CHAR*, MD_SIZE, void*);
@@ -59,40 +31,30 @@ struct MD_HTML_tag {
#define NEED_HTML_ESC_FLAG 0x1
#define NEED_URL_ESC_FLAG 0x2
-
-/*****************************************
- *** HTML rendering helper functions ***
- *****************************************/
-
#define ISDIGIT(ch) ('0' <= (ch) && (ch) <= '9')
#define ISLOWER(ch) ('a' <= (ch) && (ch) <= 'z')
#define ISUPPER(ch) ('A' <= (ch) && (ch) <= 'Z')
#define ISALNUM(ch) (ISLOWER(ch) || ISUPPER(ch) || ISDIGIT(ch))
-
static inline void
render_verbatim(MD_HTML* r, const MD_CHAR* text, MD_SIZE size)
{
r->process_output(text, size, r->userdata);
}
-/* Keep this as a macro. Most compiler should then be smart enough to replace
- * the strlen() call with a compile-time constant if the string is a C literal. */
#define RENDER_VERBATIM(r, verbatim) \
render_verbatim((r), (verbatim), (MD_SIZE) (strlen(verbatim)))
-
static void
render_html_escaped(MD_HTML* r, const MD_CHAR* data, MD_SIZE size)
{
MD_OFFSET beg = 0;
MD_OFFSET off = 0;
- /* Some characters need to be escaped in normal HTML text. */
#define NEED_HTML_ESC(ch) (r->escape_map[(unsigned char)(ch)] & NEED_HTML_ESC_FLAG)
while(1) {
- /* Optimization: Use some loop unrolling. */
+
while(off + 3 < size && !NEED_HTML_ESC(data[off+0]) && !NEED_HTML_ESC(data[off+1])
&& !NEED_HTML_ESC(data[off+2]) && !NEED_HTML_ESC(data[off+3]))
off += 4;
@@ -124,7 +86,6 @@ render_url_escaped(MD_HTML* r, const MD_CHAR* data, MD_SIZE size)
MD_OFFSET beg = 0;
MD_OFFSET off = 0;
- /* Some characters need to be escaped in URL attributes. */
#define NEED_URL_ESC(ch) (r->escape_map[(unsigned char)(ch)] & NEED_URL_ESC_FLAG)
while(1) {
@@ -200,8 +161,6 @@ render_utf8_codepoint(MD_HTML* r, unsigned codepoint,
fn_append(r, utf8_replacement_char, 3);
}
-/* Translate entity to its UTF-8 equivalent, or output the verbatim one
- * if such entity is unknown (or if the translation is disabled). */
static void
render_entity(MD_HTML* r, const MD_CHAR* text, MD_SIZE size,
void (*fn_append)(MD_HTML*, const MD_CHAR*, MD_SIZE))
@@ -211,17 +170,16 @@ render_entity(MD_HTML* r, const MD_CHAR* text, MD_SIZE size,
return;
}
- /* We assume UTF-8 output is what is desired. */
if(size > 3 && text[1] == '#') {
unsigned codepoint = 0;
if(text[2] == 'x' || text[2] == 'X') {
- /* Hexadecimal entity (e.g. "�")). */
+
MD_SIZE i;
for(i = 3; i < size-1; i++)
codepoint = 16 * codepoint + hex_val(text[i]);
} else {
- /* Decimal entity (e.g. "&1234;") */
+
MD_SIZE i;
for(i = 2; i < size-1; i++)
codepoint = 10 * codepoint + (text[i] - '0');
@@ -230,7 +188,7 @@ render_entity(MD_HTML* r, const MD_CHAR* text, MD_SIZE size,
render_utf8_codepoint(r, codepoint, fn_append);
return;
} else {
- /* Named entity (e.g. " "). */
+
const ENTITY* ent;
ent = entity_lookup(text, size);
@@ -265,7 +223,6 @@ render_attribute(MD_HTML* r, const MD_ATTRIBUTE* attr,
}
}
-
static void
render_open_ol_block(MD_HTML* r, const MD_BLOCK_OL_DETAIL* det)
{
@@ -299,7 +256,6 @@ render_open_code_block(MD_HTML* r, const MD_BLOCK_CODE_DETAIL* det)
{
RENDER_VERBATIM(r, "<pre><code");
- /* If known, output the HTML 5 attribute class="language-LANGNAME". */
if(det->lang.text != NULL) {
RENDER_VERBATIM(r, " class=\"language-");
render_attribute(r, &det->lang, render_html_escaped);
@@ -366,11 +322,6 @@ render_open_wikilink_span(MD_HTML* r, const MD_SPAN_WIKILINK_DETAIL* det)
RENDER_VERBATIM(r, "\">");
}
-
-/**************************************
- *** HTML renderer implementation ***
- **************************************/
-
static int
enter_block_callback(MD_BLOCKTYPE type, void* detail, void* userdata)
{
@@ -378,7 +329,7 @@ enter_block_callback(MD_BLOCKTYPE type, void* detail, void* userdata)
MD_HTML* r = (MD_HTML*) userdata;
switch(type) {
- case MD_BLOCK_DOC: /* noop */ break;
+ case MD_BLOCK_DOC: break;
case MD_BLOCK_QUOTE: RENDER_VERBATIM(r, "<blockquote>\n"); break;
case MD_BLOCK_UL: RENDER_VERBATIM(r, "<ul>\n"); break;
case MD_BLOCK_OL: render_open_ol_block(r, (const MD_BLOCK_OL_DETAIL*)detail); break;
@@ -386,7 +337,7 @@ enter_block_callback(MD_BLOCKTYPE type, void* detail, void* userdata)
case MD_BLOCK_HR: RENDER_VERBATIM(r, (r->flags & MD_HTML_FLAG_XHTML) ? "<hr />\n" : "<hr>\n"); break;
case MD_BLOCK_H: RENDER_VERBATIM(r, head[((MD_BLOCK_H_DETAIL*)detail)->level - 1]); break;
case MD_BLOCK_CODE: render_open_code_block(r, (const MD_BLOCK_CODE_DETAIL*) detail); break;
- case MD_BLOCK_HTML: /* noop */ break;
+ case MD_BLOCK_HTML: break;
case MD_BLOCK_P: RENDER_VERBATIM(r, "<p>"); break;
case MD_BLOCK_TABLE: RENDER_VERBATIM(r, "<table>\n"); break;
case MD_BLOCK_THEAD: RENDER_VERBATIM(r, "<thead>\n"); break;
@@ -406,15 +357,15 @@ leave_block_callback(MD_BLOCKTYPE type, void* detail, void* userdata)
MD_HTML* r = (MD_HTML*) userdata;
switch(type) {
- case MD_BLOCK_DOC: /*noop*/ break;
+ case MD_BLOCK_DOC: break;
case MD_BLOCK_QUOTE: RENDER_VERBATIM(r, "</blockquote>\n"); break;
case MD_BLOCK_UL: RENDER_VERBATIM(r, "</ul>\n"); break;
case MD_BLOCK_OL: RENDER_VERBATIM(r, "</ol>\n"); break;
case MD_BLOCK_LI: RENDER_VERBATIM(r, "</li>\n"); break;
- case MD_BLOCK_HR: /*noop*/ break;
+ case MD_BLOCK_HR: break;
case MD_BLOCK_H: RENDER_VERBATIM(r, head[((MD_BLOCK_H_DETAIL*)detail)->level - 1]); break;
case MD_BLOCK_CODE: RENDER_VERBATIM(r, "</code></pre>\n"); break;
- case MD_BLOCK_HTML: /* noop */ break;
+ case MD_BLOCK_HTML: break;
case MD_BLOCK_P: RENDER_VERBATIM(r, "</p>\n"); break;
case MD_BLOCK_TABLE: RENDER_VERBATIM(r, "</table>\n"); break;
case MD_BLOCK_THEAD: RENDER_VERBATIM(r, "</thead>\n"); break;
@@ -433,20 +384,6 @@ enter_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
MD_HTML* r = (MD_HTML*) userdata;
int inside_img = (r->image_nesting_level > 0);
- /* We are inside a Markdown image label. Markdown allows to use any emphasis
- * and other rich contents in that context similarly as in any link label.
- *
- * However, unlike in the case of links (where that contents becomescontents
- * of the <a>...</a> tag), in the case of images the contents is supposed to
- * fall into the attribute alt: <img alt="...">.
- *
- * In that context we naturally cannot output nested HTML tags. So lets
- * suppress them and only output the plain text (i.e. what falls into text()
- * callback).
- *
- * CommonMark specification declares this a recommended practice for HTML
- * output.
- */
if(type == MD_SPAN_IMG)
r->image_nesting_level++;
if(inside_img)
@@ -486,7 +423,7 @@ leave_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
case MD_SPAN_IMG: render_close_img_span(r, (MD_SPAN_IMG_DETAIL*) detail); break;
case MD_SPAN_CODE: RENDER_VERBATIM(r, "</code>"); break;
case MD_SPAN_DEL: RENDER_VERBATIM(r, "</del>"); break;
- case MD_SPAN_LATEXMATH: /*fall through*/
+ case MD_SPAN_LATEXMATH:
case MD_SPAN_LATEXMATH_DISPLAY: RENDER_VERBATIM(r, "</x-equation>"); break;
case MD_SPAN_WIKILINK: RENDER_VERBATIM(r, "</x-wikilink>"); break;
}
@@ -542,7 +479,6 @@ md_html(const MD_CHAR* input, MD_SIZE input_size,
NULL
};
- /* Build map of characters which need escaping. */
for(i = 0; i < 256; i++) {
unsigned char ch = (unsigned char) i;
@@ -553,7 +489,6 @@ md_html(const MD_CHAR* input, MD_SIZE input_size,
render.escape_map[i] |= NEED_URL_ESC_FLAG;
}
- /* Consider skipping UTF-8 byte order mark (BOM). */
if(renderer_flags & MD_HTML_FLAG_SKIP_UTF8_BOM && sizeof(MD_CHAR) == 1) {
static const MD_CHAR bom[3] = { (char)0xef, (char)0xbb, (char)0xbf };
if(input_size >= sizeof(bom) && memcmp(input, bom, sizeof(bom)) == 0) {
@@ -564,4 +499,3 @@ md_html(const MD_CHAR* input, MD_SIZE input_size,
return md_parse(input, input_size, &parser, (void*) &render);
}
-
@@ -1,28 +1,3 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#ifndef MD4C_HTML_H
#define MD4C_HTML_H
@@ -32,37 +7,17 @@
extern "C" {
#endif
-
-/* If set, debug output from md_parse() is sent to stderr. */
#define MD_HTML_FLAG_DEBUG 0x0001
#define MD_HTML_FLAG_VERBATIM_ENTITIES 0x0002
#define MD_HTML_FLAG_SKIP_UTF8_BOM 0x0004
#define MD_HTML_FLAG_XHTML 0x0008
-
-/* Render Markdown into HTML.
- *
- * Note only contents of <body> tag is generated. Caller must generate
- * HTML header/footer manually before/after calling md_html().
- *
- * Params input and input_size specify the Markdown input.
- * Callback process_output() gets called with chunks of HTML output.
- * (Typical implementation may just output the bytes to a file or append to
- * some buffer).
- * Param userdata is just propagated back to process_output() callback.
- * Param parser_flags are flags from md4c.h propagated to md_parse().
- * Param render_flags is bitmask of MD_HTML_FLAG_xxxx.
- *
- * Returns -1 on error (if md_parse() fails.)
- * Returns 0 on success.
- */
int md_html(const MD_CHAR* input, MD_SIZE input_size,
void (*process_output)(const MD_CHAR*, MD_SIZE, void*),
void* userdata, unsigned parser_flags, unsigned renderer_flags);
-
#ifdef __cplusplus
- } /* extern "C" { */
+ }
#endif
-#endif /* MD4C_HTML_H */
+#endif
@@ -1,28 +1,3 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#include "md4c.h"
#include <limits.h>
@@ -31,13 +6,8 @@
#include <stdlib.h>
#include <string.h>
-
-/*****************************
- *** Miscellaneous Stuff ***
- *****************************/
-
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L
- /* C89/90 or old compilers in general may not understand "inline". */
+
#if defined __GNUC__
#define inline __inline__
#elif defined _MSC_VER
@@ -47,12 +17,10 @@
#endif
#endif
-/* Make the UTF-8 support the default. */
#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16
#define MD4C_USE_UTF8
#endif
-/* Magic for making wide literals with MD4C_USE_UTF16. */
#ifdef _T
#undef _T
#endif
@@ -62,7 +30,6 @@
#define _T(x) x
#endif
-/* Misc. macros. */
#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0]))
#define STRINGIZE_(x) #x
@@ -106,7 +73,6 @@
#endif
#endif
-/* For falling through case labels in switch statements. */
#if defined __clang__ && __clang_major__ >= 12
#define MD_FALLTHROUGH() __attribute__((fallthrough))
#elif defined __GNUC__ && __GNUC__ >= 7
@@ -115,31 +81,12 @@
#define MD_FALLTHROUGH() ((void)0)
#endif
-/* Suppress "unused parameter" warnings. */
#define MD_UNUSED(x) ((void)x)
-
-/******************************
- *** Some internal limits ***
- ******************************/
-
-/* We limit code span marks to lower than 32 backticks. This solves the
- * pathologic case of too many openers, each of different length: Their
- * resolving would be then O(n^2). */
#define CODESPAN_MARK_MAXLEN 32
-/* We limit column count of tables to prevent quadratic explosion of output
- * from pathological input of a table thousands of columns and thousands
- * of rows where rows are requested with as little as single character
- * per-line, relying on us to "helpfully" fill all the missing "<td></td>". */
#define TABLE_MAXCOLCOUNT 128
-
-/************************
- *** Internal Types ***
- ************************/
-
-/* These are omnipresent so lets save some typing. */
#define CHAR MD_CHAR
#define SZ MD_SIZE
#define OFF MD_OFFSET
@@ -152,33 +99,24 @@ typedef struct MD_BLOCK_tag MD_BLOCK;
typedef struct MD_CONTAINER_tag MD_CONTAINER;
typedef struct MD_REF_DEF_tag MD_REF_DEF;
-
-/* During analyzes of inline marks, we need to manage stacks of unresolved
- * openers of the given type.
- * The stack connects the marks via MD_MARK::next;
- */
typedef struct MD_MARKSTACK_tag MD_MARKSTACK;
struct MD_MARKSTACK_tag {
- int top; /* -1 if empty. */
+ int top;
};
-/* Context propagated through all the parsing. */
typedef struct MD_CTX_tag MD_CTX;
struct MD_CTX_tag {
- /* Immutable stuff (parameters of md_parse()). */
+
const CHAR* text;
SZ size;
MD_PARSER parser;
void* userdata;
- /* When this is true, it allows some optimizations. */
int doc_ends_with_newline;
- /* Helper temporary growing buffer. */
CHAR* buffer;
unsigned alloc_buffer;
- /* Reference definitions. */
MD_REF_DEF* ref_defs;
int n_ref_defs;
int alloc_ref_defs;
@@ -186,10 +124,6 @@ struct MD_CTX_tag {
int ref_def_hashtable_size;
SZ max_ref_def_output;
- /* Stack of inline/span markers.
- * This is only used for parsing a single block contents but by storing it
- * here we may reuse the stack for subsequent blocks; i.e. we have fewer
- * (re)allocations. */
MD_MARK* marks;
int n_marks;
int alloc_marks;
@@ -200,18 +134,17 @@ struct MD_CTX_tag {
char mark_char_map[256];
#endif
- /* For resolving of inline spans. */
MD_MARKSTACK opener_stacks[16];
-#define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0]) /* Opener-only */
+#define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0])
#define ASTERISK_OPENERS_oo_mod3_1 (ctx->opener_stacks[1])
#define ASTERISK_OPENERS_oo_mod3_2 (ctx->opener_stacks[2])
-#define ASTERISK_OPENERS_oc_mod3_0 (ctx->opener_stacks[3]) /* Both opener and closer candidate */
+#define ASTERISK_OPENERS_oc_mod3_0 (ctx->opener_stacks[3])
#define ASTERISK_OPENERS_oc_mod3_1 (ctx->opener_stacks[4])
#define ASTERISK_OPENERS_oc_mod3_2 (ctx->opener_stacks[5])
-#define UNDERSCORE_OPENERS_oo_mod3_0 (ctx->opener_stacks[6]) /* Opener-only */
+#define UNDERSCORE_OPENERS_oo_mod3_0 (ctx->opener_stacks[6])
#define UNDERSCORE_OPENERS_oo_mod3_1 (ctx->opener_stacks[7])
#define UNDERSCORE_OPENERS_oo_mod3_2 (ctx->opener_stacks[8])
-#define UNDERSCORE_OPENERS_oc_mod3_0 (ctx->opener_stacks[9]) /* Both opener and closer candidate */
+#define UNDERSCORE_OPENERS_oc_mod3_0 (ctx->opener_stacks[9])
#define UNDERSCORE_OPENERS_oc_mod3_1 (ctx->opener_stacks[10])
#define UNDERSCORE_OPENERS_oc_mod3_2 (ctx->opener_stacks[11])
#define TILDE_OPENERS_1 (ctx->opener_stacks[12])
@@ -219,49 +152,33 @@ struct MD_CTX_tag {
#define BRACKET_OPENERS (ctx->opener_stacks[14])
#define DOLLAR_OPENERS (ctx->opener_stacks[15])
- /* Stack of dummies which need to call free() for pointers stored in them.
- * These are constructed during inline parsing and freed after all the block
- * is processed (i.e. all callbacks referring those strings are called). */
MD_MARKSTACK ptr_stack;
- /* For resolving table rows. */
int n_table_cell_boundaries;
int table_cell_boundaries_head;
int table_cell_boundaries_tail;
- /* For resolving links. */
int unresolved_link_head;
int unresolved_link_tail;
- /* For resolving raw HTML. */
OFF html_comment_horizon;
OFF html_proc_instr_horizon;
OFF html_decl_horizon;
OFF html_cdata_horizon;
- /* For block analysis.
- * Notes:
- * -- It holds MD_BLOCK as well as MD_LINE structures. After each
- * MD_BLOCK, its (multiple) MD_LINE(s) follow.
- * -- For MD_BLOCK_HTML and MD_BLOCK_CODE, MD_VERBATIMLINE(s) are used
- * instead of MD_LINE(s).
- */
void* block_bytes;
MD_BLOCK* current_block;
int n_block_bytes;
int alloc_block_bytes;
- /* For container block analysis. */
MD_CONTAINER* containers;
int n_containers;
int alloc_containers;
- /* Minimal indentation to call the block "indented code block". */
unsigned code_indent_offset;
- /* Contextual info for line analysis. */
- SZ code_fence_length; /* For checking closing fence length. */
- int html_block_type; /* For checking closing raw HTML condition. */
+ SZ code_fence_length;
+ int html_block_type;
int last_line_has_list_loosening_effect;
int last_list_item_starts_with_two_blank_lines;
};
@@ -288,7 +205,7 @@ struct MD_LINE_ANALYSIS_tag {
int enforce_new_block;
OFF beg;
OFF end;
- unsigned indent; /* Indentation level. */
+ unsigned indent;
};
typedef struct MD_LINE_tag MD_LINE;
@@ -304,17 +221,9 @@ struct MD_VERBATIMLINE_tag {
OFF indent;
};
-
-/*****************
- *** Helpers ***
- *****************/
-
-/* Character accessors. */
#define CH(off) (ctx->text[(off)])
#define STR(off) (ctx->text + (off))
-/* Character classification.
- * Note we assume ASCII compatibility of code points < 128 here. */
#define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max))
#define ISANYOF_(ch, palette) ((ch) != _T('\0') && md_strchr((palette), (ch)) != NULL)
#define ISANYOF2_(ch, ch1, ch2) ((ch) == (ch1) || (ch) == (ch2))
@@ -348,15 +257,12 @@ struct MD_VERBATIMLINE_tag {
#define ISXDIGIT(off) ISXDIGIT_(CH(off))
#define ISALNUM(off) ISALNUM_(CH(off))
-
#if defined MD4C_USE_UTF16
#define md_strchr wcschr
#else
#define md_strchr strchr
#endif
-
-/* Case insensitive check of string equality. */
static inline int
md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n)
{
@@ -411,7 +317,6 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ
}
}
-
#define MD_CHECK(func) \
do { \
ret = (func); \
@@ -419,7 +324,6 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ
goto abort; \
} while(0)
-
#define MD_TEMP_BUFFER(sz) \
do { \
if(sz > ctx->alloc_buffer) { \
@@ -438,7 +342,6 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ
} \
} while(0)
-
#define MD_ENTER_BLOCK(type, arg) \
do { \
ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \
@@ -497,9 +400,6 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ
} \
} while(0)
-
-/* If the offset falls into a gap between line, we return the following
- * line. */
static const MD_LINE*
md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_index)
{
@@ -532,25 +432,14 @@ md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_i
return NULL;
}
-
-/*************************
- *** Unicode Support ***
- *************************/
-
typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO;
struct MD_UNICODE_FOLD_INFO_tag {
unsigned codepoints[3];
unsigned n_codepoints;
};
-
#if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8
- /* Binary search over sorted "map" of codepoints. Consecutive sequences
- * of codepoints may be encoded in the map by just using the
- * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000).
- *
- * Returns index of the found record in the map (in the case of ranges,
- * the minimal value is used); or -1 on failure. */
+
static int
md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size)
{
@@ -560,7 +449,7 @@ struct MD_UNICODE_FOLD_INFO_tag {
beg = 0;
end = (int) map_size-1;
while(beg <= end) {
- /* Pivot may be a range, not just a single value. */
+
pivot_beg = pivot_end = (beg + end) / 2;
if(map[pivot_end] & 0x40000000)
pivot_end++;
@@ -583,16 +472,13 @@ struct MD_UNICODE_FOLD_INFO_tag {
{
#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
#define S(cp) (cp)
- /* Unicode "Zs" category.
- * (generated by scripts/build_whitespace_map.py) */
+
static const unsigned WHITESPACE_MAP[] = {
S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000)
};
#undef R
#undef S
- /* The ASCII ones are the most frequently used ones, also CommonMark
- * specification requests few more in this range. */
if(codepoint <= 0x7f)
return ISWHITESPACE_(codepoint);
@@ -604,8 +490,7 @@ struct MD_UNICODE_FOLD_INFO_tag {
{
#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
#define S(cp) (cp)
- /* Unicode general "P" and "S" categories.
- * (generated by scripts/build_punct_map.py) */
+
static const unsigned PUNCT_MAP[] = {
R(0x0021,0x002f), R(0x003a,0x0040), R(0x005b,0x0060), R(0x007b,0x007e), R(0x00a1,0x00a9),
R(0x00ab,0x00ac), R(0x00ae,0x00b1), S(0x00b4), R(0x00b6,0x00b8), S(0x00bb), S(0x00bf), S(0x00d7),
@@ -669,8 +554,6 @@ struct MD_UNICODE_FOLD_INFO_tag {
#undef R
#undef S
- /* The ASCII ones are the most frequently used ones, also CommonMark
- * specification requests few more in this range. */
if(codepoint <= 0x7f)
return ISPUNCT_(codepoint);
@@ -682,8 +565,7 @@ struct MD_UNICODE_FOLD_INFO_tag {
{
#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
#define S(cp) (cp)
- /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories.
- * (generated by scripts/build_folding_map.py) */
+
static const unsigned FOLD_MAP_1[] = {
R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136),
R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182),
@@ -782,7 +664,6 @@ struct MD_UNICODE_FOLD_INFO_tag {
int i;
- /* Fast path for ASCII characters. */
if(codepoint <= 0x7f) {
info->codepoints[0] = codepoint;
if(ISUPPER_(codepoint))
@@ -791,13 +672,12 @@ struct MD_UNICODE_FOLD_INFO_tag {
return;
}
- /* Try to locate the codepoint in any of the maps. */
for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) {
int index;
index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size);
if(index >= 0) {
- /* Found the mapping. */
+
unsigned n_codepoints = FOLD_MAP_LIST[i].n_codepoints;
const unsigned* map = FOLD_MAP_LIST[i].map;
const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints);
@@ -806,13 +686,12 @@ struct MD_UNICODE_FOLD_INFO_tag {
info->n_codepoints = n_codepoints;
if(FOLD_MAP_LIST[i].map[index] != codepoint) {
- /* The found mapping maps whole range of codepoints,
- * i.e. we have to offset info->codepoints[0] accordingly. */
+
if((map[index] & 0x00ffffff)+1 == codepoints[0]) {
- /* Alternating type of the range. */
+
info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0);
} else {
- /* Range to range kind of mapping. */
+
info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff));
}
}
@@ -821,13 +700,11 @@ struct MD_UNICODE_FOLD_INFO_tag {
}
}
- /* No mapping found. Map the codepoint to itself. */
info->codepoints[0] = codepoint;
info->n_codepoints = 1;
}
#endif
-
#if defined MD4C_USE_UTF16
#define IS_UTF16_SURROGATE_HI(word) (((WORD)(word) & 0xfc00) == 0xd800)
#define IS_UTF16_SURROGATE_LO(word) (((WORD)(word) & 0xfc00) == 0xdc00)
@@ -858,7 +735,6 @@ struct MD_UNICODE_FOLD_INFO_tag {
return CH(off);
}
- /* No whitespace uses surrogates, so no decoding needed here. */
#define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint)
#define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(CH(off))
#define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(CH((off)-1))
@@ -977,18 +853,6 @@ struct MD_UNICODE_FOLD_INFO_tag {
}
#endif
-
-/*************************************
- *** Helper string manipulations ***
- *************************************/
-
-/* Fill buffer with copy of the string between 'beg' and 'end' but replace any
- * line breaks with given replacement character.
- *
- * NOTE: Caller is responsible to make sure the buffer is large enough.
- * (Given the output is always shorter than input, (end - beg) is good idea
- * what the caller should allocate.)
- */
static void
md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size)
@@ -1024,8 +888,6 @@ md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_li
}
}
-/* Wrapper of md_merge_lines() which allocates new buffer for the output string.
- */
static int
md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size)
@@ -1061,18 +923,6 @@ md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size)
return off;
}
-
-/******************************
- *** Recognizing raw HTML ***
- ******************************/
-
-/* md_is_html_tag() may be called when processing inlines (inline raw HTML)
- * or when breaking document to blocks (checking for start of HTML block type 7).
- *
- * When breaking document to blocks, we do not yet know line boundaries, but
- * in that case the whole tag has to live on a single line. We distinguish this
- * by n_lines == 0.
- */
static int
md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
@@ -1087,39 +937,26 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF
return FALSE;
off++;
- /* For parsing attributes, we need a little state automaton below.
- * State -1: no attributes are allowed.
- * State 0: attribute could follow after some whitespace.
- * State 1: after a whitespace (attribute name may follow).
- * State 2: after attribute name ('=' MAY follow).
- * State 3: after '=' (value specification MUST follow).
- * State 41: in middle of unquoted attribute value.
- * State 42: in middle of single-quoted attribute value.
- * State 43: in middle of double-quoted attribute value.
- */
attr_state = 0;
if(CH(off) == _T('/')) {
- /* Closer tag "</ ... >". No attributes may be present. */
+
attr_state = -1;
off++;
}
- /* Tag name */
if(off >= line_end || !ISALPHA(off))
return FALSE;
off++;
while(off < line_end && (ISALNUM(off) || CH(off) == _T('-')))
off++;
- /* (Optional) attributes (if not closer), (optional) '/' (if not closer)
- * and final '>'. */
while(1) {
while(off < line_end && !ISNEWLINE(off)) {
if(attr_state > 40) {
if(attr_state == 41 && (ISBLANK(off) || ISANYOF(off, _T("\"'=<>`")))) {
attr_state = 0;
- off--; /* Put the char back for re-inspection in the new state. */
+ off--;
} else if(attr_state == 42 && CH(off) == _T('\'')) {
attr_state = 0;
} else if(attr_state == 43 && CH(off) == _T('"')) {
@@ -1131,24 +968,24 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF
attr_state = 1;
off++;
} else if(attr_state <= 2 && CH(off) == _T('>')) {
- /* End. */
+
goto done;
} else if(attr_state <= 2 && CH(off) == _T('/') && off+1 < line_end && CH(off+1) == _T('>')) {
- /* End with digraph '/>' */
+
off++;
goto done;
} else if((attr_state == 1 || attr_state == 2) && (ISALPHA(off) || CH(off) == _T('_') || CH(off) == _T(':'))) {
off++;
- /* Attribute name */
+
while(off < line_end && (ISALNUM(off) || ISANYOF(off, _T("_.:-"))))
off++;
attr_state = 2;
} else if(attr_state == 2 && CH(off) == _T('=')) {
- /* Attribute assignment sign */
+
off++;
attr_state = 3;
} else if(attr_state == 3) {
- /* Expecting start of attribute value. */
+
if(CH(off) == _T('"'))
attr_state = 43;
else if(CH(off) == _T('\''))
@@ -1159,13 +996,11 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF
return FALSE;
off++;
} else {
- /* Anything unexpected. */
+
return FALSE;
}
}
- /* We have to be on a single line. See definition of start condition
- * of HTML block, type 7. */
if(n_lines == 0)
return FALSE;
@@ -1201,15 +1036,14 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
MD_SIZE line_index = 0;
if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) {
- /* We have already scanned the range up to the max_end so we know
- * there is nothing to see. */
+
return FALSE;
}
while(TRUE) {
while(off + len <= lines[line_index].end && off + len <= max_end) {
if(md_ascii_eq(STR(off), str, len)) {
- /* Success. */
+
*p_end = off + len;
return TRUE;
}
@@ -1218,7 +1052,7 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
line_index++;
if(off >= max_end || line_index >= n_lines) {
- /* Failure. */
+
*p_scan_horizon = off;
return FALSE;
}
@@ -1239,10 +1073,8 @@ md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-'))
return FALSE;
- /* Skip only "<!" so that we accept also "<!-->" or "<!--->" */
off += 2;
- /* Scan for ordinary comment closer "-->". */
return md_scan_for_html_closer(ctx, _T("-->"), 3,
lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon);
}
@@ -1273,7 +1105,6 @@ md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF b
return FALSE;
off += 2;
- /* Declaration name. */
if(off >= lines[0].end || !ISALPHA(off))
return FALSE;
off++;
@@ -1313,11 +1144,6 @@ md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF
md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end));
}
-
-/****************************
- *** Recognizing Entity ***
- ****************************/
-
static int
md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end)
{
@@ -1404,11 +1230,6 @@ md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end)
return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end);
}
-
-/******************************
- *** Attribute Management ***
- ******************************/
-
typedef struct MD_ATTRIBUTE_BUILD_tag MD_ATTRIBUTE_BUILD;
struct MD_ATTRIBUTE_BUILD_tag {
CHAR* text;
@@ -1420,7 +1241,6 @@ struct MD_ATTRIBUTE_BUILD_tag {
OFF trivial_offsets[2];
};
-
#define MD_BUILD_ATTR_NO_ESCAPES 0x0001
static int
@@ -1440,7 +1260,7 @@ md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build,
MD_LOG("realloc() failed.");
return -1;
}
- /* Note +1 to reserve space for final offset (== raw_size). */
+
new_substr_offsets = (OFF*) realloc(build->substr_offsets,
(build->substr_alloc+1) * sizeof(OFF));
if(new_substr_offsets == NULL) {
@@ -1481,8 +1301,6 @@ md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size,
memset(build, 0, sizeof(MD_ATTRIBUTE_BUILD));
- /* If there is no backslash and no ampersand, build trivial attribute
- * without any malloc(). */
is_trivial = TRUE;
for(raw_off = 0; raw_off < raw_size; raw_off++) {
if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) {
@@ -1556,11 +1374,6 @@ abort:
return -1;
}
-
-/*********************************************
- *** Dictionary of Reference Definitions ***
- *********************************************/
-
#define MD_FNV1A_BASE 2166136261U
#define MD_FNV1A_PRIME 16777619U
@@ -1579,7 +1392,6 @@ md_fnv1a(unsigned base, const void* data, size_t n)
return hash;
}
-
struct MD_REF_DEF_tag {
CHAR* label;
CHAR* title;
@@ -1592,10 +1404,6 @@ struct MD_REF_DEF_tag {
unsigned char title_needs_free : 1;
};
-/* Label equivalence is quite complicated with regards to whitespace and case
- * folding. This complicates computing a hash of it as well as direct comparison
- * of two labels. */
-
static unsigned
md_link_label_hash(const CHAR* label, SZ size)
{
@@ -1635,18 +1443,17 @@ md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size,
SZ char_size;
if(off >= size) {
- /* Treat end of a link label as a whitespace. */
+
goto whitespace;
}
codepoint = md_decode_unicode(label, off, size, &char_size);
off += char_size;
if(ISUNICODEWHITESPACE_(codepoint)) {
- /* Treat all whitespace as equivalent */
+
goto whitespace;
}
- /* Get real folding info. */
md_get_unicode_fold_info(codepoint, fold_info);
return off;
@@ -1672,7 +1479,7 @@ md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size
while(a_off < a_size || a_fi_off < a_fi.n_codepoints ||
b_off < b_size || b_fi_off < b_fi.n_codepoints)
{
- /* If needed, load fold info for next char. */
+
if(a_fi_off >= a_fi.n_codepoints) {
a_fi_off = 0;
a_off = md_link_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi);
@@ -1697,7 +1504,7 @@ typedef struct MD_REF_DEF_LIST_tag MD_REF_DEF_LIST;
struct MD_REF_DEF_LIST_tag {
int n_ref_defs;
int alloc_ref_defs;
- MD_REF_DEF* ref_defs[]; /* Valid items always point into ctx->ref_defs[] */
+ MD_REF_DEF* ref_defs[];
};
static int
@@ -1721,7 +1528,6 @@ md_ref_def_cmp_for_sort(const void* a, const void* b)
cmp = md_ref_def_cmp(a, b);
- /* Ensure stability of the sorting. */
if(cmp == 0) {
const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a;
const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b;
@@ -1753,12 +1559,6 @@ md_build_ref_def_hashtable(MD_CTX* ctx)
}
memset(ctx->ref_def_hashtable, 0, ctx->ref_def_hashtable_size * sizeof(void*));
- /* Each member of ctx->ref_def_hashtable[] can be:
- * -- NULL,
- * -- pointer to the MD_REF_DEF in ctx->ref_defs[], or
- * -- pointer to a MD_REF_DEF_LIST, which holds multiple pointers to
- * such MD_REF_DEFs.
- */
for(i = 0; i < ctx->n_ref_defs; i++) {
MD_REF_DEF* def = &ctx->ref_defs[i];
void* bucket;
@@ -1768,23 +1568,20 @@ md_build_ref_def_hashtable(MD_CTX* ctx)
bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size];
if(bucket == NULL) {
- /* The bucket is empty. Make it just point to the def. */
+
ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def;
continue;
}
if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) {
- /* The bucket already contains one ref. def. Lets see whether it
- * is the same label (ref. def. duplicate) or different one
- * (hash conflict). */
+
MD_REF_DEF* old_def = (MD_REF_DEF*) bucket;
if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) {
- /* Duplicate label: Ignore this ref. def. */
+
continue;
}
- /* Make the bucket complex, i.e. able to hold more ref. defs. */
list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*));
if(list == NULL) {
MD_LOG("malloc() failed.");
@@ -1798,12 +1595,6 @@ md_build_ref_def_hashtable(MD_CTX* ctx)
continue;
}
- /* Append the def to the complex bucket list.
- *
- * Note in this case we ignore potential duplicates to avoid expensive
- * iterating over the complex bucket. Below, we revisit all the complex
- * buckets and handle it more cheaply after the complex bucket contents
- * is sorted. */
list = (MD_REF_DEF_LIST*) bucket;
if(list->n_ref_defs >= list->alloc_ref_defs) {
int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2;
@@ -1822,7 +1613,6 @@ md_build_ref_def_hashtable(MD_CTX* ctx)
list->n_ref_defs++;
}
- /* Sort the complex buckets so we can use bsearch() with them. */
for(i = 0; i < ctx->ref_def_hashtable_size; i++) {
void* bucket = ctx->ref_def_hashtable[i];
MD_REF_DEF_LIST* list;
@@ -1835,10 +1625,6 @@ md_build_ref_def_hashtable(MD_CTX* ctx)
list = (MD_REF_DEF_LIST*) bucket;
qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort);
- /* Disable all duplicates in the complex bucket by forcing all such
- * records to point to the 1st such ref. def. I.e. no matter which
- * record is found during the lookup, it will always point to the right
- * ref. def. in ctx->ref_defs[]. */
for(j = 1; j < list->n_ref_defs; j++) {
if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0)
list->ref_defs[j] = list->ref_defs[j-1];
@@ -1910,15 +1696,6 @@ md_lookup_ref_def(MD_CTX* ctx, const CHAR* label, SZ label_size)
}
}
-
-/***************************
- *** Recognizing Links ***
- ***************************/
-
-/* Note this code is partially shared between processing inlines and blocks
- * as reference definitions and links share some helper parser functions.
- */
-
typedef struct MD_LINK_ATTR_tag MD_LINK_ATTR;
struct MD_LINK_ATTR_tag {
OFF dest_beg;
@@ -1929,7 +1706,6 @@ struct MD_LINK_ATTR_tag {
int title_needs_free;
};
-
static int
md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index,
@@ -1962,14 +1738,14 @@ md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
return FALSE;
} else if(CH(off) == _T(']')) {
if(contents_beg < contents_end) {
- /* Success. */
+
*p_contents_beg = contents_beg;
*p_contents_end = contents_end;
*p_end = off+1;
*p_end_line_index = line_index;
return TRUE;
} else {
- /* Link label must have some non-whitespace contents. */
+
return FALSE;
}
} else {
@@ -2024,7 +1800,7 @@ md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
return FALSE;
if(CH(off) == _T('>')) {
- /* Success. */
+
*p_contents_beg = beg+1;
*p_contents_end = off;
*p_end = off+1;
@@ -2053,9 +1829,6 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
if(ISWHITESPACE(off) || ISCNTRL(off))
break;
- /* Link destination may include balanced pairs of unescaped '(' ')'.
- * Note we limit the maximal nesting level by 32 to protect us from
- * https://github.com/jgm/cmark/issues/214 */
if(CH(off) == _T('(')) {
parenthesis_level++;
if(parenthesis_level > 32)
@@ -2072,7 +1845,6 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
if(parenthesis_level != 0 || off == beg)
return FALSE;
- /* Success. */
*p_contents_beg = beg;
*p_contents_end = off;
*p_end = off;
@@ -2098,7 +1870,6 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
CHAR closer_char;
MD_SIZE line_index = 0;
- /* White space with up to one line break. */
while(off < lines[line_index].end && ISWHITESPACE(off))
off++;
if(off >= lines[line_index].end) {
@@ -2112,7 +1883,6 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
*p_beg_line_index = line_index;
- /* First char determines how to detect end of it. */
switch(CH(off)) {
case _T('"'): closer_char = _T('"'); break;
case _T('\''): closer_char = _T('\''); break;
@@ -2130,13 +1900,13 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
off++;
} else if(CH(off) == closer_char) {
- /* Success. */
+
*p_contents_end = off;
*p_end = off+1;
*p_end_line_index = line_index;
return TRUE;
} else if(closer_char == _T(')') && CH(off) == _T('(')) {
- /* ()-style title cannot contain (unescaped '(')) */
+
return FALSE;
}
@@ -2149,14 +1919,6 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
return FALSE;
}
-/* Returns 0 if it is not a reference definition.
- *
- * Returns N > 0 if it is a reference definition. N then corresponds to the
- * number of lines forming it). In this case the definition is stored for
- * resolving any links referring to it.
- *
- * Returns -1 in case of an error (out of memory).
- */
static int
md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
{
@@ -2176,19 +1938,16 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin
MD_REF_DEF* def = NULL;
int ret = 0;
- /* Link label. */
if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg,
&off, &label_contents_line_index, &line_index,
&label_contents_beg, &label_contents_end))
return FALSE;
label_is_multiline = (label_contents_line_index != line_index);
- /* Colon. */
if(off >= lines[line_index].end || CH(off) != _T(':'))
return FALSE;
off++;
- /* Optional white space with up to one line break. */
while(off < lines[line_index].end && ISWHITESPACE(off))
off++;
if(off >= lines[line_index].end) {
@@ -2198,13 +1957,10 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin
off = lines[line_index].beg;
}
- /* Link destination. */
if(!md_is_link_destination(ctx, off, lines[line_index].end,
&off, &dest_contents_beg, &dest_contents_end))
return FALSE;
- /* (Optional) title. Note we interpret it as an title only if nothing
- * more follows on its last line. */
if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off,
&off, &title_contents_line_index, &tmp_line_index,
&title_contents_beg, &title_contents_end)
@@ -2214,18 +1970,16 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin
title_contents_line_index += line_index;
line_index += tmp_line_index;
} else {
- /* Not a title. */
+
title_is_multiline = FALSE;
title_contents_beg = off;
title_contents_end = off;
title_contents_line_index = 0;
}
- /* Nothing more can follow on the last line. */
if(off < lines[line_index].end)
return FALSE;
- /* So, it _is_ a reference definition. Remember it. */
if(ctx->n_ref_defs >= ctx->alloc_ref_defs) {
MD_REF_DEF* new_defs;
@@ -2266,12 +2020,11 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lin
def->dest_beg = dest_contents_beg;
def->dest_end = dest_contents_end;
- /* Success. */
ctx->n_ref_defs++;
return line_index + 1;
abort:
- /* Failure. */
+
if(def != NULL && def->label_needs_free)
free(def->label);
if(def != NULL && def->title_needs_free)
@@ -1,28 +1,3 @@
-/*
- * MD4C: Markdown parser for C
- * (http://github.com/mity/md4c)
- *
- * Copyright (c) 2016-2024 Martin Mitáš
- *
- * 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.
- */
-
#ifndef MD4C_H
#define MD4C_H
@@ -31,9 +6,7 @@
#endif
#if defined MD4C_USE_UTF16
- /* Magic to support UTF-16. Note that in order to use it, you have to define
- * the macro MD4C_USE_UTF16 both when building MD4C as well as when
- * including this header in your code. */
+
#ifdef _WIN32
#include <windows.h>
typedef WCHAR MD_CHAR;
@@ -47,53 +20,28 @@
typedef unsigned MD_SIZE;
typedef unsigned MD_OFFSET;
-
-/* Block represents a part of document hierarchy structure like a paragraph
- * or list item.
- */
typedef enum MD_BLOCKTYPE {
- /* <body>...</body> */
+
MD_BLOCK_DOC = 0,
- /* <blockquote>...</blockquote> */
MD_BLOCK_QUOTE,
- /* <ul>...</ul>
- * Detail: Structure MD_BLOCK_UL_DETAIL. */
MD_BLOCK_UL,
- /* <ol>...</ol>
- * Detail: Structure MD_BLOCK_OL_DETAIL. */
MD_BLOCK_OL,
- /* <li>...</li>
- * Detail: Structure MD_BLOCK_LI_DETAIL. */
MD_BLOCK_LI,
- /* <hr> */
MD_BLOCK_HR,
- /* <h1>...</h1> (for levels up to 6)
- * Detail: Structure MD_BLOCK_H_DETAIL. */
MD_BLOCK_H,
- /* <pre><code>...</code></pre>
- * Note the text lines within code blocks are terminated with '\n'
- * instead of explicit MD_TEXT_BR. */
MD_BLOCK_CODE,
- /* Raw HTML block. This itself does not correspond to any particular HTML
- * tag. The contents of it _is_ raw HTML source intended to be put
- * in verbatim form to the HTML output. */
MD_BLOCK_HTML,
- /* <p>...</p> */
MD_BLOCK_P,
- /* <table>...</table> and its contents.
- * Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE),
- * structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD)
- * Note all of these are used only if extension MD_FLAG_TABLES is enabled. */
MD_BLOCK_TABLE,
MD_BLOCK_THEAD,
MD_BLOCK_TBODY,
@@ -102,132 +50,53 @@ typedef enum MD_BLOCKTYPE {
MD_BLOCK_TD
} MD_BLOCKTYPE;
-/* Span represents an in-line piece of a document which should be rendered with
- * the same font, color and other attributes. A sequence of spans forms a block
- * like paragraph or list item. */
typedef enum MD_SPANTYPE {
- /* <em>...</em> */
+
MD_SPAN_EM,
- /* <strong>...</strong> */
MD_SPAN_STRONG,
- /* <a href="xxx">...</a>
- * Detail: Structure MD_SPAN_A_DETAIL. */
MD_SPAN_A,
- /* <img src="xxx">...</a>
- * Detail: Structure MD_SPAN_IMG_DETAIL.
- * Note: Image text can contain nested spans and even nested images.
- * If rendered into ALT attribute of HTML <IMG> tag, it's responsibility
- * of the parser to deal with it.
- */
MD_SPAN_IMG,
- /* <code>...</code> */
MD_SPAN_CODE,
- /* <del>...</del>
- * Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled.
- */
MD_SPAN_DEL,
- /* For recognizing inline ($) and display ($$) equations
- * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled.
- */
MD_SPAN_LATEXMATH,
MD_SPAN_LATEXMATH_DISPLAY,
- /* Wiki links
- * Note: Recognized only when MD_FLAG_WIKILINKS is enabled.
- */
MD_SPAN_WIKILINK,
- /* <u>...</u>
- * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */
MD_SPAN_U
} MD_SPANTYPE;
-/* Text is the actual textual contents of span. */
typedef enum MD_TEXTTYPE {
- /* Normal text. */
+
MD_TEXT_NORMAL = 0,
- /* NULL character. CommonMark requires replacing NULL character with
- * the replacement char U+FFFD, so this allows caller to do that easily. */
MD_TEXT_NULLCHAR,
- /* Line breaks.
- * Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE
- * or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */
- MD_TEXT_BR, /* <br> (hard break) */
- MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */
-
- /* Entity.
- * (a) Named entity, e.g.
- * (Note MD4C does not have a list of known entities.
- * Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is
- * treated as a named entity.)
- * (b) Numerical entity, e.g. Ӓ
- * (c) Hexadecimal entity, e.g. ካ
- *
- * As MD4C is mostly encoding agnostic, application gets the verbatim
- * entity text into the MD_PARSER::text_callback(). */
+ MD_TEXT_BR,
+ MD_TEXT_SOFTBR,
+
MD_TEXT_ENTITY,
- /* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`).
- * If it is inside MD_BLOCK_CODE, it includes spaces for indentation and
- * '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this
- * kind of text. */
MD_TEXT_CODE,
- /* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not
- * an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used.
- * The text contains verbatim '\n' for the new lines. */
MD_TEXT_HTML,
- /* Text is inside an equation. This is processed the same way as inlined code
- * spans (`code`). */
MD_TEXT_LATEXMATH
} MD_TEXTTYPE;
-
-/* Alignment enumeration. */
typedef enum MD_ALIGN {
- MD_ALIGN_DEFAULT = 0, /* When unspecified. */
+ MD_ALIGN_DEFAULT = 0,
MD_ALIGN_LEFT,
MD_ALIGN_CENTER,
MD_ALIGN_RIGHT
} MD_ALIGN;
-
-/* String attribute.
- *
- * This wraps strings which are outside of a normal text flow and which are
- * propagated within various detailed structures, but which still may contain
- * string portions of different types like e.g. entities.
- *
- * So, for example, lets consider this image:
- *
- * 
- *
- * The image alt text is propagated as a normal text via the MD_PARSER::text()
- * callback. However, the image title ('foo " bar') is propagated as
- * MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title.
- *
- * Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following:
- * -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0)
- * -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4)
- * -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10)
- * -- [3]: (n/a) (n/a ; substr_offsets[3] == 14)
- *
- * Note that these invariants are always guaranteed:
- * -- substr_offsets[0] == 0
- * -- substr_offsets[LAST+1] == size
- * -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR
- * substrings can appear. This could change only of the specification
- * changes.
- */
typedef struct MD_ATTRIBUTE {
const MD_CHAR* text;
MD_SIZE size;
@@ -235,173 +104,105 @@ typedef struct MD_ATTRIBUTE {
const MD_OFFSET* substr_offsets;
} MD_ATTRIBUTE;
-
-/* Detailed info for MD_BLOCK_UL. */
typedef struct MD_BLOCK_UL_DETAIL {
- int is_tight; /* Non-zero if tight list, zero if loose. */
- MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */
+ int is_tight;
+ MD_CHAR mark;
} MD_BLOCK_UL_DETAIL;
-/* Detailed info for MD_BLOCK_OL. */
typedef struct MD_BLOCK_OL_DETAIL {
- unsigned start; /* Start index of the ordered list. */
- int is_tight; /* Non-zero if tight list, zero if loose. */
- MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */
+ unsigned start;
+ int is_tight;
+ MD_CHAR mark_delimiter;
} MD_BLOCK_OL_DETAIL;
-/* Detailed info for MD_BLOCK_LI. */
typedef struct MD_BLOCK_LI_DETAIL {
- int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */
- MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */
- MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */
+ int is_task;
+ MD_CHAR task_mark;
+ MD_OFFSET task_mark_offset;
} MD_BLOCK_LI_DETAIL;
-/* Detailed info for MD_BLOCK_H. */
typedef struct MD_BLOCK_H_DETAIL {
- unsigned level; /* Header level (1 - 6) */
+ unsigned level;
} MD_BLOCK_H_DETAIL;
-/* Detailed info for MD_BLOCK_CODE. */
typedef struct MD_BLOCK_CODE_DETAIL {
MD_ATTRIBUTE info;
MD_ATTRIBUTE lang;
- MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */
+ MD_CHAR fence_char;
} MD_BLOCK_CODE_DETAIL;
-/* Detailed info for MD_BLOCK_TABLE. */
typedef struct MD_BLOCK_TABLE_DETAIL {
- unsigned col_count; /* Count of columns in the table. */
- unsigned head_row_count; /* Count of rows in the table header (currently always 1) */
- unsigned body_row_count; /* Count of rows in the table body */
+ unsigned col_count;
+ unsigned head_row_count;
+ unsigned body_row_count;
} MD_BLOCK_TABLE_DETAIL;
-/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */
typedef struct MD_BLOCK_TD_DETAIL {
MD_ALIGN align;
} MD_BLOCK_TD_DETAIL;
-/* Detailed info for MD_SPAN_A. */
typedef struct MD_SPAN_A_DETAIL {
MD_ATTRIBUTE href;
MD_ATTRIBUTE title;
- int is_autolink; /* nonzero if this is an autolink */
+ int is_autolink;
} MD_SPAN_A_DETAIL;
-/* Detailed info for MD_SPAN_IMG. */
typedef struct MD_SPAN_IMG_DETAIL {
MD_ATTRIBUTE src;
MD_ATTRIBUTE title;
} MD_SPAN_IMG_DETAIL;
-/* Detailed info for MD_SPAN_WIKILINK. */
typedef struct MD_SPAN_WIKILINK {
MD_ATTRIBUTE target;
} MD_SPAN_WIKILINK_DETAIL;
-/* Flags specifying extensions/deviations from CommonMark specification.
- *
- * By default (when MD_PARSER::flags == 0), we follow CommonMark specification.
- * The following flags may allow some extensions or deviations from it.
- */
-#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */
-#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */
-#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */
-#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */
-#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */
-#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */
-#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */
-#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */
-#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */
-#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */
-#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */
-#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */
-#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */
-#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */
-#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */
+#define MD_FLAG_COLLAPSEWHITESPACE 0x0001
+#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002
+#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004
+#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008
+#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010
+#define MD_FLAG_NOHTMLBLOCKS 0x0020
+#define MD_FLAG_NOHTMLSPANS 0x0040
+#define MD_FLAG_TABLES 0x0100
+#define MD_FLAG_STRIKETHROUGH 0x0200
+#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400
+#define MD_FLAG_TASKLISTS 0x0800
+#define MD_FLAG_LATEXMATHSPANS 0x1000
+#define MD_FLAG_WIKILINKS 0x2000
+#define MD_FLAG_UNDERLINE 0x4000
+#define MD_FLAG_HARD_SOFT_BREAKS 0x8000
#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS)
#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS)
-/* Convenient sets of flags corresponding to well-known Markdown dialects.
- *
- * Note we may only support subset of features of the referred dialect.
- * The constant just enables those extensions which bring us as close as
- * possible given what features we implement.
- *
- * ABI compatibility note: Meaning of these can change in time as new
- * extensions, bringing the dialect closer to the original, are implemented.
- */
#define MD_DIALECT_COMMONMARK 0
#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS)
-/* Parser structure.
- */
typedef struct MD_PARSER {
- /* Reserved. Set to zero.
- */
+
unsigned abi_version;
- /* Dialect options. Bitmask of MD_FLAG_xxxx values.
- */
unsigned flags;
- /* Caller-provided rendering callbacks.
- *
- * For some block/span types, more detailed information is provided in a
- * type-specific structure pointed by the argument 'detail'.
- *
- * The last argument of all callbacks, 'userdata', is just propagated from
- * md_parse() and is available for any use by the application.
- *
- * Note any strings provided to the callbacks as their arguments or as
- * members of any detail structure are generally not zero-terminated.
- * Application has to take the respective size information into account.
- *
- * Any rendering callback may abort further parsing of the document by
- * returning non-zero.
- */
- int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
- int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
-
- int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
- int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
-
- int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/);
-
- /* Debug callback. Optional (may be NULL).
- *
- * If provided and something goes wrong, this function gets called.
- * This is intended for debugging and problem diagnosis for developers;
- * it is not intended to provide any errors suitable for displaying to an
- * end user.
- */
- void (*debug_log)(const char* /*msg*/, void* /*userdata*/);
-
- /* Reserved. Set to NULL.
- */
+ int (*enter_block)(MD_BLOCKTYPE , void* , void* );
+ int (*leave_block)(MD_BLOCKTYPE , void* , void* );
+
+ int (*enter_span)(MD_SPANTYPE , void* , void* );
+ int (*leave_span)(MD_SPANTYPE , void* , void* );
+
+ int (*text)(MD_TEXTTYPE , const MD_CHAR* , MD_SIZE , void* );
+
+ void (*debug_log)(const char* , void* );
+
void (*syntax)(void);
} MD_PARSER;
-
-/* For backward compatibility. Do not use in new code.
- */
typedef MD_PARSER MD_RENDERER;
-
-/* Parse the Markdown document stored in the string 'text' of size 'size'.
- * The parser provides callbacks to be called during the parsing so the
- * caller can render the document on the screen or convert the Markdown
- * to another format.
- *
- * Zero is returned on success. If a runtime error occurs (e.g. a memory
- * fails), -1 is returned. If the processing is aborted due any callback
- * returning non-zero, the return value of the callback is returned.
- */
int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata);
-
#ifdef __cplusplus
- } /* extern "C" { */
+ }
#endif
-#endif /* MD4C_H */
+#endif
@@ -1,381 +1,15 @@
-/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
- no warranty implied; use at your own risk
-
- Do this:
- #define STB_IMAGE_IMPLEMENTATION
- before you include this file in *one* C or C++ file to create the implementation.
-
- // i.e. it should look like this:
- #include ...
- #include ...
- #include ...
- #define STB_IMAGE_IMPLEMENTATION
- #include "stb_image.h"
-
- You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
- And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
-
-
- QUICK NOTES:
- Primarily of interest to game developers and other people who can
- avoid problematic images and only need the trivial interface
-
- JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
- PNG 1/2/4/8/16-bit-per-channel
-
- TGA (not sure what subset, if a subset)
- BMP non-1bpp, non-RLE
- PSD (composited view only, no extra channels, 8/16 bit-per-channel)
-
- GIF (*comp always reports as 4-channel)
- HDR (radiance rgbE format)
- PIC (Softimage PIC)
- PNM (PPM and PGM binary only)
-
- Animated GIF still needs a proper API, but here's one way to do it:
- http://gist.github.com/urraka/685d9a6340b26b830d49
-
- - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
- - decode from arbitrary I/O callbacks
- - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
-
- Full documentation under "DOCUMENTATION" below.
-
-
-LICENSE
-
- See end of file for license information.
-
-RECENT REVISION HISTORY:
-
- 2.30 (2024-05-31) avoid erroneous gcc warning
- 2.29 (2023-05-xx) optimizations
- 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
- 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
- 2.26 (2020-07-13) many minor fixes
- 2.25 (2020-02-02) fix warnings
- 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
- 2.23 (2019-08-11) fix clang static analysis warning
- 2.22 (2019-03-04) gif fixes, fix warnings
- 2.21 (2019-02-25) fix typo in comment
- 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
- 2.19 (2018-02-11) fix warning
- 2.18 (2018-01-30) fix warnings
- 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
- 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
- 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
- 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
- 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
- 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
- 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
- RGB-format JPEG; remove white matting in PSD;
- allocate large structures on the stack;
- correct channel count for PNG & BMP
- 2.10 (2016-01-22) avoid warning introduced in 2.09
- 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
-
- See end of file for full revision history.
-
-
- ============================ Contributors =========================
-
- Image formats Extensions, features
- Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
- Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
- Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
- Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
- Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
- Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
- Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
- github:urraka (animated gif) Junggon Kim (PNM comments)
- Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
- socks-the-fox (16-bit PNG)
- Jeremy Sawicki (handle all ImageNet JPGs)
- Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
- Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
- Arseny Kapoulkine Simon Breuss (16-bit PNM)
- John-Mark Allen
- Carmelo J Fdez-Aguera
-
- Bug & warning fixes
- Marc LeBlanc David Woo Guillaume George Martins Mozeiko
- Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
- Phil Jordan Dave Moore Roy Eltham
- Hayaki Saito Nathan Reed Won Chun
- Luke Graham Johan Duparc Nick Verigakis the Horde3D community
- Thomas Ruf Ronny Chevalier github:rlyeh
- Janez Zemva John Bartholomew Michal Cichon github:romigrou
- Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
- Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
- Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
- Cass Everitt Ryamond Barbiero github:grim210
- Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
- Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
- Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
- Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
- Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
- Brad Weinberger Matvey Cherevko github:mosra
- Luca Sas Alexander Veselov Zack Middleton [reserved]
- Ryan C. Gordon [reserved] [reserved]
- DO NOT ADD YOUR NAME HERE
-
- Jacko Dirks
-
- To add your name to the credits, pick a random blank space in the middle and fill it.
- 80% of merge conflicts on stb PRs are due to people adding their name at the end
- of the credits.
-*/
-
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STBI_INCLUDE_STB_IMAGE_H
-// DOCUMENTATION
-//
-// Limitations:
-// - no 12-bit-per-channel JPEG
-// - no JPEGs with arithmetic coding
-// - GIF always returns *comp=4
-//
-// Basic usage (see HDR discussion below for HDR usage):
-// int x,y,n;
-// unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
-// // ... process data if not NULL ...
-// // ... x = width, y = height, n = # 8-bit components per pixel ...
-// // ... replace '0' with '1'..'4' to force that many components per pixel
-// // ... but 'n' will always be the number that it would have been if you said 0
-// stbi_image_free(data);
-//
-// Standard parameters:
-// int *x -- outputs image width in pixels
-// int *y -- outputs image height in pixels
-// int *channels_in_file -- outputs # of image components in image file
-// int desired_channels -- if non-zero, # of image components requested in result
-//
-// The return value from an image loader is an 'unsigned char *' which points
-// to the pixel data, or NULL on an allocation failure or if the image is
-// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
-// with each pixel consisting of N interleaved 8-bit components; the first
-// pixel pointed to is top-left-most in the image. There is no padding between
-// image scanlines or between pixels, regardless of format. The number of
-// components N is 'desired_channels' if desired_channels is non-zero, or
-// *channels_in_file otherwise. If desired_channels is non-zero,
-// *channels_in_file has the number of components that _would_ have been
-// output otherwise. E.g. if you set desired_channels to 4, you will always
-// get RGBA output, but you can check *channels_in_file to see if it's trivially
-// opaque because e.g. there were only 3 channels in the source image.
-//
-// An output image with N components has the following components interleaved
-// in this order in each pixel:
-//
-// N=#comp components
-// 1 grey
-// 2 grey, alpha
-// 3 red, green, blue
-// 4 red, green, blue, alpha
-//
-// If image loading fails for any reason, the return value will be NULL,
-// and *x, *y, *channels_in_file will be unchanged. The function
-// stbi_failure_reason() can be queried for an extremely brief, end-user
-// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
-// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
-// more user-friendly ones.
-//
-// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
-//
-// To query the width, height and component count of an image without having to
-// decode the full file, you can use the stbi_info family of functions:
-//
-// int x,y,n,ok;
-// ok = stbi_info(filename, &x, &y, &n);
-// // returns ok=1 and sets x, y, n if image is a supported format,
-// // 0 otherwise.
-//
-// Note that stb_image pervasively uses ints in its public API for sizes,
-// including sizes of memory buffers. This is now part of the API and thus
-// hard to change without causing breakage. As a result, the various image
-// loaders all have certain limits on image size; these differ somewhat
-// by format but generally boil down to either just under 2GB or just under
-// 1GB. When the decoded image would be larger than this, stb_image decoding
-// will fail.
-//
-// Additionally, stb_image will reject image files that have any of their
-// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
-// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
-// the only way to have an image with such dimensions load correctly
-// is for it to have a rather extreme aspect ratio. Either way, the
-// assumption here is that such larger images are likely to be malformed
-// or malicious. If you do need to load an image with individual dimensions
-// larger than that, and it still fits in the overall size limit, you can
-// #define STBI_MAX_DIMENSIONS on your own to be something larger.
-//
-// ===========================================================================
-//
-// UNICODE:
-//
-// If compiling for Windows and you wish to use Unicode filenames, compile
-// with
-// #define STBI_WINDOWS_UTF8
-// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
-// Windows wchar_t filenames to utf8.
-//
-// ===========================================================================
-//
-// Philosophy
-//
-// stb libraries are designed with the following priorities:
-//
-// 1. easy to use
-// 2. easy to maintain
-// 3. good performance
-//
-// Sometimes I let "good performance" creep up in priority over "easy to maintain",
-// and for best performance I may provide less-easy-to-use APIs that give higher
-// performance, in addition to the easy-to-use ones. Nevertheless, it's important
-// to keep in mind that from the standpoint of you, a client of this library,
-// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
-//
-// Some secondary priorities arise directly from the first two, some of which
-// provide more explicit reasons why performance can't be emphasized.
-//
-// - Portable ("ease of use")
-// - Small source code footprint ("easy to maintain")
-// - No dependencies ("ease of use")
-//
-// ===========================================================================
-//
-// I/O callbacks
-//
-// I/O callbacks allow you to read from arbitrary sources, like packaged
-// files or some other source. Data read from callbacks are processed
-// through a small internal buffer (currently 128 bytes) to try to reduce
-// overhead.
-//
-// The three functions you must define are "read" (reads some bytes of data),
-// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
-//
-// ===========================================================================
-//
-// SIMD support
-//
-// The JPEG decoder will try to automatically use SIMD kernels on x86 when
-// supported by the compiler. For ARM Neon support, you must explicitly
-// request it.
-//
-// (The old do-it-yourself SIMD API is no longer supported in the current
-// code.)
-//
-// On x86, SSE2 will automatically be used when available based on a run-time
-// test; if not, the generic C versions are used as a fall-back. On ARM targets,
-// the typical path is to have separate builds for NEON and non-NEON devices
-// (at least this is true for iOS and Android). Therefore, the NEON support is
-// toggled by a build flag: define STBI_NEON to get NEON loops.
-//
-// If for some reason you do not want to use any of SIMD code, or if
-// you have issues compiling it, you can disable it entirely by
-// defining STBI_NO_SIMD.
-//
-// ===========================================================================
-//
-// HDR image support (disable by defining STBI_NO_HDR)
-//
-// stb_image supports loading HDR images in general, and currently the Radiance
-// .HDR file format specifically. You can still load any file through the existing
-// interface; if you attempt to load an HDR file, it will be automatically remapped
-// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
-// both of these constants can be reconfigured through this interface:
-//
-// stbi_hdr_to_ldr_gamma(2.2f);
-// stbi_hdr_to_ldr_scale(1.0f);
-//
-// (note, do not use _inverse_ constants; stbi_image will invert them
-// appropriately).
-//
-// Additionally, there is a new, parallel interface for loading files as
-// (linear) floats to preserve the full dynamic range:
-//
-// float *data = stbi_loadf(filename, &x, &y, &n, 0);
-//
-// If you load LDR images through this interface, those images will
-// be promoted to floating point values, run through the inverse of
-// constants corresponding to the above:
-//
-// stbi_ldr_to_hdr_scale(1.0f);
-// stbi_ldr_to_hdr_gamma(2.2f);
-//
-// Finally, given a filename (or an open file or memory block--see header
-// file for details) containing image data, you can query for the "most
-// appropriate" interface to use (that is, whether the image is HDR or
-// not), using:
-//
-// stbi_is_hdr(char *filename);
-//
-// ===========================================================================
-//
-// iPhone PNG support:
-//
-// We optionally support converting iPhone-formatted PNGs (which store
-// premultiplied BGRA) back to RGB, even though they're internally encoded
-// differently. To enable this conversion, call
-// stbi_convert_iphone_png_to_rgb(1).
-//
-// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
-// pixel to remove any premultiplied alpha *only* if the image file explicitly
-// says there's premultiplied data (currently only happens in iPhone images,
-// and only if iPhone convert-to-rgb processing is on).
-//
-// ===========================================================================
-//
-// ADDITIONAL CONFIGURATION
-//
-// - You can suppress implementation of any of the decoders to reduce
-// your code footprint by #defining one or more of the following
-// symbols before creating the implementation.
-//
-// STBI_NO_JPEG
-// STBI_NO_PNG
-// STBI_NO_BMP
-// STBI_NO_PSD
-// STBI_NO_TGA
-// STBI_NO_GIF
-// STBI_NO_HDR
-// STBI_NO_PIC
-// STBI_NO_PNM (.ppm and .pgm)
-//
-// - You can request *only* certain decoders and suppress all other ones
-// (this will be more forward-compatible, as addition of new decoders
-// doesn't require you to disable them explicitly):
-//
-// STBI_ONLY_JPEG
-// STBI_ONLY_PNG
-// STBI_ONLY_BMP
-// STBI_ONLY_PSD
-// STBI_ONLY_TGA
-// STBI_ONLY_GIF
-// STBI_ONLY_HDR
-// STBI_ONLY_PIC
-// STBI_ONLY_PNM (.ppm and .pgm)
-//
-// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
-// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
-//
-// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
-// than that size (in either width or height) without further processing.
-// This is to let programs in the wild set an upper bound to prevent
-// denial-of-service attacks on untrusted data, as one could generate a
-// valid image of gigantic dimensions and force stb_image to allocate a
-// huge block of memory and spend disproportionate time decoding it. By
-// default this is set to (1 << 24), which is 16777216, but that's still
-// very big.
-
#ifndef STBI_NO_STDIO
#include <stdio.h>
-#endif // STBI_NO_STDIO
+#endif
#define STBI_VERSION 1
enum
{
- STBI_default = 0, // only used for desired_channels
+ STBI_default = 0,
STBI_grey = 1,
STBI_grey_alpha = 2,
@@ -399,34 +33,20 @@ extern "C" {
#endif
#endif
-//////////////////////////////////////////////////////////////////////////////
-//
-// PRIMARY API - works on images of any type
-//
-
-//
-// load image by filename, open file, or memory buffer
-//
-
typedef struct
{
- int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read
- void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
- int (*eof) (void *user); // returns nonzero if we are at end of file/data
+ int (*read) (void *user,char *data,int size);
+ void (*skip) (void *user,int n);
+ int (*eof) (void *user);
} stbi_io_callbacks;
-////////////////////////////////////
-//
-// 8-bits-per-channel interface
-//
-
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
-// for stbi_load_from_file, file pointer is left pointing immediately after image
+
#endif
#ifndef STBI_NO_GIF
@@ -437,11 +57,6 @@ STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int *
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
#endif
-////////////////////////////////////
-//
-// 16-bits-per-channel interface
-//
-
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
@@ -450,10 +65,6 @@ STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, in
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
-////////////////////////////////////
-//
-// float-per-channel interface
-//
#ifndef STBI_NO_LINEAR
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
@@ -467,30 +78,24 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i
#ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale);
-#endif // STBI_NO_HDR
+#endif
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale);
-#endif // STBI_NO_LINEAR
+#endif
-// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
#ifndef STBI_NO_STDIO
STBIDEF int stbi_is_hdr (char const *filename);
STBIDEF int stbi_is_hdr_from_file(FILE *f);
-#endif // STBI_NO_STDIO
-
+#endif
-// get a VERY brief reason for failure
-// on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void);
-// free the loaded image -- this is just free()
STBIDEF void stbi_image_free (void *retval_from_stbi_load);
-// get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
@@ -503,29 +108,16 @@ STBIDEF int stbi_is_16_bit (char const *filename);
STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif
-
-
-// for image formats that explicitly notate that they have premultiplied alpha,
-// we just return the colors as stored in the file. set this flag to force
-// unpremultiplication. results are undefined if the unpremultiply overflow.
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
-// indicate whether we should process iphone images back to canonical format,
-// or just pass them through "as-is"
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
-// flip the image vertically, so the first pixel in the output array is the bottom left
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
-// as above, but only applies to images loaded on the thread that calls the function
-// this function is only available if your compiler supports thread-local variables;
-// calling it will fail to link if your compiler doesn't
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
-// ZLIB client - used by PNG, available for other purposes
-
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
@@ -534,15 +126,11 @@ STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuff
STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
-
#ifdef __cplusplus
}
#endif
-//
-//
-//// end header file /////////////////////////////////////////////////////
-#endif // STBI_INCLUDE_STB_IMAGE_H
+#endif
#ifdef STB_IMAGE_IMPLEMENTATION
@@ -583,15 +171,14 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define STBI_NO_ZLIB
#endif
-
#include <stdarg.h>
-#include <stddef.h> // ptrdiff_t on osx
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
-#include <math.h> // ldexp, pow
+#include <math.h>
#endif
#ifndef STBI_NO_STDIO
@@ -609,7 +196,6 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define STBI_EXTERN extern
#endif
-
#ifndef _MSC_VER
#ifdef __cplusplus
#define stbi_inline inline
@@ -651,7 +237,6 @@ typedef uint32_t stbi__uint32;
typedef int32_t stbi__int32;
#endif
-// should produce compiler error if size is wrong
typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#ifdef _MSC_VER
@@ -671,9 +256,9 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
-// ok
+
#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
-// ok
+
#else
#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
#endif
@@ -688,7 +273,6 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
#endif
-// x86/x64 detection
#if defined(__x86_64__) || defined(_M_X64)
#define STBI__X64_TARGET
#elif defined(__i386) || defined(_M_IX86)
@@ -696,28 +280,12 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#endif
#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
-// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
-// which in turn means it gets to use SSE2 everywhere. This is unfortunate,
-// but previous attempts to provide the SSE2 functions with runtime
-// detection caused numerous issues. The way architecture extensions are
-// exposed in GCC/Clang is, sadly, not really suited for one-file libs.
-// New behavior: if compiled with -msse2, we use SSE2 without any
-// detection; if not, we don't use it at all.
+
#define STBI_NO_SIMD
#endif
#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
-// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
-//
-// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
-// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
-// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
-// simultaneously enabling "-mstackrealign".
-//
-// See https://github.com/nothings/stb/issues/81 for more information.
-//
-// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
-// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+
#define STBI_NO_SIMD
#endif
@@ -727,8 +295,8 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#ifdef _MSC_VER
-#if _MSC_VER >= 1400 // not VC6
-#include <intrin.h> // __cpuid
+#if _MSC_VER >= 1400
+#include <intrin.h>
static int stbi__cpuid3(void)
{
int info[4];
@@ -758,15 +326,13 @@ static int stbi__sse2_available(void)
}
#endif
-#else // assume GCC-style if not VC++
+#else
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
static int stbi__sse2_available(void)
{
- // If we're even attempting to compile this on GCC/Clang, that means
- // -msse2 is on, which means the compiler is allowed to use SSE2
- // instructions at will, and so are we.
+
return 1;
}
#endif
@@ -774,7 +340,6 @@ static int stbi__sse2_available(void)
#endif
#endif
-// ARM NEON
#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
#undef STBI_NEON
#endif
@@ -796,12 +361,6 @@ static int stbi__sse2_available(void)
#define STBI_MAX_DIMENSIONS (1 << 24)
#endif
-///////////////////////////////////////////////
-//
-// stbi__context struct and start_xxx functions
-
-// stbi__context structure is our basic context used by all images, so it
-// contains all the IO context, plus some basic image information
typedef struct
{
stbi__uint32 img_x, img_y;
@@ -819,10 +378,8 @@ typedef struct
stbi_uc *img_buffer_original, *img_buffer_original_end;
} stbi__context;
-
static void stbi__refill_buffer(stbi__context *s);
-// initialize a memory-decode context
static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
{
s->io.read = NULL;
@@ -832,7 +389,6 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
}
-// initialize a callback-based context
static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
{
s->io = *c;
@@ -856,9 +412,9 @@ static void stbi__stdio_skip(void *user, int n)
{
int ch;
fseek((FILE*) user, n, SEEK_CUR);
- ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */
+ ch = fgetc((FILE*) user);
if (ch != EOF) {
- ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */
+ ungetc(ch, (FILE *) user);
}
}
@@ -879,15 +435,11 @@ static void stbi__start_file(stbi__context *s, FILE *f)
stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
}
-//static void stop_file(stbi__context *s) { }
-
-#endif // !STBI_NO_STDIO
+#endif
static void stbi__rewind(stbi__context *s)
{
- // conceptually rewind SHOULD rewind to the beginning of the stream,
- // but we just rewind to the beginning of the initial buffer, because
- // we only use it after doing 'test', which only ever looks at at most 92 bytes
+
s->img_buffer = s->img_buffer_original;
s->img_buffer_end = s->img_buffer_original_end;
}
@@ -987,54 +539,35 @@ static void *stbi__malloc(size_t size)
return STBI_MALLOC(size);
}
-// stb_image uses ints pervasively, including for offset calculations.
-// therefore the largest decoded image size we can support with the
-// current code, even on 64-bit targets, is INT_MAX. this is not a
-// significant limitation for the intended use case.
-//
-// we do, however, need to make sure our size calculations don't
-// overflow. hence a few helper functions for size calculations that
-// multiply integers together, making sure that they're non-negative
-// and no overflow occurs.
-
-// return 1 if the sum is valid, 0 on overflow.
-// negative terms are considered invalid.
static int stbi__addsizes_valid(int a, int b)
{
if (b < 0) return 0;
- // now 0 <= b <= INT_MAX, hence also
- // 0 <= INT_MAX - b <= INTMAX.
- // And "a + b <= INT_MAX" (which might overflow) is the
- // same as a <= INT_MAX - b (no overflow)
+
return a <= INT_MAX - b;
}
-// returns 1 if the product is valid, 0 on overflow.
-// negative factors are considered invalid.
static int stbi__mul2sizes_valid(int a, int b)
{
if (a < 0 || b < 0) return 0;
- if (b == 0) return 1; // mul-by-0 is always safe
- // portable way to check for no overflows in a*b
+ if (b == 0) return 1;
+
return a <= INT_MAX/b;
}
#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
-// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+
static int stbi__mad2sizes_valid(int a, int b, int add)
{
return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
}
#endif
-// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
static int stbi__mad3sizes_valid(int a, int b, int c, int add)
{
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
stbi__addsizes_valid(a*b*c, add);
}
-// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
{
@@ -1044,7 +577,7 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
#endif
#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
-// mallocs with size overflow checking
+
static void *stbi__malloc_mad2(int a, int b, int add)
{
if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
@@ -1066,27 +599,21 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
}
#endif
-// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.
static int stbi__addints_valid(int a, int b)
{
- if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow
- if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.
+ if ((a >= 0) != (b >= 0)) return 1;
+ if (a < 0 && b < 0) return a >= INT_MIN - b;
return a <= INT_MAX - b;
}
-// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
static int stbi__mul2shorts_valid(int a, int b)
{
- if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
- if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
- if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN
+ if (b == 0 || b == -1) return 1;
+ if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b;
+ if (b < 0) return a <= SHRT_MIN / b;
return a >= SHRT_MIN / b;
}
-// stbi__err - error
-// stbi__errpf - error returning pointer to float
-// stbi__errpuc - error returning pointer to unsigned char
-
#ifdef STBI_NO_FAILURE_STRINGS
#define stbi__err(x,y) 0
#elif defined(STBI_FAILURE_USERMSG)
@@ -1132,17 +659,15 @@ STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_fli
#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \
? stbi__vertically_flip_on_load_local \
: stbi__vertically_flip_on_load_global)
-#endif // STBI_THREAD_LOCAL
+#endif
static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
{
- memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
- ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
- ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+ memset(ri, 0, sizeof(*ri));
+ ri->bits_per_channel = 8;
+ ri->channel_order = STBI_ORDER_RGB;
ri->num_channels = 0;
- // test the formats with a very explicit header first (at least a FOURCC
- // or distinctive magic number first)
#ifndef STBI_NO_PNG
if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
#endif
@@ -1161,9 +686,6 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
#endif
- // then the formats that can end up attempting to load with just 1 or 2
- // bytes matching expectations; these are prone to false positives, so
- // try them later
#ifndef STBI_NO_JPEG
if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
#endif
@@ -1179,7 +701,7 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
#endif
#ifndef STBI_NO_TGA
- // test tga last because it's a crappy test!
+
if (stbi__tga_test(s))
return stbi__tga_load(s,x,y,comp,req_comp, ri);
#endif
@@ -1197,7 +719,7 @@ static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int chan
if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
for (i = 0; i < img_len; ++i)
- reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+ reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF);
STBI_FREE(orig);
return reduced;
@@ -1213,7 +735,7 @@ static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int chan
if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
for (i = 0; i < img_len; ++i)
- enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+ enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]);
STBI_FREE(orig);
return enlarged;
@@ -1229,7 +751,7 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
for (row = 0; row < (h>>1); row++) {
stbi_uc *row0 = bytes + row*bytes_per_row;
stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
- // swap row0 with row1
+
size_t bytes_left = bytes_per_row;
while (bytes_left) {
size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
@@ -1265,7 +787,6 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
if (result == NULL)
return NULL;
- // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
if (ri.bits_per_channel != 8) {
@@ -1273,8 +794,6 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
ri.bits_per_channel = 8;
}
- // @TODO: move stbi__convert_format to here
-
if (stbi__vertically_flip_on_load) {
int channels = req_comp ? req_comp : *comp;
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
@@ -1291,7 +810,6 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
if (result == NULL)
return NULL;
- // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
if (ri.bits_per_channel != 16) {
@@ -1299,9 +817,6 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
ri.bits_per_channel = 16;
}
- // @TODO: move stbi__convert_format16 to here
- // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
-
if (stbi__vertically_flip_on_load) {
int channels = req_comp ? req_comp : *comp;
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
@@ -1330,7 +845,7 @@ STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{
- return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+ return WideCharToMultiByte(65001 , 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
}
#endif
@@ -1340,10 +855,10 @@ static FILE *stbi__fopen(char const *filename, char const *mode)
#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
wchar_t wMode[64];
wchar_t wFilename[1024];
- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
+ if (0 == MultiByteToWideChar(65001 , 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0;
- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
+ if (0 == MultiByteToWideChar(65001 , 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -1362,7 +877,6 @@ static FILE *stbi__fopen(char const *filename, char const *mode)
return f;
}
-
STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
{
FILE *f = stbi__fopen(filename, "rb");
@@ -1380,7 +894,7 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req
stbi__start_file(&s,f);
result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
if (result) {
- // need to 'unget' all the characters in the IO buffer
+
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
}
return result;
@@ -1393,7 +907,7 @@ STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp,
stbi__start_file(&s,f);
result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
if (result) {
- // need to 'unget' all the characters in the IO buffer
+
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
}
return result;
@@ -1409,8 +923,7 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, i
return result;
}
-
-#endif //!STBI_NO_STDIO
+#endif
STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
{
@@ -1506,13 +1019,9 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_
stbi__start_file(&s,f);
return stbi__loadf_main(&s,x,y,comp,req_comp);
}
-#endif // !STBI_NO_STDIO
-
-#endif // !STBI_NO_LINEAR
+#endif
-// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
-// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
-// reports false!
+#endif
STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
{
@@ -1554,7 +1063,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f)
return 0;
#endif
}
-#endif // !STBI_NO_STDIO
+#endif
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
{
@@ -1581,12 +1090,6 @@ static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Common code used by all image loaders
-//
-
enum
{
STBI__SCAN_load=0,
@@ -1,159 +1,8 @@
-/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
- writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
- no warranty implied; use at your own risk
-
- Before #including,
-
- #define STB_IMAGE_WRITE_IMPLEMENTATION
-
- in the file that you want to have the implementation.
-
- Will probably not work correctly with strict-aliasing optimizations.
-
-ABOUT:
-
- This header file is a library for writing images to C stdio or a callback.
-
- The PNG output is not optimal; it is 20-50% larger than the file
- written by a decent optimizing implementation; though providing a custom
- zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
- This library is designed for source code compactness and simplicity,
- not optimal image file size or run-time performance.
-
-BUILDING:
-
- You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
- You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
- malloc,realloc,free.
- You can #define STBIW_MEMMOVE() to replace memmove()
- You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
- for PNG compression (instead of the builtin one), it must have the following signature:
- unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
- The returned data will be freed with STBIW_FREE() (free() by default),
- so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
-
-UNICODE:
-
- If compiling for Windows and you wish to use Unicode filenames, compile
- with
- #define STBIW_WINDOWS_UTF8
- and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
- Windows wchar_t filenames to utf8.
-
-USAGE:
-
- There are five functions, one for each image file format:
-
- int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
- int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
- int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
- int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
- int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
-
- void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
-
- There are also five equivalent functions that use an arbitrary write function. You are
- expected to open/close your file-equivalent before and after calling these:
-
- int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
- int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
- int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
- int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
- int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
-
- where the callback is:
- void stbi_write_func(void *context, void *data, int size);
-
- You can configure it with these global variables:
- int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
- int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
- int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
-
-
- You can define STBI_WRITE_NO_STDIO to disable the file variant of these
- functions, so the library will not use stdio.h at all. However, this will
- also disable HDR writing, because it requires stdio for formatted output.
-
- Each function returns 0 on failure and non-0 on success.
-
- The functions create an image file defined by the parameters. The image
- is a rectangle of pixels stored from left-to-right, top-to-bottom.
- Each pixel contains 'comp' channels of data stored interleaved with 8-bits
- per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
- monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
- The *data pointer points to the first byte of the top-left-most pixel.
- For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
- a row of pixels to the first byte of the next row of pixels.
-
- PNG creates output files with the same number of components as the input.
- The BMP format expands Y to RGB in the file format and does not
- output alpha.
-
- PNG supports writing rectangles of data even when the bytes storing rows of
- data are not consecutive in memory (e.g. sub-rectangles of a larger image),
- by supplying the stride between the beginning of adjacent rows. The other
- formats do not. (Thus you cannot write a native-format BMP through the BMP
- writer, both because it is in BGR order and because it may have padding
- at the end of the line.)
-
- PNG allows you to set the deflate compression level by setting the global
- variable 'stbi_write_png_compression_level' (it defaults to 8).
-
- HDR expects linear float data. Since the format is always 32-bit rgb(e)
- data, alpha (if provided) is discarded, and for monochrome data it is
- replicated across all three channels.
-
- TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
- data, set the global variable 'stbi_write_tga_with_rle' to 0.
-
- JPEG does ignore alpha channels in input data; quality is between 1 and 100.
- Higher quality looks better but results in a bigger image.
- JPEG baseline (no JPEG progressive).
-
-CREDITS:
-
-
- Sean Barrett - PNG/BMP/TGA
- Baldur Karlsson - HDR
- Jean-Sebastien Guay - TGA monochrome
- Tim Kelsey - misc enhancements
- Alan Hickman - TGA RLE
- Emmanuel Julien - initial file IO callback implementation
- Jon Olick - original jo_jpeg.cpp code
- Daniel Gibson - integrate JPEG, allow external zlib
- Aarni Koskela - allow choosing PNG filter
-
- bugfixes:
- github:Chribba
- Guillaume Chereau
- github:jry2
- github:romigrou
- Sergio Gonzalez
- Jonas Karlsson
- Filip Wasil
- Thatcher Ulrich
- github:poppolopoppo
- Patrick Boettcher
- github:xeekworx
- Cap Petschulat
- Simon Rodriguez
- Ivan Tikhonov
- github:ignotion
- Adam Schackart
- Andrew Kensler
-
-LICENSE
-
- See end of file for license information.
-
-*/
-
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#include <stdlib.h>
-// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
#ifndef STBIWDEF
#ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static
@@ -166,7 +15,7 @@ LICENSE
#endif
#endif
-#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
+#ifndef STB_IMAGE_WRITE_STATIC
STBIWDEF int stbi_write_tga_with_rle;
STBIWDEF int stbi_write_png_compression_level;
STBIWDEF int stbi_write_force_png_filter;
@@ -194,7 +43,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
-#endif//INCLUDE_STB_IMAGE_WRITE_H
+#endif
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
@@ -209,7 +58,7 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#ifndef STBI_WRITE_NO_STDIO
#include <stdio.h>
-#endif // STBI_WRITE_NO_STDIO
+#endif
#include <stdarg.h>
#include <stdlib.h>
@@ -217,9 +66,9 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#include <math.h>
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
-// ok
+
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
-// ok
+
#else
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
#endif
@@ -234,12 +83,10 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif
-
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif
-
#ifndef STBIW_ASSERT
#include <assert.h>
#define STBIW_ASSERT(x) assert(x)
@@ -272,7 +119,6 @@ typedef struct
int buf_used;
} stbi__write_context;
-// initialize a callback-based context
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
{
s->func = c;
@@ -297,7 +143,7 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
{
- return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+ return WideCharToMultiByte(65001 , 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
}
#endif
@@ -307,10 +153,10 @@ static FILE *stbiw__fopen(char const *filename, char const *mode)
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
wchar_t wMode[64];
wchar_t wFilename[1024];
- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
+ if (0 == MultiByteToWideChar(65001 , 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
return 0;
- if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
+ if (0 == MultiByteToWideChar(65001 , 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
return 0;
#if defined(_MSC_VER) && _MSC_VER >= 1400
@@ -341,7 +187,7 @@ static void stbi__end_write_file(stbi__write_context *s)
fclose((FILE *)s->context);
}
-#endif // !STBI_WRITE_NO_STDIO
+#endif
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
@@ -424,22 +270,22 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in
stbiw__write1(s, d[comp - 1]);
switch (comp) {
- case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
+ case 2:
case 1:
if (expand_mono)
- stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
+ stbiw__write3(s, d[0], d[0], d[0]);
else
- stbiw__write1(s, d[0]); // monochrome TGA
+ stbiw__write1(s, d[0]);
break;
case 4:
if (!write_alpha) {
- // composite against pink background
+
for (k = 0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
break;
}
- /* FALLTHROUGH */
+
case 3:
stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
break;
@@ -492,20 +338,18 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x,
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
{
if (comp != 4) {
- // write RGB bitmap
+
int pad = (-x*3) & 3;
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
- 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
- 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
+ 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,
+ 40, x,y, 1,24, 0,0,0,0,0,0);
} else {
- // RGBA bitmaps need a v4 header
- // use BI_BITFIELDS mode with 32bpp and alpha mask
- // (straight BI_RGB with alpha mask doesn't work in most readers)
+
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
- 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header
- 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header
+ 'B', 'M', 14+108+x*y*4, 0, 0, 14+108,
+ 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0);
}
}
@@ -527,13 +371,13 @@ STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const
} else
return 0;
}
-#endif //!STBI_WRITE_NO_STDIO
+#endif
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
{
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp;
- int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
+ int format = colorbytes < 2 ? 3 : 2;
if (y < 0 || x < 0)
return 0;
@@ -628,10 +472,6 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const
}
#endif
-// *************************************************************************************************
-// Radiance RGBE HDR writer
-// by Baldur Karlsson
-
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
#ifndef STBI_WRITE_NO_STDIO
@@ -664,7 +504,7 @@ static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned c
static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
{
unsigned char lengthbyte = STBIW_UCHAR(length);
- STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
+ STBIW_ASSERT(length <= 128);
s->func(s->context, &lengthbyte, 1);
s->func(s->context, data, length);
}
@@ -679,11 +519,10 @@ static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int nco
scanlineheader[2] = (width&0xff00)>>8;
scanlineheader[3] = (width&0x00ff);
- /* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) {
switch (ncomp) {
- case 4: /* fallthrough */
+ case 4:
case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*ncomp + 0];
@@ -697,10 +536,10 @@ static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int nco
}
} else {
int c,r;
- /* encode into scratch buffer */
+
for (x=0; x < width; x++) {
switch(ncomp) {
- case 4: /* fallthrough */
+ case 4:
case 3: linear[2] = scanline[x*ncomp + 2];
linear[1] = scanline[x*ncomp + 1];
linear[0] = scanline[x*ncomp + 0];
@@ -718,13 +557,12 @@ static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int nco
s->func(s->context, scanlineheader, 4);
- /* RLE each component separately */
for (c=0; c < 4; c++) {
unsigned char *comp = &scratch[width*c];
x = 0;
while (x < width) {
- // find first run
+
r = x;
while (r+2 < width) {
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
@@ -733,19 +571,19 @@ static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int nco
}
if (r+2 >= width)
r = width;
- // dump up to first run
+
while (x < r) {
int len = r-x;
if (len > 128) len = 128;
stbiw__write_dump_data(s, len, &comp[x]);
x += len;
}
- // if there's a run, output it
- if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
- // find next byte after run
+
+ if (r+2 < width) {
+
while (r < width && comp[r] == comp[x])
++r;
- // output run up to r
+
while (x < r) {
int len = r-x;
if (len > 127) len = 127;
@@ -763,7 +601,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
if (y <= 0 || x <= 0 || data == NULL)
return 0;
else {
- // Each component is stored separately. Allocate scratch space for full output scanline.
+
unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
int i, len;
char buffer[128];
@@ -801,16 +639,10 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
} else
return 0;
}
-#endif // STBI_WRITE_NO_STDIO
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// PNG writer
-//
+#endif
#ifndef STBIW_ZLIB_COMPRESS
-// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
+
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
@@ -880,7 +712,7 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
-// default huffman tables
+
#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
@@ -890,14 +722,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
#define stbiw__ZHASH 16384
-#endif // STBIW_ZLIB_COMPRESS
+#endif
STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
#ifdef STBIW_ZLIB_COMPRESS
- // user provided a zlib compress implementation, use that
+
return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
-#else // use builtin
+#else
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
@@ -910,28 +742,28 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
return NULL;
if (quality < 5) quality = 5;
- stbiw__sbpush(out, 0x78); // DEFLATE 32K window
- stbiw__sbpush(out, 0x5e); // FLEVEL = 1
- stbiw__zlib_add(1,1); // BFINAL = 1
- stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
+ stbiw__sbpush(out, 0x78);
+ stbiw__sbpush(out, 0x5e);
+ stbiw__zlib_add(1,1);
+ stbiw__zlib_add(1,2);
for (i=0; i < stbiw__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
- // hash next 3 bytes of data to be compressed
+
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
- if (hlist[j]-data > i-32768) { // if entry lies within window
+ if (hlist[j]-data > i-32768) {
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) { best=d; bestloc=hlist[j]; }
}
}
- // when hash table entry is too long, delete half the entries
+
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbiw__sbn(hash_table[h]) = quality;
@@ -939,14 +771,14 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
stbiw__sbpush(hash_table[h],data+i);
if (bestloc) {
- // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
+
h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
hlist = hash_table[h];
n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
- if (e > best) { // if next match is better, bail on current match
+ if (e > best) {
bestloc = NULL;
break;
}
@@ -955,7 +787,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
}
if (bestloc) {
- int d = (int) (data+i - bestloc); // distance back
+ int d = (int) (data+i - bestloc);
STBIW_ASSERT(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbiw__zlib_huff(j+257);
@@ -969,11 +801,11 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
++i;
}
}
- // write out final bytes
+
for (;i < data_len; ++i)
stbiw__zlib_huffb(data[i]);
- stbiw__zlib_huff(256); // end of block
- // pad with 0 bits to byte boundary
+ stbiw__zlib_huff(256);
+
while (bitcount)
stbiw__zlib_add(0,1);
@@ -981,16 +813,15 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
(void) stbiw__sbfree(hash_table[i]);
STBIW_FREE(hash_table);
- // store uncompressed instead if compression was worse
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
- stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1
+ stbiw__sbn(out) = 2;
for (j = 0; j < data_len;) {
int blocklen = data_len - j;
if (blocklen > 32767) blocklen = 32767;
- stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression
- stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN
+ stbiw__sbpush(out, data_len - j == blocklen);
+ stbiw__sbpush(out, STBIW_UCHAR(blocklen));
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
- stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN
+ stbiw__sbpush(out, STBIW_UCHAR(~blocklen));
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
memcpy(out+stbiw__sbn(out), data+j, blocklen);
stbiw__sbn(out) += blocklen;
@@ -999,7 +830,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
}
{
- // compute adler32 on input
+
unsigned int s1=1, s2=0;
int blocklen = (int) (data_len % 5552);
j=0;
@@ -1015,10 +846,10 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i
stbiw__sbpush(out, STBIW_UCHAR(s1));
}
*out_len = stbiw__sbn(out);
- // make returned pointer freeable
+
STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out);
-#endif // STBIW_ZLIB_COMPRESS
+#endif
}
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@@ -1088,7 +919,6 @@ static unsigned char stbiw__paeth(int a, int b, int c)
return STBIW_UCHAR(c);
}
-// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
{
static int mapping[] = { 0,1,2,3,4 };
@@ -1104,7 +934,6 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int
return;
}
- // first loop isn't optimized since it's just one pixel
for (i = 0; i < n; ++i) {
switch (type) {
case 1: line_buffer[i] = z[i]; break;
@@ -1148,12 +977,11 @@ STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int s
if (force_filter > -1) {
filter_type = force_filter;
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);
- } else { // Estimate the best filter by running through all of them:
+ } else {
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
for (filter_type = 0; filter_type < 5; filter_type++) {
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);
- // Estimate the entropy of the line using this filter; the less, the better.
est = 0;
for (i = 0; i < x*n; ++i) {
est += abs((signed char) line_buffer[i]);
@@ -1163,12 +991,12 @@ STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int s
best_filter = filter_type;
}
}
- if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
+ if (filter_type != best_filter) {
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);
filter_type = best_filter;
}
}
- // when we get here, filter_type contains the filter type, and line_buffer contains the data
+
filt[j*(x*n+1)] = (unsigned char) filter_type;
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
}
@@ -1177,14 +1005,13 @@ STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int s
STBIW_FREE(filt);
if (!zlib) return 0;
- // each tag requires 12 bytes of overhead
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
STBIW_MEMMOVE(o,sig,8); o+= 8;
- stbiw__wp32(o, 13); // header length
+ stbiw__wp32(o, 13);
stbiw__wptag(o, "IHDR");
stbiw__wp32(o, x);
stbiw__wp32(o, y);
@@ -1238,15 +1065,6 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
return 1;
}
-
-/* ***************************************************************************
- *
- * JPEG writer
- *
- * This is based on Jon Olick's jo_jpeg.cpp:
- * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
- */
-
static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
@@ -1280,34 +1098,31 @@ static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float
float tmp3 = d3 + d4;
float tmp4 = d3 - d4;
- // Even part
- float tmp10 = tmp0 + tmp3; // phase 2
+ float tmp10 = tmp0 + tmp3;
float tmp13 = tmp0 - tmp3;
float tmp11 = tmp1 + tmp2;
float tmp12 = tmp1 - tmp2;
- d0 = tmp10 + tmp11; // phase 3
+ d0 = tmp10 + tmp11;
d4 = tmp10 - tmp11;
- z1 = (tmp12 + tmp13) * 0.707106781f; // c4
- d2 = tmp13 + z1; // phase 5
+ z1 = (tmp12 + tmp13) * 0.707106781f;
+ d2 = tmp13 + z1;
d6 = tmp13 - z1;
- // Odd part
- tmp10 = tmp4 + tmp5; // phase 2
+ tmp10 = tmp4 + tmp5;
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
- // The rotator is modified from fig 4-8 to avoid extra negations.
- z5 = (tmp10 - tmp12) * 0.382683433f; // c6
- z2 = tmp10 * 0.541196100f + z5; // c2-c6
- z4 = tmp12 * 1.306562965f + z5; // c2+c6
- z3 = tmp11 * 0.707106781f; // c4
+ z5 = (tmp10 - tmp12) * 0.382683433f;
+ z2 = tmp10 * 0.541196100f + z5;
+ z4 = tmp12 * 1.306562965f + z5;
+ z3 = tmp11 * 0.707106781f;
- z11 = tmp7 + z3; // phase 5
+ z11 = tmp7 + z3;
z13 = tmp7 - z3;
- *d5p = z13 + z2; // phase 6
+ *d5p = z13 + z2;
*d3p = z13 - z2;
*d1p = z11 + z4;
*d7p = z11 - z4;
@@ -1331,28 +1146,25 @@ static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt
int dataOff, i, j, n, diff, end0pos, x, y;
int DU[64];
- // DCT rows
for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
- // DCT columns
+
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
}
- // Quantize/descale/zigzag the coefficients
+
for(y = 0, j=0; y < 8; ++y) {
for(x = 0; x < 8; ++x,++j) {
float v;
i = y*du_stride+x;
v = CDU[i]*fdtbl[j];
- // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
- // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
+
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
}
- // Encode DC
diff = DU[0] - DC;
if (diff == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
@@ -1362,11 +1174,11 @@ static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
- // Encode ACs
+
end0pos = 63;
for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
}
- // end0pos = first element in reverse order !=0
+
if(end0pos == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
return DU[0];
@@ -1396,7 +1208,7 @@ static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt
}
static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
- // Constants that don't pollute global namespace
+
static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
@@ -1421,7 +1233,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
};
- // Huffman tables
+
static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};
static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};
static const unsigned short YAC_HT[256][2] = {
@@ -1494,7 +1306,6 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
}
}
- // Write Headers
{
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
@@ -1507,24 +1318,23 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
s->func(s->context, (void*)head1, sizeof(head1));
s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
- stbiw__putc(s, 0x10); // HTYACinfo
+ stbiw__putc(s, 0x10);
s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
- stbiw__putc(s, 1); // HTUDCinfo
+ stbiw__putc(s, 1);
s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
- stbiw__putc(s, 0x11); // HTUACinfo
+ stbiw__putc(s, 0x11);
s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
s->func(s->context, (void*)head2, sizeof(head2));
}
- // Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
- // comp == 2 is grey+alpha (alpha is ignored)
+
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
const unsigned char *dataR = (const unsigned char *)data;
const unsigned char *dataG = dataR + ofsG;
@@ -1535,11 +1345,11 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
for(x = 0; x < width; x += 16) {
float Y[256], U[256], V[256];
for(row = y, pos = 0; row < y+16; ++row) {
- // row >= height => use last input row
+
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+16; ++col, ++pos) {
- // if col >= width => use pixel from last input column
+
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
@@ -1552,7 +1362,6 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
- // subsample U,V
{
float subU[64], subV[64];
int yy, xx;
@@ -1573,11 +1382,11 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
for(x = 0; x < width; x += 8) {
float Y[64], U[64], V[64];
for(row = y, pos = 0; row < y+8; ++row) {
- // row >= height => use last input row
+
int clamped_row = (row < height) ? row : height - 1;
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
for(col = x; col < x+8; ++col, ++pos) {
- // if col >= width => use pixel from last input column
+
int p = base_p + ((col < width) ? col : (width-1))*comp;
float r = dataR[p], g = dataG[p], b = dataB[p];
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
@@ -1593,11 +1402,9 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
}
}
- // Do the bit alignment of the EOI marker
stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
}
- // EOI
stbiw__putc(s, 0xFF);
stbiw__putc(s, 0xD9);
@@ -1611,7 +1418,6 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
-
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
{
@@ -1625,100 +1431,4 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
}
#endif
-#endif // STB_IMAGE_WRITE_IMPLEMENTATION
-
-/* Revision history
- 1.16 (2021-07-11)
- make Deflate code emit uncompressed blocks when it would otherwise expand
- support writing BMPs with alpha channel
- 1.15 (2020-07-13) unknown
- 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
- 1.13
- 1.12
- 1.11 (2019-08-11)
-
- 1.10 (2019-02-07)
- support utf8 filenames in Windows; fix warnings and platform ifdefs
- 1.09 (2018-02-11)
- fix typo in zlib quality API, improve STB_I_W_STATIC in C++
- 1.08 (2018-01-29)
- add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
- 1.07 (2017-07-24)
- doc fix
- 1.06 (2017-07-23)
- writing JPEG (using Jon Olick's code)
- 1.05 ???
- 1.04 (2017-03-03)
- monochrome BMP expansion
- 1.03 ???
- 1.02 (2016-04-02)
- avoid allocating large structures on the stack
- 1.01 (2016-01-16)
- STBIW_REALLOC_SIZED: support allocators with no realloc support
- avoid race-condition in crc initialization
- minor compile issues
- 1.00 (2015-09-14)
- installable file IO function
- 0.99 (2015-09-13)
- warning fixes; TGA rle support
- 0.98 (2015-04-08)
- added STBIW_MALLOC, STBIW_ASSERT etc
- 0.97 (2015-01-18)
- fixed HDR asserts, rewrote HDR rle logic
- 0.96 (2015-01-17)
- add HDR output
- fix monochrome BMP
- 0.95 (2014-08-17)
- add monochrome TGA output
- 0.94 (2014-05-31)
- rename private functions to avoid conflicts with stb_image.h
- 0.93 (2014-05-27)
- warning fixes
- 0.92 (2010-08-01)
- casts to unsigned char to fix warnings
- 0.91 (2010-07-17)
- first public release
- 0.90 first internal release
-*/
-
-/*
-------------------------------------------------------------------------------
-This software is available under 2 licenses -- choose whichever you prefer.
-------------------------------------------------------------------------------
-ALTERNATIVE A - MIT License
-Copyright (c) 2017 Sean Barrett
-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.
-------------------------------------------------------------------------------
-ALTERNATIVE B - Public Domain (www.unlicense.org)
-This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
-commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
-this software under copyright law.
-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 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.
-------------------------------------------------------------------------------
-*/
+#endif