summaryrefslogtreecommitdiffstats
path: root/src/3rdparty
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty')
-rw-r--r--src/3rdparty/CMakeLists.txt4
-rw-r--r--src/3rdparty/libcroco/CMakeLists.txt65
-rw-r--r--src/3rdparty/libcroco/README11
-rw-r--r--src/3rdparty/libcroco/cr-additional-sel.c500
-rw-r--r--src/3rdparty/libcroco/cr-additional-sel.h98
-rw-r--r--src/3rdparty/libcroco/cr-attr-sel.c232
-rw-r--r--src/3rdparty/libcroco/cr-attr-sel.h74
-rw-r--r--src/3rdparty/libcroco/cr-cascade.c213
-rw-r--r--src/3rdparty/libcroco/cr-cascade.h74
-rw-r--r--src/3rdparty/libcroco/cr-declaration.c804
-rw-r--r--src/3rdparty/libcroco/cr-declaration.h136
-rw-r--r--src/3rdparty/libcroco/cr-doc-handler.c276
-rw-r--r--src/3rdparty/libcroco/cr-doc-handler.h298
-rw-r--r--src/3rdparty/libcroco/cr-enc-handler.c184
-rw-r--r--src/3rdparty/libcroco/cr-enc-handler.h94
-rw-r--r--src/3rdparty/libcroco/cr-fonts.c943
-rw-r--r--src/3rdparty/libcroco/cr-fonts.h315
-rw-r--r--src/3rdparty/libcroco/cr-input.c1184
-rw-r--r--src/3rdparty/libcroco/cr-input.h174
-rw-r--r--src/3rdparty/libcroco/cr-libxml-node-iface.c81
-rw-r--r--src/3rdparty/libcroco/cr-libxml-node-iface.h14
-rw-r--r--src/3rdparty/libcroco/cr-node-iface.h34
-rw-r--r--src/3rdparty/libcroco/cr-num.c315
-rw-r--r--src/3rdparty/libcroco/cr-num.h127
-rw-r--r--src/3rdparty/libcroco/cr-om-parser.c1151
-rw-r--r--src/3rdparty/libcroco/cr-om-parser.h98
-rw-r--r--src/3rdparty/libcroco/cr-parser.c4538
-rw-r--r--src/3rdparty/libcroco/cr-parser.h130
-rw-r--r--src/3rdparty/libcroco/cr-parsing-location.c172
-rw-r--r--src/3rdparty/libcroco/cr-parsing-location.h70
-rw-r--r--src/3rdparty/libcroco/cr-prop-list.c404
-rw-r--r--src/3rdparty/libcroco/cr-prop-list.h80
-rw-r--r--src/3rdparty/libcroco/cr-pseudo.c167
-rw-r--r--src/3rdparty/libcroco/cr-pseudo.h66
-rw-r--r--src/3rdparty/libcroco/cr-rgb.c688
-rw-r--r--src/3rdparty/libcroco/cr-rgb.h94
-rw-r--r--src/3rdparty/libcroco/cr-sel-eng.c2294
-rw-r--r--src/3rdparty/libcroco/cr-sel-eng.h120
-rw-r--r--src/3rdparty/libcroco/cr-selector.c330
-rw-r--r--src/3rdparty/libcroco/cr-selector.h95
-rw-r--r--src/3rdparty/libcroco/cr-simple-sel.c328
-rw-r--r--src/3rdparty/libcroco/cr-simple-sel.h131
-rw-r--r--src/3rdparty/libcroco/cr-statement.c2809
-rw-r--r--src/3rdparty/libcroco/cr-statement.h440
-rw-r--r--src/3rdparty/libcroco/cr-string.c168
-rw-r--r--src/3rdparty/libcroco/cr-string.h76
-rw-r--r--src/3rdparty/libcroco/cr-style.c2850
-rw-r--r--src/3rdparty/libcroco/cr-style.h339
-rw-r--r--src/3rdparty/libcroco/cr-stylesheet.c261
-rw-r--r--src/3rdparty/libcroco/cr-stylesheet.h118
-rw-r--r--src/3rdparty/libcroco/cr-term.c788
-rw-r--r--src/3rdparty/libcroco/cr-term.h195
-rw-r--r--src/3rdparty/libcroco/cr-tknzr.c2754
-rw-r--r--src/3rdparty/libcroco/cr-tknzr.h115
-rw-r--r--src/3rdparty/libcroco/cr-token.c636
-rw-r--r--src/3rdparty/libcroco/cr-token.h212
-rw-r--r--src/3rdparty/libcroco/cr-utils.c1330
-rw-r--r--src/3rdparty/libcroco/cr-utils.h249
-rw-r--r--src/3rdparty/libcroco/libcroco.h48
-rw-r--r--src/3rdparty/libdepixelize/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README9
-rw-r--r--src/3rdparty/libdepixelize/CMakeLists.txt23
-rw-r--r--src/3rdparty/libdepixelize/kopftracer2011.cpp665
-rw-r--r--src/3rdparty/libdepixelize/kopftracer2011.h150
-rw-r--r--src/3rdparty/libdepixelize/priv/branchless.h58
-rw-r--r--src/3rdparty/libdepixelize/priv/colorspace.h111
-rw-r--r--src/3rdparty/libdepixelize/priv/curvature.h115
-rw-r--r--src/3rdparty/libdepixelize/priv/homogeneoussplines.h472
-rw-r--r--src/3rdparty/libdepixelize/priv/integral.h61
-rw-r--r--src/3rdparty/libdepixelize/priv/iterator.h123
-rw-r--r--src/3rdparty/libdepixelize/priv/optimization-kopf2011.h263
-rw-r--r--src/3rdparty/libdepixelize/priv/pixelgraph.h555
-rw-r--r--src/3rdparty/libdepixelize/priv/point.h112
-rw-r--r--src/3rdparty/libdepixelize/priv/simplifiedvoronoi.h1707
-rw-r--r--src/3rdparty/libdepixelize/priv/splines-kopf2011.h167
-rw-r--r--src/3rdparty/libdepixelize/splines.h120
-rw-r--r--src/3rdparty/libuemf/CMakeLists.txt30
-rw-r--r--src/3rdparty/libuemf/README577
-rw-r--r--src/3rdparty/libuemf/symbol_convert.c1008
-rw-r--r--src/3rdparty/libuemf/symbol_convert.h51
-rw-r--r--src/3rdparty/libuemf/uemf.c5606
-rw-r--r--src/3rdparty/libuemf/uemf.h3653
-rw-r--r--src/3rdparty/libuemf/uemf_endian.c2270
-rw-r--r--src/3rdparty/libuemf/uemf_endian.h59
-rw-r--r--src/3rdparty/libuemf/uemf_print.c2704
-rw-r--r--src/3rdparty/libuemf/uemf_print.h177
-rw-r--r--src/3rdparty/libuemf/uemf_safe.c1204
-rw-r--r--src/3rdparty/libuemf/uemf_safe.h32
-rw-r--r--src/3rdparty/libuemf/uemf_utf.c720
-rw-r--r--src/3rdparty/libuemf/uemf_utf.h55
-rw-r--r--src/3rdparty/libuemf/upmf.c8660
-rw-r--r--src/3rdparty/libuemf/upmf.h3178
-rw-r--r--src/3rdparty/libuemf/upmf_print.c3400
-rw-r--r--src/3rdparty/libuemf/upmf_print.h181
-rw-r--r--src/3rdparty/libuemf/uwmf.c7039
-rw-r--r--src/3rdparty/libuemf/uwmf.h2677
-rw-r--r--src/3rdparty/libuemf/uwmf_endian.c1774
-rw-r--r--src/3rdparty/libuemf/uwmf_endian.h34
-rw-r--r--src/3rdparty/libuemf/uwmf_print.c1635
-rw-r--r--src/3rdparty/libuemf/uwmf_print.h52
99 files changed, 82081 insertions, 0 deletions
diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt
new file mode 100644
index 000000000..13b736ebf
--- /dev/null
+++ b/src/3rdparty/CMakeLists.txt
@@ -0,0 +1,4 @@
+#include(ExternalProject)
+add_subdirectory(libuemf)
+add_subdirectory(libcroco)
+add_subdirectory(libdepixelize)
diff --git a/src/3rdparty/libcroco/CMakeLists.txt b/src/3rdparty/libcroco/CMakeLists.txt
new file mode 100644
index 000000000..af7f49654
--- /dev/null
+++ b/src/3rdparty/libcroco/CMakeLists.txt
@@ -0,0 +1,65 @@
+
+set(libcroco_SRC
+ cr-additional-sel.c
+ cr-attr-sel.c
+ cr-cascade.c
+ cr-declaration.c
+ cr-doc-handler.c
+ cr-enc-handler.c
+ cr-fonts.c
+ cr-input.c
+ cr-libxml-node-iface.c
+ cr-num.c
+ cr-om-parser.c
+ cr-parser.c
+ cr-parsing-location.c
+ cr-prop-list.c
+ cr-pseudo.c
+ cr-rgb.c
+ cr-selector.c
+ cr-sel-eng.c
+ cr-simple-sel.c
+ cr-statement.c
+ cr-string.c
+ cr-style.c
+ cr-stylesheet.c
+ cr-term.c
+ cr-tknzr.c
+ cr-token.c
+ cr-utils.c
+
+
+ # -------
+ # Headers
+ cr-additional-sel.h
+ cr-attr-sel.h
+ cr-cascade.h
+ cr-declaration.h
+ cr-doc-handler.h
+ cr-enc-handler.h
+ cr-fonts.h
+ cr-input.h
+ cr-libxml-node-iface.h
+ cr-node-iface.h
+ cr-num.h
+ cr-om-parser.h
+ cr-parser.h
+ cr-parsing-location.h
+ cr-prop-list.h
+ cr-pseudo.h
+ cr-rgb.h
+ cr-sel-eng.h
+ cr-selector.h
+ cr-simple-sel.h
+ cr-statement.h
+ cr-string.h
+ cr-style.h
+ cr-stylesheet.h
+ cr-term.h
+ cr-tknzr.h
+ cr-token.h
+ cr-utils.h
+ libcroco.h
+)
+
+add_inkscape_lib(croco_LIB "${libcroco_SRC}")
diff --git a/src/3rdparty/libcroco/README b/src/3rdparty/libcroco/README
new file mode 100644
index 000000000..74df23145
--- /dev/null
+++ b/src/3rdparty/libcroco/README
@@ -0,0 +1,11 @@
+This code is derived from libcroco-0.6. We hope that the changes will find
+their way into libcroco-0.7 (in some form).
+
+The main changed file is cr-sel-eng.{c,h}. The cr-sel-eng in libcroco-0.6 is
+somewhat experimental: it has a few bugs, and the interface requires that the
+XML node storage be libxml2. The version in this directory has a modification
+of allowing passing in a "vtable" of operations so that we can use our
+preferred representation Inkscape::XML::Node.
+
+Once libcroco-0.7 is widely available (with the vtable interface or a
+functional equivalent), this directory should be removed.
diff --git a/src/3rdparty/libcroco/cr-additional-sel.c b/src/3rdparty/libcroco/cr-additional-sel.c
new file mode 100644
index 000000000..c34b8d243
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-additional-sel.c
@@ -0,0 +1,500 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ *
+ */
+
+#include "cr-additional-sel.h"
+#include "string.h"
+
+/**
+ * CRAdditionalSel:
+ *
+ * #CRAdditionalSel abstracts an additionnal selector.
+ * An additional selector is the selector part
+ * that comes after the combination of type selectors.
+ * It can be either "a class selector (the .class part),
+ * a pseudo class selector, an attribute selector
+ * or an id selector.
+ */
+
+/**
+ * cr_additional_sel_new:
+ *
+ * Default constructor of #CRAdditionalSel.
+ * Returns the newly build instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new (void)
+{
+ CRAdditionalSel *result = NULL;
+
+ result = g_try_malloc (sizeof (CRAdditionalSel));
+
+ if (result == NULL) {
+ cr_utils_trace_debug ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRAdditionalSel));
+
+ return result;
+}
+
+/**
+ * cr_additional_sel_new_with_type:
+ * @a_sel_type: the type of the newly built instance
+ * of #CRAdditionalSel.
+ *
+ * Constructor of #CRAdditionalSel.
+ * Returns the newly built instance of #CRAdditionalSel.
+ */
+CRAdditionalSel *
+cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type)
+{
+ CRAdditionalSel *result = NULL;
+
+ result = cr_additional_sel_new ();
+
+ g_return_val_if_fail (result, NULL);
+
+ result->type = a_sel_type;
+
+ return result;
+}
+
+/**
+ * cr_additional_sel_set_class_name:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_class_name: the new class name to set.
+ *
+ * Sets a new class name to a
+ * CLASS additional selector.
+ */
+void
+cr_additional_sel_set_class_name (CRAdditionalSel * a_this,
+ CRString * a_class_name)
+{
+ g_return_if_fail (a_this && a_this->type == CLASS_ADD_SELECTOR);
+
+ if (a_this->content.class_name) {
+ cr_string_destroy (a_this->content.class_name);
+ }
+
+ a_this->content.class_name = a_class_name;
+}
+
+/**
+ * cr_additional_sel_set_id_name:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_id: the new id to set.
+ *
+ * Sets a new id name to an
+ * ID additional selector.
+ */
+void
+cr_additional_sel_set_id_name (CRAdditionalSel * a_this, CRString * a_id)
+{
+ g_return_if_fail (a_this && a_this->type == ID_ADD_SELECTOR);
+
+ if (a_this->content.id_name) {
+ cr_string_destroy (a_this->content.id_name);
+ }
+
+ a_this->content.id_name = a_id;
+}
+
+/**
+ * cr_additional_sel_set_pseudo:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_pseudo: the new pseudo to set.
+ *
+ * Sets a new pseudo to a
+ * PSEUDO additional selector.
+ */
+void
+cr_additional_sel_set_pseudo (CRAdditionalSel * a_this, CRPseudo * a_pseudo)
+{
+ g_return_if_fail (a_this
+ && a_this->type == PSEUDO_CLASS_ADD_SELECTOR);
+
+ if (a_this->content.pseudo) {
+ cr_pseudo_destroy (a_this->content.pseudo);
+ }
+
+ a_this->content.pseudo = a_pseudo;
+}
+
+/**
+ * cr_additional_sel_set_attr_sel:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance of #CRAttrSel to set.
+ *
+ * Sets a new instance of #CRAttrSel to
+ * a ATTRIBUTE additional selector.
+ */
+void
+cr_additional_sel_set_attr_sel (CRAdditionalSel * a_this, CRAttrSel * a_sel)
+{
+ g_return_if_fail (a_this && a_this->type == ATTRIBUTE_ADD_SELECTOR);
+
+ if (a_this->content.attr_sel) {
+ cr_attr_sel_destroy (a_this->content.attr_sel);
+ }
+
+ a_this->content.attr_sel = a_sel;
+}
+
+/**
+ * cr_additional_sel_append:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance to #CRAdditional to append.
+ *
+ * Appends a new instance of #CRAdditional to the
+ * current list of #CRAdditional.
+ *
+ * Returns the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_append (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
+{
+ CRAdditionalSel *cur_sel = NULL;
+
+ g_return_val_if_fail (a_sel, NULL);
+
+ if (a_this == NULL) {
+ return a_sel;
+ }
+
+ if (a_sel == NULL)
+ return NULL;
+
+ for (cur_sel = a_this;
+ cur_sel && cur_sel->next; cur_sel = cur_sel->next) ;
+
+ g_return_val_if_fail (cur_sel != NULL, NULL);
+
+ cur_sel->next = a_sel;
+ a_sel->prev = cur_sel;
+
+ return a_this;
+}
+
+/**
+ * cr_additional_sel_prepend:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ * @a_sel: the new instance to #CRAdditional to preappend.
+ *
+ * Preppends a new instance of #CRAdditional to the
+ * current list of #CRAdditional.
+ *
+ * Returns the new list of CRAdditionalSel or NULL if an error arises.
+ */
+CRAdditionalSel *
+cr_additional_sel_prepend (CRAdditionalSel * a_this, CRAdditionalSel * a_sel)
+{
+ g_return_val_if_fail (a_sel, NULL);
+
+ if (a_this == NULL) {
+ return a_sel;
+ }
+
+ a_sel->next = a_this;
+ a_this->prev = a_sel;
+
+ return a_sel;
+}
+
+guchar *
+cr_additional_sel_to_string (CRAdditionalSel const * a_this)
+{
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+ CRAdditionalSel const *cur = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ switch (cur->type) {
+ case CLASS_ADD_SELECTOR:
+ {
+ guchar *name = NULL;
+
+ if (cur->content.class_name) {
+ name = (guchar *) g_strndup
+ (cur->content.class_name->stryng->str,
+ cur->content.class_name->stryng->len);
+
+ if (name) {
+ g_string_append_printf
+ (str_buf, ".%s",
+ name);
+ g_free (name);
+ name = NULL;
+ }
+ }
+ }
+ break;
+
+ case ID_ADD_SELECTOR:
+ {
+ guchar *name = NULL;
+
+ if (cur->content.id_name) {
+ name = (guchar *) g_strndup
+ (cur->content.id_name->stryng->str,
+ cur->content.id_name->stryng->len);
+
+ if (name) {
+ g_string_append_printf
+ (str_buf, "#%s",
+ name);
+ g_free (name);
+ name = NULL;
+ }
+ }
+ }
+
+ break;
+
+ case PSEUDO_CLASS_ADD_SELECTOR:
+ {
+ if (cur->content.pseudo) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_pseudo_to_string
+ (cur->content.pseudo);
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf, ":%s",
+ tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ }
+ break;
+
+ case ATTRIBUTE_ADD_SELECTOR:
+ if (cur->content.attr_sel) {
+ guchar *tmp_str = NULL;
+
+ g_string_append_c (str_buf, '[');
+ tmp_str = cr_attr_sel_to_string
+ (cur->content.attr_sel);
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf, "%s]", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+guchar *
+cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
+{
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ str_buf = g_string_new (NULL) ;
+
+ switch (a_this->type) {
+ case CLASS_ADD_SELECTOR:
+ {
+ guchar *name = NULL;
+
+ if (a_this->content.class_name) {
+ name = (guchar *) g_strndup
+ (a_this->content.class_name->stryng->str,
+ a_this->content.class_name->stryng->len);
+
+ if (name) {
+ g_string_append_printf
+ (str_buf, ".%s",
+ name);
+ g_free (name);
+ name = NULL;
+ }
+ }
+ }
+ break;
+
+ case ID_ADD_SELECTOR:
+ {
+ guchar *name = NULL;
+
+ if (a_this->content.id_name) {
+ name = (guchar *) g_strndup
+ (a_this->content.id_name->stryng->str,
+ a_this->content.id_name->stryng->len);
+
+ if (name) {
+ g_string_append_printf
+ (str_buf, "#%s",
+ name);
+ g_free (name);
+ name = NULL;
+ }
+ }
+ }
+
+ break;
+
+ case PSEUDO_CLASS_ADD_SELECTOR:
+ {
+ if (a_this->content.pseudo) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_pseudo_to_string
+ (a_this->content.pseudo);
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf, ":%s",
+ tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ }
+ break;
+
+ case ATTRIBUTE_ADD_SELECTOR:
+ if (a_this->content.attr_sel) {
+ guchar *tmp_str = NULL;
+
+ g_string_append_printf (str_buf, "[");
+ tmp_str = cr_attr_sel_to_string
+ (a_this->content.attr_sel);
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf, "%s]", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_additional_sel_dump:
+ * @a_this: the "this pointer" of the current instance of
+ * #CRAdditionalSel.
+ * @a_fp: the destination file.
+ *
+ * Dumps the current instance of #CRAdditionalSel to a file
+ */
+void
+cr_additional_sel_dump (CRAdditionalSel const * a_this, FILE * a_fp)
+{
+ guchar *tmp_str = NULL;
+
+ g_return_if_fail (a_fp);
+
+ if (a_this) {
+ tmp_str = cr_additional_sel_to_string (a_this);
+ if (tmp_str) {
+ fprintf (a_fp, "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+}
+
+/**
+ * cr_additional_sel_destroy:
+ * @a_this: the "this pointer" of the current instance
+ * of #CRAdditionalSel .
+ *
+ * Destroys an instance of #CRAdditional.
+ */
+void
+cr_additional_sel_destroy (CRAdditionalSel * a_this)
+{
+ g_return_if_fail (a_this);
+
+ switch (a_this->type) {
+ case CLASS_ADD_SELECTOR:
+ cr_string_destroy (a_this->content.class_name);
+ a_this->content.class_name = NULL;
+ break;
+
+ case PSEUDO_CLASS_ADD_SELECTOR:
+ cr_pseudo_destroy (a_this->content.pseudo);
+ a_this->content.pseudo = NULL;
+ break;
+
+ case ID_ADD_SELECTOR:
+ cr_string_destroy (a_this->content.id_name);
+ a_this->content.id_name = NULL;
+ break;
+
+ case ATTRIBUTE_ADD_SELECTOR:
+ cr_attr_sel_destroy (a_this->content.attr_sel);
+ a_this->content.attr_sel = NULL;
+ break;
+
+ default:
+ break;
+ }
+
+ if (a_this->next) {
+ cr_additional_sel_destroy (a_this->next);
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-additional-sel.h b/src/3rdparty/libcroco/cr-additional-sel.h
new file mode 100644
index 000000000..7ca3e07d5
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-additional-sel.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_ADD_SEL_H__
+#define __CR_ADD_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-attr-sel.h"
+#include "cr-pseudo.h"
+#include "cr-additional-sel.h"
+
+G_BEGIN_DECLS
+
+enum AddSelectorType
+{
+ NO_ADD_SELECTOR = 0 ,
+ CLASS_ADD_SELECTOR = 1 ,
+ PSEUDO_CLASS_ADD_SELECTOR = 1 << 1,
+ ID_ADD_SELECTOR = 1 << 3,
+ ATTRIBUTE_ADD_SELECTOR = 1 << 4
+} ;
+
+union CRAdditionalSelectorContent
+{
+ CRString *class_name ;
+ CRString *id_name ;
+ CRPseudo *pseudo ;
+ CRAttrSel *attr_sel ;
+} ;
+
+typedef struct _CRAdditionalSel CRAdditionalSel ;
+
+struct _CRAdditionalSel
+{
+ enum AddSelectorType type ;
+ union CRAdditionalSelectorContent content ;
+
+ CRAdditionalSel * next ;
+ CRAdditionalSel * prev ;
+ CRParsingLocation location ;
+} ;
+
+CRAdditionalSel * cr_additional_sel_new (void) ;
+
+CRAdditionalSel * cr_additional_sel_new_with_type (enum AddSelectorType a_sel_type) ;
+
+CRAdditionalSel * cr_additional_sel_append (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel) ;
+
+void cr_additional_sel_set_class_name (CRAdditionalSel *a_this,
+ CRString *a_class_name) ;
+
+void cr_additional_sel_set_id_name (CRAdditionalSel *a_this,
+ CRString *a_id) ;
+
+void cr_additional_sel_set_pseudo (CRAdditionalSel *a_this,
+ CRPseudo *a_pseudo) ;
+
+void cr_additional_sel_set_attr_sel (CRAdditionalSel *a_this,
+ CRAttrSel *a_sel) ;
+
+CRAdditionalSel * cr_additional_sel_prepend (CRAdditionalSel *a_this,
+ CRAdditionalSel *a_sel) ;
+
+guchar * cr_additional_sel_to_string (CRAdditionalSel const *a_this) ;
+
+guchar * cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) ;
+
+void cr_additional_sel_dump (CRAdditionalSel const *a_this, FILE *a_fp) ;
+
+void cr_additional_sel_destroy (CRAdditionalSel *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_ADD_SEL_H*/
diff --git a/src/3rdparty/libcroco/cr-attr-sel.c b/src/3rdparty/libcroco/cr-attr-sel.c
new file mode 100644
index 000000000..31d9da579
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-attr-sel.c
@@ -0,0 +1,232 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include <stdio.h>
+#include "cr-attr-sel.h"
+
+/**
+ * CRAttrSel:
+ *
+ * #CRAdditionalSel abstracts an attribute selector.
+ * Attributes selectors are described in the css2 spec [5.8].
+ * There are more generally used in the css2 selectors described in
+ * css2 spec [5] .
+ */
+
+/**
+ * cr_attr_sel_new:
+ * The constructor of #CRAttrSel.
+ * Returns the newly allocated instance
+ * of #CRAttrSel.
+ */
+CRAttrSel *
+cr_attr_sel_new (void)
+{
+ CRAttrSel *result = NULL;
+
+ result = g_malloc0 (sizeof (CRAttrSel));
+
+ return result;
+}
+
+/**
+ * cr_attr_sel_append_attr_sel:
+ * @a_this: the this pointer of the current instance of #CRAttrSel.
+ * @a_attr_sel: selector to append.
+ *
+ * Appends an attribute selector to the current list of
+ * attribute selectors represented by a_this.
+ * Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_append_attr_sel (CRAttrSel * a_this, CRAttrSel * a_attr_sel)
+{
+ CRAttrSel *cur_sel = NULL;
+
+ g_return_val_if_fail (a_this && a_attr_sel,
+ CR_BAD_PARAM_ERROR);
+
+ for (cur_sel = a_this;
+ cur_sel->next;
+ cur_sel = cur_sel->next) ;
+
+ cur_sel->next = a_attr_sel;
+ a_attr_sel->prev = cur_sel;
+
+ return CR_OK;
+}
+
+/**
+ * cr_attr_sel_prepend_attr_sel:
+ *@a_this: the "this pointer" of the current instance *of #CRAttrSel.
+ *@a_attr_sel: the attribute selector to append.
+ *
+ *Prepends an attribute selector to the list of
+ *attributes selector represented by a_this.
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_attr_sel_prepend_attr_sel (CRAttrSel * a_this,
+ CRAttrSel * a_attr_sel)
+{
+ g_return_val_if_fail (a_this && a_attr_sel,
+ CR_BAD_PARAM_ERROR);
+
+ a_attr_sel->next = a_this;
+ a_this->prev = a_attr_sel;
+
+ return CR_OK;
+}
+
+/**
+ * cr_attr_sel_to_string:
+ * @a_this: the current instance of #CRAttrSel.
+ *
+ * Serializes an attribute selector into a string
+ * Returns the serialized attribute selector.
+ */
+guchar *
+cr_attr_sel_to_string (CRAttrSel const * a_this)
+{
+ CRAttrSel const *cur = NULL;
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ if (cur->prev) {
+ g_string_append_c (str_buf, ' ');
+ }
+
+ if (cur->name) {
+ guchar *name = NULL;
+
+ name = (guchar *) g_strndup (cur->name->stryng->str,
+ cur->name->stryng->len);
+ if (name) {
+ g_string_append (str_buf, (const gchar *) name);
+ g_free (name);
+ name = NULL;
+ }
+ }
+
+ if (cur->value) {
+ guchar *value = NULL;
+
+ value = (guchar *) g_strndup (cur->value->stryng->str,
+ cur->value->stryng->len);
+ if (value) {
+ switch (cur->match_way) {
+ case SET:
+ break;
+
+ case EQUALS:
+ g_string_append_c (str_buf, '=');
+ break;
+
+ case INCLUDES:
+ g_string_append (str_buf, "~=");
+ break;
+
+ case DASHMATCH:
+ g_string_append (str_buf, "|=");
+ break;
+
+ default:
+ break;
+ }
+
+ g_string_append_printf
+ (str_buf, "\"%s\"", value);
+
+ g_free (value);
+ value = NULL;
+ }
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ }
+
+ return result;
+}
+
+/**
+ * cr_attr_sel_dump:
+ * @a_this: the "this pointer" of the current instance of
+ * #CRAttrSel.
+ * @a_fp: the destination file.
+ *
+ * Dumps the current instance of #CRAttrSel to a file.
+ */
+void
+cr_attr_sel_dump (CRAttrSel const * a_this, FILE * a_fp)
+{
+ guchar *tmp_str = NULL;
+
+ g_return_if_fail (a_this);
+
+ tmp_str = cr_attr_sel_to_string (a_this);
+
+ if (tmp_str) {
+ fprintf (a_fp, "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+}
+
+/**
+ *cr_attr_sel_destroy:
+ *@a_this: the "this pointer" of the current
+ *instance of #CRAttrSel.
+ *
+ *Destroys the current instance of #CRAttrSel.
+ *Frees all the fields if they are non null.
+ */
+void
+cr_attr_sel_destroy (CRAttrSel * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->name) {
+ cr_string_destroy (a_this->name);
+ a_this->name = NULL;
+ }
+
+ if (a_this->value) {
+ cr_string_destroy (a_this->value);
+ a_this->value = NULL;
+ }
+
+ if (a_this->next) {
+ cr_attr_sel_destroy (a_this->next);
+ a_this->next = NULL;
+ }
+
+ g_free (a_this);
+}
+
diff --git a/src/3rdparty/libcroco/cr-attr-sel.h b/src/3rdparty/libcroco/cr-attr-sel.h
new file mode 100644
index 000000000..82d5a87d7
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-attr-sel.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_ATTR_SEL_H__
+#define __CR_ATTR_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+#include "cr-string.h"
+
+G_BEGIN_DECLS
+
+
+struct _CRAttrSel ;
+typedef struct _CRAttrSel CRAttrSel ;
+
+enum AttrMatchWay
+{
+ NO_MATCH = 0,
+ SET,
+ EQUALS,
+ INCLUDES,
+ DASHMATCH
+} ;
+
+struct _CRAttrSel
+{
+ CRString *name ;
+ CRString *value ;
+ enum AttrMatchWay match_way ;
+ CRAttrSel *next ;
+ CRAttrSel *prev ;
+ CRParsingLocation location ;
+} ;
+
+CRAttrSel * cr_attr_sel_new (void) ;
+
+enum CRStatus cr_attr_sel_append_attr_sel (CRAttrSel * a_this,
+ CRAttrSel *a_attr_sel) ;
+
+enum CRStatus cr_attr_sel_prepend_attr_sel (CRAttrSel *a_this,
+ CRAttrSel *a_attr_sel) ;
+
+guchar * cr_attr_sel_to_string (CRAttrSel const *a_this) ;
+
+void cr_attr_sel_dump (CRAttrSel const *a_this, FILE *a_fp) ;
+
+void cr_attr_sel_destroy (CRAttrSel *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_ATTR_SEL_H__*/
diff --git a/src/3rdparty/libcroco/cr-cascade.c b/src/3rdparty/libcroco/cr-cascade.c
new file mode 100644
index 000000000..9f8dbdf8d
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-cascade.c
@@ -0,0 +1,213 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+#include <string.h>
+#include "cr-cascade.h"
+
+#define PRIVATE(a_this) ((a_this)->priv)
+
+struct _CRCascadePriv {
+ /**
+ *the 3 style sheets of the cascade:
+ *author, user, and useragent sheet.
+ *Intended to be addressed by
+ *sheets[ORIGIN_AUTHOR] or sheets[ORIGIN_USER]
+ *of sheets[ORIGIN_UA] ;
+ */
+ CRStyleSheet *sheets[3];
+ guint ref_count;
+};
+
+/**
+ * cr_cascade_new:
+ *@a_author_sheet: the author origin style sheet. May be NULL.
+ *@a_user_sheet: the user origin style sheet. May be NULL.
+ *@a_ua_sheet: the user agent origin style sheet. May be NULL.
+ *
+ *Constructor of the #CRCascade class.
+ *Note that all three parameters of this
+ *method are ref counted and their refcount is increased.
+ *Their refcount will be decreased at the destruction of
+ *the instance of #CRCascade.
+ *So the caller should not call their destructor. The caller
+ *should call their ref/unref method instead if it wants
+ *
+ *Returns the newly built instance of CRCascade or NULL if
+ *an error arose during constrution.
+ */
+CRCascade *
+cr_cascade_new (CRStyleSheet * a_author_sheet,
+ CRStyleSheet * a_user_sheet, CRStyleSheet * a_ua_sheet)
+{
+ CRCascade *result = NULL;
+
+ result = g_try_malloc (sizeof (CRCascade));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRCascade));
+
+ PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv));
+ if (!PRIVATE (result)) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (PRIVATE (result), 0, sizeof (CRCascadePriv));
+
+ if (a_author_sheet) {
+ cr_cascade_set_sheet (result, a_author_sheet, ORIGIN_AUTHOR);
+ }
+ if (a_user_sheet) {
+ cr_cascade_set_sheet (result, a_user_sheet, ORIGIN_USER);
+ }
+ if (a_ua_sheet) {
+ cr_cascade_set_sheet (result, a_ua_sheet, ORIGIN_UA);
+ }
+
+ return result;
+}
+
+/**
+ * cr_cascade_get_sheet:
+ *@a_this: the current instance of #CRCascade.
+ *@a_origin: the origin of the style sheet as
+ *defined in the css2 spec in chapter 6.4.
+ *Gets a given origin sheet.
+ *
+ *Gets a sheet, part of the cascade.
+ *Note that the returned stylesheet
+ *is refcounted so if the caller wants
+ *to manage its lifecycle, it must use
+ *cr_stylesheet_ref()/cr_stylesheet_unref() instead
+ *of the cr_stylesheet_destroy() method.
+ *Returns the style sheet, or NULL if it does not
+ *exist.
+ */
+CRStyleSheet *
+cr_cascade_get_sheet (CRCascade * a_this, enum CRStyleOrigin a_origin)
+{
+ g_return_val_if_fail (a_this
+ && (unsigned)a_origin < NB_ORIGINS, NULL);
+
+ return PRIVATE (a_this)->sheets[a_origin];
+}
+
+/**
+ * cr_cascade_set_sheet:
+ *@a_this: the current instance of #CRCascade.
+ *@a_sheet: the stylesheet to set.
+ *@a_origin: the origin of the stylesheet.
+ *
+ *Sets a stylesheet in the cascade
+ *
+ *Returns CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_cascade_set_sheet (CRCascade * a_this,
+ CRStyleSheet * a_sheet, enum CRStyleOrigin a_origin)
+{
+ g_return_val_if_fail (a_this
+ && a_sheet
+ && (unsigned)a_origin < NB_ORIGINS, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->sheets[a_origin])
+ cr_stylesheet_unref (PRIVATE (a_this)->sheets[a_origin]);
+ PRIVATE (a_this)->sheets[a_origin] = a_sheet;
+ cr_stylesheet_ref (a_sheet);
+ a_sheet->origin = a_origin;
+ return CR_OK;
+}
+
+/**
+ *cr_cascade_ref:
+ *@a_this: the current instance of #CRCascade
+ *
+ *Increases the reference counter of the current instance
+ *of #CRCascade.
+ */
+void
+cr_cascade_ref (CRCascade * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ PRIVATE (a_this)->ref_count++;
+}
+
+/**
+ * cr_cascade_unref:
+ *@a_this: the current instance of
+ *#CRCascade.
+ *
+ *Decrements the reference counter associated
+ *to this instance of #CRCascade. If the reference
+ *counter reaches zero, the instance is destroyed
+ *using cr_cascade_destroy()
+ */
+void
+cr_cascade_unref (CRCascade * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ if (PRIVATE (a_this)->ref_count)
+ PRIVATE (a_this)->ref_count--;
+ if (!PRIVATE (a_this)->ref_count) {
+ cr_cascade_destroy (a_this);
+ }
+}
+
+/**
+ * cr_cascade_destroy:
+ * @a_this: the current instance of #CRCascade
+ *
+ * Destructor of #CRCascade.
+ */
+void
+cr_cascade_destroy (CRCascade * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (PRIVATE (a_this)) {
+ gulong i = 0;
+
+ for (i = 0; PRIVATE (a_this)->sheets && i < NB_ORIGINS; i++) {
+ if (PRIVATE (a_this)->sheets[i]) {
+ if (cr_stylesheet_unref
+ (PRIVATE (a_this)->sheets[i])
+ == TRUE) {
+ PRIVATE (a_this)->sheets[i] = NULL;
+ }
+ }
+ }
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ }
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-cascade.h b/src/3rdparty/libcroco/cr-cascade.h
new file mode 100644
index 000000000..3119ae85f
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-cascade.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_CASCADE_H__
+#define __CR_CASCADE_H__
+
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *the declaration of the #CRCascade class.
+ */
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRCascadePriv CRCascadePriv ;
+
+/**
+ *An abstraction of the "Cascade" defined
+ *in the css2 spec, chapter 6.4.
+ */
+typedef struct _CRCascade CRCascade ;
+
+struct _CRCascade
+{
+ CRCascadePriv *priv ;
+};
+
+
+CRCascade * cr_cascade_new (CRStyleSheet *a_author_sheet,
+ CRStyleSheet *a_user_sheet,
+ CRStyleSheet *a_ua_sheet) ;
+
+CRStyleSheet * cr_cascade_get_sheet (CRCascade *a_this,
+ enum CRStyleOrigin a_origin) ;
+
+enum CRStatus cr_cascade_set_sheet (CRCascade *a_this,
+ CRStyleSheet *a_sheet,
+ enum CRStyleOrigin a_origin) ;
+
+void cr_cascade_ref (CRCascade *a_this) ;
+
+void cr_cascade_unref (CRCascade *a_this) ;
+
+void cr_cascade_destroy (CRCascade *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_CASCADE_H__*/
diff --git a/src/3rdparty/libcroco/cr-declaration.c b/src/3rdparty/libcroco/cr-declaration.c
new file mode 100644
index 000000000..69c24b376
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-declaration.c
@@ -0,0 +1,804 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS file for copyright information.
+ */
+
+
+#include <string.h>
+#include "cr-declaration.h"
+#include "cr-statement.h"
+#include "cr-parser.h"
+
+/**
+ *@CRDeclaration:
+ *
+ *The definition of the #CRDeclaration class.
+ */
+
+/**
+ * dump:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white char.
+ *
+ *Dumps (serializes) one css declaration to a file.
+ */
+static void
+dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
+{
+ guchar *str = NULL;
+
+ g_return_if_fail (a_this);
+
+ str = (guchar *) cr_declaration_to_string (a_this, a_indent);
+ if (str) {
+ fprintf (a_fp, "%s", str);
+ g_free (str);
+ str = NULL;
+ }
+}
+
+/**
+ * cr_declaration_new:
+ * @a_statement: the statement this declaration belongs to. can be NULL.
+ *@a_property: the property string of the declaration
+ *@a_value: the value expression of the declaration.
+ *Constructor of #CRDeclaration.
+ *
+ *Returns the newly built instance of #CRDeclaration, or NULL in
+ *case of error.
+ *
+ *The returned CRDeclaration takes ownership of @a_property and @a_value.
+ *(E.g. cr_declaration_destroy on this CRDeclaration will also free
+ *@a_property and @a_value.)
+ */
+CRDeclaration *
+cr_declaration_new (CRStatement * a_statement,
+ CRString * a_property, CRTerm * a_value)
+{
+ CRDeclaration *result = NULL;
+
+ g_return_val_if_fail (a_property, NULL);
+
+ if (a_statement)
+ g_return_val_if_fail (a_statement
+ && ((a_statement->type == RULESET_STMT)
+ || (a_statement->type
+ == AT_FONT_FACE_RULE_STMT)
+ || (a_statement->type
+ == AT_PAGE_RULE_STMT)), NULL);
+
+ result = g_try_malloc (sizeof (CRDeclaration));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRDeclaration));
+ result->property = a_property;
+ result->value = a_value;
+
+ if (a_value) {
+ cr_term_ref (a_value);
+ }
+ result->parent_statement = a_statement;
+ return result;
+}
+
+/**
+ * cr_declaration_parse_from_buf:
+ *@a_statement: the parent css2 statement of this
+ *this declaration. Must be non NULL and of type
+ *RULESET_STMT (must be a ruleset).
+ *@a_str: the string that contains the statement.
+ *@a_enc: the encoding of a_str.
+ *
+ *Parses a text buffer that contains
+ *a css declaration.
+ *Returns the parsed declaration, or NULL in case of error.
+ */
+CRDeclaration *
+cr_declaration_parse_from_buf (CRStatement * a_statement,
+ const guchar * a_str, enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_OK;
+ CRTerm *value = NULL;
+ CRString *property = NULL;
+ CRDeclaration *result = NULL;
+ CRParser *parser = NULL;
+ gboolean important = FALSE;
+
+ g_return_val_if_fail (a_str, NULL);
+ if (a_statement)
+ g_return_val_if_fail (a_statement->type == RULESET_STMT,
+ NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
+ g_return_val_if_fail (parser, NULL);
+
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_declaration (parser, &property,
+ &value, &important);
+ if (status != CR_OK || !property)
+ goto cleanup;
+
+ result = cr_declaration_new (a_statement, property, value);
+ if (result) {
+ property = NULL;
+ value = NULL;
+ result->important = important;
+ }
+
+ cleanup:
+
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+
+ if (value) {
+ cr_term_destroy (value);
+ value = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_declaration_parse_list_from_buf:
+ *@a_str: the input buffer that contains the list of declaration to
+ *parse.
+ *@a_enc: the encoding of a_str
+ *
+ *Parses a ';' separated list of properties declaration.
+ *Returns the parsed list of declaration, NULL if parsing failed.
+ */
+CRDeclaration *
+cr_declaration_parse_list_from_buf (const guchar * a_str,
+ enum CREncoding a_enc)
+{
+
+ enum CRStatus status = CR_OK;
+ CRTerm *value = NULL;
+ CRString *property = NULL;
+ CRDeclaration *result = NULL,
+ *cur_decl = NULL;
+ CRParser *parser = NULL;
+ CRTknzr *tokenizer = NULL;
+ gboolean important = FALSE;
+
+ g_return_val_if_fail (a_str, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
+ g_return_val_if_fail (parser, NULL);
+ status = cr_parser_get_tknzr (parser, &tokenizer);
+ if (status != CR_OK || !tokenizer) {
+ if (status == CR_OK)
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_declaration (parser, &property,
+ &value, &important);
+ if (status != CR_OK || !property) {
+ if (status != CR_OK)
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ result = cr_declaration_new (NULL, property, value);
+ if (result) {
+ property = NULL;
+ value = NULL;
+ result->important = important;
+ }
+ /*now, go parse the other declarations */
+ for (;;) {
+ guint32 c = 0;
+
+ cr_parser_try_to_skip_spaces_and_comments (parser);
+ status = cr_tknzr_peek_char (tokenizer, &c);
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR)
+ status = CR_OK;
+ goto cleanup;
+ }
+ if (c == ';') {
+ status = cr_tknzr_read_char (tokenizer, &c);
+ } else {
+ cr_tknzr_read_char (tokenizer, &c);
+ continue; // try to keep reading until we reach the end or a ;
+ }
+ important = FALSE;
+ cr_parser_try_to_skip_spaces_and_comments (parser);
+ status = cr_parser_parse_declaration (parser, &property,
+ &value, &important);
+ if (status != CR_OK || !property) {
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK; // simply the end of input, do not delete what we got so far, just finish
+ break;
+ } else {
+ continue; // even if one declaration is broken, it's no reason to discard others (see http://www.w3.org/TR/CSS21/syndata.html#declaration)
+ }
+ }
+ cur_decl = cr_declaration_new (NULL, property, value);
+ if (cur_decl) {
+ cur_decl->important = important;
+ result = cr_declaration_append (result, cur_decl);
+ property = NULL;
+ value = NULL;
+ cur_decl = NULL;
+ } else {
+ break;
+ }
+ }
+
+ cleanup:
+
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+
+ if (value) {
+ cr_term_destroy (value);
+ value = NULL;
+ }
+
+ if (status != CR_OK && result) {
+ cr_declaration_destroy (result);
+ result = NULL;
+ }
+ return result;
+}
+
+/**
+ * cr_declaration_append:
+ *@a_this: the current declaration list.
+ *@a_new: the declaration to append.
+ *
+ *Appends a new declaration to the current declarations list.
+ *Returns the declaration list with a_new appended to it, or NULL
+ *in case of error.
+ */
+CRDeclaration *
+cr_declaration_append (CRDeclaration * a_this, CRDeclaration * a_new)
+{
+ CRDeclaration *cur = NULL;
+
+ g_return_val_if_fail (a_new, NULL);
+
+ if (!a_this)
+ return a_new;
+
+ for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+ cur->next = a_new;
+ a_new->prev = cur;
+
+ return a_this;
+}
+
+/**
+ * cr_declaration_unlink:
+ *@a_decls: the declaration to unlink.
+ *
+ *Unlinks the declaration from the declaration list.
+ *case of a successfull completion, NULL otherwise.
+ *
+ *Returns a pointer to the unlinked declaration in
+ */
+CRDeclaration *
+cr_declaration_unlink (CRDeclaration * a_decl)
+{
+ CRDeclaration *result = a_decl;
+
+ g_return_val_if_fail (result, NULL);
+
+ /*
+ *some sanity checks first
+ */
+ if (a_decl->prev) {
+ g_return_val_if_fail (a_decl->prev->next == a_decl, NULL);
+
+ }
+ if (a_decl->next) {
+ g_return_val_if_fail (a_decl->next->prev == a_decl, NULL);
+ }
+
+ /*
+ *now, the real unlinking job.
+ */
+ if (a_decl->prev) {
+ a_decl->prev->next = a_decl->next;
+ }
+ if (a_decl->next) {
+ a_decl->next->prev = a_decl->prev;
+ }
+ if (a_decl->parent_statement) {
+ CRDeclaration **children_decl_ptr = NULL;
+
+ switch (a_decl->parent_statement->type) {
+ case RULESET_STMT:
+ if (a_decl->parent_statement->kind.ruleset) {
+ children_decl_ptr =
+ &a_decl->parent_statement->
+ kind.ruleset->decl_list;
+ }
+
+ break;
+
+ case AT_FONT_FACE_RULE_STMT:
+ if (a_decl->parent_statement->kind.font_face_rule) {
+ children_decl_ptr =
+ &a_decl->parent_statement->
+ kind.font_face_rule->decl_list;
+ }
+ break;
+ case AT_PAGE_RULE_STMT:
+ if (a_decl->parent_statement->kind.page_rule) {
+ children_decl_ptr =
+ &a_decl->parent_statement->
+ kind.page_rule->decl_list;
+ }
+
+ default:
+ break;
+ }
+ if (children_decl_ptr
+ && *children_decl_ptr && *children_decl_ptr == a_decl)
+ *children_decl_ptr = (*children_decl_ptr)->next;
+ }
+
+ a_decl->next = NULL;
+ a_decl->prev = NULL;
+ a_decl->parent_statement = NULL;
+
+ return result;
+}
+
+/**
+ * cr_declaration_prepend:
+ * @a_this: the current declaration list.
+ * @a_new: the declaration to prepend.
+ *
+ * prepends a declaration to the current declaration list.
+ *
+ * Returns the list with a_new prepended or NULL in case of error.
+ */
+CRDeclaration *
+cr_declaration_prepend (CRDeclaration * a_this, CRDeclaration * a_new)
+{
+ CRDeclaration *cur = NULL;
+
+ g_return_val_if_fail (a_new, NULL);
+
+ if (!a_this)
+ return a_new;
+
+ a_this->prev = a_new;
+ a_new->next = a_this;
+
+ for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+ return cur;
+}
+
+/**
+ * cr_declaration_append2:
+ *@a_this: the current declaration list.
+ *@a_prop: the property string of the declaration to append.
+ *@a_value: the value of the declaration to append.
+ *
+ *Appends a declaration to the current declaration list.
+ *Returns the list with the new property appended to it, or NULL in
+ *case of an error.
+ */
+CRDeclaration *
+cr_declaration_append2 (CRDeclaration * a_this,
+ CRString * a_prop, CRTerm * a_value)
+{
+ CRDeclaration *new_elem = NULL;
+
+ if (a_this) {
+ new_elem = cr_declaration_new (a_this->parent_statement,
+ a_prop, a_value);
+ } else {
+ new_elem = cr_declaration_new (NULL, a_prop, a_value);
+ }
+
+ g_return_val_if_fail (new_elem, NULL);
+
+ return cr_declaration_append (a_this, new_elem);
+}
+
+/**
+ * cr_declaration_dump:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file.
+ *@a_indent: the number of indentation white char.
+ *@a_one_per_line: whether to put one declaration per line of not .
+ *
+ *
+ *Dumps a declaration list to a file.
+ */
+void
+cr_declaration_dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent,
+ gboolean a_one_per_line)
+{
+ CRDeclaration const *cur = NULL;
+
+ g_return_if_fail (a_this);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ if (cur->prev) {
+ if (a_one_per_line == TRUE)
+ fprintf (a_fp, ";\n");
+ else
+ fprintf (a_fp, "; ");
+ }
+ dump (cur, a_fp, a_indent);
+ }
+}
+
+/**
+ * cr_declaration_dump_one:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_fp: the destination file.
+ *@a_indent: the number of indentation white char.
+ *
+ *Dumps the first declaration of the declaration list to a file.
+ */
+void
+cr_declaration_dump_one (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
+{
+ g_return_if_fail (a_this);
+
+ dump (a_this, a_fp, a_indent);
+}
+
+/**
+ * cr_declaration_to_string:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration into a string
+ *Returns the serialized form the declaration. The caller must
+ *free the string using g_free().
+ */
+gchar *
+cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent)
+{
+ GString *stringue = NULL;
+
+ gchar *str = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ stringue = g_string_new (NULL);
+
+ if (a_this->property
+ && a_this->property->stryng
+ && a_this->property->stryng->str) {
+ str = g_strndup (a_this->property->stryng->str,
+ a_this->property->stryng->len);
+ if (str) {
+ cr_utils_dump_n_chars2 (' ', stringue,
+ a_indent);
+ g_string_append (stringue, str);
+ g_free (str);
+ str = NULL;
+ } else
+ goto error;
+
+ if (a_this->value) {
+ guchar *value_str = NULL;
+
+ value_str = cr_term_to_string (a_this->value);
+ if (value_str) {
+ g_string_append_printf (stringue, " : %s",
+ value_str);
+ g_free (value_str);
+ } else
+ goto error;
+ }
+ if (a_this->important == TRUE) {
+ g_string_append_printf (stringue, " %s",
+ "!important");
+ }
+ }
+ if (stringue && stringue->str) {
+ result = stringue->str;
+ g_string_free (stringue, FALSE);
+ }
+ return result;
+
+ error:
+ if (stringue) {
+ g_string_free (stringue, TRUE);
+ stringue = NULL;
+ }
+ if (str) {
+ g_free (str);
+ str = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_declaration_list_to_string:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration list into a string
+ */
+guchar *
+cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent)
+{
+ CRDeclaration const *cur = NULL;
+ GString *stringue = NULL;
+ guchar *str = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ stringue = g_string_new (NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ str = (guchar *) cr_declaration_to_string (cur, a_indent);
+ if (str) {
+ g_string_append_printf (stringue, "%s;", str);
+ g_free (str);
+ } else
+ break;
+ }
+ if (stringue && stringue->str) {
+ result = (guchar *) stringue->str;
+ g_string_free (stringue, FALSE);
+ }
+
+ return result;
+}
+
+/**
+ * cr_declaration_list_to_string2:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_indent: the number of indentation white char
+ *@a_one_decl_per_line: whether to output one doc per line or not.
+ *to put before the actual serialisation.
+ *
+ *Serializes the declaration list into a string
+ *Returns the serialized form the declararation.
+ */
+guchar *
+cr_declaration_list_to_string2 (CRDeclaration const * a_this,
+ gulong a_indent, gboolean a_one_decl_per_line)
+{
+ CRDeclaration const *cur = NULL;
+ GString *stringue = NULL;
+ guchar *str = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ stringue = g_string_new (NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ str = (guchar *) cr_declaration_to_string (cur, a_indent);
+ if (str) {
+ if (a_one_decl_per_line == TRUE) {
+ if (cur->next)
+ g_string_append_printf (stringue,
+ "%s;\n", str);
+ else
+ g_string_append (stringue,
+ (const gchar *) str);
+ } else {
+ if (cur->next)
+ g_string_append_printf (stringue,
+ "%s;", str);
+ else
+ g_string_append (stringue,
+ (const gchar *) str);
+ }
+ g_free (str);
+ } else
+ break;
+ }
+ if (stringue && stringue->str) {
+ result = (guchar *) stringue->str;
+ g_string_free (stringue, FALSE);
+ }
+
+ return result;
+}
+
+/**
+ * cr_declaration_nr_props:
+ *@a_this: the current instance of #CRDeclaration.
+ *Return the number of properties in the declaration
+ */
+gint
+cr_declaration_nr_props (CRDeclaration const * a_this)
+{
+ CRDeclaration const *cur = NULL;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, -1);
+
+ for (cur = a_this; cur; cur = cur->next)
+ nr++;
+ return nr;
+}
+
+/**
+ * cr_declaration_get_from_list:
+ *@a_this: the current instance of #CRDeclaration.
+ *@itemnr: the index into the declaration list.
+ *
+ *Use an index to get a CRDeclaration from the declaration list.
+ *
+ *Returns #CRDeclaration at position itemnr,
+ *if itemnr > number of declarations - 1,
+ *it will return NULL.
+ */
+CRDeclaration *
+cr_declaration_get_from_list (CRDeclaration * a_this, int itemnr)
+{
+ CRDeclaration *cur = NULL;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ for (cur = a_this; cur; cur = cur->next)
+ if (nr++ == itemnr)
+ return cur;
+ return NULL;
+}
+
+/**
+ * cr_declaration_get_by_prop_name:
+ *@a_this: the current instance of #CRDeclaration.
+ *@a_prop: the property name to search for.
+ *
+ *Use property name to get a CRDeclaration from the declaration list.
+ *Returns #CRDeclaration with property name a_prop, or NULL if not found.
+ */
+CRDeclaration *
+cr_declaration_get_by_prop_name (CRDeclaration * a_this,
+ const guchar * a_prop)
+{
+ CRDeclaration *cur = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+ g_return_val_if_fail (a_prop, NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ if (cur->property
+ && cur->property->stryng
+ && cur->property->stryng->str) {
+ if (!strcmp (cur->property->stryng->str,
+ (const char *) a_prop)) {
+ return cur;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * cr_declaration_ref:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Increases the ref count of the current instance of #CRDeclaration.
+ */
+void
+cr_declaration_ref (CRDeclaration * a_this)
+{
+ g_return_if_fail (a_this);
+
+ a_this->ref_count++;
+}
+
+/**
+ * cr_declaration_unref:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Decrements the ref count of the current instance of #CRDeclaration.
+ *If the ref count reaches zero, the current instance of #CRDeclaration
+ *if destroyed.
+ *Returns TRUE if @a_this was destroyed (ref count reached zero),
+ *FALSE otherwise.
+ */
+gboolean
+cr_declaration_unref (CRDeclaration * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count) {
+ a_this->ref_count--;
+ }
+
+ if (a_this->ref_count == 0) {
+ cr_declaration_destroy (a_this);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * cr_declaration_destroy:
+ *@a_this: the current instance of #CRDeclaration.
+ *
+ *Destructor of the declaration list.
+ */
+void
+cr_declaration_destroy (CRDeclaration * a_this)
+{
+ CRDeclaration *cur = NULL;
+
+ g_return_if_fail (a_this);
+
+ /*
+ * Go to the last element of the list.
+ */
+ for (cur = a_this; cur->next; cur = cur->next)
+ g_assert (cur->next->prev == cur);
+
+ /*
+ * Walk backward the list and free each "next" element.
+ * Meanwhile, free each property/value pair contained in the list.
+ */
+ for (; cur; cur = cur->prev) {
+ g_free (cur->next);
+ cur->next = NULL;
+
+ if (cur->property) {
+ cr_string_destroy (cur->property);
+ cur->property = NULL;
+ }
+
+ if (cur->value) {
+ cr_term_destroy (cur->value);
+ cur->value = NULL;
+ }
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-declaration.h b/src/3rdparty/libcroco/cr-declaration.h
new file mode 100644
index 000000000..eee8be321
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-declaration.h
@@ -0,0 +1,136 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_DECLARATION_H__
+#define __CR_DECLARATION_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRDeclaration class.
+ */
+
+/*forward declaration of what is defined in cr-statement.h*/
+typedef struct _CRStatement CRStatement ;
+
+/**
+ *The abstraction of a css declaration defined by the
+ *css2 spec in chapter 4.
+ *It is actually a chained list of property/value pairs.
+ */
+typedef struct _CRDeclaration CRDeclaration ;
+struct _CRDeclaration
+{
+ /**The property.*/
+ CRString *property ;
+
+ /**The value of the property.*/
+ CRTerm *value ;
+
+ /*the ruleset that contains this declaration*/
+ CRStatement *parent_statement ;
+
+ /*the next declaration*/
+ CRDeclaration *next ;
+
+ /*the previous one declaration*/
+ CRDeclaration *prev ;
+
+ /*does the declaration have the important keyword ?*/
+ gboolean important ;
+
+ glong ref_count ;
+
+ CRParsingLocation location ;
+ /*reserved for future usage*/
+ gpointer rfu0 ;
+ gpointer rfu1 ;
+ gpointer rfu2 ;
+ gpointer rfu3 ;
+} ;
+
+
+CRDeclaration * cr_declaration_new (CRStatement *a_statement,
+ CRString *a_property,
+ CRTerm *a_value) ;
+
+
+CRDeclaration * cr_declaration_parse_from_buf (CRStatement *a_statement,
+ const guchar *a_str,
+ enum CREncoding a_enc) ;
+
+CRDeclaration * cr_declaration_parse_list_from_buf (const guchar *a_str,
+ enum CREncoding a_enc) ;
+
+CRDeclaration * cr_declaration_append (CRDeclaration *a_this,
+ CRDeclaration *a_new) ;
+
+CRDeclaration * cr_declaration_append2 (CRDeclaration *a_this,
+ CRString *a_prop,
+ CRTerm *a_value) ;
+
+CRDeclaration * cr_declaration_prepend (CRDeclaration *a_this,
+ CRDeclaration *a_new) ;
+
+CRDeclaration * cr_declaration_unlink (CRDeclaration * a_decl) ;
+
+void
+cr_declaration_dump (CRDeclaration const *a_this,
+ FILE *a_fp, glong a_indent,
+ gboolean a_one_per_line) ;
+
+void cr_declaration_dump_one (CRDeclaration const *a_this,
+ FILE *a_fp, glong a_indent) ;
+
+gint cr_declaration_nr_props (CRDeclaration const *a_this) ;
+
+CRDeclaration * cr_declaration_get_from_list (CRDeclaration *a_this,
+ int itemnr) ;
+
+CRDeclaration * cr_declaration_get_by_prop_name (CRDeclaration *a_this,
+ const guchar *a_str) ;
+
+gchar * cr_declaration_to_string (CRDeclaration const *a_this,
+ gulong a_indent) ;
+
+guchar * cr_declaration_list_to_string (CRDeclaration const *a_this,
+ gulong a_indent) ;
+
+guchar * cr_declaration_list_to_string2 (CRDeclaration const *a_this,
+ gulong a_indent,
+ gboolean a_one_decl_per_line) ;
+
+void cr_declaration_ref (CRDeclaration *a_this) ;
+
+gboolean cr_declaration_unref (CRDeclaration *a_this) ;
+
+void cr_declaration_destroy (CRDeclaration *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DECLARATION_H__*/
diff --git a/src/3rdparty/libcroco/cr-doc-handler.c b/src/3rdparty/libcroco/cr-doc-handler.c
new file mode 100644
index 000000000..bbb158298
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-doc-handler.c
@@ -0,0 +1,276 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPRYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-doc-handler.h"
+#include "cr-parser.h"
+
+/**
+ *@CRDocHandler:
+ *
+ *The definition of the CRDocHandler class.
+ *Contains methods to instantiate, destroy,
+ *and initialyze instances of #CRDocHandler
+ *to custom values.
+ */
+
+#define PRIVATE(obj) (obj)->priv
+
+struct _CRDocHandlerPriv {
+ /**
+ *This pointer is to hold an application parsing context.
+ *For example, it used by the Object Model parser to
+ *store it parsing context. #CRParser does not touch it, but
+ *#CROMParser does. #CROMParser allocates this pointer at
+ *the beginning of the css document, and frees it at the end
+ *of the document.
+ */
+ gpointer context;
+
+ /**
+ *The place where #CROMParser puts the result of its parsing, if
+ *any.
+ */
+ gpointer result;
+ /**
+ *a pointer to the parser used to parse
+ *the current document.
+ */
+ CRParser *parser ;
+};
+
+/**
+ * cr_doc_handler_new:
+ *Constructor of #CRDocHandler.
+ *
+ *Returns the newly built instance of
+ *#CRDocHandler
+ *
+ */
+CRDocHandler *
+cr_doc_handler_new (void)
+{
+ CRDocHandler *result = NULL;
+
+ result = g_try_malloc (sizeof (CRDocHandler));
+
+ g_return_val_if_fail (result, NULL);
+
+ memset (result, 0, sizeof (CRDocHandler));
+ result->ref_count++;
+
+ result->priv = g_try_malloc (sizeof (CRDocHandlerPriv));
+ if (!result->priv) {
+ cr_utils_trace_info ("Out of memory exception");
+ g_free (result);
+ return NULL;
+ }
+
+ cr_doc_handler_set_default_sac_handler (result);
+
+ return result;
+}
+
+/**
+ * cr_doc_handler_get_ctxt:
+ *@a_this: the current instance of #CRDocHandler.
+ *@a_ctxt: out parameter. The new parsing context.
+ *
+ *Gets the private parsing context associated to the document handler
+ *The private parsing context is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_get_ctxt (CRDocHandler const * a_this, gpointer * a_ctxt)
+{
+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+
+ *a_ctxt = a_this->priv->context;
+
+ return CR_OK;
+}
+
+/**
+ * cr_doc_handler_set_ctxt:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_ctxt: a pointer to the parsing context.
+ *
+ *Sets the private parsing context.
+ *This is used by libcroco only.
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_ctxt (CRDocHandler * a_this, gpointer a_ctxt)
+{
+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+ a_this->priv->context = a_ctxt;
+ return CR_OK;
+}
+
+/**
+ * cr_doc_handler_get_result:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_result: out parameter. The returned result.
+ *
+ *Gets the private parsing result.
+ *The private parsing result is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_get_result (CRDocHandler const * a_this, gpointer * a_result)
+{
+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+
+ *a_result = a_this->priv->result;
+
+ return CR_OK;
+}
+
+/**
+ * cr_doc_handler_set_result:
+ *@a_this: the current instance of #CRDocHandler
+ *@a_result: the new result.
+ *
+ *Sets the private parsing context.
+ *This is used by libcroco only.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_result (CRDocHandler * a_this, gpointer a_result)
+{
+ g_return_val_if_fail (a_this && a_this->priv, CR_BAD_PARAM_ERROR);
+ a_this->priv->result = a_result;
+ return CR_OK;
+}
+
+/**
+ *cr_doc_handler_set_default_sac_handler:
+ *@a_this: a pointer to the current instance of #CRDocHandler.
+ *
+ *Sets the sac handlers contained in the current
+ *instance of DocHandler to the default handlers.
+ *For the time being the default handlers are
+ *test handlers. This is expected to change in a
+ *near future, when the libcroco gets a bit debugged.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_doc_handler_set_default_sac_handler (CRDocHandler * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ a_this->start_document = NULL;
+ a_this->end_document = NULL;
+ a_this->import_style = NULL;
+ a_this->namespace_declaration = NULL;
+ a_this->comment = NULL;
+ a_this->start_selector = NULL;
+ a_this->end_selector = NULL;
+ a_this->property = NULL;
+ a_this->start_font_face = NULL;
+ a_this->end_font_face = NULL;
+ a_this->start_media = NULL;
+ a_this->end_media = NULL;
+ a_this->start_page = NULL;
+ a_this->end_page = NULL;
+ a_this->ignorable_at_rule = NULL;
+ a_this->error = NULL;
+ a_this->unrecoverable_error = NULL;
+ return CR_OK;
+}
+
+/**
+ * cr_doc_handler_ref:
+ *@a_this: the current instance of #CRDocHandler.
+ */
+void
+cr_doc_handler_ref (CRDocHandler * a_this)
+{
+ g_return_if_fail (a_this);
+
+ a_this->ref_count++;
+}
+
+/**
+ * cr_doc_handler_unref:
+ *@a_this: the currrent instance of #CRDocHandler.
+ *
+ *Decreases the ref count of the current instance of #CRDocHandler.
+ *If the ref count reaches '0' then, destroys the instance.
+ *
+ *Returns TRUE if the instance as been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_doc_handler_unref (CRDocHandler * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count > 0) {
+ a_this->ref_count--;
+ }
+
+ if (a_this->ref_count == 0) {
+ cr_doc_handler_destroy (a_this);
+ return TRUE;
+ }
+ return FALSE ;
+}
+
+/**
+ * cr_doc_handler_destroy:
+ *@a_this: the instance of #CRDocHandler to
+ *destroy.
+ *
+ *The destructor of the #CRDocHandler class.
+ */
+void
+cr_doc_handler_destroy (CRDocHandler * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->priv) {
+ g_free (a_this->priv);
+ a_this->priv = NULL;
+ }
+ g_free (a_this);
+}
+
+/**
+ * cr_doc_handler_associate_a_parser:
+ *Associates a parser to the current document handler
+ *
+ *@a_this: the current instance of document handler.
+ *@a_parser: the parser to associate.
+ */
+void
+cr_doc_handler_associate_a_parser (CRDocHandler *a_this,
+ gpointer a_parser)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this)
+ && a_parser) ;
+
+ PRIVATE (a_this)->parser = a_parser ;
+}
diff --git a/src/3rdparty/libcroco/cr-doc-handler.h b/src/3rdparty/libcroco/cr-doc-handler.h
new file mode 100644
index 000000000..d12673f31
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-doc-handler.h
@@ -0,0 +1,298 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_DOC_HANDLER_H__
+#define __CR_DOC_HANDLER_H__
+
+/**
+ *@file
+ *The declaration of the #CRDocumentHandler class.
+ *This class is actually the parsing events handler.
+ */
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-stylesheet.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRDocHandler CRDocHandler ;
+
+struct _CRDocHandlerPriv ;
+typedef struct _CRDocHandlerPriv CRDocHandlerPriv ;
+
+
+/**
+ *The SAC document handler.
+ *An instance of this class is to
+ *be passed to a parser. Then, during the parsing
+ *the parser calls the convenient function pointer
+ *whenever a particular event (a css construction) occurs.
+ */
+struct _CRDocHandler
+{
+ CRDocHandlerPriv *priv ;
+
+ /**
+ *This pointer is to be used by the application for
+ *it custom needs. It is there to extend the doc handler.
+ */
+ gpointer app_data ;
+
+ /**
+ *Is called at the beginning of the parsing of the document.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*start_document) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify the end of the parsing of the document.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*end_document) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify an at charset rule.
+ *@param a_this the document handler.
+ *@param a_charset the declared charset.
+ */
+ void (*charset) (CRDocHandler *a_this,
+ CRString *a_charset,
+ CRParsingLocation *a_charset_sym_location) ;
+
+ /**
+ *Is called to notify an import statement in
+ *the stylesheet.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_media_list a doubly linked list of GString objects.
+ *Each GString object contains a string which is the
+ *destination media for style information.
+ *@param a_uri the uri of the imported style sheet.
+ *@param a_uri_default_ns the default namespace of URI
+ *@param a_location the parsing location of the '\@import'
+ *keyword.
+ *of the imported style sheet.
+ */
+ void (*import_style) (CRDocHandler *a_this,
+ GList *a_media_list,
+ CRString *a_uri,
+ CRString *a_uri_default_ns,
+ CRParsingLocation *a_location) ;
+
+ void (*import_style_result) (CRDocHandler *a_this,
+ GList *a_media_list,
+ CRString *a_uri,
+ CRString *a_uri_default_ns,
+ CRStyleSheet *a_sheet) ;
+
+ /**
+ *Is called to notify a namespace declaration.
+ *Not used yet.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_prefix the prefix of the namespace.
+ *@param a_uri the uri of the namespace.
+ *@param a_location the location of the "@namespace" keyword.
+ */
+ void (*namespace_declaration) (CRDocHandler *a_this,
+ CRString *a_prefix,
+ CRString *a_uri,
+ CRParsingLocation *a_location) ;
+
+ /**
+ *Is called to notify a comment.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_comment the comment.
+ */
+ void (*comment) (CRDocHandler *a_this,
+ CRString *a_comment) ;
+
+ /**
+ *Is called to notify the beginning of a rule
+ *statement.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_selector_list the list of selectors that precedes
+ *the rule declarations.
+ */
+ void (*start_selector) (CRDocHandler * a_this,
+ CRSelector *a_selector_list) ;
+
+ /**
+ *Is called to notify the end of a rule statement.
+ *@param a_this the current instance of #CRDocHandler.
+ *@param a_selector_list the list of selectors that precedes
+ *the rule declarations. This pointer is the same as
+ *the one passed to start_selector() ;
+ */
+ void (*end_selector) (CRDocHandler *a_this,
+ CRSelector *a_selector_list) ;
+
+
+ /**
+ *Is called to notify a declaration.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_name the name of the parsed property.
+ *@param a_expression a css expression that represents
+ *the value of the property. A css expression is
+ *actually a linked list of 'terms'. Each term can
+ *be linked to other using operators.
+ *
+ */
+ void (*property) (CRDocHandler *a_this,
+ CRString *a_name,
+ CRTerm *a_expression,
+ gboolean a_is_important) ;
+ /**
+ *Is called to notify the start of a font face statement.
+ *The parser invokes this method at the beginning of every
+ *font face statement in the style sheet. There will
+ *be a corresponding end_font_face () event for every
+ *start_font_face () event.
+ *
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_location the parsing location of the "\@font-face"
+ *keyword.
+ */
+ void (*start_font_face) (CRDocHandler *a_this,
+ CRParsingLocation *a_location) ;
+
+ /**
+ *Is called to notify the end of a font face statement.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ */
+ void (*end_font_face) (CRDocHandler *a_this) ;
+
+
+ /**
+ *Is called to notify the beginning of a media statement.
+ *The parser will invoke this method at the beginning of
+ *every media statement in the style sheet. There will be
+ *a corresponding end_media() event for every start_media()
+ *event.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_media_list a double linked list of
+ #CRString * objects.
+ *Each CRString objects is actually a destination media for
+ *the style information.
+ */
+ void (*start_media) (CRDocHandler *a_this,
+ GList *a_media_list,
+ CRParsingLocation *a_location) ;
+
+ /**
+ *Is called to notify the end of a media statement.
+ *@param a_this a pointer to the current instance
+ *of #CRDocHandler.
+ *@param a_media_list a double linked list of GString * objects.
+ *Each GString objects is actually a destination media for
+ *the style information.
+ */
+ void (*end_media) (CRDocHandler *a_this,
+ GList *a_media_list) ;
+
+ /**
+ *Is called to notify the beginning of a page statement.
+ *The parser invokes this function at the beginning of
+ *every page statement in the style sheet. There will be
+ *a corresponding end_page() event for every single
+ *start_page() event.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_name the name of the page (if any, null otherwise).
+ *@param a_pseudo_page the pseudo page (if any, null otherwise).
+ *@param a_location the parsing location of the "\@page" keyword.
+ */
+ void (*start_page) (CRDocHandler *a_this,
+ CRString *a_name,
+ CRString *a_pseudo_page,
+ CRParsingLocation *a_location) ;
+
+ /**
+ *Is called to notify the end of a page statement.
+ *@param a_this a pointer to the current instance of
+ *#CRDocHandler.
+ *@param a_name the name of the page (if any, null otherwise).
+ *@param a_pseudo_page the pseudo page (if any, null otherwise).
+ */
+ void (*end_page) (CRDocHandler *a_this,
+ CRString *a_name,
+ CRString *pseudo_page) ;
+
+ /**
+ *Is Called to notify an unknown at-rule not supported
+ *by this parser.
+ */
+ void (*ignorable_at_rule) (CRDocHandler *a_this,
+ CRString *a_name) ;
+
+ /**
+ *Is called to notify a parsing error. After this error
+ *the application must ignore the rule being parsed, if
+ *any. After completion of this callback,
+ *the parser will then try to resume the parsing,
+ *ignoring the current error.
+ */
+ void (*error) (CRDocHandler *a_this) ;
+
+ /**
+ *Is called to notify an unrecoverable parsing error.
+ *This is the place to put emergency routines that free allocated
+ *resources.
+ */
+ void (*unrecoverable_error) (CRDocHandler *a_this) ;
+
+ gboolean resolve_import ;
+ gulong ref_count ;
+} ;
+
+CRDocHandler * cr_doc_handler_new (void) ;
+
+enum CRStatus cr_doc_handler_set_result (CRDocHandler *a_this, gpointer a_result) ;
+
+enum CRStatus cr_doc_handler_get_result (CRDocHandler const *a_this, gpointer * a_result) ;
+
+enum CRStatus cr_doc_handler_set_ctxt (CRDocHandler *a_this, gpointer a_ctxt) ;
+
+enum CRStatus cr_doc_handler_get_ctxt (CRDocHandler const *a_this, gpointer * a_ctxt) ;
+
+enum CRStatus cr_doc_handler_set_default_sac_handler (CRDocHandler *a_this) ;
+
+void cr_doc_handler_associate_a_parser (CRDocHandler *a_this,
+ gpointer a_parser) ;
+
+void cr_doc_handler_ref (CRDocHandler *a_this) ;
+
+gboolean cr_doc_handler_unref (CRDocHandler *a_this) ;
+
+void cr_doc_handler_destroy (CRDocHandler *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_DOC_HANDLER_H__*/
diff --git a/src/3rdparty/libcroco/cr-enc-handler.c b/src/3rdparty/libcroco/cr-enc-handler.c
new file mode 100644
index 000000000..a7c4269ad
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-enc-handler.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file
+ *The definition of the #CREncHandler class.
+ */
+
+#include "cr-enc-handler.h"
+#include "cr-utils.h"
+
+#include <string.h>
+
+struct CREncAlias {
+ const gchar *name;
+ enum CREncoding encoding;
+};
+
+static struct CREncAlias gv_default_aliases[] = {
+ {"UTF-8", CR_UTF_8},
+ {"UTF_8", CR_UTF_8},
+ {"UTF8", CR_UTF_8},
+ {"UTF-16", CR_UTF_16},
+ {"UTF_16", CR_UTF_16},
+ {"UTF16", CR_UTF_16},
+ {"UCS1", CR_UCS_1},
+ {"UCS-1", CR_UCS_1},
+ {"UCS_1", CR_UCS_1},
+ {"ISO-8859-1", CR_UCS_1},
+ {"ISO_8859-1", CR_UCS_1},
+ {"UCS-1", CR_UCS_1},
+ {"UCS_1", CR_UCS_1},
+ {"UCS4", CR_UCS_4},
+ {"UCS-4", CR_UCS_4},
+ {"UCS_4", CR_UCS_4},
+ {"ASCII", CR_ASCII},
+ {0, 0}
+};
+
+static CREncHandler gv_default_enc_handlers[] = {
+ {CR_UCS_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {CR_ISO_8859_1, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {CR_ASCII, cr_utils_ucs1_to_utf8, cr_utils_utf8_to_ucs1,
+ cr_utils_ucs1_str_len_as_utf8, cr_utils_utf8_str_len_as_ucs1},
+
+ {0, NULL, NULL, NULL, NULL}
+};
+
+/**
+ * cr_enc_handler_get_instance:
+ *@a_enc: the encoding of the Handler.
+ *
+ *Gets the instance of encoding handler.
+ *This function implements a singleton pattern.
+ *
+ *Returns the instance of #CREncHandler.
+ */
+CREncHandler *
+cr_enc_handler_get_instance (enum CREncoding a_enc)
+{
+ gulong i = 0;
+
+ for (i = 0; gv_default_enc_handlers[i].encoding; i++) {
+ if (gv_default_enc_handlers[i].encoding == a_enc) {
+ return (CREncHandler *) & gv_default_enc_handlers[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * cr_enc_handler_resolve_enc_alias:
+ *@a_alias_name: the encoding name.
+ *@a_enc: output param. The returned encoding type
+ *or 0 if the alias is not supported.
+ *
+ *Given an encoding name (called an alias name)
+ *the function returns the matching encoding type.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name,
+ enum CREncoding *a_enc)
+{
+ gulong i = 0;
+ guchar *alias_name_up = NULL;
+ enum CRStatus status = CR_ENCODING_NOT_FOUND_ERROR;
+
+ g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR);
+
+ alias_name_up = (guchar *) g_ascii_strup ((const gchar *) a_alias_name, -1);
+
+ for (i = 0; gv_default_aliases[i].name; i++) {
+ if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) {
+ *a_enc = gv_default_aliases[i].encoding;
+ status = CR_OK;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * cr_enc_handler_convert_input:
+ *@a_this: the current instance of #CREncHandler.
+ *@a_in: the input buffer to convert.
+ *@a_in_len: in/out parameter. The len of the input
+ *buffer to convert. After return, contains the number of
+ *bytes actually consumed.
+ *@a_out: output parameter. The converted output buffer.
+ *Must be freed by the buffer.
+ *@a_out_len: output parameter. The length of the output buffer.
+ *
+ *Converts a raw input buffer into an utf8 buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_enc_handler_convert_input (CREncHandler * a_this,
+ const guchar * a_in,
+ gulong * a_in_len,
+ guchar ** a_out, gulong * a_out_len)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && a_in && a_in_len && a_out,
+ CR_BAD_PARAM_ERROR);
+
+ if (a_this->decode_input == NULL)
+ return CR_OK;
+
+ if (a_this->enc_str_len_as_utf8) {
+ status = a_this->enc_str_len_as_utf8 (a_in,
+ &a_in[*a_in_len - 1],
+ a_out_len);
+
+ g_return_val_if_fail (status == CR_OK, status);
+ } else {
+ *a_out_len = *a_in_len;
+ }
+
+ *a_out = g_malloc0 (*a_out_len);
+
+ status = a_this->decode_input (a_in, a_in_len, *a_out, a_out_len);
+
+ if (status != CR_OK) {
+ g_free (*a_out);
+ *a_out = NULL;
+ }
+
+ g_return_val_if_fail (status == CR_OK, status);
+
+ return CR_OK;
+}
diff --git a/src/3rdparty/libcroco/cr-enc-handler.h b/src/3rdparty/libcroco/cr-enc-handler.h
new file mode 100644
index 000000000..0727764c0
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-enc-handler.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+/**
+ *@file:
+ *The declaration of the #CREncHandler class.
+ *
+ */
+
+#ifndef __CR_ENC_HANDLER_H__
+#define __CR_ENC_HANDLER_H__
+
+#include "cr-utils.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CREncHandler CREncHandler ;
+
+typedef enum CRStatus (*CREncInputFunc) (const guchar * a_in,
+ gulong *a_in_len,
+ guchar *a_out,
+ gulong *a_out_len) ;
+
+typedef enum CRStatus (*CREncOutputFunc) (const guchar * a_in,
+ gulong *a_in_len,
+ guchar *a_out,
+ gulong *a_out_len) ;
+
+typedef enum CRStatus (*CREncInputStrLenAsUtf8Func)
+(const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_in_size);
+
+typedef enum CRStatus (*CREncUtf8StrLenAsOutputFunc)
+(const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_in_size) ;
+
+/**
+ *This class is responsible of the
+ *the encoding conversions stuffs in
+ *libcroco.
+ */
+
+struct _CREncHandler
+{
+ enum CREncoding encoding ;
+ CREncInputFunc decode_input ;
+ CREncInputFunc encode_output ;
+ CREncInputStrLenAsUtf8Func enc_str_len_as_utf8 ;
+ CREncUtf8StrLenAsOutputFunc utf8_str_len_as_enc ;
+} ;
+
+CREncHandler *
+cr_enc_handler_get_instance (enum CREncoding a_enc) ;
+
+enum CRStatus
+cr_enc_handler_resolve_enc_alias (const guchar *a_alias_name,
+ enum CREncoding *a_enc) ;
+
+enum CRStatus
+cr_enc_handler_convert_input (CREncHandler *a_this,
+ const guchar *a_in,
+ gulong *a_in_len,
+ guchar **a_out,
+ gulong *a_out_len) ;
+
+G_END_DECLS
+
+#endif /*__CR_ENC_HANDLER_H__*/
diff --git a/src/3rdparty/libcroco/cr-fonts.c b/src/3rdparty/libcroco/cr-fonts.c
new file mode 100644
index 000000000..78e261149
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-fonts.c
@@ -0,0 +1,943 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of
+ * the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *See COPYRIGHTS file for copyright information
+ */
+
+#include "cr-fonts.h"
+#include <string.h>
+
+static enum CRStatus
+cr_font_family_to_string_real (CRFontFamily const * a_this,
+ gboolean a_walk_list, GString ** a_string)
+{
+ guchar const *name = NULL;
+ enum CRStatus result = CR_OK;
+
+ if (!*a_string) {
+ *a_string = g_string_new (NULL);
+ g_return_val_if_fail (*a_string,
+ CR_INSTANCIATION_FAILED_ERROR);
+ }
+
+ if (!a_this) {
+ g_string_append (*a_string, "NULL");
+ return CR_OK;
+ }
+
+ switch (a_this->type) {
+ case FONT_FAMILY_SANS_SERIF:
+ name = (guchar const *) "sans-serif";
+ break;
+
+ case FONT_FAMILY_SERIF:
+ name = (guchar const *) "sans-serif";
+ break;
+
+ case FONT_FAMILY_CURSIVE:
+ name = (guchar const *) "cursive";
+ break;
+
+ case FONT_FAMILY_FANTASY:
+ name = (guchar const *) "fantasy";
+ break;
+
+ case FONT_FAMILY_MONOSPACE:
+ name = (guchar const *) "monospace";
+ break;
+
+ case FONT_FAMILY_NON_GENERIC:
+ name = (guchar const *) a_this->name;
+ break;
+
+ default:
+ name = NULL;
+ break;
+ }
+
+ if (name) {
+ if (a_this->prev) {
+ g_string_append_printf (*a_string, ", %s", name);
+ } else {
+ g_string_append (*a_string, (const gchar *) name);
+ }
+ }
+ if (a_walk_list == TRUE && a_this->next) {
+ result = cr_font_family_to_string_real (a_this->next,
+ TRUE, a_string);
+ }
+ return result;
+}
+
+static const gchar *
+cr_predefined_absolute_font_size_to_string (enum CRPredefinedAbsoluteFontSize
+ a_code)
+{
+ gchar const *str = NULL;
+
+ switch (a_code) {
+ case FONT_SIZE_XX_SMALL:
+ str = "xx-small";
+ break;
+ case FONT_SIZE_X_SMALL:
+ str = "x-small";
+ break;
+ case FONT_SIZE_SMALL:
+ str = "small";
+ break;
+ case FONT_SIZE_MEDIUM:
+ str = "medium";
+ break;
+ case FONT_SIZE_LARGE:
+ str = "large";
+ break;
+ case FONT_SIZE_X_LARGE:
+ str = "x-large";
+ break;
+ case FONT_SIZE_XX_LARGE:
+ str = "xx-large";
+ break;
+ default:
+ str = "unknown absolute font size value";
+ }
+ return str;
+}
+
+static const gchar *
+cr_relative_font_size_to_string (enum CRRelativeFontSize a_code)
+{
+ gchar const *str = NULL;
+
+ switch (a_code) {
+ case FONT_SIZE_LARGER:
+ str = "larger";
+ break;
+ case FONT_SIZE_SMALLER:
+ str = "smaller";
+ break;
+ default:
+ str = "unknown relative font size value";
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_family_new:
+ * @a_type: the type of font family to create.
+ * @a_name: the name of the font family.
+ *
+ * create a font family.
+ *
+ * Returns the newly built font family.
+ */
+CRFontFamily *
+cr_font_family_new (enum CRFontFamilyType a_type, guchar * a_name)
+{
+ CRFontFamily *result = NULL;
+
+ result = g_try_malloc (sizeof (CRFontFamily));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRFontFamily));
+ result->type = a_type;
+
+ cr_font_family_set_name (result, a_name);
+
+ return result;
+}
+
+/**
+ * cr_font_family_to_string:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_walk_font_family_list: wether the serialize the entire list.
+ *
+ * Returns the seriliazed font family. The caller has to free it using
+ * g_free().
+ */
+guchar *
+cr_font_family_to_string (CRFontFamily const * a_this,
+ gboolean a_walk_font_family_list)
+{
+ enum CRStatus status = CR_OK;
+ guchar *result = NULL;
+ GString *stringue = NULL;
+
+ if (!a_this) {
+ result = (guchar *) g_strdup ("NULL");
+ g_return_val_if_fail (result, NULL);
+ return result;
+ }
+ status = cr_font_family_to_string_real (a_this,
+ a_walk_font_family_list,
+ &stringue);
+
+ if (status == CR_OK && stringue) {
+ result = (guchar *) stringue->str;
+ g_string_free (stringue, FALSE);
+ stringue = NULL;
+
+ } else {
+ if (stringue) {
+ g_string_free (stringue, TRUE);
+ stringue = NULL;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * cr_font_family_set_name:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_name: the new name
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_family_set_name (CRFontFamily * a_this, guchar * a_name)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ /*
+ *only non generic font families can have a name
+ */
+
+ if (a_this->type != FONT_FAMILY_NON_GENERIC) {
+ return CR_BAD_PARAM_ERROR;
+ }
+
+ if (a_this->name) {
+ g_free (a_this->name);
+ a_this->name = NULL;
+ }
+
+ a_this->name = a_name;
+ return CR_OK;
+}
+
+/**
+ * cr_font_family_append:
+ * @a_this: the current instance of #CRFontFamily.
+ * @a_family_to_append: the font family to append to the list
+ *
+ * Returns the new font family list.
+ */
+CRFontFamily *
+cr_font_family_append (CRFontFamily * a_this,
+ CRFontFamily * a_family_to_append)
+{
+ CRFontFamily *cur_ff = NULL;
+
+ g_return_val_if_fail (a_family_to_append, NULL);
+
+ if (!a_this)
+ return a_family_to_append;
+
+ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ;
+
+ cur_ff->next = a_family_to_append;
+ a_family_to_append->prev = cur_ff;
+
+ return a_this;
+
+}
+
+/**
+ * cr_font_family_prepend:
+ * @a_this: the current instance #CRFontFamily.
+ * @a_family_to_prepend: the font family to prepend to the list.
+ *
+ * Returns the font family list.
+ */
+CRFontFamily *
+cr_font_family_prepend (CRFontFamily * a_this,
+ CRFontFamily * a_family_to_prepend)
+{
+ g_return_val_if_fail (a_this && a_family_to_prepend, NULL);
+
+ if (!a_this)
+ return a_family_to_prepend;
+
+ a_family_to_prepend->next = a_this;
+ a_this->prev = a_family_to_prepend;
+
+ return a_family_to_prepend;
+}
+
+/**
+ * cr_font_family_destroy:
+ * @a_this: the current instance of #CRFontFamily.
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_family_destroy (CRFontFamily * a_this)
+{
+ CRFontFamily *cur_ff = NULL;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ for (cur_ff = a_this; cur_ff && cur_ff->next; cur_ff = cur_ff->next) ;
+
+ for (; cur_ff; cur_ff = cur_ff->prev) {
+ if (a_this->name) {
+ g_free (a_this->name);
+ a_this->name = NULL;
+ }
+
+ if (cur_ff->next) {
+ g_free (cur_ff->next);
+
+ }
+
+ if (cur_ff->prev == NULL) {
+ g_free (a_this);
+ }
+ }
+
+ return CR_OK;
+}
+
+/***************************************************
+ *'font-size' manipulation functions definitions
+ ***************************************************/
+
+/**
+ * cr_font_size_new:
+ *
+ * Returns the newly created font size.
+ */
+CRFontSize *
+cr_font_size_new (void)
+{
+ CRFontSize *result = NULL;
+
+ result = g_try_malloc (sizeof (CRFontSize));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRFontSize));
+
+ return result;
+}
+
+/**
+ * cr_font_size_clear:
+ * @a_this: the current instance of #CRFontSize
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_clear (CRFontSize * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ switch (a_this->type) {
+ case PREDEFINED_ABSOLUTE_FONT_SIZE:
+ case RELATIVE_FONT_SIZE:
+ case INHERITED_FONT_SIZE:
+ memset (a_this, 0, sizeof (CRFontSize));
+ break;
+
+ case ABSOLUTE_FONT_SIZE:
+ memset (a_this, 0, sizeof (CRFontSize));
+ break;
+
+ default:
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ return CR_OK;
+}
+
+/**
+ * cr_font_size_copy:
+ * @a_dst: the destination #CRFontSize (where to copy to).
+ * @a_src: the source #CRFontSize (where to copy from).
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_copy (CRFontSize * a_dst, CRFontSize const * a_src)
+{
+ g_return_val_if_fail (a_dst && a_src, CR_BAD_PARAM_ERROR);
+
+ switch (a_src->type) {
+ case PREDEFINED_ABSOLUTE_FONT_SIZE:
+ case RELATIVE_FONT_SIZE:
+ case INHERITED_FONT_SIZE:
+ cr_font_size_clear (a_dst);
+ memcpy (a_dst, a_src, sizeof (CRFontSize));
+ break;
+
+ case ABSOLUTE_FONT_SIZE:
+ cr_font_size_clear (a_dst);
+ cr_num_copy (&a_dst->value.absolute,
+ &a_src->value.absolute);
+ a_dst->type = a_src->type;
+ break;
+
+ default:
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+ return CR_OK;
+}
+
+/**
+ * cr_font_size_set_predefined_absolute_font_size:
+ * @a_this: the current instance of #CRFontSize.
+ * @a_predefined: what to set.
+ *
+ * Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this,
+ enum CRPredefinedAbsoluteFontSize a_predefined)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+ g_return_val_if_fail ((unsigned)a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES,
+ CR_BAD_PARAM_ERROR) ;
+
+ a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ;
+ a_this->value.predefined = a_predefined ;
+
+ return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_relative_font_size:
+ * @a_this: the current instance of #CRFontSize
+ * @a_relative: the new relative font size
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_set_relative_font_size (CRFontSize *a_this,
+ enum CRRelativeFontSize a_relative)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+ g_return_val_if_fail ((unsigned)a_relative < NB_RELATIVE_FONT_SIZE,
+ CR_BAD_PARAM_ERROR) ;
+
+ a_this->type = RELATIVE_FONT_SIZE ;
+ a_this->value.relative = a_relative ;
+ return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_absolute_font_size:
+ * @a_this: the current instance of #CRFontSize
+ * @a_num_type: the type of number to set.
+ * @a_value: the actual value to set.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_set_absolute_font_size (CRFontSize *a_this,
+ enum CRNumType a_num_type,
+ gdouble a_value)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+ g_return_val_if_fail ((unsigned)a_num_type < NB_NUM_TYPE,
+ CR_BAD_PARAM_ERROR) ;
+
+ a_this->type = ABSOLUTE_FONT_SIZE ;
+ cr_num_set (&a_this->value.absolute,
+ a_value, a_num_type) ;
+ return CR_OK ;
+}
+
+/**
+ * cr_font_size_set_to_inherit:
+ * @a_this: the current instance of #CRFontSize
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_font_size_set_to_inherit (CRFontSize *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ cr_font_size_clear (a_this) ;
+ a_this->type = INHERITED_FONT_SIZE ;
+
+ return CR_OK ;
+}
+
+/**
+ * cr_font_size_is_set_to_inherit:
+ * @a_this: the current instance of #CRFontSize.
+ *
+ * Returns TRUE if the current instance is set to 'inherit'.
+ */
+gboolean
+cr_font_size_is_set_to_inherit (CRFontSize const *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+
+ return a_this->type == INHERITED_FONT_SIZE ;
+}
+
+/**
+ * cr_font_size_to_string:
+ * @a_this: the current instance of #CRFontSize
+ *
+ * Returns the serialized form of #CRFontSize. The returned string
+ * has to bee freed using g_free().
+ */
+gchar *
+cr_font_size_to_string (CRFontSize const * a_this)
+{
+ gchar *str = NULL;
+
+ if (!a_this) {
+ str = g_strdup ("NULL");
+ g_return_val_if_fail (str, NULL);
+ return str;
+ }
+ switch (a_this->type) {
+ case PREDEFINED_ABSOLUTE_FONT_SIZE:
+ str = g_strdup (cr_predefined_absolute_font_size_to_string
+ (a_this->value.predefined));
+ break;
+ case ABSOLUTE_FONT_SIZE:
+ str = (gchar *) cr_num_to_string (&a_this->value.absolute);
+ break;
+ case RELATIVE_FONT_SIZE:
+ str = g_strdup (cr_relative_font_size_to_string
+ (a_this->value.relative));
+ break;
+ case INHERITED_FONT_SIZE:
+ str = g_strdup ("inherit");
+ break;
+ default:
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_size_get_smaller_predefined:
+ * @a_font_size: the font size to consider.
+ * @a_smaller_size: out parameter. The a smaller value than @a_font_size.
+ */
+void
+cr_font_size_get_smaller_predefined_font_size
+ (enum CRPredefinedAbsoluteFontSize a_font_size,
+ enum CRPredefinedAbsoluteFontSize *a_smaller_size)
+{
+ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ;
+
+ g_return_if_fail (a_smaller_size) ;
+ g_return_if_fail ((unsigned)a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) ;
+
+ switch (a_font_size) {
+ case FONT_SIZE_XX_SMALL:
+ result = FONT_SIZE_XX_SMALL ;
+ break ;
+ case FONT_SIZE_X_SMALL:
+ result = FONT_SIZE_XX_SMALL ;
+ break ;
+ case FONT_SIZE_SMALL:
+ result = FONT_SIZE_X_SMALL;
+ break ;
+ case FONT_SIZE_MEDIUM:
+ result = FONT_SIZE_SMALL;
+ break ;
+ case FONT_SIZE_LARGE:
+ result = FONT_SIZE_MEDIUM;
+ break ;
+ case FONT_SIZE_X_LARGE:
+ result = FONT_SIZE_LARGE;
+ break ;
+ case FONT_SIZE_XX_LARGE:
+ result = FONT_SIZE_XX_LARGE;
+ break ;
+ case FONT_SIZE_INHERIT:
+ cr_utils_trace_info ("can't return a smaller size for FONT_SIZE_INHERIT") ;
+ result = FONT_SIZE_MEDIUM ;
+ break ;
+ default:
+ cr_utils_trace_info ("Unknown FONT_SIZE") ;
+ result = FONT_SIZE_MEDIUM ;
+ break ;
+ }
+ *a_smaller_size = result ;
+}
+
+
+/**
+ * cr_font_size_get_larger_predefined_font_size:
+ * @a_font_size: the font size to consider.
+ * @a_larger_size: out parameter. the font size considered larger than
+ * @a_font_size.
+ *
+ */
+void
+cr_font_size_get_larger_predefined_font_size
+ (enum CRPredefinedAbsoluteFontSize a_font_size,
+ enum CRPredefinedAbsoluteFontSize *a_larger_size)
+{
+ enum CRPredefinedAbsoluteFontSize result = FONT_SIZE_MEDIUM ;
+
+ g_return_if_fail (a_larger_size) ;
+ g_return_if_fail ((unsigned)a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) ;
+
+ switch (a_font_size) {
+ case FONT_SIZE_XX_SMALL:
+ result = FONT_SIZE_X_SMALL ;
+ break ;
+ case FONT_SIZE_X_SMALL:
+ result = FONT_SIZE_SMALL ;
+ break ;
+ case FONT_SIZE_SMALL:
+ result = FONT_SIZE_MEDIUM;
+ break ;
+ case FONT_SIZE_MEDIUM:
+ result = FONT_SIZE_LARGE;
+ break ;
+ case FONT_SIZE_LARGE:
+ result = FONT_SIZE_X_LARGE;
+ break ;
+ case FONT_SIZE_X_LARGE:
+ result = FONT_SIZE_XX_LARGE ;
+ break ;
+ case FONT_SIZE_XX_LARGE:
+ result = FONT_SIZE_XX_LARGE;
+ break ;
+ case FONT_SIZE_INHERIT:
+ cr_utils_trace_info ("can't return a bigger size for FONT_SIZE_INHERIT") ;
+ result = FONT_SIZE_MEDIUM ;
+ break ;
+ default:
+ cr_utils_trace_info ("Unknown FONT_SIZE") ;
+ result = FONT_SIZE_MEDIUM ;
+ break ;
+ }
+ *a_larger_size = result ;
+}
+
+/**
+ * cr_font_size_is_predefined_absolute_font_size:
+ * @a_font_size: the font size to consider.
+ *
+ * Returns TRUE if the instance is an predefined absolute font size, FALSE
+ * otherwise.
+ */
+gboolean
+cr_font_size_is_predefined_absolute_font_size
+ (enum CRPredefinedAbsoluteFontSize a_font_size)
+{
+ if ((unsigned)a_font_size < NB_PREDEFINED_ABSOLUTE_FONT_SIZES) {
+ return TRUE ;
+ } else {
+ return FALSE ;
+ }
+}
+
+/**
+ * cr_font_size_adjust_to_string:
+ * @a_this: the instance of #CRFontSizeAdjust.
+ *
+ * Returns the serialized form of #CRFontSizeAdjust
+ */
+gchar *
+cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this)
+{
+ gchar *str = NULL;
+
+ if (!a_this) {
+ str = g_strdup ("NULL");
+ g_return_val_if_fail (str, NULL);
+ return str;
+ }
+
+ switch (a_this->type) {
+ case FONT_SIZE_ADJUST_NONE:
+ str = g_strdup ("none");
+ break;
+ case FONT_SIZE_ADJUST_NUMBER:
+ if (a_this->num)
+ str = (gchar *) cr_num_to_string (a_this->num);
+ else
+ str = g_strdup ("unknow font-size-adjust property value"); /* Should raise an error no?*/
+ break;
+ case FONT_SIZE_ADJUST_INHERIT:
+ str = g_strdup ("inherit");
+ }
+ return str;
+}
+
+/**
+ * cr_font_style_to_string:
+ * @a_code: the current instance of #CRFontStyle .
+ *
+ * Returns the serialized #CRFontStyle. The caller must free the returned
+ * string using g_free().
+ */
+const gchar *
+cr_font_style_to_string (enum CRFontStyle a_code)
+{
+ gchar *str = NULL;
+
+ switch (a_code) {
+ case FONT_STYLE_NORMAL:
+ str = (gchar *) "normal";
+ break;
+ case FONT_STYLE_ITALIC:
+ str = (gchar *) "italic";
+ break;
+ case FONT_STYLE_OBLIQUE:
+ str = (gchar *) "oblique";
+ break;
+ case FONT_STYLE_INHERIT:
+ str = (gchar *) "inherit";
+ break;
+ default:
+ str = (gchar *) "unknown font style value";
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_variant_to_string:
+ * @a_code: the current instance of #CRFontVariant.
+ *
+ * Returns the serialized form of #CRFontVariant. The caller has
+ * to free the returned string using g_free().
+ */
+const gchar *
+cr_font_variant_to_string (enum CRFontVariant a_code)
+{
+ gchar *str = NULL;
+
+ switch (a_code) {
+ case FONT_VARIANT_NORMAL:
+ str = (gchar *) "normal";
+ break;
+ case FONT_VARIANT_SMALL_CAPS:
+ str = (gchar *) "small-caps";
+ break;
+ case FONT_VARIANT_INHERIT:
+ str = (gchar *) "inherit";
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_weight_get_bolder:
+ * @a_weight: the #CRFontWeight to consider.
+ *
+ * Returns a font weight bolder than @a_weight
+ */
+enum CRFontWeight
+cr_font_weight_get_bolder (enum CRFontWeight a_weight)
+{
+ if (a_weight == FONT_WEIGHT_INHERIT) {
+ cr_utils_trace_info ("can't return a bolder weight for FONT_WEIGHT_INHERIT") ;
+ return a_weight;
+ } else if (a_weight >= FONT_WEIGHT_900) {
+ return FONT_WEIGHT_900 ;
+ } else if (a_weight < FONT_WEIGHT_NORMAL) {
+ return FONT_WEIGHT_NORMAL ;
+ } else if (a_weight == FONT_WEIGHT_BOLDER
+ || a_weight == FONT_WEIGHT_LIGHTER) {
+ cr_utils_trace_info ("FONT_WEIGHT_BOLDER or FONT_WEIGHT_LIGHTER should not appear here") ;
+ return FONT_WEIGHT_NORMAL ;
+ } else {
+ return a_weight << 1 ;
+ }
+}
+
+/**
+ * cr_font_weight_to_string:
+ * @a_code: the font weight to consider.
+ *
+ * Returns the serialized form of #CRFontWeight.
+ */
+const gchar *
+cr_font_weight_to_string (enum CRFontWeight a_code)
+{
+ gchar *str = NULL;
+
+ switch (a_code) {
+ case FONT_WEIGHT_NORMAL:
+ str = (gchar *) "normal";
+ break;
+ case FONT_WEIGHT_BOLD:
+ str = (gchar *) "bold";
+ break;
+ case FONT_WEIGHT_BOLDER:
+ str = (gchar *) "bolder";
+ break;
+ case FONT_WEIGHT_LIGHTER:
+ str = (gchar *) "lighter";
+ break;
+ case FONT_WEIGHT_100:
+ str = (gchar *) "100";
+ break;
+ case FONT_WEIGHT_200:
+ str = (gchar *) "200";
+ break;
+ case FONT_WEIGHT_300:
+ str = (gchar *) "300";
+ break;
+ case FONT_WEIGHT_400:
+ str = (gchar *) "400";
+ break;
+ case FONT_WEIGHT_500:
+ str = (gchar *) "500";
+ break;
+ case FONT_WEIGHT_600:
+ str = (gchar *) "600";
+ break;
+ case FONT_WEIGHT_700:
+ str = (gchar *) "700";
+ break;
+ case FONT_WEIGHT_800:
+ str = (gchar *) "800";
+ break;
+ case FONT_WEIGHT_900:
+ str = (gchar *) "900";
+ break;
+ case FONT_WEIGHT_INHERIT:
+ str = (gchar *) "inherit";
+ break;
+ default:
+ str = (gchar *) "unknown font-weight property value";
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_stretch_to_string:
+ * @a_code: the instance of #CRFontStretch to consider.
+ *
+ * Returns the serialized form of #CRFontStretch.
+ */
+const gchar *
+cr_font_stretch_to_string (enum CRFontStretch a_code)
+{
+ gchar *str = NULL;
+
+ switch (a_code) {
+ case FONT_STRETCH_NORMAL:
+ str = (gchar *) "normal";
+ break;
+ case FONT_STRETCH_WIDER:
+ str = (gchar *) "wider";
+ break;
+ case FONT_STRETCH_NARROWER:
+ str = (gchar *) "narrower";
+ break;
+ case FONT_STRETCH_ULTRA_CONDENSED:
+ str = (gchar *) "ultra-condensed";
+ break;
+ case FONT_STRETCH_EXTRA_CONDENSED:
+ str = (gchar *) "extra-condensed";
+ break;
+ case FONT_STRETCH_CONDENSED:
+ str = (gchar *) "condensed";
+ break;
+ case FONT_STRETCH_SEMI_CONDENSED:
+ str = (gchar *) "semi-condensed";
+ break;
+ case FONT_STRETCH_SEMI_EXPANDED:
+ str = (gchar *) "semi-expanded";
+ break;
+ case FONT_STRETCH_EXPANDED:
+ str = (gchar *) "expanded";
+ break;
+ case FONT_STRETCH_EXTRA_EXPANDED:
+ str = (gchar *) "extra-expaned";
+ break;
+ case FONT_STRETCH_ULTRA_EXPANDED:
+ str = (gchar *) "ultra-expanded";
+ break;
+ case FONT_STRETCH_INHERIT:
+ str = (gchar *) "inherit";
+ break;
+ }
+ return str;
+}
+
+/**
+ * cr_font_size_destroy:
+ * @a_font_size: the font size to destroy
+ *
+ */
+void
+cr_font_size_destroy (CRFontSize * a_font_size)
+{
+ g_return_if_fail (a_font_size);
+
+ g_free (a_font_size) ;
+}
+
+/*******************************************************
+ *'font-size-adjust' manipulation function definition
+ *******************************************************/
+
+/**
+ * cr_font_size_adjust_new:
+ *
+ * Returns a newly built instance of #CRFontSizeAdjust
+ */
+CRFontSizeAdjust *
+cr_font_size_adjust_new (void)
+{
+ CRFontSizeAdjust *result = NULL;
+
+ result = g_try_malloc (sizeof (CRFontSizeAdjust));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRFontSizeAdjust));
+
+ return result;
+}
+
+/**
+ * cr_font_size_adjust_destroy:
+ * @a_this: the current instance of #CRFontSizeAdjust.
+ *
+ */
+void
+cr_font_size_adjust_destroy (CRFontSizeAdjust * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->type == FONT_SIZE_ADJUST_NUMBER && a_this->num) {
+ cr_num_destroy (a_this->num);
+ a_this->num = NULL;
+ }
+}
diff --git a/src/3rdparty/libcroco/cr-fonts.h b/src/3rdparty/libcroco/cr-fonts.h
new file mode 100644
index 000000000..9eaeeeb98
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-fonts.h
@@ -0,0 +1,315 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of
+ * the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_FONTS_H__
+#define __CR_FONTS_H__
+
+#include "cr-utils.h"
+#include "cr-num.h"
+
+/**
+ *@file
+ *Various type declarations about font selection related
+ *properties.
+ */
+G_BEGIN_DECLS
+
+
+enum CRFontFamilyType
+{
+ FONT_FAMILY_SANS_SERIF,
+ FONT_FAMILY_SERIF,
+ FONT_FAMILY_CURSIVE,
+ FONT_FAMILY_FANTASY,
+ FONT_FAMILY_MONOSPACE,
+ FONT_FAMILY_NON_GENERIC,
+ FONT_FAMILY_INHERIT,
+ /**/
+ NB_FONT_FAMILIE_TYPES
+} ;
+
+typedef struct _CRFontFamily CRFontFamily ;
+
+struct _CRFontFamily
+{
+ enum CRFontFamilyType type ;
+
+ /*
+ *The name of the font family, in case
+ *it is non generic.
+ *Is set only if the type is FONT_FAMILY_NON_GENERIC.
+ */
+ guchar *name ;
+
+ CRFontFamily *next ;
+ CRFontFamily *prev ;
+} ;
+
+
+/**
+ *The different types
+ *of absolute font size.
+ *This is used by the 'font-size'
+ *property defined in css2 spec
+ *in chapter 15.2.4 .
+ *These values a indexes of
+ *table of size so please, do not
+ *change their definition order unless
+ *you know what you are doing.
+ */
+enum CRPredefinedAbsoluteFontSize
+{
+ FONT_SIZE_XX_SMALL=0,
+ FONT_SIZE_X_SMALL,
+ FONT_SIZE_SMALL,
+ FONT_SIZE_MEDIUM,
+ FONT_SIZE_LARGE,
+ FONT_SIZE_X_LARGE,
+ FONT_SIZE_XX_LARGE,
+ FONT_SIZE_INHERIT,
+ NB_PREDEFINED_ABSOLUTE_FONT_SIZES
+} ;
+
+/**
+ *The different types
+ *of relative font size.
+ *This is used by the 'font-size'
+ *property defined in css2 spec
+ *in chapter 15.2.4 .
+ *These values a indexes of
+ *table of size so please, do not
+ *change their definition order unless
+ *you know what you are doing.
+ */
+enum CRRelativeFontSize
+{
+ FONT_SIZE_LARGER,
+ FONT_SIZE_SMALLER,
+ NB_RELATIVE_FONT_SIZE
+} ;
+
+/**
+ *The type of font-size property.
+ *Used to define the type of #CRFontSize .
+ *See css2 spec chapter 15.2.4 to understand.
+ */
+enum CRFontSizeType {
+ /**
+ *If the type of #CRFontSize is
+ *PREDEFINED_ABSOLUTE_FONT_SIZE,
+ *the CRFontSize::value.predefined_absolute
+ *field will be defined.
+ */
+ PREDEFINED_ABSOLUTE_FONT_SIZE,
+
+ /**
+ *If the type of #CRFontSize is
+ *ABSOLUTE_FONT_SIZE,
+ *the CRFontSize::value.absolute
+ *field will be defined.
+ */
+ ABSOLUTE_FONT_SIZE,
+
+ /**
+ *If the type of #CRFontSize is
+ *RELATIVE_FONT_SIZE,
+ *the CRFontSize::value.relative
+ *field will be defined.
+ */
+ RELATIVE_FONT_SIZE,
+
+ /**
+ *If the type of #CRFontSize is
+ *INHERITED_FONT_SIZE,
+ *the None of the field of the CRFontSize::value enum
+ *will be defined.
+ */
+ INHERITED_FONT_SIZE,
+
+ NB_FONT_SIZE_TYPE
+} ;
+
+typedef struct _CRFontSize CRFontSize ;
+struct _CRFontSize {
+ enum CRFontSizeType type ;
+ union {
+ enum CRPredefinedAbsoluteFontSize predefined ;
+ enum CRRelativeFontSize relative ;
+ CRNum absolute ;
+ } value;
+} ;
+
+enum CRFontSizeAdjustType
+{
+ FONT_SIZE_ADJUST_NONE = 0,
+ FONT_SIZE_ADJUST_NUMBER,
+ FONT_SIZE_ADJUST_INHERIT
+} ;
+typedef struct _CRFontSizeAdjust CRFontSizeAdjust ;
+struct _CRFontSizeAdjust
+{
+ enum CRFontSizeAdjustType type ;
+ CRNum *num ;
+} ;
+
+enum CRFontStyle
+{
+ FONT_STYLE_NORMAL=0,
+ FONT_STYLE_ITALIC,
+ FONT_STYLE_OBLIQUE,
+ FONT_STYLE_INHERIT
+} ;
+
+enum CRFontVariant
+{
+ FONT_VARIANT_NORMAL=0,
+ FONT_VARIANT_SMALL_CAPS,
+ FONT_VARIANT_INHERIT
+} ;
+
+enum CRFontWeight
+{
+ FONT_WEIGHT_NORMAL = 1,
+ FONT_WEIGHT_BOLD = 1<<1,
+ FONT_WEIGHT_BOLDER = 1<<2,
+ FONT_WEIGHT_LIGHTER = 1<<3,
+ FONT_WEIGHT_100 = 1<<4,
+ FONT_WEIGHT_200 = 1<<5,
+ FONT_WEIGHT_300 = 1<<6,
+ FONT_WEIGHT_400 = 1<<7,
+ FONT_WEIGHT_500 = 1<<8,
+ FONT_WEIGHT_600 = 1<<9,
+ FONT_WEIGHT_700 = 1<<10,
+ FONT_WEIGHT_800 = 1<<11,
+ FONT_WEIGHT_900 = 1<<12,
+ FONT_WEIGHT_INHERIT = 1<<13,
+ NB_FONT_WEIGHTS
+} ;
+
+enum CRFontStretch
+{
+ FONT_STRETCH_NORMAL=0,
+ FONT_STRETCH_WIDER,
+ FONT_STRETCH_NARROWER,
+ FONT_STRETCH_ULTRA_CONDENSED,
+ FONT_STRETCH_EXTRA_CONDENSED,
+ FONT_STRETCH_CONDENSED,
+ FONT_STRETCH_SEMI_CONDENSED,
+ FONT_STRETCH_SEMI_EXPANDED,
+ FONT_STRETCH_EXPANDED,
+ FONT_STRETCH_EXTRA_EXPANDED,
+ FONT_STRETCH_ULTRA_EXPANDED,
+ FONT_STRETCH_INHERIT
+} ;
+
+/**************************************
+ *'font-family' manipulation functions
+ ***************************************/
+CRFontFamily *
+cr_font_family_new (enum CRFontFamilyType a_type, guchar *a_name) ;
+
+CRFontFamily *
+cr_font_family_append (CRFontFamily *a_this,
+ CRFontFamily *a_family_to_append) ;
+
+guchar *
+cr_font_family_to_string (CRFontFamily const *a_this,
+ gboolean a_walk_font_family_list) ;
+
+CRFontFamily *
+cr_font_family_prepend (CRFontFamily *a_this,
+ CRFontFamily *a_family_to_prepend);
+
+enum CRStatus
+cr_font_family_destroy (CRFontFamily *a_this) ;
+
+enum CRStatus
+cr_font_family_set_name (CRFontFamily *a_this, guchar *a_name) ;
+
+
+/************************************
+ *'font-size' manipulation functions
+ ***********************************/
+
+CRFontSize * cr_font_size_new (void) ;
+
+enum CRStatus cr_font_size_clear (CRFontSize *a_this) ;
+
+enum CRStatus cr_font_size_copy (CRFontSize *a_dst,
+ CRFontSize const *a_src) ;
+enum CRStatus cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this,
+ enum CRPredefinedAbsoluteFontSize a_predefined) ;
+enum CRStatus cr_font_size_set_relative_font_size (CRFontSize *a_this,
+ enum CRRelativeFontSize a_relative) ;
+
+enum CRStatus cr_font_size_set_absolute_font_size (CRFontSize *a_this,
+ enum CRNumType a_num_type,
+ gdouble a_value) ;
+
+enum CRStatus cr_font_size_set_to_inherit (CRFontSize *a_this) ;
+
+gboolean cr_font_size_is_set_to_inherit (CRFontSize const *a_this) ;
+
+gchar* cr_font_size_to_string (CRFontSize const *a_this) ;
+
+void cr_font_size_destroy (CRFontSize *a_font_size) ;
+
+/*******************************************************
+ *'font-size-adjust' manipulation function declarations
+ *******************************************************/
+
+CRFontSizeAdjust * cr_font_size_adjust_new (void) ;
+
+gchar * cr_font_size_adjust_to_string (CRFontSizeAdjust const *a_this) ;
+
+void cr_font_size_adjust_destroy (CRFontSizeAdjust *a_this) ;
+
+void
+cr_font_size_get_smaller_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size,
+ enum CRPredefinedAbsoluteFontSize *a_smaller_size) ;
+void
+cr_font_size_get_larger_predefined_font_size (enum CRPredefinedAbsoluteFontSize a_font_size,
+ enum CRPredefinedAbsoluteFontSize *a_larger_size) ;
+
+gboolean
+cr_font_size_is_predefined_absolute_font_size (enum CRPredefinedAbsoluteFontSize a_font_size) ;
+
+/***********************************
+ *various other font related functions
+ ***********************************/
+const gchar * cr_font_style_to_string (enum CRFontStyle a_code) ;
+
+const gchar * cr_font_weight_to_string (enum CRFontWeight a_code) ;
+
+enum CRFontWeight
+cr_font_weight_get_bolder (enum CRFontWeight a_weight) ;
+
+const gchar * cr_font_variant_to_string (enum CRFontVariant a_code) ;
+
+const gchar * cr_font_stretch_to_string (enum CRFontStretch a_code) ;
+
+G_END_DECLS
+
+#endif
diff --git a/src/3rdparty/libcroco/cr-input.c b/src/3rdparty/libcroco/cr-input.c
new file mode 100644
index 000000000..732068aff
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-input.c
@@ -0,0 +1,1184 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "stdio.h"
+#include <string.h>
+#include "cr-input.h"
+#include "cr-enc-handler.h"
+
+/**
+ *@CRInput:
+ *
+ *The definition of the #CRInput class.
+ */
+
+/*******************
+ *Private type defs
+ *******************/
+
+/**
+ *The private attributes of
+ *the #CRInputPriv class.
+ */
+struct _CRInputPriv {
+ /*
+ *The input buffer
+ */
+ guchar *in_buf;
+ gulong in_buf_size;
+
+ gulong nb_bytes;
+
+ /*
+ *The index of the next byte
+ *to be read.
+ */
+ gulong next_byte_index;
+
+ /*
+ *The current line number
+ */
+ gulong line;
+
+ /*
+ *The current col number
+ */
+ gulong col;
+
+ gboolean end_of_line;
+ gboolean end_of_input;
+
+ /*
+ *the reference count of this
+ *instance.
+ */
+ guint ref_count;
+ gboolean free_in_buf;
+};
+
+#define PRIVATE(object) (object)->priv
+
+/***************************
+ *private constants
+ **************************/
+#define CR_INPUT_MEM_CHUNK_SIZE 1024 * 4
+
+static CRInput *cr_input_new_real (void);
+
+static CRInput *
+cr_input_new_real (void)
+{
+ CRInput *result = NULL;
+
+ result = g_try_malloc (sizeof (CRInput));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRInput));
+
+ PRIVATE (result) = g_try_malloc (sizeof (CRInputPriv));
+ if (!PRIVATE (result)) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (PRIVATE (result), 0, sizeof (CRInputPriv));
+ PRIVATE (result)->free_in_buf = TRUE;
+ return result;
+}
+
+/****************
+ *Public methods
+ ***************/
+
+/**
+ * cr_input_new_from_buf:
+ *@a_buf: the memory buffer to create the input stream from.
+ *The #CRInput keeps this pointer so user should not free it !.
+ *@a_len: the size of the input buffer.
+ *@a_enc: the buffer's encoding.
+ *@a_free_buf: if set to TRUE, this a_buf will be freed
+ *at the destruction of this instance. If set to false, it is up
+ *to the caller to free it.
+ *
+ *Creates a new input stream from a memory buffer.
+ *Returns the newly built instance of #CRInput.
+ */
+CRInput *
+cr_input_new_from_buf (guchar * a_buf,
+ gulong a_len,
+ enum CREncoding a_enc,
+ gboolean a_free_buf)
+{
+ CRInput *result = NULL;
+ enum CRStatus status = CR_OK;
+ CREncHandler *enc_handler = NULL;
+ gulong len = a_len;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ result = cr_input_new_real ();
+ g_return_val_if_fail (result, NULL);
+
+ /*transform the encoding in utf8 */
+ if (a_enc != CR_UTF_8) {
+ enc_handler = cr_enc_handler_get_instance (a_enc);
+ if (!enc_handler) {
+ goto error;
+ }
+
+ status = cr_enc_handler_convert_input
+ (enc_handler, a_buf, &len,
+ &PRIVATE (result)->in_buf,
+ &PRIVATE (result)->in_buf_size);
+ if (status != CR_OK)
+ goto error;
+ PRIVATE (result)->free_in_buf = TRUE;
+ if (a_free_buf == TRUE && a_buf) {
+ g_free (a_buf) ;
+ a_buf = NULL ;
+ }
+ PRIVATE (result)->nb_bytes = PRIVATE (result)->in_buf_size;
+ } else {
+ PRIVATE (result)->in_buf = (guchar *) a_buf;
+ PRIVATE (result)->in_buf_size = a_len;
+ PRIVATE (result)->nb_bytes = a_len;
+ PRIVATE (result)->free_in_buf = a_free_buf;
+ }
+ PRIVATE (result)->line = 1;
+ PRIVATE (result)->col = 0;
+ return result;
+
+ error:
+ if (result) {
+ cr_input_destroy (result);
+ result = NULL;
+ }
+
+ return NULL;
+}
+
+/**
+ * cr_input_new_from_uri:
+ *@a_file_uri: the file to create *the input stream from.
+ *@a_enc: the encoding of the file *to create the input from.
+ *
+ *Creates a new input stream from
+ *a file.
+ *
+ *Returns the newly created input stream if
+ *this method could read the file and create it,
+ *NULL otherwise.
+ */
+
+CRInput *
+cr_input_new_from_uri (const gchar * a_file_uri, enum CREncoding a_enc)
+{
+ CRInput *result = NULL;
+ enum CRStatus status = CR_OK;
+ FILE *file_ptr = NULL;
+ guchar tmp_buf[CR_INPUT_MEM_CHUNK_SIZE] = { 0 };
+ gulong nb_read = 0,
+ len = 0,
+ buf_size = 0;
+ gboolean loop = TRUE;
+ guchar *buf = NULL;
+
+ g_return_val_if_fail (a_file_uri, NULL);
+
+ file_ptr = fopen (a_file_uri, "r");
+
+ if (file_ptr == NULL) {
+
+#ifdef CR_DEBUG
+ cr_utils_trace_debug ("could not open file");
+#endif
+ g_warning ("Could not open file %s\n", a_file_uri);
+
+ return NULL;
+ }
+
+ /*load the file */
+ while (loop) {
+ nb_read = fread (tmp_buf, 1 /*read bytes */ ,
+ CR_INPUT_MEM_CHUNK_SIZE /*nb of bytes */ ,
+ file_ptr);
+
+ if (nb_read != CR_INPUT_MEM_CHUNK_SIZE) {
+ /*we read less chars than we wanted */
+ if (feof (file_ptr)) {
+ /*we reached eof */
+ loop = FALSE;
+ } else {
+ /*a pb occured !! */
+ cr_utils_trace_debug ("an io error occured");
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ }
+
+ if (status == CR_OK) {
+ /*read went well */
+ buf = g_realloc (buf, len + CR_INPUT_MEM_CHUNK_SIZE);
+ memcpy (buf + len, tmp_buf, nb_read);
+ len += nb_read;
+ buf_size += CR_INPUT_MEM_CHUNK_SIZE;
+ }
+ }
+
+ if (status == CR_OK) {
+ result = cr_input_new_from_buf (buf, len, a_enc, TRUE);
+ if (!result) {
+ goto cleanup;
+ }
+ /*
+ *we should free buf here because it's own by CRInput.
+ *(see the last parameter of cr_input_new_from_buf().
+ */
+ buf = NULL ;
+ }
+
+ cleanup:
+ if (file_ptr) {
+ fclose (file_ptr);
+ file_ptr = NULL;
+ }
+
+ if (buf) {
+ g_free (buf);
+ buf = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_input_destroy:
+ *@a_this: the current instance of #CRInput.
+ *
+ *The destructor of the #CRInput class.
+ */
+void
+cr_input_destroy (CRInput * a_this)
+{
+ if (a_this == NULL)
+ return;
+
+ if (PRIVATE (a_this)) {
+ if (PRIVATE (a_this)->in_buf && PRIVATE (a_this)->free_in_buf) {
+ g_free (PRIVATE (a_this)->in_buf);
+ PRIVATE (a_this)->in_buf = NULL;
+ }
+
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ }
+
+ g_free (a_this);
+}
+
+/**
+ * cr_input_ref:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Increments the reference count of the current
+ *instance of #CRInput.
+ */
+void
+cr_input_ref (CRInput * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ PRIVATE (a_this)->ref_count++;
+}
+
+/**
+ * cr_input_unref:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Decrements the reference count of this instance
+ *of #CRInput. If the reference count goes down to
+ *zero, this instance is destroyed.
+ *
+ * Returns TRUE if the instance of #CRInput got destroyed, false otherwise.
+ */
+gboolean
+cr_input_unref (CRInput * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
+
+ if (PRIVATE (a_this)->ref_count) {
+ PRIVATE (a_this)->ref_count--;
+ }
+
+ if (PRIVATE (a_this)->ref_count == 0) {
+ cr_input_destroy (a_this);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * cr_input_end_of_input:
+ *@a_this: the current instance of #CRInput.
+ *@a_end_of_input: out parameter. Is set to TRUE if
+ *the current instance has reached the end of its input buffer,
+ *FALSE otherwise.
+ *
+ *Tests wether the current instance of
+ *#CRInput has reached its input buffer.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ * Note that all the out parameters of this method are valid if
+ * and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_end_of_input (CRInput const * a_this, gboolean * a_end_of_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_end_of_input, CR_BAD_PARAM_ERROR);
+
+ *a_end_of_input = (PRIVATE (a_this)->next_byte_index
+ >= PRIVATE (a_this)->in_buf_size) ? TRUE : FALSE;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_nb_bytes_left:
+ *@a_this: the current instance of #CRInput.
+ *
+ *Returns the number of bytes left in the input stream
+ *before the end, -1 in case of error.
+ */
+glong
+cr_input_get_nb_bytes_left (CRInput const * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), -1);
+ g_return_val_if_fail (PRIVATE (a_this)->nb_bytes
+ <= PRIVATE (a_this)->in_buf_size, -1);
+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index
+ <= PRIVATE (a_this)->nb_bytes, -1);
+
+ if (PRIVATE (a_this)->end_of_input)
+ return 0;
+
+ return PRIVATE (a_this)->nb_bytes - PRIVATE (a_this)->next_byte_index;
+}
+
+/**
+ * cr_input_read_byte:
+ *@a_this: the current instance of #CRInput.
+ *@a_byte: out parameter the returned byte.
+ *
+ *Gets the next byte of the input.
+ *Updates the state of the input so that
+ *the next invocation of this method returns
+ *the next coming byte.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise. All the out parameters of this method are valid if
+ *and only if this method returns CR_OK.
+ */
+enum CRStatus
+cr_input_read_byte (CRInput * a_this, guchar * a_byte)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_byte, CR_BAD_PARAM_ERROR);
+
+ g_return_val_if_fail (PRIVATE (a_this)->next_byte_index <=
+ PRIVATE (a_this)->nb_bytes, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->end_of_input == TRUE)
+ return CR_END_OF_INPUT_ERROR;
+
+ *a_byte = PRIVATE (a_this)->in_buf[PRIVATE (a_this)->next_byte_index];
+
+ if (PRIVATE (a_this)->nb_bytes -
+ PRIVATE (a_this)->next_byte_index < 2) {
+ PRIVATE (a_this)->end_of_input = TRUE;
+ } else {
+ PRIVATE (a_this)->next_byte_index++;
+ }
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_read_char:
+ *@a_this: the current instance of CRInput.
+ *@a_char: out parameter. The read character.
+ *
+ *Reads an unicode character from the current instance of
+ *#CRInput.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_read_char (CRInput * a_this, guint32 * a_char)
+{
+ enum CRStatus status = CR_OK;
+ gulong consumed = 0,
+ nb_bytes_left = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+ CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->end_of_input == TRUE)
+ return CR_END_OF_INPUT_ERROR;
+
+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
+
+ if (nb_bytes_left < 1) {
+ return CR_END_OF_INPUT_ERROR;
+ }
+
+ status = cr_utils_read_char_from_utf8_buf
+ (PRIVATE (a_this)->in_buf
+ +
+ PRIVATE (a_this)->next_byte_index,
+ nb_bytes_left, a_char, &consumed);
+
+ if (status == CR_OK) {
+ /*update next byte index */
+ PRIVATE (a_this)->next_byte_index += consumed;
+
+ /*update line and column number */
+ if (PRIVATE (a_this)->end_of_line == TRUE) {
+ PRIVATE (a_this)->col = 1;
+ PRIVATE (a_this)->line++;
+ PRIVATE (a_this)->end_of_line = FALSE;
+ } else if (*a_char != '\n') {
+ PRIVATE (a_this)->col++;
+ }
+
+ if (*a_char == '\n') {
+ PRIVATE (a_this)->end_of_line = TRUE;
+ }
+
+ }
+
+ return status;
+}
+
+/**
+ * cr_input_set_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_line_num: the new line number.
+ *
+ *Setter of the current line number.
+ *
+ *Return CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_line_num (CRInput * a_this, glong a_line_num)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->line = a_line_num;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_line_num: the returned line number.
+ *
+ *Getter of the current line number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_line_num (CRInput const * a_this, glong * a_line_num)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_line_num, CR_BAD_PARAM_ERROR);
+
+ *a_line_num = PRIVATE (a_this)->line;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_set_column_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_col: the new column number.
+ *
+ *Setter of the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_column_num (CRInput * a_this, glong a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->col = a_col;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_column_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_col: out parameter
+ *
+ *Getter of the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_column_num (CRInput const * a_this, glong * a_col)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_col,
+ CR_BAD_PARAM_ERROR);
+
+ *a_col = PRIVATE (a_this)->col;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_increment_line_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_increment: the increment to add to the line number.
+ *
+ *Increments the current line number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_line_num (CRInput * a_this, glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->line += a_increment;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_increment_col_num:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_increment: the increment to add to the column number.
+ *
+ *Increments the current column number.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_increment_col_num (CRInput * a_this, glong a_increment)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->col += a_increment;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_consume_char:
+ *@a_this: the this pointer.
+ *@a_char: the character to consume. If set to zero,
+ *consumes any character.
+ *
+ *Consumes the next character of the input stream if
+ *and only if that character equals a_char.
+ *
+ *Returns CR_OK upon successful completion, CR_PARSING_ERROR if
+ *next char is different from a_char, an other error code otherwise
+ */
+enum CRStatus
+cr_input_consume_char (CRInput * a_this, guint32 a_char)
+{
+ guint32 c;
+ enum CRStatus status;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ if ((status = cr_input_peek_char (a_this, &c)) != CR_OK) {
+ return status;
+ }
+
+ if (c == a_char || a_char == 0) {
+ status = cr_input_read_char (a_this, &c);
+ } else {
+ return CR_PARSING_ERROR;
+ }
+
+ return status;
+}
+
+/**
+ * cr_input_consume_chars:
+ *@a_this: the this pointer of the current instance of #CRInput.
+ *@a_char: the character to consume.
+ *@a_nb_char: in/out parameter. The number of characters to consume.
+ *If set to a negative value, the function will consume all the occurences
+ *of a_char found.
+ *After return, if the return value equals CR_OK, this variable contains
+ *the number of characters actually consumed.
+ *
+ *Consumes up to a_nb_char occurences of the next contiguous characters
+ *which equal a_char. Note that the next character of the input stream
+ **MUST* equal a_char to trigger the consumption, or else, the error
+ *code CR_PARSING_ERROR is returned.
+ *If the number of contiguous characters that equals a_char is less than
+ *a_nb_char, then this function consumes all the characters it can consume.
+ *
+ *Returns CR_OK if at least one character has been consumed, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_consume_chars (CRInput * a_this, guint32 a_char, gulong * a_nb_char)
+{
+ enum CRStatus status = CR_OK;
+ gulong nb_consumed = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_char,
+ CR_BAD_PARAM_ERROR);
+
+ g_return_val_if_fail (a_char != 0 || a_nb_char != NULL,
+ CR_BAD_PARAM_ERROR);
+
+ for (nb_consumed = 0; ((status == CR_OK)
+ && (*a_nb_char > 0
+ && nb_consumed < *a_nb_char));
+ nb_consumed++) {
+ status = cr_input_consume_char (a_this, a_char);
+ }
+
+ *a_nb_char = nb_consumed;
+
+ if ((nb_consumed > 0)
+ && ((status == CR_PARSING_ERROR)
+ || (status == CR_END_OF_INPUT_ERROR))) {
+ status = CR_OK;
+ }
+
+ return status;
+}
+
+/**
+ * cr_input_consume_white_spaces:
+ *@a_this: the "this pointer" of the current instance of #CRInput.
+ *@a_nb_chars: in/out parameter. The number of white spaces to
+ *consume. After return, holds the number of white spaces actually consumed.
+ *
+ *Same as cr_input_consume_chars() but this one consumes white
+ *spaces.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
+{
+ enum CRStatus status = CR_OK;
+ guint32 cur_char = 0,
+ nb_consumed = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_nb_chars,
+ CR_BAD_PARAM_ERROR);
+
+ for (nb_consumed = 0;
+ ((*a_nb_chars > 0) && (nb_consumed < *a_nb_chars));
+ nb_consumed++) {
+ status = cr_input_peek_char (a_this, &cur_char);
+ if (status != CR_OK)
+ break;
+
+ /*if the next char is a white space, consume it ! */
+ if (cr_utils_is_white_space (cur_char) == TRUE) {
+ status = cr_input_read_char (a_this, &cur_char);
+ if (status != CR_OK)
+ break;
+ continue;
+ }
+
+ break;
+
+ }
+
+ *a_nb_chars = (gulong) nb_consumed;
+
+ if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ }
+
+ return status;
+}
+
+/**
+ * cr_input_peek_char:
+ *@a_this: the current instance of #CRInput.
+ *@a_char: out parameter. The returned character.
+ *
+ *Same as cr_input_read_char() but does not update the
+ *internal state of the input stream. The next call
+ *to cr_input_peek_char() or cr_input_read_char() will thus
+ *return the same character as the current one.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_peek_char (CRInput const * a_this, guint32 * a_char)
+{
+ enum CRStatus status = CR_OK;
+ gulong consumed = 0,
+ nb_bytes_left = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_char, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->next_byte_index >=
+ PRIVATE (a_this)->in_buf_size) {
+ return CR_END_OF_INPUT_ERROR;
+ }
+
+ nb_bytes_left = cr_input_get_nb_bytes_left (a_this);
+
+ if (nb_bytes_left < 1) {
+ return CR_END_OF_INPUT_ERROR;
+ }
+
+ status = cr_utils_read_char_from_utf8_buf
+ (PRIVATE (a_this)->in_buf +
+ PRIVATE (a_this)->next_byte_index,
+ nb_bytes_left, a_char, &consumed);
+
+ return status;
+}
+
+/**
+ * cr_input_peek_byte:
+ *@a_this: the current instance of #CRInput.
+ *@a_origin: the origin to consider in the calculation
+ *of the position of the byte to peek.
+ *@a_offset: the offset of the byte to peek, starting from
+ *the origin specified by a_origin.
+ *@a_byte: out parameter the peeked byte.
+ *
+ *Gets a byte from the input stream,
+ *starting from the current position in the input stream.
+ *Unlike cr_input_peek_next_byte() this method
+ *does not update the state of the current input stream.
+ *Subsequent calls to cr_input_peek_byte with the same arguments
+ *will return the same byte.
+ *
+ *Returns CR_OK upon successful completion or,
+ *CR_BAD_PARAM_ERROR if at least one of the parameters is invalid;
+ *CR_OUT_OF_BOUNDS_ERROR if the indexed byte is out of bounds.
+ */
+enum CRStatus
+cr_input_peek_byte (CRInput const * a_this, enum CRSeekPos a_origin,
+ gulong a_offset, guchar * a_byte)
+{
+ gulong abs_offset = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_byte, CR_BAD_PARAM_ERROR);
+
+ switch (a_origin) {
+
+ case CR_SEEK_CUR:
+ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_offset;
+ break;
+
+ case CR_SEEK_BEGIN:
+ abs_offset = a_offset;
+ break;
+
+ case CR_SEEK_END:
+ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_offset;
+ break;
+
+ default:
+ return CR_BAD_PARAM_ERROR;
+ }
+
+ if (abs_offset < PRIVATE (a_this)->in_buf_size) {
+
+ *a_byte = PRIVATE (a_this)->in_buf[abs_offset];
+
+ return CR_OK;
+
+ } else {
+ return CR_END_OF_INPUT_ERROR;
+ }
+}
+
+/**
+ * cr_input_peek_byte2:
+ *@a_this: the current byte input stream.
+ *@a_offset: the offset of the byte to peek, starting
+ *from the current input position pointer.
+ *@a_eof: out parameter. Is set to true is we reach end of
+ *stream. If set to NULL by the caller, this parameter is not taken
+ *in account.
+ *
+ *Same as cr_input_peek_byte() but with a simplified
+ *interface.
+ *
+ *Returns the read byte or 0 if something bad happened.
+ */
+guchar
+cr_input_peek_byte2 (CRInput const * a_this, gulong a_offset, gboolean * a_eof)
+{
+ guchar result = 0;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), 0);
+
+ if (a_eof)
+ *a_eof = FALSE;
+
+ status = cr_input_peek_byte (a_this, CR_SEEK_CUR, a_offset, &result);
+
+ if ((status == CR_END_OF_INPUT_ERROR)
+ && a_eof)
+ *a_eof = TRUE;
+
+ return result;
+}
+
+/**
+ * cr_input_get_byte_addr:
+ *@a_this: the current instance of #CRInput.
+ *@a_offset: the offset of the byte in the input stream starting
+ *from the beginning of the stream.
+ *
+ *Gets the memory address of the byte located at a given offset
+ *in the input stream.
+ *
+ *Returns the address, otherwise NULL if an error occured.
+ */
+guchar *
+cr_input_get_byte_addr (CRInput * a_this, gulong a_offset)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+ if (a_offset >= PRIVATE (a_this)->nb_bytes) {
+ return NULL;
+ }
+
+ return &PRIVATE (a_this)->in_buf[a_offset];
+}
+
+/**
+ * cr_input_get_cur_byte_addr:
+ *@a_this: the current input stream
+ *@a_offset: out parameter. The returned address.
+ *
+ *Gets the address of the current character pointer.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_cur_byte_addr (CRInput * a_this, guchar ** a_offset)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_offset,
+ CR_BAD_PARAM_ERROR);
+
+ if (!PRIVATE (a_this)->next_byte_index) {
+ return CR_START_OF_INPUT_ERROR;
+ }
+
+ *a_offset = cr_input_get_byte_addr
+ (a_this, PRIVATE (a_this)->next_byte_index - 1);
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_seek_index:
+ *@a_this: the current instance of #CRInput.
+ *@a_origin: the origin to consider during the calculation
+ *of the absolute position of the new "current byte index".
+ *@a_pos: the relative offset of the new "current byte index."
+ *This offset is relative to the origin a_origin.
+ *
+ *Sets the "current byte index" of the current instance
+ *of #CRInput. Next call to cr_input_get_byte() will return
+ *the byte next after the new "current byte index".
+ *
+ *Returns CR_OK upon successful completion otherwise returns
+ *CR_BAD_PARAM_ERROR if at least one of the parameters is not valid
+ *or CR_OUT_BOUNDS_ERROR in case of error.
+ */
+enum CRStatus
+cr_input_seek_index (CRInput * a_this, enum CRSeekPos a_origin, gint a_pos)
+{
+
+ glong abs_offset = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ switch (a_origin) {
+
+ case CR_SEEK_CUR:
+ abs_offset = PRIVATE (a_this)->next_byte_index - 1 + a_pos;
+ break;
+
+ case CR_SEEK_BEGIN:
+ abs_offset = a_pos;
+ break;
+
+ case CR_SEEK_END:
+ abs_offset = PRIVATE (a_this)->in_buf_size - 1 - a_pos;
+ break;
+
+ default:
+ return CR_BAD_PARAM_ERROR;
+ }
+
+ if ((abs_offset > 0)
+ && (gulong) abs_offset < PRIVATE (a_this)->nb_bytes) {
+
+ /*update the input stream's internal state */
+ PRIVATE (a_this)->next_byte_index = abs_offset + 1;
+
+ return CR_OK;
+ }
+
+ return CR_OUT_OF_BOUNDS_ERROR;
+}
+
+/**
+ * cr_input_get_cur_pos:
+ *@a_this: the current instance of #CRInput.
+ *@a_pos: out parameter. The returned position.
+ *
+ *Gets the position of the "current byte index" which
+ *is basically the position of the last returned byte in the
+ *input stream.
+ *
+ *Returns CR_OK upon successful completion. Otherwise,
+ *CR_BAD_PARAMETER_ERROR if at least one of the arguments is invalid.
+ *CR_START_OF_INPUT if no call to either cr_input_read_byte()
+ *or cr_input_seek_index() have been issued before calling
+ *cr_input_get_cur_pos()
+ *Note that the out parameters of this function are valid if and only if this
+ *function returns CR_OK.
+ */
+enum CRStatus
+cr_input_get_cur_pos (CRInput const * a_this, CRInputPos * a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR);
+
+ a_pos->next_byte_index = PRIVATE (a_this)->next_byte_index;
+ a_pos->line = PRIVATE (a_this)->line;
+ a_pos->col = PRIVATE (a_this)->col;
+ a_pos->end_of_line = PRIVATE (a_this)->end_of_line;
+ a_pos->end_of_file = PRIVATE (a_this)->end_of_input;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_parsing_location:
+ *@a_this: the current instance of #CRInput
+ *@a_loc: the set parsing location.
+ *
+ *Gets the current parsing location.
+ *The Parsing location is a public datastructure that
+ *represents the current line/column/byte offset/ in the input
+ *stream.
+ *
+ *Returns CR_OK upon successful completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_input_get_parsing_location (CRInput const *a_this,
+ CRParsingLocation *a_loc)
+{
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && a_loc,
+ CR_BAD_PARAM_ERROR) ;
+
+ a_loc->line = PRIVATE (a_this)->line ;
+ a_loc->column = PRIVATE (a_this)->col ;
+ if (PRIVATE (a_this)->next_byte_index) {
+ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index - 1 ;
+ } else {
+ a_loc->byte_offset = PRIVATE (a_this)->next_byte_index ;
+ }
+ return CR_OK ;
+}
+
+/**
+ * cr_input_get_cur_index:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRInput
+ *@a_index: out parameter. The returned index.
+ *
+ *Getter of the next byte index.
+ *It actually returns the index of the
+ *next byte to be read.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_cur_index (CRInput const * a_this, glong * a_index)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_index, CR_BAD_PARAM_ERROR);
+
+ *a_index = PRIVATE (a_this)->next_byte_index;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_set_cur_index:
+ *@a_this: the "this pointer" of the current instance
+ *of #CRInput .
+ *@a_index: the new index to set.
+ *
+ *Setter of the next byte index.
+ *It sets the index of the next byte to be read.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_cur_index (CRInput * a_this, glong a_index)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->next_byte_index = a_index;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_set_end_of_file:
+ *@a_this: the current instance of #CRInput.
+ *@a_eof: the new end of file flag.
+ *
+ *Sets the end of file flag.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_file (CRInput * a_this, gboolean a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->end_of_input = a_eof;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_end_of_file:
+ *@a_this: the current instance of #CRInput.
+ *@a_eof: out parameter the place to put the end of
+ *file flag.
+ *
+ *Gets the end of file flag.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_file (CRInput const * a_this, gboolean * a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_eof, CR_BAD_PARAM_ERROR);
+
+ *a_eof = PRIVATE (a_this)->end_of_input;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_set_end_of_line:
+ *@a_this: the current instance of #CRInput.
+ *@a_eol: the new end of line flag.
+ *
+ *Sets the end of line flag.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_set_end_of_line (CRInput * a_this, gboolean a_eol)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->end_of_line = a_eol;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_get_end_of_line:
+ *@a_this: the current instance of #CRInput
+ *@a_eol: out parameter. The place to put
+ *the returned flag
+ *
+ *Gets the end of line flag of the current input.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_input_get_end_of_line (CRInput const * a_this, gboolean * a_eol)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_eol, CR_BAD_PARAM_ERROR);
+
+ *a_eol = PRIVATE (a_this)->end_of_line;
+
+ return CR_OK;
+}
+
+/**
+ * cr_input_set_cur_pos:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRInput.
+ *@a_pos: the new position.
+ *
+ *Sets the current position in the input stream.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_input_set_cur_pos (CRInput * a_this, CRInputPos const * a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pos,
+ CR_BAD_PARAM_ERROR);
+
+ cr_input_set_column_num (a_this, a_pos->col);
+ cr_input_set_line_num (a_this, a_pos->line);
+ cr_input_set_cur_index (a_this, a_pos->next_byte_index);
+ cr_input_set_end_of_line (a_this, a_pos->end_of_line);
+ cr_input_set_end_of_file (a_this, a_pos->end_of_file);
+
+ return CR_OK;
+}
diff --git a/src/3rdparty/libcroco/cr-input.h b/src/3rdparty/libcroco/cr-input.h
new file mode 100644
index 000000000..9eb402a87
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-input.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset:8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_INPUT_SRC_H__
+#define __CR_INPUT_SRC_H__
+
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The libcroco basic input stream class
+ *declaration file.
+ */
+
+typedef struct _CRInput CRInput ;
+typedef struct _CRInputPriv CRInputPriv ;
+
+/**
+ *The #CRInput class provides the abstraction of
+ *an utf8-encoded character stream.
+ */
+struct _CRInput
+{
+ CRInputPriv *priv ;
+} ;
+
+typedef struct _CRInputPos CRInputPos ;
+
+struct _CRInputPos
+{
+ glong line ;
+ glong col ;
+ gboolean end_of_file ;
+ gboolean end_of_line ;
+ glong next_byte_index ;
+} ;
+
+CRInput *
+cr_input_new_from_buf (guchar *a_buf, gulong a_len,
+ enum CREncoding a_enc, gboolean a_free_buf) ;
+CRInput *
+cr_input_new_from_uri (const gchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+void
+cr_input_destroy (CRInput *a_this) ;
+
+void
+cr_input_ref (CRInput *a_this) ;
+
+gboolean
+cr_input_unref (CRInput *a_this) ;
+
+enum CRStatus
+cr_input_read_byte (CRInput *a_this, guchar *a_byte) ;
+
+enum CRStatus
+cr_input_read_char (CRInput *a_this, guint32 *a_char) ;
+
+enum CRStatus
+cr_input_consume_chars (CRInput *a_this, guint32 a_char,
+ gulong *a_nb_char) ;
+
+enum CRStatus
+cr_input_consume_char (CRInput *a_this, guint32 a_char) ;
+
+enum CRStatus
+cr_input_consume_white_spaces (CRInput *a_this, gulong *a_nb_chars) ;
+
+enum CRStatus
+cr_input_peek_byte (CRInput const *a_this, enum CRSeekPos a_origin,
+ gulong a_offset, guchar *a_byte) ;
+
+guchar
+cr_input_peek_byte2 (CRInput const *a_this, gulong a_offset,
+ gboolean *a_eof) ;
+
+enum CRStatus
+cr_input_peek_char (CRInput const *a_this, guint32 *a_char) ;
+
+guchar *
+cr_input_get_byte_addr (CRInput *a_this,
+ gulong a_offset) ;
+
+enum CRStatus
+cr_input_get_cur_byte_addr (CRInput *a_this, guchar ** a_offset) ;
+
+enum CRStatus
+cr_input_seek_index (CRInput *a_this,
+ enum CRSeekPos a_origin, gint a_pos) ;
+
+enum CRStatus
+cr_input_get_cur_index (CRInput const *a_this, glong *a_index) ;
+
+enum CRStatus
+cr_input_set_cur_index (CRInput *a_this, glong a_index) ;
+
+enum CRStatus
+cr_input_get_cur_pos (CRInput const *a_this, CRInputPos * a_pos) ;
+
+enum CRStatus
+cr_input_set_cur_pos (CRInput *a_this, CRInputPos const *a_pos) ;
+
+enum CRStatus
+cr_input_get_parsing_location (CRInput const *a_this,
+ CRParsingLocation *a_loc) ;
+
+enum CRStatus
+cr_input_get_end_of_line (CRInput const *a_this, gboolean *a_eol) ;
+
+enum CRStatus
+cr_input_set_end_of_line (CRInput *a_this, gboolean a_eol) ;
+
+enum CRStatus
+cr_input_get_end_of_file (CRInput const *a_this, gboolean *a_eof) ;
+
+enum CRStatus
+cr_input_set_end_of_file (CRInput *a_this, gboolean a_eof) ;
+
+enum CRStatus
+cr_input_set_line_num (CRInput *a_this, glong a_line_num) ;
+
+enum CRStatus
+cr_input_get_line_num (CRInput const *a_this, glong *a_line_num) ;
+
+enum CRStatus
+cr_input_set_column_num (CRInput *a_this, glong a_col) ;
+
+enum CRStatus
+cr_input_get_column_num (CRInput const *a_this, glong *a_col) ;
+
+enum CRStatus
+cr_input_increment_line_num (CRInput *a_this,
+ glong a_increment) ;
+
+enum CRStatus
+cr_input_increment_col_num (CRInput *a_this,
+ glong a_increment) ;
+
+glong
+cr_input_get_nb_bytes_left (CRInput const *a_this) ;
+
+enum CRStatus
+cr_input_end_of_input (CRInput const *a_this, gboolean *a_end_of_input) ;
+
+G_END_DECLS
+
+#endif /*__CR_INPUT_SRC_H__*/
+
diff --git a/src/3rdparty/libcroco/cr-libxml-node-iface.c b/src/3rdparty/libcroco/cr-libxml-node-iface.c
new file mode 100644
index 000000000..bc860f974
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-libxml-node-iface.c
@@ -0,0 +1,81 @@
+#include <libxml/tree.h>
+#include <string.h>
+#include "cr-libxml-node-iface.h"
+
+static CRXMLNodePtr
+libxml_getParentNode(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return xnode->parent;
+}
+
+static CRXMLNodePtr
+libxml_getFirstChild(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return xnode->children;
+}
+
+static CRXMLNodePtr
+libxml_getNextSibling(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return xnode->next;
+}
+
+static CRXMLNodePtr
+libxml_getPrevSibling(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return xnode->prev;
+}
+
+static char const *
+local_part(char const *const qname)
+{
+ char const *ret = strrchr(qname, ':');
+ if (ret)
+ return ++ret;
+ else
+ return qname;
+}
+
+static char const *
+libxml_getLocalName(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return local_part((char *)xnode->name);
+}
+
+static char *
+libxml_getProp(CRXMLNodePtr cnode, char const *cprop)
+{
+ xmlNodePtr xnode = (xmlNodePtr) cnode;
+ xmlChar const *xprop = (xmlChar const *) cprop;
+ return (char *)xmlGetProp(xnode, xprop);
+}
+
+static gboolean
+libxml_isElementNode(CRXMLNodePtr cnode)
+{
+ xmlNode const *xnode = (xmlNode const *) cnode;
+ return xnode->type == XML_ELEMENT_NODE;
+}
+
+static void
+libxml_freePropVal(void *const cval)
+{
+ xmlFree(cval);
+}
+
+CRNodeIface const cr_libxml_node_iface = {
+ libxml_getParentNode,
+ libxml_getFirstChild,
+ libxml_getNextSibling,
+ libxml_getPrevSibling,
+ libxml_getLocalName,
+ libxml_getProp, /* fixme: Check whether we want xmlGetNoNsProp instead. */
+
+ libxml_freePropVal,
+ libxml_isElementNode
+};
diff --git a/src/3rdparty/libcroco/cr-libxml-node-iface.h b/src/3rdparty/libcroco/cr-libxml-node-iface.h
new file mode 100644
index 000000000..b4a621293
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-libxml-node-iface.h
@@ -0,0 +1,14 @@
+#ifndef __CR_LIBXML_NODE_IFACE_H__
+#define __CR_LIBXML_NODE_IFACE_H__
+
+#include <glib.h>
+#include "cr-node-iface.h"
+
+G_BEGIN_DECLS
+
+extern CRNodeIface const cr_libxml_node_iface;
+
+G_END_DECLS
+
+
+#endif/*__CR_LIBXML_NODE_IFACE_H__*/
diff --git a/src/3rdparty/libcroco/cr-node-iface.h b/src/3rdparty/libcroco/cr-node-iface.h
new file mode 100644
index 000000000..01898d641
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-node-iface.h
@@ -0,0 +1,34 @@
+#ifndef __CR_NODE_IFACE_H__
+#define __CR_NODE_IFACE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef gconstpointer CRXMLNodePtr ;
+typedef struct _CRNodeIface CRNodeIface ;
+
+struct _CRNodeIface {
+ /* Names based on DOM. */
+ CRXMLNodePtr (*getParentNode)(CRXMLNodePtr);
+ CRXMLNodePtr (*getFirstChild)(CRXMLNodePtr);
+ CRXMLNodePtr (*getNextSibling)(CRXMLNodePtr);
+ CRXMLNodePtr (*getPrevSibling)(CRXMLNodePtr);
+ char const *(*getLocalName)(CRXMLNodePtr);
+ char *(*getProp)(CRXMLNodePtr, char const *);
+
+ /* Others. */
+ void (*freePropVal)(void *);
+ gboolean (*isElementNode)(CRXMLNodePtr);
+
+#if 0
+ char const *getLang(CRXMLNodePtr);
+ /* todo: Make it easy to have the default xml rules for lang. Maybe interpret NULL
+ like this. Or provide a cr_get_xml_lang(CRNodeIface const *, CRXMLNodePtr) function. */
+#endif
+};
+
+G_END_DECLS
+
+
+#endif/*__CR_NODE_IFACE_H__*/
diff --git a/src/3rdparty/libcroco/cr-num.c b/src/3rdparty/libcroco/cr-num.c
new file mode 100644
index 000000000..6cc5150a1
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-num.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@CRNum:
+ *
+ *The definition
+ *of the #CRNum class.
+ */
+
+#include "cr-num.h"
+#include "string.h"
+
+/**
+ * cr_num_new:
+ *
+ *#CRNum.
+ *
+ *Returns the newly built instance of
+ *#CRNum.
+ */
+CRNum *
+cr_num_new (void)
+{
+ CRNum *result = NULL;
+
+ result = g_try_malloc (sizeof (CRNum));
+
+ if (result == NULL) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRNum));
+
+ return result;
+}
+
+/**
+ * cr_num_new_with_val:
+ * @a_val: the numerical value of the number.
+ * @a_type: the type of number.
+ *
+ * A constructor of #CRNum.
+ *
+ * Returns the newly built instance of #CRNum or
+ * NULL if an error arises.
+ */
+CRNum *
+cr_num_new_with_val (gdouble a_val, enum CRNumType a_type)
+{
+ CRNum *result = NULL;
+
+ result = cr_num_new ();
+
+ g_return_val_if_fail (result, NULL);
+
+ result->val = a_val;
+ result->type = a_type;
+
+ return result;
+}
+
+/**
+ * cr_num_to_string:
+ *@a_this: the current instance of #CRNum.
+ *
+ *Returns the newly built string representation
+ *of the current instance of #CRNum. The returned
+ *string is NULL terminated. The caller *must*
+ *free the returned string.
+ */
+guchar *
+cr_num_to_string (CRNum const * a_this)
+{
+ gdouble test_val = 0.0;
+
+ guchar *tmp_char1 = NULL,
+ *tmp_char2 = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ test_val = a_this->val - (glong) a_this->val;
+
+ if (!test_val) {
+ tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val);
+ } else {
+ /* We can't use g_ascii_dtostr, because that sometimes uses
+ e notation (which wouldn't be a valid number in CSS). */
+ size_t const buflen = 35; /* fairly arbitrary. */
+ tmp_char1 = (guchar *)g_malloc (buflen);
+ g_ascii_formatd ((gchar *)tmp_char1, buflen, "%.17f", a_this->val);
+ }
+
+ g_return_val_if_fail (tmp_char1, NULL);
+
+ switch (a_this->type) {
+ case NUM_LENGTH_EM:
+ tmp_char2 = (guchar *) "em";
+ break;
+
+ case NUM_LENGTH_EX:
+ tmp_char2 = (guchar *) "ex";
+ break;
+
+ case NUM_LENGTH_PX:
+ tmp_char2 = (guchar *) "px";
+ break;
+
+ case NUM_LENGTH_IN:
+ tmp_char2 = (guchar *) "in";
+ break;
+
+ case NUM_LENGTH_CM:
+ tmp_char2 = (guchar *) "cm";
+ break;
+
+ case NUM_LENGTH_MM:
+ tmp_char2 = (guchar *) "mm";
+ break;
+
+ case NUM_LENGTH_PT:
+ tmp_char2 = (guchar *) "pt";
+ break;
+
+ case NUM_LENGTH_PC:
+ tmp_char2 = (guchar *) "pc";
+ break;
+
+ case NUM_ANGLE_DEG:
+ tmp_char2 = (guchar *) "deg";
+ break;
+
+ case NUM_ANGLE_RAD:
+ tmp_char2 = (guchar *) "rad";
+ break;
+
+ case NUM_ANGLE_GRAD:
+ tmp_char2 = (guchar *) "grad";
+ break;
+
+ case NUM_TIME_MS:
+ tmp_char2 = (guchar *) "ms";
+ break;
+
+ case NUM_TIME_S:
+ tmp_char2 = (guchar *) "s";
+ break;
+
+ case NUM_FREQ_HZ:
+ tmp_char2 = (guchar *) "Hz";
+ break;
+
+ case NUM_FREQ_KHZ:
+ tmp_char2 = (guchar *) "KHz";
+ break;
+
+ case NUM_PERCENTAGE:
+ tmp_char2 = (guchar *) "%";
+ break;
+ case NUM_INHERIT:
+ tmp_char2 = (guchar *) "inherit";
+ break ;
+ case NUM_AUTO:
+ tmp_char2 = (guchar *) "auto";
+ break ;
+ case NUM_GENERIC:
+ tmp_char2 = NULL ;
+ break ;
+ default:
+ tmp_char2 = (guchar *) "unknown";
+ break;
+ }
+
+ if (tmp_char2) {
+ result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL);
+ g_free (tmp_char1);
+ } else {
+ result = tmp_char1;
+ }
+
+ return result;
+}
+
+/**
+ * cr_num_copy:
+ *@a_src: the instance of #CRNum to copy.
+ *Must be non NULL.
+ *@a_dest: the destination of the copy.
+ *Must be non NULL
+ *
+ *Copies an instance of #CRNum.
+ *
+ *Returns CR_OK upon successful completion, an
+ *error code otherwise.
+ */
+enum CRStatus
+cr_num_copy (CRNum * a_dest, CRNum const * a_src)
+{
+ g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);
+
+ memcpy (a_dest, a_src, sizeof (CRNum));
+
+ return CR_OK;
+}
+
+/**
+ * cr_num_dup:
+ *@a_this: the instance of #CRNum to duplicate.
+ *
+ *Duplicates an instance of #CRNum
+ *
+ *Returns the newly created (duplicated) instance of #CRNum.
+ *Must be freed by cr_num_destroy().
+ */
+CRNum *
+cr_num_dup (CRNum const * a_this)
+{
+ CRNum *result = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ result = cr_num_new ();
+ g_return_val_if_fail (result, NULL);
+
+ status = cr_num_copy (result, a_this);
+ g_return_val_if_fail (status == CR_OK, NULL);
+
+ return result;
+}
+
+/**
+ * cr_num_set:
+ *Sets an instance of #CRNum.
+ *@a_this: the current instance of #CRNum to be set.
+ *@a_val: the new numerical value to be hold by the current
+ *instance of #CRNum
+ *@a_type: the new type of #CRNum.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_num_set (CRNum * a_this, gdouble a_val, enum CRNumType a_type)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ a_this->val = a_val;
+ a_this->type = a_type;
+
+ return CR_OK;
+}
+
+/**
+ * cr_num_is_fixed_length:
+ * @a_this: the current instance of #CRNum .
+ *
+ *Tests if the current instance of #CRNum is a fixed
+ *length value or not. Typically a fixed length value
+ *is anything from NUM_LENGTH_EM to NUM_LENGTH_PC.
+ *See the definition of #CRNumType to see what we mean.
+ *
+ *Returns TRUE if the instance of #CRNum is a fixed length number,
+ *FALSE otherwise.
+ */
+gboolean
+cr_num_is_fixed_length (CRNum const * a_this)
+{
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->type >= NUM_LENGTH_EM
+ && a_this->type <= NUM_LENGTH_PC) {
+ result = TRUE ;
+ }
+ return result ;
+}
+
+/**
+ * cr_num_destroy:
+ *@a_this: the this pointer of
+ *the current instance of #CRNum.
+ *
+ *The destructor of #CRNum.
+ */
+void
+cr_num_destroy (CRNum * a_this)
+{
+ g_return_if_fail (a_this);
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-num.h b/src/3rdparty/libcroco/cr-num.h
new file mode 100644
index 000000000..2b73aaf79
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-num.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information
+ */
+
+
+/**
+ *@file
+ *The declaration
+ *of the #CRNum class.
+ */
+
+#ifndef __CR_NUM_H__
+#define __CR_NUM_H__
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRNum class.
+ *
+ */
+
+/**
+ *The different types
+ *of numbers.
+ *Please, do not modify
+ *the declaration order of the enum
+ *members, unless you know
+ *what you are doing.
+ */
+enum CRNumType
+{
+ NUM_AUTO = 0,
+ NUM_GENERIC,
+ NUM_LENGTH_EM,
+ NUM_LENGTH_EX,
+ NUM_LENGTH_PX,
+ NUM_LENGTH_IN,
+ NUM_LENGTH_CM,
+ NUM_LENGTH_MM,
+ NUM_LENGTH_PT,
+ NUM_LENGTH_PC,
+ NUM_ANGLE_DEG,
+ NUM_ANGLE_RAD,
+ NUM_ANGLE_GRAD,
+ NUM_TIME_MS,
+ NUM_TIME_S,
+ NUM_FREQ_HZ,
+ NUM_FREQ_KHZ,
+ NUM_PERCENTAGE,
+ NUM_INHERIT,
+ NUM_UNKNOWN_TYPE,
+ NB_NUM_TYPE
+} ;
+
+
+/**
+ *An abstraction of a number (num)
+ *as defined in the css2 spec.
+ */
+typedef struct _CRNum CRNum ;
+
+/**
+ *An abstraction of a number (num)
+ *as defined in the css2 spec.
+ */
+struct _CRNum
+{
+ enum CRNumType type ;
+ gdouble val ;
+ CRParsingLocation location ;
+} ;
+
+CRNum *
+cr_num_new (void) ;
+
+CRNum *
+cr_num_new_with_val (gdouble a_val,
+ enum CRNumType a_type) ;
+
+CRNum *
+cr_num_dup (CRNum const *a_this) ;
+
+guchar *
+cr_num_to_string (CRNum const *a_this) ;
+
+enum CRStatus
+cr_num_copy (CRNum *a_dest, CRNum const *a_src) ;
+
+enum CRStatus
+cr_num_set (CRNum *a_this, gdouble a_val,
+ enum CRNumType a_type) ;
+
+gboolean
+cr_num_is_fixed_length (CRNum const *a_this) ;
+
+void
+cr_num_destroy (CRNum *a_this) ;
+
+
+G_END_DECLS
+
+
+#endif /*__CR_NUM_H__*/
diff --git a/src/3rdparty/libcroco/cr-om-parser.c b/src/3rdparty/libcroco/cr-om-parser.c
new file mode 100644
index 000000000..596cd6e6b
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-om-parser.c
@@ -0,0 +1,1151 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-utils.h"
+#include "cr-om-parser.h"
+
+/**
+ *@CROMParser:
+ *
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+struct _CROMParserPriv {
+ CRParser *parser;
+};
+
+#define PRIVATE(a_this) ((a_this)->priv)
+
+/*
+ *Forward declaration of a type defined later
+ *in this file.
+ */
+struct _ParsingContext;
+typedef struct _ParsingContext ParsingContext;
+
+static ParsingContext *new_parsing_context (void);
+
+static void destroy_context (ParsingContext * a_ctxt);
+
+static void unrecoverable_error (CRDocHandler * a_this);
+
+static void error (CRDocHandler * a_this);
+
+static void property (CRDocHandler * a_this,
+ CRString * a_name,
+ CRTerm * a_expression,
+ gboolean a_important);
+
+static void end_selector (CRDocHandler * a_this,
+ CRSelector * a_selector_list);
+
+static void start_selector (CRDocHandler * a_this,
+ CRSelector * a_selector_list);
+
+static void start_font_face (CRDocHandler * a_this,
+ CRParsingLocation *a_location);
+
+static void end_font_face (CRDocHandler * a_this);
+
+static void end_document (CRDocHandler * a_this);
+
+static void start_document (CRDocHandler * a_this);
+
+static void charset (CRDocHandler * a_this,
+ CRString * a_charset,
+ CRParsingLocation *a_location);
+
+static void start_page (CRDocHandler * a_this, CRString * a_page,
+ CRString * a_pseudo_page,
+ CRParsingLocation *a_location);
+
+static void end_page (CRDocHandler * a_this, CRString * a_page,
+ CRString * a_pseudo_page);
+
+static void start_media (CRDocHandler * a_this,
+ GList * a_media_list,
+ CRParsingLocation *a_location);
+
+static void end_media (CRDocHandler * a_this,
+ GList * a_media_list);
+
+static void import_style (CRDocHandler * a_this,
+ GList * a_media_list,
+ CRString * a_uri,
+ CRString * a_uri_default_ns,
+ CRParsingLocation *a_location);
+
+struct _ParsingContext {
+ CRStyleSheet *stylesheet;
+ CRStatement *cur_stmt;
+ CRStatement *cur_media_stmt;
+};
+
+/********************************************
+ *Private methods
+ ********************************************/
+
+static ParsingContext *
+new_parsing_context (void)
+{
+ ParsingContext *result = NULL;
+
+ result = g_try_malloc (sizeof (ParsingContext));
+ if (!result) {
+ cr_utils_trace_info ("Out of Memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (ParsingContext));
+ return result;
+}
+
+static void
+destroy_context (ParsingContext * a_ctxt)
+{
+ g_return_if_fail (a_ctxt);
+
+ if (a_ctxt->stylesheet) {
+ cr_stylesheet_destroy (a_ctxt->stylesheet);
+ a_ctxt->stylesheet = NULL;
+ }
+ if (a_ctxt->cur_stmt) {
+ cr_statement_destroy (a_ctxt->cur_stmt);
+ a_ctxt->cur_stmt = NULL;
+ }
+ g_free (a_ctxt);
+}
+
+static enum CRStatus
+cr_om_parser_init_default_sac_handler (CROMParser * a_this)
+{
+ CRDocHandler *sac_handler = NULL;
+ gboolean created_handler = FALSE;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->parser,
+ CR_BAD_PARAM_ERROR);
+
+ status = cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+ &sac_handler);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ if (!sac_handler) {
+ sac_handler = cr_doc_handler_new ();
+ created_handler = TRUE;
+ }
+
+ /*
+ *initialyze here the sac handler.
+ */
+ sac_handler->start_document = start_document;
+ sac_handler->end_document = end_document;
+ sac_handler->start_selector = start_selector;
+ sac_handler->end_selector = end_selector;
+ sac_handler->property = property;
+ sac_handler->start_font_face = start_font_face;
+ sac_handler->end_font_face = end_font_face;
+ sac_handler->error = error;
+ sac_handler->unrecoverable_error = unrecoverable_error;
+ sac_handler->charset = charset;
+ sac_handler->start_page = start_page;
+ sac_handler->end_page = end_page;
+ sac_handler->start_media = start_media;
+ sac_handler->end_media = end_media;
+ sac_handler->import_style = import_style;
+
+ if (created_handler) {
+ status = cr_parser_set_sac_handler (PRIVATE (a_this)->parser,
+ sac_handler);
+ cr_doc_handler_unref (sac_handler);
+ }
+
+ return status;
+
+}
+
+static void
+start_document (CRDocHandler * a_this)
+{
+ ParsingContext *ctxt = NULL;
+ CRStyleSheet *stylesheet = NULL;
+
+ g_return_if_fail (a_this);
+
+ ctxt = new_parsing_context ();
+ g_return_if_fail (ctxt);
+
+ stylesheet = cr_stylesheet_new (NULL);
+ ctxt->stylesheet = stylesheet;
+ cr_doc_handler_set_ctxt (a_this, ctxt);
+}
+
+static void
+start_font_face (CRDocHandler * a_this,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ (void) a_location;
+
+ g_return_if_fail (a_this);
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+ g_return_if_fail (ctxt->cur_stmt == NULL);
+
+ ctxt->cur_stmt =
+ cr_statement_new_at_font_face_rule (ctxt->stylesheet, NULL);
+
+ g_return_if_fail (ctxt->cur_stmt);
+}
+
+static void
+end_font_face (CRDocHandler * a_this)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ CRStatement *stmts = NULL;
+
+ g_return_if_fail (a_this);
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+ g_return_if_fail
+ (ctxt->cur_stmt
+ && ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+ && ctxt->stylesheet);
+
+ stmts = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_stmt);
+ if (!stmts)
+ goto error;
+
+ ctxt->stylesheet->statements = stmts;
+ stmts = NULL;
+ ctxt->cur_stmt = NULL;
+
+ return;
+
+ error:
+
+ if (ctxt->cur_stmt) {
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ }
+
+ if (!stmts) {
+ cr_statement_destroy (stmts);
+ stmts = NULL;
+ }
+}
+
+static void
+end_document (CRDocHandler * a_this)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ if (!ctxt->stylesheet || ctxt->cur_stmt)
+ goto error;
+
+ status = cr_doc_handler_set_result (a_this, ctxt->stylesheet);
+ g_return_if_fail (status == CR_OK);
+
+ ctxt->stylesheet = NULL;
+ destroy_context (ctxt);
+ cr_doc_handler_set_ctxt (a_this, NULL);
+
+ return;
+
+ error:
+ if (ctxt) {
+ destroy_context (ctxt);
+ }
+}
+
+static void
+charset (CRDocHandler * a_this, CRString * a_charset,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *stmt = NULL,
+ *stmt2 = NULL;
+ CRString *charset = NULL;
+
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ (void) a_location;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+ g_return_if_fail (ctxt->stylesheet);
+
+ charset = cr_string_dup (a_charset) ;
+ stmt = cr_statement_new_at_charset_rule (ctxt->stylesheet, charset);
+ g_return_if_fail (stmt);
+ stmt2 = cr_statement_append (ctxt->stylesheet->statements, stmt);
+ if (!stmt2) {
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ stmt = NULL;
+ }
+ if (charset) {
+ cr_string_destroy (charset);
+ }
+ return;
+ }
+ ctxt->stylesheet->statements = stmt2;
+ stmt2 = NULL;
+}
+
+static void
+start_page (CRDocHandler * a_this,
+ CRString * a_page,
+ CRString * a_pseudo,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ (void) a_location;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+ g_return_if_fail (ctxt->cur_stmt == NULL);
+
+ ctxt->cur_stmt = cr_statement_new_at_page_rule
+ (ctxt->stylesheet, NULL, NULL, NULL);
+ if (a_page) {
+ ctxt->cur_stmt->kind.page_rule->name =
+ cr_string_dup (a_page) ;
+
+ if (!ctxt->cur_stmt->kind.page_rule->name) {
+ goto error;
+ }
+ }
+ if (a_pseudo) {
+ ctxt->cur_stmt->kind.page_rule->pseudo =
+ cr_string_dup (a_pseudo) ;
+ if (!ctxt->cur_stmt->kind.page_rule->pseudo) {
+ goto error;
+ }
+ }
+ return;
+
+ error:
+ if (ctxt->cur_stmt) {
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ }
+}
+
+static void
+end_page (CRDocHandler * a_this,
+ CRString * a_page,
+ CRString * a_pseudo_page)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ CRStatement *stmt = NULL;
+
+ (void) a_page;
+ (void) a_pseudo_page;
+
+ g_return_if_fail (a_this);
+
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ g_return_if_fail (ctxt->cur_stmt
+ && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
+ && ctxt->stylesheet);
+
+ stmt = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_stmt);
+
+ if (stmt) {
+ ctxt->stylesheet->statements = stmt;
+ stmt = NULL;
+ ctxt->cur_stmt = NULL;
+ }
+
+ if (ctxt->cur_stmt) {
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ }
+ a_page = NULL; /*keep compiler happy */
+ a_pseudo_page = NULL; /*keep compiler happy */
+}
+
+static void
+start_media (CRDocHandler * a_this,
+ GList * a_media_list,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ GList *media_list = NULL;
+
+ (void) a_location;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ g_return_if_fail (ctxt
+ && ctxt->cur_stmt == NULL
+ && ctxt->cur_media_stmt == NULL
+ && ctxt->stylesheet);
+ if (a_media_list) {
+ /*duplicate the media_list */
+ media_list = cr_utils_dup_glist_of_cr_string
+ (a_media_list);
+ }
+ ctxt->cur_media_stmt =
+ cr_statement_new_at_media_rule
+ (ctxt->stylesheet, NULL, media_list);
+
+}
+
+static void
+end_media (CRDocHandler * a_this, GList * a_media_list)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ CRStatement *stmts = NULL;
+
+ (void) a_media_list;
+
+ g_return_if_fail (a_this);
+
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ g_return_if_fail (ctxt
+ && ctxt->cur_media_stmt
+ && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
+ && ctxt->stylesheet);
+
+ stmts = cr_statement_append (ctxt->stylesheet->statements,
+ ctxt->cur_media_stmt);
+
+ if (!stmts) {
+ cr_statement_destroy (ctxt->cur_media_stmt);
+ ctxt->cur_media_stmt = NULL;
+ }
+
+ ctxt->stylesheet->statements = stmts;
+ stmts = NULL;
+
+ ctxt->cur_stmt = NULL ;
+ ctxt->cur_media_stmt = NULL ;
+ a_media_list = NULL;
+}
+
+static void
+import_style (CRDocHandler * a_this,
+ GList * a_media_list,
+ CRString * a_uri,
+ CRString * a_uri_default_ns,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ CRString *uri = NULL;
+ CRStatement *stmt = NULL,
+ *stmt2 = NULL;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ GList *media_list = NULL ;
+
+ (void) a_uri_default_ns;
+ (void) a_location;
+
+ g_return_if_fail (a_this);
+
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ g_return_if_fail (ctxt->stylesheet);
+
+ uri = cr_string_dup (a_uri) ;
+
+ if (a_media_list)
+ media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
+
+ stmt = cr_statement_new_at_import_rule
+ (ctxt->stylesheet, uri, media_list, NULL);
+
+ if (!stmt)
+ goto error;
+
+ if (ctxt->cur_stmt) {
+ stmt2 = cr_statement_append (ctxt->cur_stmt, stmt);
+ if (!stmt2)
+ goto error;
+ ctxt->cur_stmt = stmt2;
+ stmt2 = NULL;
+ stmt = NULL;
+ } else {
+ stmt2 = cr_statement_append (ctxt->stylesheet->statements,
+ stmt);
+ if (!stmt2)
+ goto error;
+ ctxt->stylesheet->statements = stmt2;
+ stmt2 = NULL;
+ stmt = NULL;
+ }
+
+ return;
+
+ error:
+ if (uri) {
+ cr_string_destroy (uri);
+ }
+
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ stmt = NULL;
+ }
+ a_uri_default_ns = NULL; /*keep compiler happy */
+}
+
+static void
+start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
+{
+ enum CRStatus status = CR_OK ;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+ if (ctxt->cur_stmt) {
+ /*hmm, this should be NULL so free it */
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ }
+
+ ctxt->cur_stmt = cr_statement_new_ruleset
+ (ctxt->stylesheet, a_selector_list, NULL, NULL);
+}
+
+static void
+end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ (void) a_selector_list;
+
+ g_return_if_fail (a_this);
+
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
+
+ if (ctxt->cur_stmt) {
+ CRStatement *stmts = NULL;
+
+ if (ctxt->cur_media_stmt) {
+ CRAtMediaRule *media_rule = NULL;
+
+ media_rule = ctxt->cur_media_stmt->kind.media_rule;
+
+ stmts = cr_statement_append
+ (media_rule->rulesets, ctxt->cur_stmt);
+
+ if (!stmts) {
+ cr_utils_trace_info
+ ("Could not append a new statement");
+ cr_statement_destroy (media_rule->rulesets);
+ ctxt->cur_media_stmt->
+ kind.media_rule->rulesets = NULL;
+ return;
+ }
+ media_rule->rulesets = stmts;
+ ctxt->cur_stmt = NULL;
+ } else {
+ stmts = cr_statement_append
+ (ctxt->stylesheet->statements,
+ ctxt->cur_stmt);
+ if (!stmts) {
+ cr_utils_trace_info
+ ("Could not append a new statement");
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ return;
+ }
+ ctxt->stylesheet->statements = stmts;
+ ctxt->cur_stmt = NULL;
+ }
+
+ }
+
+ a_selector_list = NULL; /*keep compiler happy */
+}
+
+static void
+property (CRDocHandler * a_this,
+ CRString * a_name,
+ CRTerm * a_expression,
+ gboolean a_important)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+ CRDeclaration *decl = NULL,
+ *decl2 = NULL;
+ CRString *str = NULL;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ /*
+ *make sure a current ruleset statement has been allocated
+ *already.
+ */
+ g_return_if_fail
+ (ctxt->cur_stmt
+ &&
+ (ctxt->cur_stmt->type == RULESET_STMT
+ || ctxt->cur_stmt->type == AT_FONT_FACE_RULE_STMT
+ || ctxt->cur_stmt->type == AT_PAGE_RULE_STMT));
+
+ if (a_name) {
+ str = cr_string_dup (a_name);
+ g_return_if_fail (str);
+ }
+
+ /*instanciates a new declaration */
+ decl = cr_declaration_new (ctxt->cur_stmt, str, a_expression);
+ g_return_if_fail (decl);
+ str = NULL;
+ decl->important = a_important;
+ /*
+ *add the new declaration to the current statement
+ *being build.
+ */
+ switch (ctxt->cur_stmt->type) {
+ case RULESET_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.ruleset->decl_list, decl);
+ if (!decl2) {
+ cr_declaration_destroy (decl);
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error;
+ }
+ ctxt->cur_stmt->kind.ruleset->decl_list = decl2;
+ decl = NULL;
+ decl2 = NULL;
+ break;
+
+ case AT_FONT_FACE_RULE_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.font_face_rule->decl_list,
+ decl);
+ if (!decl2) {
+ cr_declaration_destroy (decl);
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error;
+ }
+ ctxt->cur_stmt->kind.font_face_rule->decl_list = decl2;
+ decl = NULL;
+ decl2 = NULL;
+ break;
+ case AT_PAGE_RULE_STMT:
+ decl2 = cr_declaration_append
+ (ctxt->cur_stmt->kind.page_rule->decl_list, decl);
+ if (!decl2) {
+ cr_declaration_destroy (decl);
+ cr_utils_trace_info
+ ("Could not append decl to ruleset");
+ goto error;
+ }
+ ctxt->cur_stmt->kind.page_rule->decl_list = decl2;
+ decl = NULL;
+ decl2 = NULL;
+ break;
+
+ default:
+ goto error;
+ break;
+ }
+
+ return;
+
+ error:
+ if (str) {
+ g_free (str);
+ str = NULL;
+ }
+
+ if (decl) {
+ cr_declaration_destroy (decl);
+ decl = NULL;
+ }
+}
+
+static void
+error (CRDocHandler * a_this)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ g_return_if_fail (a_this);
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK && ctxt);
+
+ if (ctxt->cur_stmt) {
+ cr_statement_destroy (ctxt->cur_stmt);
+ ctxt->cur_stmt = NULL;
+ }
+}
+
+static void
+unrecoverable_error (CRDocHandler * a_this)
+{
+ enum CRStatus status = CR_OK;
+ ParsingContext *ctxt = NULL;
+ ParsingContext **ctxtptr = NULL;
+
+ ctxtptr = &ctxt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+ g_return_if_fail (status == CR_OK);
+
+ if (ctxt) {
+ if (ctxt->stylesheet) {
+ status = cr_doc_handler_set_result
+ (a_this, ctxt->stylesheet);
+ g_return_if_fail (status == CR_OK);
+ }
+ g_free (ctxt);
+ cr_doc_handler_set_ctxt (a_this, NULL);
+ }
+}
+
+/********************************************
+ *Public methods
+ ********************************************/
+
+/**
+ * cr_om_parser_new:
+ *@a_input: the input stream.
+ *
+ *Constructor of the CROMParser.
+ *Returns the newly built instance of #CROMParser.
+ */
+CROMParser *
+cr_om_parser_new (CRInput * a_input)
+{
+ CROMParser *result = NULL;
+ enum CRStatus status = CR_OK;
+
+ result = g_try_malloc (sizeof (CROMParser));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CROMParser));
+ PRIVATE (result) = g_try_malloc (sizeof (CROMParserPriv));
+
+ if (!PRIVATE (result)) {
+ cr_utils_trace_info ("Out of memory");
+ goto error;
+ }
+
+ memset (PRIVATE (result), 0, sizeof (CROMParserPriv));
+
+ PRIVATE (result)->parser = cr_parser_new_from_input (a_input);
+
+ if (!PRIVATE (result)->parser) {
+ cr_utils_trace_info ("parsing instanciation failed");
+ goto error;
+ }
+
+ status = cr_om_parser_init_default_sac_handler (result);
+
+ if (status != CR_OK) {
+ goto error;
+ }
+
+ return result;
+
+ error:
+
+ if (result) {
+ cr_om_parser_destroy (result);
+ }
+
+ return NULL;
+}
+
+/**
+ * cr_om_parser_parse_buf:
+ *@a_this: the current instance of #CROMParser.
+ *@a_buf: the in memory buffer to parse.
+ *@a_len: the length of the in memory buffer in number of bytes.
+ *@a_enc: the encoding of the in memory buffer.
+ *@a_result: out parameter the resulting style sheet
+ *
+ *Parses the content of an in memory buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_parse_buf (CROMParser * a_this,
+ const guchar * a_buf,
+ gulong a_len,
+ enum CREncoding a_enc, CRStyleSheet ** a_result)
+{
+
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && a_result, CR_BAD_PARAM_ERROR);
+
+ if (!PRIVATE (a_this)->parser) {
+ PRIVATE (a_this)->parser = cr_parser_new (NULL);
+ }
+
+ status = cr_parser_parse_buf (PRIVATE (a_this)->parser,
+ a_buf, a_len, a_enc);
+
+ if (status == CR_OK) {
+ CRStyleSheet *result = NULL;
+ CRStyleSheet **resultptr = NULL;
+ CRDocHandler *sac_handler = NULL;
+
+ cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+ &sac_handler);
+ g_return_val_if_fail (sac_handler, CR_ERROR);
+ resultptr = &result;
+ status = cr_doc_handler_get_result (sac_handler,
+ (gpointer *) resultptr);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ if (result)
+ *a_result = result;
+ }
+
+ return status;
+}
+
+/**
+ * cr_om_parser_simply_parse_buf:
+ *@a_buf: the css2 in memory buffer.
+ *@a_len: the length of the in memory buffer.
+ *@a_enc: the encoding of the in memory buffer.
+ *@a_result: out parameter. The resulting css2 style sheet.
+ *
+ *The simpler way to parse an in memory css2 buffer.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_simply_parse_buf (const guchar * a_buf,
+ gulong a_len,
+ enum CREncoding a_enc,
+ CRStyleSheet ** a_result)
+{
+ CROMParser *parser = NULL;
+ enum CRStatus status = CR_OK;
+
+ parser = cr_om_parser_new (NULL);
+ if (!parser) {
+ cr_utils_trace_info ("Could not create om parser");
+ cr_utils_trace_info ("System possibly out of memory");
+ return CR_ERROR;
+ }
+
+ status = cr_om_parser_parse_buf (parser, a_buf, a_len,
+ a_enc, a_result);
+
+ if (parser) {
+ cr_om_parser_destroy (parser);
+ parser = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * cr_om_parser_parse_file:
+ *@a_this: the current instance of the cssom parser.
+ *@a_file_uri: the uri of the file.
+ *(only local file paths are suppported so far)
+ *@a_enc: the encoding of the file.
+ *@a_result: out parameter. A pointer
+ *the build css object model.
+ *
+ *Parses a css2 stylesheet contained
+ *in a file.
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_om_parser_parse_file (CROMParser * a_this,
+ const guchar * a_file_uri,
+ enum CREncoding a_enc, CRStyleSheet ** a_result)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && a_file_uri && a_result,
+ CR_BAD_PARAM_ERROR);
+
+ if (!PRIVATE (a_this)->parser) {
+ PRIVATE (a_this)->parser = cr_parser_new_from_file
+ (a_file_uri, a_enc);
+ }
+
+ status = cr_parser_parse_file (PRIVATE (a_this)->parser,
+ a_file_uri, a_enc);
+
+ if (status == CR_OK) {
+ CRStyleSheet *result = NULL;
+ CRStyleSheet **resultptr = NULL;
+ CRDocHandler *sac_handler = NULL;
+
+ cr_parser_get_sac_handler (PRIVATE (a_this)->parser,
+ &sac_handler);
+ g_return_val_if_fail (sac_handler, CR_ERROR);
+ resultptr = &result;
+ status = cr_doc_handler_get_result
+ (sac_handler, (gpointer *) resultptr);
+ g_return_val_if_fail (status == CR_OK, status);
+ if (result)
+ *a_result = result;
+ }
+
+ return status;
+}
+
+/**
+ * cr_om_parser_simply_parse_file:
+ *@a_file_path: the css2 local file path.
+ *@a_enc: the file encoding.
+ *@a_result: out parameter. The returned css stylesheet.
+ *Must be freed by the caller using cr_stylesheet_destroy.
+ *
+ *The simpler method to parse a css2 file.
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ *Note that this method uses cr_om_parser_parse_file() so both methods
+ *have the same return values.
+ */
+enum CRStatus
+cr_om_parser_simply_parse_file (const guchar * a_file_path,
+ enum CREncoding a_enc,
+ CRStyleSheet ** a_result)
+{
+ CROMParser *parser = NULL;
+ enum CRStatus status = CR_OK;
+
+ parser = cr_om_parser_new (NULL);
+ if (!parser) {
+ cr_utils_trace_info ("Could not allocate om parser");
+ cr_utils_trace_info ("System may be out of memory");
+ return CR_ERROR;
+ }
+
+ status = cr_om_parser_parse_file (parser, a_file_path,
+ a_enc, a_result);
+ if (parser) {
+ cr_om_parser_destroy (parser);
+ parser = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * cr_om_parser_parse_paths_to_cascade:
+ *@a_this: the current instance of #CROMParser
+ *@a_author_path: the path to the author stylesheet
+ *@a_user_path: the path to the user stylesheet
+ *@a_ua_path: the path to the User Agent stylesheet
+ *@a_encoding: the encoding of the sheets.
+ *@a_result: out parameter. The resulting cascade if the parsing
+ *was okay
+ *
+ *Parses three sheets located by their paths and build a cascade
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise
+ */
+enum CRStatus
+cr_om_parser_parse_paths_to_cascade (CROMParser * a_this,
+ const guchar * a_author_path,
+ const guchar * a_user_path,
+ const guchar * a_ua_path,
+ enum CREncoding a_encoding,
+ CRCascade ** a_result)
+{
+ enum CRStatus status = CR_OK;
+
+ /*0->author sheet, 1->user sheet, 2->UA sheet */
+ CRStyleSheet *sheets[3];
+ guchar *paths[3];
+ CRCascade *result = NULL;
+ gint i = 0;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ memset (sheets, 0, sizeof (CRStyleSheet*) * 3);
+ paths[0] = (guchar *) a_author_path;
+ paths[1] = (guchar *) a_user_path;
+ paths[2] = (guchar *) a_ua_path;
+
+ for (i = 0; i < 3; i++) {
+ status = cr_om_parser_parse_file (a_this, paths[i],
+ a_encoding, &sheets[i]);
+ if (status != CR_OK) {
+ if (sheets[i]) {
+ cr_stylesheet_unref (sheets[i]);
+ sheets[i] = NULL;
+ }
+ continue;
+ }
+ }
+ result = cr_cascade_new (sheets[0], sheets[1], sheets[2]);
+ if (!result) {
+ for (i = 0; i < 3; i++) {
+ cr_stylesheet_unref (sheets[i]);
+ sheets[i] = 0;
+ }
+ return CR_ERROR;
+ }
+ *a_result = result;
+ return CR_OK;
+}
+
+/**
+ * cr_om_parser_simply_parse_paths_to_cascade:
+ *@a_author_path: the path to the author stylesheet
+ *@a_user_path: the path to the user stylesheet
+ *@a_ua_path: the path to the User Agent stylesheet
+ *@a_encoding: the encoding of the sheets.
+ *@a_result: out parameter. The resulting cascade if the parsing
+ *was okay
+ *
+ *Parses three sheets located by their paths and build a cascade
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise
+ */
+enum CRStatus
+cr_om_parser_simply_parse_paths_to_cascade (const guchar * a_author_path,
+ const guchar * a_user_path,
+ const guchar * a_ua_path,
+ enum CREncoding a_encoding,
+ CRCascade ** a_result)
+{
+ enum CRStatus status = CR_OK;
+ CROMParser *parser = NULL;
+
+ parser = cr_om_parser_new (NULL);
+ if (!parser) {
+ cr_utils_trace_info ("could not allocated om parser");
+ cr_utils_trace_info ("System may be out of memory");
+ return CR_ERROR;
+ }
+ status = cr_om_parser_parse_paths_to_cascade (parser,
+ a_author_path,
+ a_user_path,
+ a_ua_path,
+ a_encoding, a_result);
+ if (parser) {
+ cr_om_parser_destroy (parser);
+ parser = NULL;
+ }
+ return status;
+}
+
+/**
+ * cr_om_parser_destroy:
+ *@a_this: the current instance of #CROMParser.
+ *
+ *Destructor of the #CROMParser.
+ */
+void
+cr_om_parser_destroy (CROMParser * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ if (PRIVATE (a_this)->parser) {
+ cr_parser_destroy (PRIVATE (a_this)->parser);
+ PRIVATE (a_this)->parser = NULL;
+ }
+
+ if (PRIVATE (a_this)) {
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ }
+
+ if (a_this) {
+ g_free (a_this);
+ a_this = NULL;
+ }
+}
diff --git a/src/3rdparty/libcroco/cr-om-parser.h b/src/3rdparty/libcroco/cr-om-parser.h
new file mode 100644
index 000000000..13d35b1cd
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-om-parser.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ *$Id$
+ */
+
+#ifndef __CR_OM_PARSER_H__
+#define __CR_OM_PARSER_H__
+
+#include "cr-parser.h"
+#include "cr-cascade.h"
+
+
+/**
+ *@file
+ *The definition of the CSS Object Model Parser.
+ *This parser uses (and sits) the SAC api of libcroco defined
+ *in cr-parser.h and cr-doc-handler.h
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CROMParser CROMParser ;
+typedef struct _CROMParserPriv CROMParserPriv ;
+
+/**
+ *The Object model parser.
+ *Can parse a css file and build a css object model.
+ *This parser uses an instance of #CRParser and defines
+ *a set of SAC callbacks to build the Object Model.
+ */
+struct _CROMParser
+{
+ CROMParserPriv *priv ;
+} ;
+
+CROMParser * cr_om_parser_new (CRInput *a_input) ;
+
+
+enum CRStatus cr_om_parser_simply_parse_file (const guchar *a_file_path,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_file (CROMParser *a_this,
+ const guchar *a_file_uri,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_simply_parse_buf (const guchar *a_buf,
+ gulong a_len,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_buf (CROMParser *a_this,
+ const guchar *a_buf,
+ gulong a_len,
+ enum CREncoding a_enc,
+ CRStyleSheet **a_result) ;
+
+enum CRStatus cr_om_parser_parse_paths_to_cascade (CROMParser *a_this,
+ const guchar *a_author_path,
+ const guchar *a_user_path,
+ const guchar *a_ua_path,
+ enum CREncoding a_encoding,
+ CRCascade ** a_result) ;
+
+enum CRStatus cr_om_parser_simply_parse_paths_to_cascade (const guchar *a_author_path,
+ const guchar *a_user_path,
+ const guchar *a_ua_path,
+ enum CREncoding a_encoding,
+ CRCascade ** a_result) ;
+
+void cr_om_parser_destroy (CROMParser *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_OM_PARSER_H__*/
diff --git a/src/3rdparty/libcroco/cr-parser.c b/src/3rdparty/libcroco/cr-parser.c
new file mode 100644
index 000000000..6d1e64d28
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-parser.c
@@ -0,0 +1,4538 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the
+ * GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@CRParser:
+ *
+ *The definition of the #CRParser class.
+ */
+
+#include "string.h"
+#include "cr-parser.h"
+#include "cr-num.h"
+#include "cr-term.h"
+#include "cr-simple-sel.h"
+#include "cr-attr-sel.h"
+
+/*
+ *Random notes:
+ *CSS core syntax vs CSS level 2 syntax
+ *=====================================
+ *
+ *One must keep in mind
+ *that css UA must comply with two syntaxes.
+ *
+ *1/the specific syntax that defines the css language
+ *for a given level of specificatin (e.g css2 syntax
+ *defined in appendix D.1 of the css2 spec)
+ *
+ *2/the core (general) syntax that is there to allow
+ *UAs to parse style sheets written in levels of CSS that
+ *didn't exist at the time the UAs were created.
+ *
+ *the name of parsing functions (or methods) contained in this file
+ *follows the following scheme: cr_parser_parse_<production_name> (...) ;
+ *where <production_name> is the name
+ *of a production of the css2 language.
+ *When a given production is
+ *defined by the css2 level grammar *and* by the
+ *css core syntax, there will be two functions to parse that production:
+ *one will parse the production defined by the css2 level grammar and the
+ *other will parse the production defined by the css core grammar.
+ *The css2 level grammar related parsing function will be called:
+ *cr_parser_parse_<production_name> (...) ;
+ *Then css core grammar related parsing function will be called:
+ *cr_parser_parse_<production_name>_core (...) ;
+ *
+ *If a production is defined only by the css core grammar, then
+ *it will be named:
+ *cr_parser_parse_<production_name>_core (...) ;
+ */
+
+typedef struct _CRParserError CRParserError;
+
+/**
+ *An abstraction of an error reported by by the
+ *parsing routines.
+ */
+struct _CRParserError {
+ guchar *msg;
+ enum CRStatus status;
+ glong line;
+ glong column;
+ glong byte_num;
+};
+
+enum CRParserState {
+ READY_STATE = 0,
+ TRY_PARSE_CHARSET_STATE,
+ CHARSET_PARSED_STATE,
+ TRY_PARSE_IMPORT_STATE,
+ IMPORT_PARSED_STATE,
+ TRY_PARSE_RULESET_STATE,
+ RULESET_PARSED_STATE,
+ TRY_PARSE_MEDIA_STATE,
+ MEDIA_PARSED_STATE,
+ TRY_PARSE_PAGE_STATE,
+ PAGE_PARSED_STATE,
+ TRY_PARSE_FONT_FACE_STATE,
+ FONT_FACE_PARSED_STATE
+} ;
+
+/**
+ *The private attributes of
+ *#CRParser.
+ */
+struct _CRParserPriv {
+ /**
+ *The tokenizer
+ */
+ CRTknzr *tknzr;
+
+ /**
+ *The sac handlers to call
+ *to notify the parsing of
+ *the css2 constructions.
+ */
+ CRDocHandler *sac_handler;
+
+ /**
+ *A stack of errors reported
+ *by the parsing routines.
+ *Contains instance of #CRParserError.
+ *This pointer is the top of the stack.
+ */
+ GList *err_stack;
+
+ enum CRParserState state;
+ gboolean resolve_import;
+ gboolean is_case_sensitive;
+ gboolean use_core_grammar;
+};
+
+#define PRIVATE(obj) ((obj)->priv)
+
+#define CHARS_TAB_SIZE 12
+
+/**
+ * IS_NUM:
+ *@a_char: the char to test.
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned
+ *by the current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+ if (is_exception == FALSE) \
+ { \
+ status = CR_PARSING_ERROR ; \
+ } \
+ goto error ; \
+}
+
+/**
+ * CHECK_PARSING_STATUS_ERR:
+ *@a_this: the current instance of #CRParser .
+ *@a_status: the status to check. Is of type enum #CRStatus.
+ *@a_is_exception: in case of error, if is TRUE, the status
+ *is set to CR_PARSING_ERROR before goto error. If is false, the
+ *real low level status is kept and will be returned by the
+ *upper level function that called this macro. Usually, this must
+ *be set to FALSE.
+ *
+ *same as CHECK_PARSING_STATUS() but this one pushes an error
+ *on the parser error stack when an error arises.
+ *
+ */
+#define CHECK_PARSING_STATUS_ERR(a_this, a_status, a_is_exception,\
+ a_err_msg, a_err_status) \
+if ((a_status) != CR_OK) \
+{ \
+ if (a_is_exception == FALSE) a_status = CR_PARSING_ERROR ; \
+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+ goto error ; \
+}
+
+/**
+ *Peeks the next char from the input stream of the current parser
+ *by invoking cr_tknzr_input_peek_char().
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_peek_char().
+ *
+ *@param a_this the current instance of #CRParser.
+ *@param a_to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_this, a_to_char) \
+{\
+enum CRStatus pnc_status ; \
+pnc_status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (pnc_status, TRUE) \
+}
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param a_this the curent instance of #CRParser
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_this, a_to_char) \
+status = cr_tknzr_read_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param a_this the current instance of #CRParser.
+ *@param a_pos out parameter. A pointer to the position
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_this, a_pos) \
+status = cr_tknzr_get_cur_pos (PRIVATE \
+(a_this)->tknzr, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRParser.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_this, a_addr) \
+status = cr_tknzr_get_cur_byte_addr \
+ (PRIVATE (a_this)->tknzr, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRParser.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_parser, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr, \
+ a_offset, \
+ a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+#define BYTE(a_parser, a_offset, a_eof) \
+cr_tknzr_peek_byte2 (PRIVATE (a_this)->tknzr, a_offset, a_eof)
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_this the current instance of #CRParser.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_this, a_byte_ptr) \
+status = cr_tknzr_read_byte (PRIVATE (a_this)->tknzr, a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_this, a_nb_bytes) \
+status = cr_tknzr_seek_index (PRIVATE (a_this)->tknzr, \
+ CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRParser.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_parser, a_nb_chars) \
+{ \
+glong nb_chars = a_nb_chars ; \
+status = cr_tknzr_consume_chars \
+ (PRIVATE (a_parser)->tknzr,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+#define ENSURE_PARSING_COND_ERR(a_this, a_condition, \
+ a_err_msg, a_err_status) \
+if (! (a_condition)) \
+{ \
+ status = CR_PARSING_ERROR; \
+ cr_parser_push_error (a_this, a_err_msg, a_err_status) ; \
+ goto error ; \
+}
+
+#define GET_NEXT_TOKEN(a_this, a_token_ptr) \
+status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, \
+ a_token_ptr) ; \
+ENSURE_PARSING_COND (status == CR_OK) ;
+
+#ifdef WITH_UNICODE_ESCAPE_AND_RANGE
+static enum CRStatus cr_parser_parse_unicode_escape (CRParser * a_this,
+ guint32 * a_unicode);
+static enum CRStatus cr_parser_parse_escape (CRParser * a_this,
+ guint32 * a_esc_code);
+
+static enum CRStatus cr_parser_parse_unicode_range (CRParser * a_this,
+ CRString ** a_inf,
+ CRString ** a_sup);
+#endif
+
+static enum CRStatus cr_parser_parse_stylesheet_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_atrule_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_ruleset_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_any_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_block_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_value_core (CRParser * a_this);
+
+static enum CRStatus cr_parser_parse_string (CRParser * a_this,
+ CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_ident (CRParser * a_this,
+ CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_uri (CRParser * a_this,
+ CRString ** a_str);
+
+static enum CRStatus cr_parser_parse_function (CRParser * a_this,
+ CRString ** a_func_name,
+ CRTerm ** a_expr);
+static enum CRStatus cr_parser_parse_property (CRParser * a_this,
+ CRString ** a_property);
+
+static enum CRStatus cr_parser_parse_attribute_selector (CRParser * a_this,
+ CRAttrSel ** a_sel);
+
+static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
+ CRSimpleSel ** a_sel);
+
+static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
+ CRSimpleSel ** a_sel);
+
+static CRParserError *cr_parser_error_new (const guchar * a_msg,
+ enum CRStatus);
+
+static void cr_parser_error_set_msg (CRParserError * a_this,
+ const guchar * a_msg);
+
+static void cr_parser_error_dump (CRParserError * a_this);
+
+static void cr_parser_error_set_status (CRParserError * a_this,
+ enum CRStatus a_status);
+
+static void cr_parser_error_set_pos (CRParserError * a_this,
+ glong a_line,
+ glong a_column, glong a_byte_num);
+static void
+ cr_parser_error_destroy (CRParserError * a_this);
+
+static enum CRStatus cr_parser_push_error (CRParser * a_this,
+ const guchar * a_msg,
+ enum CRStatus a_status);
+
+static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
+ gboolean a_clear_errs);
+static enum CRStatus
+ cr_parser_clear_errors (CRParser * a_this);
+
+/*****************************
+ *error managemet methods
+ *****************************/
+
+/**
+ *Constructor of #CRParserError class.
+ *@param a_msg the brute error message.
+ *@param a_status the error status.
+ *@return the newly built instance of #CRParserError.
+ */
+static CRParserError *
+cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
+{
+ CRParserError *result = NULL;
+
+ result = g_try_malloc (sizeof (CRParserError));
+
+ if (result == NULL) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRParserError));
+
+ cr_parser_error_set_msg (result, a_msg);
+ cr_parser_error_set_status (result, a_status);
+
+ return result;
+}
+
+/**
+ *Sets the message associated to this instance of #CRError.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_msg the new message.
+ */
+static void
+cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->msg) {
+ g_free (a_this->msg);
+ }
+
+ a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg);
+}
+
+/**
+ *Sets the error status.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_status the new error status.
+ *
+ */
+static void
+cr_parser_error_set_status (CRParserError * a_this, enum CRStatus a_status)
+{
+ g_return_if_fail (a_this);
+
+ a_this->status = a_status;
+}
+
+/**
+ *Sets the position of the parser error.
+ *@param a_this the current instance of #CRParserError.
+ *@param a_line the line number.
+ *@param a_column the column number.
+ *@param a_byte_num the byte number.
+ */
+static void
+cr_parser_error_set_pos (CRParserError * a_this,
+ glong a_line, glong a_column, glong a_byte_num)
+{
+ g_return_if_fail (a_this);
+
+ a_this->line = a_line;
+ a_this->column = a_column;
+ a_this->byte_num = a_byte_num;
+}
+
+static void
+cr_parser_error_dump (CRParserError * a_this)
+{
+ g_return_if_fail (a_this);
+
+ g_printerr ("parsing error: %ld:%ld:", a_this->line, a_this->column);
+
+ g_printerr ("%s\n", a_this->msg);
+}
+
+/**
+ *The destructor of #CRParserError.
+ *@param a_this the current instance of #CRParserError.
+ */
+static void
+cr_parser_error_destroy (CRParserError * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->msg) {
+ g_free (a_this->msg);
+ a_this->msg = NULL;
+ }
+
+ g_free (a_this);
+}
+
+/**
+ *Pushes an error on the parser error stack.
+ *@param a_this the current instance of #CRParser.
+ *@param a_msg the error message.
+ *@param a_status the error status.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_push_error (CRParser * a_this,
+ const guchar * a_msg, enum CRStatus a_status)
+{
+ enum CRStatus status = CR_OK;
+
+ CRParserError *error = NULL;
+ CRInputPos pos;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_msg, CR_BAD_PARAM_ERROR);
+
+ error = cr_parser_error_new (a_msg, a_status);
+
+ g_return_val_if_fail (error, CR_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &pos);
+
+ cr_parser_error_set_pos
+ (error, pos.line, pos.col, pos.next_byte_index - 1);
+
+ PRIVATE (a_this)->err_stack =
+ g_list_prepend (PRIVATE (a_this)->err_stack, error);
+
+ if (PRIVATE (a_this)->err_stack == NULL)
+ goto error;
+
+ return CR_OK;
+
+ error:
+
+ if (error) {
+ cr_parser_error_destroy (error);
+ error = NULL;
+ }
+
+ return status;
+}
+
+/**
+ *Dumps the error stack using g_printerr.
+ *@param a_this the current instance of #CRParser.
+ *@param a_clear_errs whether to clear the error stack
+ *after the dump or not.
+ *@return CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_dump_err_stack (CRParser * a_this, gboolean a_clear_errs)
+{
+ GList *cur = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->err_stack == NULL)
+ return CR_OK;
+
+ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
+ cr_parser_error_dump ((CRParserError *) cur->data);
+ }
+
+ if (a_clear_errs == TRUE) {
+ cr_parser_clear_errors (a_this);
+ }
+
+ return CR_OK;
+}
+
+/**
+ *Clears all the errors contained in the parser error stack.
+ *Frees all the errors, and the stack that contains'em.
+ *@param a_this the current instance of #CRParser.
+ */
+static enum CRStatus
+cr_parser_clear_errors (CRParser * a_this)
+{
+ GList *cur = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ for (cur = PRIVATE (a_this)->err_stack; cur; cur = cur->next) {
+ if (cur->data) {
+ cr_parser_error_destroy ((CRParserError *)
+ cur->data);
+ }
+ }
+
+ if (PRIVATE (a_this)->err_stack) {
+ g_list_free (PRIVATE (a_this)->err_stack);
+ PRIVATE (a_this)->err_stack = NULL;
+ }
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_try_to_skip_spaces_and_comments:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Same as cr_parser_try_to_skip_spaces() but this one skips
+ *spaces and comments.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_try_to_skip_spaces_and_comments (CRParser * a_this)
+{
+ enum CRStatus status = CR_ERROR;
+ CRToken *token = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+ do {
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ if (status != CR_OK)
+ goto error;
+ }
+ while ((token != NULL)
+ && (token->type == COMMENT_TK || token->type == S_TK));
+
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+
+ return status;
+
+ error:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ return status;
+}
+
+/***************************************
+ *End of Parser input handling routines
+ ***************************************/
+
+
+/*************************************
+ *Non trivial terminal productions
+ *parsing routines
+ *************************************/
+
+/**
+ *Parses a css stylesheet following the core css grammar.
+ *This is mainly done for test purposes.
+ *During the parsing, no callback is called. This is just
+ *to validate that the stylesheet is well formed according to the
+ *css core syntax.
+ *stylesheet : [ CDO | CDC | S | statement ]*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ continue_parsing:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ goto done;
+ } else if (status != CR_OK) {
+ goto error;
+ }
+
+ switch (token->type) {
+
+ case CDO_TK:
+ case CDC_TK:
+ goto continue_parsing;
+ break;
+ default:
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+ status = cr_parser_parse_statement_core (a_this);
+ cr_parser_clear_errors (a_this);
+ if (status == CR_OK) {
+ goto continue_parsing;
+ } else if (status == CR_END_OF_INPUT_ERROR) {
+ goto done;
+ } else {
+ goto error;
+ }
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+ cr_parser_push_error
+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
+
+ cr_parser_dump_err_stack (a_this, TRUE);
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses an at-rule as defined by the css core grammar
+ *in chapter 4.1 in the css2 spec.
+ *at-rule : ATKEYWORD S* any* [ block | ';' S* ];
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_atrule_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ &&
+ (token->type == ATKEYWORD_TK
+ || token->type == IMPORT_SYM_TK
+ || token->type == PAGE_SYM_TK
+ || token->type == MEDIA_SYM_TK
+ || token->type == FONT_FACE_SYM_TK
+ || token->type == CHARSET_SYM_TK));
+
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ do {
+ status = cr_parser_parse_any_core (a_this);
+ } while (status == CR_OK);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == CBO_TK) {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ status = cr_parser_parse_block_core (a_this);
+ CHECK_PARSING_STATUS (status,
+ FALSE);
+ goto done;
+ } else if (token->type == SEMICOLON_TK) {
+ goto done;
+ } else {
+ status = CR_PARSING_ERROR ;
+ goto error;
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr,
+ &init_pos);
+ return status;
+}
+
+/**
+ *Parses a ruleset as defined by the css core grammar in chapter
+ *4.1 of the css2 spec.
+ *ruleset ::= selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ruleset_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_selector_core (a_this);
+
+ ENSURE_PARSING_COND (status == CR_OK
+ || status == CR_PARSING_ERROR
+ || status == CR_END_OF_INPUT_ERROR);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == CBO_TK);
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_declaration_core (a_this);
+
+ parse_declaration_list:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+ if (token->type == CBC_TK) {
+ goto done;
+ }
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == SEMICOLON_TK);
+
+ cr_token_destroy (token);
+ token = NULL;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_declaration_core (a_this);
+ cr_parser_clear_errors (a_this);
+ ENSURE_PARSING_COND (status == CR_OK || status == CR_PARSING_ERROR);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+ if (token->type == CBC_TK) {
+ cr_token_destroy (token);
+ token = NULL;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ goto done;
+ } else {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ goto parse_declaration_list;
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (status == CR_OK) {
+ return CR_OK;
+ }
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a "selector" as specified by the css core
+ *grammar.
+ *selector : any+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_selector_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_any_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ do {
+ status = cr_parser_parse_any_core (a_this);
+
+ } while (status == CR_OK);
+
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a "block" as defined in the css core grammar
+ *in chapter 4.1 of the css2 spec.
+ *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*;
+ *@param a_this the current instance of #CRParser.
+ *FIXME: code this function.
+ */
+static enum CRStatus
+cr_parser_parse_block_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == CBO_TK);
+
+ parse_block_content:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == CBC_TK) {
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ goto done;
+ } else if (token->type == SEMICOLON_TK) {
+ goto parse_block_content;
+ } else if (token->type == ATKEYWORD_TK) {
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ goto parse_block_content;
+ } else if (token->type == CBO_TK) {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ status = cr_parser_parse_block_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+ goto parse_block_content;
+ } else {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ status = cr_parser_parse_any_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+ goto parse_block_content;
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (status == CR_OK)
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+static enum CRStatus
+cr_parser_parse_declaration_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+ CRString *prop = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_property (a_this, &prop);
+ CHECK_PARSING_STATUS (status, FALSE);
+ cr_parser_clear_errors (a_this);
+ ENSURE_PARSING_COND (status == CR_OK && prop);
+ cr_string_destroy (prop);
+ prop = NULL;
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == DELIM_TK
+ && token->u.unichar == ':');
+ cr_token_destroy (token);
+ token = NULL;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_value_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ return CR_OK;
+
+ error:
+
+ if (prop) {
+ cr_string_destroy (prop);
+ prop = NULL;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a "value" production as defined by the css core grammar
+ *in chapter 4.1.
+ *value ::= [ any | block | ATKEYWORD S* ]+;
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_value_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+ glong ref = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ continue_parsing:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ switch (token->type) {
+ case CBO_TK:
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ status = cr_parser_parse_block_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+ ref++;
+ goto continue_parsing;
+
+ case ATKEYWORD_TK:
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ ref++;
+ goto continue_parsing;
+
+ default:
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ status = cr_parser_parse_any_core (a_this);
+ if (status == CR_OK) {
+ ref++;
+ goto continue_parsing;
+ } else if (status == CR_PARSING_ERROR) {
+ status = CR_OK;
+ goto done;
+ } else {
+ goto error;
+ }
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (status == CR_OK && ref)
+ return CR_OK;
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses an "any" as defined by the css core grammar in the
+ *css2 spec in chapter 4.1.
+ *any ::= [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
+ * | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
+ * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*;
+ *
+ *@param a_this the current instance of #CRParser.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_any_core (CRParser * a_this)
+{
+ CRToken *token1 = NULL,
+ *token2 = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1);
+
+ ENSURE_PARSING_COND (status == CR_OK && token1);
+
+ switch (token1->type) {
+ case IDENT_TK:
+ case NUMBER_TK:
+ case RGB_TK:
+ case PERCENTAGE_TK:
+ case DIMEN_TK:
+ case EMS_TK:
+ case EXS_TK:
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case FREQ_TK:
+ case TIME_TK:
+ case STRING_TK:
+ case DELIM_TK:
+ case URI_TK:
+ case HASH_TK:
+ case UNICODERANGE_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case S_TK:
+ case COMMENT_TK:
+ case IMPORTANT_SYM_TK:
+ status = CR_OK;
+ break;
+ case FUNCTION_TK:
+ /*
+ *this case isn't specified by the spec but it
+ *does happen. So we have to handle it.
+ *We must consider function with parameters.
+ *We consider parameter as being an "any*" production.
+ */
+ do {
+ status = cr_parser_parse_any_core (a_this);
+ } while (status == CR_OK);
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2 && token2->type == PC_TK);
+ break;
+ case PO_TK:
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2);
+ ENSURE_PARSING_COND (status == CR_OK && token2);
+
+ if (token2->type == PC_TK) {
+ cr_token_destroy (token2);
+ token2 = NULL;
+ goto done;
+ } else {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token2);
+ token2 = NULL;
+ }
+
+ do {
+ status = cr_parser_parse_any_core (a_this);
+ } while (status == CR_OK);
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2 && token2->type == PC_TK);
+ status = CR_OK;
+ break;
+
+ case BO_TK:
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2);
+ ENSURE_PARSING_COND (status == CR_OK && token2);
+
+ if (token2->type == BC_TK) {
+ cr_token_destroy (token2);
+ token2 = NULL;
+ goto done;
+ } else {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token2);
+ token2 = NULL;
+ }
+
+ do {
+ status = cr_parser_parse_any_core (a_this);
+ } while (status == CR_OK);
+
+ ENSURE_PARSING_COND (status == CR_PARSING_ERROR);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token2);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token2 && token2->type == BC_TK);
+ status = CR_OK;
+ break;
+ default:
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ done:
+ if (token1) {
+ cr_token_destroy (token1);
+ token1 = NULL;
+ }
+
+ if (token2) {
+ cr_token_destroy (token2);
+ token2 = NULL;
+ }
+
+ return CR_OK;
+
+ error:
+
+ if (token1) {
+ cr_token_destroy (token1);
+ token1 = NULL;
+ }
+
+ if (token2) {
+ cr_token_destroy (token2);
+ token2 = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+ return status;
+}
+
+/**
+ *Parses an attribute selector as defined in the css2 spec in
+ *appendix D.1:
+ *attrib ::= '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+ * [ IDENT | STRING ] S* ]? ']'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser .
+ *@param a_sel out parameter. The successfully parsed attribute selector.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_attribute_selector (CRParser * a_this,
+ CRAttrSel ** a_sel)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ CRAttrSel *result = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == BO_TK);
+ cr_parsing_location_copy
+ (&location, &token->location) ;
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ result = cr_attr_sel_new ();
+ if (!result) {
+ cr_utils_trace_info ("result failed") ;
+ status = CR_OUT_OF_MEMORY_ERROR ;
+ goto error ;
+ }
+ cr_parsing_location_copy (&result->location,
+ &location) ;
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == IDENT_TK);
+
+ result->name = token->u.str;
+ token->u.str = NULL;
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == INCLUDES_TK) {
+ result->match_way = INCLUDES;
+ goto parse_right_part;
+ } else if (token->type == DASHMATCH_TK) {
+ result->match_way = DASHMATCH;
+ goto parse_right_part;
+ } else if (token->type == DELIM_TK && token->u.unichar == '=') {
+ result->match_way = EQUALS;
+ goto parse_right_part;
+ } else if (token->type == BC_TK) {
+ result->match_way = SET;
+ goto done;
+ }
+
+ parse_right_part:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == IDENT_TK) {
+ result->value = token->u.str;
+ token->u.str = NULL;
+ } else if (token->type == STRING_TK) {
+ result->value = token->u.str;
+ token->u.str = NULL;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == BC_TK);
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (*a_sel) {
+ status = cr_attr_sel_append_attr_sel (*a_sel, result);
+ CHECK_PARSING_STATUS (status, FALSE);
+ } else {
+ *a_sel = result;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ if (result) {
+ cr_attr_sel_destroy (result);
+ result = NULL;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a "property" as specified by the css2 spec at [4.1.1]:
+ *property : IDENT S*;
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param GString a_property out parameter. The parsed property without the
+ *trailing spaces. If *a_property is NULL, this function allocates a
+ *new instance of GString and set it content to the parsed property.
+ *If not, the property is just appended to a_property's previous content.
+ *In both cases, it is up to the caller to free a_property.
+ *@return CR_OK upon successful completion, CR_PARSING_ERROR if the
+ *next construction was not a "property", or an error code.
+ */
+static enum CRStatus
+cr_parser_parse_property (CRParser * a_this,
+ CRString ** a_property)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_property,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_ident (a_this, a_property);
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_term:
+ *@a_term: out parameter. The successfully parsed term.
+ *
+ *Parses a "term" as defined in the css2 spec, appendix D.1:
+ *term ::= unary_operator? [NUMBER S* | PERCENTAGE S* | LENGTH S* |
+ *EMS S* | EXS S* | ANGLE S* | TIME S* | FREQ S* | function ] |
+ *STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
+ *
+ * As a special case for 'an+b', parse integer followed immediately by 'n'.
+ * The 'an' is parsed as a DIMEN.
+ *
+ *TODO: handle parsing of 'RGB'
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_term (CRParser * a_this, CRTerm ** a_term)
+{
+ enum CRStatus status = CR_PARSING_ERROR;
+ CRInputPos init_pos;
+ CRTerm *result = NULL;
+ CRTerm *param = NULL;
+ CRToken *token = NULL;
+ CRString *func_name = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && a_term, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ result = cr_term_new ();
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ if (status != CR_OK || !token)
+ goto error;
+
+ cr_parsing_location_copy (&location, &token->location) ;
+ if (token->type == DELIM_TK && token->u.unichar == '+') {
+ result->unary_op = PLUS_UOP;
+ cr_token_destroy (token) ;
+ token = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ if (status != CR_OK || !token)
+ goto error;
+ } else if (token->type == DELIM_TK && token->u.unichar == '-') {
+ result->unary_op = MINUS_UOP;
+ cr_token_destroy (token) ;
+ token = NULL ;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ if (status != CR_OK || !token)
+ goto error;
+ }
+
+ if (token->type == EMS_TK
+ || token->type == EXS_TK
+ || token->type == LENGTH_TK
+ || token->type == ANGLE_TK
+ || token->type == TIME_TK
+ || token->type == FREQ_TK
+ || token->type == PERCENTAGE_TK
+ || token->type == NUMBER_TK) {
+ status = cr_term_set_number (result, token->u.num);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.num = NULL;
+ status = CR_OK;
+ } else if (token && token->type == FUNCTION_TK) {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ status = cr_parser_parse_function (a_this, &func_name,
+ &param);
+
+ if (status == CR_OK) {
+ status = cr_term_set_function (result,
+ func_name,
+ param);
+ CHECK_PARSING_STATUS (status, TRUE);
+ }
+ } else if (token && token->type == STRING_TK) {
+ status = cr_term_set_string (result,
+ token->u.str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.str = NULL;
+ } else if (token && token->type == IDENT_TK) {
+ status = cr_term_set_ident (result, token->u.str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.str = NULL;
+ } else if (token && token->type == URI_TK) {
+ status = cr_term_set_uri (result, token->u.str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.str = NULL;
+ } else if (token && token->type == RGB_TK) {
+ status = cr_term_set_rgb (result, token->u.rgb);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.rgb = NULL;
+ } else if (token && token->type == UNICODERANGE_TK) {
+ result->type = TERM_UNICODERANGE;
+ status = CR_PARSING_ERROR;
+ } else if (token && token->type == HASH_TK) {
+ status = cr_term_set_hash (result, token->u.str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.str = NULL;
+ } else if (token && token->type == DIMEN_TK) {
+ gboolean n = !strcmp(token->dimen->stryng->str, "n");
+ status = cr_term_set_number (result, token->u.num);
+ result->n = n; // For nth-child (an+b)
+ CHECK_PARSING_STATUS (status, TRUE);
+ token->u.num = NULL;
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ }
+
+ if (status != CR_OK) {
+ goto error;
+ }
+ cr_parsing_location_copy (&result->location,
+ &location) ;
+ *a_term = cr_term_append_term (*a_term, result);
+
+ result = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ if (result) {
+ cr_term_destroy (result);
+ result = NULL;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (param) {
+ cr_term_destroy (param);
+ param = NULL;
+ }
+
+ if (func_name) {
+ cr_string_destroy (func_name);
+ func_name = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_simple_selector:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_sel: out parameter. Is set to the successfully parsed simple
+ *selector.
+ *
+ *Parses a "simple_selector" as defined by the css2 spec in appendix D.1 :
+ *element_name? [ HASH | class | attrib | pseudo ]* S*
+ *and where pseudo is:
+ *pseudo ::= ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ CRSimpleSel *sel = NULL;
+ CRAdditionalSel *add_sel_list = NULL;
+ gboolean found_sel = FALSE;
+ guint32 cur_char = 0;
+
+ g_return_val_if_fail (a_this && a_sel, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ if (status != CR_OK)
+ goto error;
+
+ sel = cr_simple_sel_new ();
+ ENSURE_PARSING_COND (sel);
+
+ cr_parsing_location_copy
+ (&sel->location,
+ &token->location) ;
+
+ if (token && token->type == DELIM_TK
+ && token->u.unichar == '*') {
+ int comb = (int)sel->type_mask | (int) UNIVERSAL_SELECTOR;
+ sel->type_mask = (enum SimpleSelectorType)comb;
+ sel->name = cr_string_new_from_string ("*");
+ found_sel = TRUE;
+ } else if (token && token->type == IDENT_TK) {
+ sel->name = token->u.str;
+ int comb = (int)sel->type_mask | (int) TYPE_SELECTOR;
+ sel->type_mask = (enum SimpleSelectorType)comb;
+ token->u.str = NULL;
+ found_sel = TRUE;
+ } else {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ for (;;) {
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr,
+ &token);
+ if (status != CR_OK)
+ goto error;
+
+ if (token && token->type == HASH_TK) {
+ /*we parsed an attribute id */
+ CRAdditionalSel *add_sel = NULL;
+
+ add_sel = cr_additional_sel_new_with_type
+ (ID_ADD_SELECTOR);
+
+ add_sel->content.id_name = token->u.str;
+ token->u.str = NULL;
+
+ cr_parsing_location_copy
+ (&add_sel->location,
+ &token->location) ;
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel);
+ found_sel = TRUE;
+ } else if (token && (token->type == DELIM_TK)
+ && (token->u.unichar == '.')) {
+ cr_token_destroy (token);
+ token = NULL;
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ if (status != CR_OK)
+ goto error;
+
+ if (token && token->type == IDENT_TK) {
+ CRAdditionalSel *add_sel = NULL;
+
+ add_sel = cr_additional_sel_new_with_type
+ (CLASS_ADD_SELECTOR);
+
+ add_sel->content.class_name = token->u.str;
+ token->u.str = NULL;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel);
+ found_sel = TRUE;
+
+ cr_parsing_location_copy
+ (&add_sel->location,
+ & token->location) ;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ } else if (token && token->type == BO_TK) {
+ CRAttrSel *attr_sel = NULL;
+ CRAdditionalSel *add_sel = NULL;
+
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ if (status != CR_OK)
+ goto error;
+ token = NULL;
+
+ status = cr_parser_parse_attribute_selector
+ (a_this, &attr_sel);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ add_sel = cr_additional_sel_new_with_type
+ (ATTRIBUTE_ADD_SELECTOR);
+
+ ENSURE_PARSING_COND (add_sel != NULL);
+
+ add_sel->content.attr_sel = attr_sel;
+
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel);
+ found_sel = TRUE;
+ cr_parsing_location_copy
+ (&add_sel->location,
+ &attr_sel->location) ;
+ } else if (token && (token->type == DELIM_TK)
+ && (token->u.unichar == ':')) {
+ CRPseudo *pseudo = NULL;
+
+ /*try to parse a pseudo */
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ pseudo = cr_pseudo_new ();
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ cr_parsing_location_copy
+ (&pseudo->location,
+ &token->location) ;
+
+ /* Save selector name for use by 'type' pseudo selectors */
+ if (sel->name)
+ pseudo->sel_name = cr_string_dup (sel->name);
+
+ if (token->type == IDENT_TK) {
+ pseudo->type = IDENT_PSEUDO;
+ pseudo->name = token->u.str;
+ token->u.str = NULL;
+ found_sel = TRUE;
+ } else if (token->type == FUNCTION_TK) {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ status = cr_parser_parse_function (a_this, &pseudo->name, &pseudo->term);
+ ENSURE_PARSING_COND (status == CR_OK);
+
+ pseudo->type = FUNCTION_PSEUDO;
+ found_sel = TRUE;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ if (status == CR_OK) {
+ CRAdditionalSel *add_sel = NULL;
+
+ add_sel = cr_additional_sel_new_with_type
+ (PSEUDO_CLASS_ADD_SELECTOR);
+
+ add_sel->content.pseudo = pseudo;
+ cr_parsing_location_copy
+ (&add_sel->location,
+ &pseudo->location) ;
+ add_sel_list =
+ cr_additional_sel_append
+ (add_sel_list, add_sel);
+ status = CR_OK;
+ }
+ } else {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ break;
+ }
+ } // for loop
+
+ if (status == CR_OK && found_sel == TRUE) {
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ sel->add_sel = add_sel_list;
+ add_sel_list = NULL;
+
+ if (*a_sel == NULL) {
+ *a_sel = sel;
+ } else {
+ cr_simple_sel_append_simple_sel (*a_sel, sel);
+ }
+
+ sel = NULL;
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ }
+
+ error:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (add_sel_list) {
+ cr_additional_sel_destroy (add_sel_list);
+ add_sel_list = NULL;
+ }
+
+ if (sel) {
+ cr_simple_sel_destroy (sel);
+ sel = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+
+}
+
+/**
+ * cr_parser_parse_simple_sels:
+ *@a_this: the this pointer of the current instance of #CRParser.
+ *@a_start: a pointer to the
+ *first chararcter of the successfully parsed
+ *string.
+ *@a_end: a pointer to the last character of the successfully parsed
+ *string.
+ *
+ *Parses a "selector" as defined by the css2 spec in appendix D.1:
+ *selector ::= simple_selector [ combinator simple_selector ]*
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_simple_sels (CRParser * a_this,
+ CRSimpleSel ** a_sel)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ CRSimpleSel *sel = NULL;
+ guint32 cur_char = 0;
+
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && a_sel,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_simple_selector (a_this, &sel);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel, sel);
+
+ for (;;) {
+ guint32 next_char = 0;
+ int comb = 0;
+
+ sel = NULL;
+
+ PEEK_NEXT_CHAR (a_this, &next_char);
+
+ if (next_char == '+') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ comb = COMB_PLUS;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ } else if (next_char == '~') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ comb = COMB_TILDE;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ } else if (next_char == '>') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ comb = COMB_GT;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ } else {
+ comb = COMB_WS;
+ }
+
+ status = cr_parser_parse_simple_selector (a_this, &sel);
+ if (status != CR_OK)
+ break;
+
+ if (comb && sel) {
+ sel->combinator = (enum Combinator)comb;
+ comb = 0;
+ }
+ if (sel) {
+ *a_sel = cr_simple_sel_append_simple_sel (*a_sel,
+ sel) ;
+ }
+ }
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_selector:
+ *@a_this: the current instance of #CRParser.
+ *@a_selector: the parsed list of comma separated
+ *selectors.
+ *
+ *Parses a comma separated list of selectors.
+ *
+ *Returns CR_OK upon successful completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_selector (CRParser * a_this,
+ CRSelector ** a_selector)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ guint32 cur_char = 0,
+ next_char = 0;
+ CRSimpleSel *simple_sels = NULL;
+ CRSelector *selector = NULL;
+
+ g_return_val_if_fail (a_this && a_selector, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_simple_sels (a_this, &simple_sels);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ if (simple_sels) {
+ selector = cr_selector_append_simple_sel
+ (selector, simple_sels);
+ if (selector) {
+ cr_parsing_location_copy
+ (&selector->location,
+ &simple_sels->location) ;
+ }
+ simple_sels = NULL;
+ } else {
+ status = CR_PARSING_ERROR ;
+ goto error ;
+ }
+
+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+ &next_char);
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ goto okay;
+ } else {
+ goto error;
+ }
+ }
+
+ if (next_char == ',') {
+ for (;;) {
+ simple_sels = NULL;
+
+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+ &next_char);
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ break;
+ } else {
+ goto error;
+ }
+ }
+
+ if (next_char != ',')
+ break;
+
+ /*consume the ',' char */
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_simple_sels
+ (a_this, &simple_sels);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ if (simple_sels) {
+ selector =
+ cr_selector_append_simple_sel
+ (selector, simple_sels);
+
+ simple_sels = NULL;
+ }
+ }
+ }
+
+ okay:
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ if (!*a_selector) {
+ *a_selector = selector;
+ } else {
+ *a_selector = cr_selector_append (*a_selector, selector);
+ }
+
+ selector = NULL;
+ return CR_OK;
+
+ error:
+
+ if (simple_sels) {
+ cr_simple_sel_destroy (simple_sels);
+ simple_sels = NULL;
+ }
+
+ if (selector) {
+ cr_selector_unref (selector);
+ selector = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_function:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *@a_func_name: out parameter. The parsed function name
+ *@a_expr: out parameter. The successfully parsed term.
+ *
+ *Parses a "function" as defined in css spec at appendix D.1:
+ *function ::= FUNCTION S* expr ')' S*
+ *FUNCTION ::= ident'('
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_function (CRParser * a_this,
+ CRString ** a_func_name,
+ CRTerm ** a_expr)
+{
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ CRToken *token = NULL;
+ CRTerm *expr = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_func_name,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ if (status != CR_OK)
+ goto error;
+
+ if (token && token->type == FUNCTION_TK) {
+ *a_func_name = token->u.str;
+ token->u.str = NULL;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+
+ status = cr_parser_parse_expr (a_this, &expr);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ if (status != CR_OK)
+ goto error;
+
+ ENSURE_PARSING_COND (token && token->type == PC_TK);
+
+ cr_token_destroy (token);
+ token = NULL;
+
+ if (expr) {
+ *a_expr = cr_term_append_term (*a_expr, expr);
+ expr = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ if (*a_func_name) {
+ cr_string_destroy (*a_func_name);
+ *a_func_name = NULL;
+ }
+
+ if (expr) {
+ cr_term_destroy (expr);
+ expr = NULL;
+ }
+
+ if (token) {
+ cr_token_destroy (token);
+
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_uri:
+ *@a_this: the current instance of #CRParser.
+ *@a_str: the successfully parsed url.
+ *
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_uri (CRParser * a_this, CRString ** a_str)
+{
+
+ enum CRStatus status = CR_PARSING_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ URI_TK, NO_ET, a_str, NULL);
+ return status;
+}
+
+/**
+ * cr_parser_parse_string:
+ *@a_this: the current instance of #CRParser.
+ *@a_start: out parameter. Upon successful completion,
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@a_end: out parameter. Upon successful completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_string (CRParser * a_this, CRString ** a_str)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_str, CR_BAD_PARAM_ERROR);
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ STRING_TK, NO_ET, a_str, NULL);
+ return status;
+}
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *@param a_this the currens instance of #CRParser.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of #CRString. If not,
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_ident (CRParser * a_this, CRString ** a_str)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr
+ && a_str, CR_BAD_PARAM_ERROR);
+
+ status = cr_tknzr_parse_token (PRIVATE (a_this)->tknzr,
+ IDENT_TK, NO_ET, a_str, NULL);
+ return status;
+}
+
+/**
+ *the next rule is ignored as well. This seems to be a bug
+ *Parses a stylesheet as defined in the css2 spec in appendix D.1:
+ *stylesheet ::= [ CHARSET_SYM S* STRING S* ';' ]?
+ * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
+ * [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
+ *
+ *TODO: Finish the code of this function. Think about splitting it into
+ *smaller functions.
+ *
+ *@param a_this the "this pointer" of the current instance of #CRParser.
+ *@param a_start out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *@param a_end out parameter. A pointer to the first character of
+ *the successfully parsed string.
+ *
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_parser_parse_stylesheet (CRParser * a_this)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ CRString *charset = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PRIVATE (a_this)->state = READY_STATE;
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_document) {
+ PRIVATE (a_this)->sac_handler->start_document
+ (PRIVATE (a_this)->sac_handler);
+ }
+
+ parse_charset:
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done;
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ if (token && token->type == CHARSET_SYM_TK) {
+ CRParsingLocation location = {0,0,0} ;
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+
+ status = cr_parser_parse_charset (a_this,
+ &charset,
+ &location);
+
+ if (status == CR_OK && charset) {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->charset) {
+ PRIVATE (a_this)->sac_handler->charset
+ (PRIVATE (a_this)->sac_handler,
+ charset, &location);
+ }
+ } else if (status != CR_END_OF_INPUT_ERROR) {
+ status = cr_parser_parse_atrule_core (a_this);
+ CHECK_PARSING_STATUS (status, FALSE);
+ }
+
+ if (charset) {
+ cr_string_destroy (charset);
+ charset = NULL;
+ }
+ } else if (token
+ && (token->type == S_TK
+ || token->type == COMMENT_TK)) {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ goto parse_charset ;
+ } else if (token) {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ CHECK_PARSING_STATUS (status, TRUE);
+ }
+
+/* parse_imports:*/
+ do {
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this) ;
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done;
+ CHECK_PARSING_STATUS (status, TRUE);
+ } while (token
+ && (token->type == S_TK
+ || token->type == CDO_TK || token->type == CDC_TK));
+
+ if (token) {
+ status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL;
+ }
+
+ for (;;) {
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done;
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ if (token && token->type == IMPORT_SYM_TK) {
+ GList *media_list = NULL;
+ CRString *import_string = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ status = cr_parser_parse_import (a_this,
+ &media_list,
+ &import_string,
+ &location);
+ if (status == CR_OK) {
+ if (import_string
+ && PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->import_style) {
+ PRIVATE (a_this)->sac_handler->import_style
+ (PRIVATE(a_this)->sac_handler,
+ media_list,
+ import_string,
+ NULL, &location) ;
+
+ if (PRIVATE (a_this)->sac_handler->resolve_import == TRUE) {
+ /*
+ *TODO: resolve the
+ *import rule.
+ */
+ }
+
+ if (PRIVATE (a_this)->sac_handler->import_style_result) {
+ PRIVATE (a_this)->sac_handler->import_style_result
+ (PRIVATE (a_this)->sac_handler,
+ media_list, import_string,
+ NULL, NULL);
+ }
+ }
+ } else if (status != CR_END_OF_INPUT_ERROR) {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->error
+ (PRIVATE (a_this)->sac_handler);
+ }
+ status = cr_parser_parse_atrule_core (a_this);
+ CHECK_PARSING_STATUS (status, TRUE) ;
+ } else {
+ goto error ;
+ }
+
+ /*
+ *then, after calling the appropriate
+ *SAC handler, free
+ *the media_list and import_string.
+ */
+ if (media_list) {
+ GList *cur = NULL;
+
+ /*free the medium list */
+ for (cur = media_list; cur; cur = cur->next) {
+ if (cur->data) {
+ cr_string_destroy (cur->data);
+ }
+ }
+
+ g_list_free (media_list);
+ media_list = NULL;
+ }
+
+ if (import_string) {
+ cr_string_destroy (import_string);
+ import_string = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ } else if (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK)) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+
+ do {
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done;
+ CHECK_PARSING_STATUS (status, TRUE);
+ } while (token
+ && (token->type == S_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK));
+ } else {
+ if (token) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ }
+ goto parse_ruleset_and_others;
+ }
+ }
+
+ parse_ruleset_and_others:
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ for (;;) {
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto done;
+ CHECK_PARSING_STATUS (status, TRUE);
+
+ if (token
+ && (token->type == S_TK
+ || token->type == CDO_TK || token->type == CDC_TK)) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+
+ do {
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this);
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ } while (token
+ && (token->type == S_TK
+ || token->type == COMMENT_TK
+ || token->type == CDO_TK
+ || token->type == CDC_TK));
+ if (token) {
+ cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ }
+ } else if (token
+ && (token->type == HASH_TK
+ || (token->type == DELIM_TK
+ && token->u.unichar == '.')
+ || (token->type == DELIM_TK
+ && token->u.unichar == ':')
+ || (token->type == DELIM_TK
+ && token->u.unichar == '*')
+ || (token->type == BO_TK)
+ || token->type == IDENT_TK)) {
+ /*
+ *Try to parse a CSS2 ruleset.
+ *if the parsing fails, try to parse
+ *a css core ruleset.
+ */
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+
+ status = cr_parser_parse_ruleset (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE (a_this)->
+ sac_handler);
+ }
+
+ status = cr_parser_parse_ruleset_core
+ (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ } else if (token && token->type == MEDIA_SYM_TK) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+
+ status = cr_parser_parse_media (a_this);
+ if (status == CR_OK) {
+ continue;
+ } else {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE (a_this)->
+ sac_handler);
+ }
+
+ status = cr_parser_parse_atrule_core (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ } else if (token && token->type == PAGE_SYM_TK) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+ status = cr_parser_parse_page (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE (a_this)->
+ sac_handler);
+ }
+
+ status = cr_parser_parse_atrule_core (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ } else if (token && token->type == FONT_FACE_SYM_TK) {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+ status = cr_parser_parse_font_face (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->
+ error
+ (PRIVATE (a_this)->
+ sac_handler);
+ }
+
+ status = cr_parser_parse_atrule_core (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ } else {
+ status = cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr, token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ token = NULL;
+ status = cr_parser_parse_statement_core (a_this);
+
+ if (status == CR_OK) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ done:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (status == CR_END_OF_INPUT_ERROR || status == CR_OK) {
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_document) {
+ PRIVATE (a_this)->sac_handler->end_document
+ (PRIVATE (a_this)->sac_handler);
+ }
+
+ return CR_OK;
+ }
+
+ cr_parser_push_error
+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
+ PRIVATE (a_this)->sac_handler->
+ unrecoverable_error (PRIVATE (a_this)->sac_handler);
+ }
+
+ cr_parser_dump_err_stack (a_this, TRUE);
+
+ return status;
+
+ error:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->unrecoverable_error) {
+ PRIVATE (a_this)->sac_handler->
+ unrecoverable_error (PRIVATE (a_this)->sac_handler);
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/****************************************
+ *Public CRParser Methods
+ ****************************************/
+
+/**
+ * cr_parser_new:
+ * @a_tknzr: the tokenizer to use for the parsing.
+ *
+ *Creates a new parser to parse data
+ *coming the input stream given in parameter.
+ *
+ *Returns the newly created instance of #CRParser,
+ *or NULL if an error occurred.
+ */
+CRParser *
+cr_parser_new (CRTknzr * a_tknzr)
+{
+ CRParser *result = NULL;
+ enum CRStatus status = CR_OK;
+
+ result = g_malloc0 (sizeof (CRParser));
+
+ PRIVATE (result) = g_malloc0 (sizeof (CRParserPriv));
+
+ if (a_tknzr) {
+ status = cr_parser_set_tknzr (result, a_tknzr);
+ }
+
+ g_return_val_if_fail (status == CR_OK, NULL);
+
+ return result;
+}
+
+/**
+ * cr_parser_new_from_buf:
+ *@a_buf: the buffer to parse.
+ *@a_len: the length of the data in the buffer.
+ *@a_enc: the encoding of the input buffer a_buf.
+ *@a_free_buf: if set to TRUE, a_buf will be freed
+ *during the destruction of the newly built instance
+ *of #CRParser. If set to FALSE, it is up to the caller to
+ *eventually free it.
+ *
+ *Instanciates a new parser from a memory buffer.
+ *
+ *Returns the newly built parser, or NULL if an error arises.
+ */
+CRParser *
+cr_parser_new_from_buf (guchar * a_buf,
+ gulong a_len,
+ enum CREncoding a_enc,
+ gboolean a_free_buf)
+{
+ CRParser *result = NULL;
+ CRInput *input = NULL;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ input = cr_input_new_from_buf (a_buf, a_len, a_enc, a_free_buf);
+ g_return_val_if_fail (input, NULL);
+
+ result = cr_parser_new_from_input (input);
+ if (!result) {
+ cr_input_destroy (input);
+ input = NULL;
+ return NULL;
+ }
+ return result;
+}
+
+/**
+ * cr_parser_new_from_input:
+ * @a_input: the parser input stream to use.
+ *
+ * Returns a newly built parser input.
+ */
+CRParser *
+cr_parser_new_from_input (CRInput * a_input)
+{
+ CRParser *result = NULL;
+ CRTknzr *tokenizer = NULL;
+
+ if (a_input) {
+ tokenizer = cr_tknzr_new (a_input);
+ g_return_val_if_fail (tokenizer, NULL);
+ }
+
+ result = cr_parser_new (tokenizer);
+ g_return_val_if_fail (result, NULL);
+
+ return result;
+}
+
+/**
+ * cr_parser_new_from_file:
+ * @a_file_uri: the uri of the file to parse.
+ * @a_enc: the file encoding to use.
+ *
+ * Returns the newly built parser.
+ */
+CRParser *
+cr_parser_new_from_file (const guchar * a_file_uri, enum CREncoding a_enc)
+{
+ CRParser *result = NULL;
+ CRTknzr *tokenizer = NULL;
+
+ tokenizer = cr_tknzr_new_from_uri (a_file_uri, a_enc);
+ if (!tokenizer) {
+ cr_utils_trace_info ("Could not open input file");
+ return NULL;
+ }
+
+ result = cr_parser_new (tokenizer);
+ g_return_val_if_fail (result, NULL);
+ return result;
+}
+
+/**
+ * cr_parser_set_sac_handler:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_handler: the handler to set.
+ *
+ *Sets a SAC document handler to the parser.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_sac_handler (CRParser * a_this, CRDocHandler * a_handler)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->sac_handler) {
+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
+ }
+
+ PRIVATE (a_this)->sac_handler = a_handler;
+ cr_doc_handler_ref (a_handler);
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_get_sac_handler:
+ *@a_this: the "this pointer" of the current instance of
+ *#CRParser.
+ *@a_handler: out parameter. The returned handler.
+ *
+ *Gets the SAC document handler.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_get_sac_handler (CRParser * a_this, CRDocHandler ** a_handler)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ *a_handler = PRIVATE (a_this)->sac_handler;
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_set_default_sac_handler:
+ *@a_this: a pointer to the current instance of #CRParser.
+ *
+ *Sets the SAC handler associated to the current instance
+ *of #CRParser to the default SAC handler.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_default_sac_handler (CRParser * a_this)
+{
+ CRDocHandler *default_sac_handler = NULL;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ default_sac_handler = cr_doc_handler_new ();
+
+ cr_doc_handler_set_default_sac_handler (default_sac_handler);
+
+ status = cr_parser_set_sac_handler (a_this, default_sac_handler);
+
+ if (status != CR_OK) {
+ cr_doc_handler_destroy (default_sac_handler);
+ default_sac_handler = NULL;
+ }
+
+ return status;
+}
+
+/**
+ * cr_parser_set_use_core_grammar:
+ * @a_this: the current instance of #CRParser.
+ * @a_use_core_grammar: where to parse against the css core grammar.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_use_core_grammar (CRParser * a_this,
+ gboolean a_use_core_grammar)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->use_core_grammar = a_use_core_grammar;
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_get_use_core_grammar:
+ * @a_this: the current instance of #CRParser.
+ * @a_use_core_grammar: whether to use the core grammar or not.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_get_use_core_grammar (CRParser const * a_this,
+ gboolean * a_use_core_grammar)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ *a_use_core_grammar = PRIVATE (a_this)->use_core_grammar;
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_parse_file:
+ *@a_this: a pointer to the current instance of #CRParser.
+ *@a_file_uri: the uri to the file to load. For the time being,
+ *@a_enc: the encoding of the file to parse.
+ *only local files are supported.
+ *
+ *Parses a the given in parameter.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_file (CRParser * a_this,
+ const guchar * a_file_uri, enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_ERROR;
+ CRTknzr *tknzr = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_file_uri, CR_BAD_PARAM_ERROR);
+
+ tknzr = cr_tknzr_new_from_uri (a_file_uri, a_enc);
+
+ g_return_val_if_fail (tknzr != NULL, CR_ERROR);
+
+ status = cr_parser_set_tknzr (a_this, tknzr);
+ g_return_val_if_fail (status == CR_OK, CR_ERROR);
+
+ status = cr_parser_parse (a_this);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_expr:
+ * @a_this: the current instance of #CRParser.
+ * @a_expr: out parameter. the parsed expression.
+ *
+ *Parses an expression as defined by the css2 spec in appendix
+ *D.1:
+ *expr: term [ operator term ]*
+ *
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_expr (CRParser * a_this, CRTerm ** a_expr)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ CRTerm *expr = NULL,
+ *expr2 = NULL;
+ guchar next_byte = 0;
+ gulong nb_terms = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_expr, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_term (a_this, &expr);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ for (;;) {
+ guchar operatr = 0;
+
+ status = cr_tknzr_peek_byte (PRIVATE (a_this)->tknzr,
+ 1, &next_byte);
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR) {
+ /*
+ if (!nb_terms)
+ {
+ goto error ;
+ }
+ */
+ status = CR_OK;
+ break;
+ } else {
+ goto error;
+ }
+ }
+
+ if (next_byte == '/' || next_byte == ',') {
+ READ_NEXT_BYTE (a_this, &operatr);
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_term (a_this, &expr2);
+
+ if (status != CR_OK || expr2 == NULL) {
+ status = CR_OK;
+ break;
+ }
+
+ switch (operatr) {
+ case '/':
+ expr2->the_operator = DIVIDE;
+ break;
+ case ',':
+ expr2->the_operator = COMMA;
+
+ default:
+ break;
+ }
+
+ expr = cr_term_append_term (expr, expr2);
+ expr2 = NULL;
+ operatr = 0;
+ nb_terms++;
+ }
+
+ if (status == CR_OK) {
+ *a_expr = cr_term_append_term (*a_expr, expr);
+ expr = NULL;
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+ }
+
+ error:
+
+ if (expr) {
+ cr_term_destroy (expr);
+ expr = NULL;
+ }
+
+ if (expr2) {
+ cr_term_destroy (expr2);
+ expr2 = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_prio:
+ *@a_this: the current instance of #CRParser.
+ *@a_prio: a string representing the priority.
+ *Today, only "!important" is returned as only this
+ *priority is defined by css2.
+ *
+ *Parses a declaration priority as defined by
+ *the css2 grammar in appendix C:
+ *prio: IMPORTANT_SYM S*
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_prio (CRParser * a_this, CRString ** a_prio)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_prio
+ && *a_prio == NULL, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ if (status == CR_END_OF_INPUT_ERROR) {
+ goto error;
+ }
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == IMPORTANT_SYM_TK);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ *a_prio = cr_string_new_from_string ("!important");
+ cr_token_destroy (token);
+ token = NULL;
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_declaration:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_property: the successfully parsed property. The caller
+ * *must* free the returned pointer.
+ *@a_expr: the expression that represents the attribute value.
+ *The caller *must* free the returned pointer.
+ *
+ *TODO: return the parsed priority, so that
+ *upper layers can take benefit from it.
+ *Parses a "declaration" as defined by the css2 spec in appendix D.1:
+ *declaration ::= [property ':' S* expr prio?]?
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_declaration (CRParser * a_this,
+ CRString ** a_property,
+ CRTerm ** a_expr, gboolean * a_important)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ guint32 cur_char = 0;
+ CRTerm *expr = NULL;
+ CRString *prio = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_property && a_expr
+ && a_important, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_property (a_this, a_property);
+
+ if (status == CR_END_OF_INPUT_ERROR)
+ goto error;
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ (const guchar *) "while parsing declaration: next property is malformed",
+ CR_SYNTAX_ERROR);
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char != ':') {
+ status = CR_PARSING_ERROR;
+ cr_parser_push_error
+ (a_this,
+ (const guchar *) "while parsing declaration: this char must be ':'",
+ CR_SYNTAX_ERROR);
+ goto error;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_expr (a_this, &expr);
+
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ (const guchar *) "while parsing declaration: next expression is malformed",
+ CR_SYNTAX_ERROR);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_prio (a_this, &prio);
+ if (prio) {
+ cr_string_destroy (prio);
+ prio = NULL;
+ *a_important = TRUE;
+ } else {
+ *a_important = FALSE;
+ }
+ if (*a_expr) {
+ cr_term_append_term (*a_expr, expr);
+ expr = NULL;
+ } else {
+ *a_expr = expr;
+ expr = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ return CR_OK;
+
+ error:
+
+ if (expr) {
+ cr_term_destroy (expr);
+ expr = NULL;
+ }
+
+ if (*a_property) {
+ cr_string_destroy (*a_property);
+ *a_property = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_statement_core:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses a statement as defined by the css core grammar in
+ *chapter 4.1 of the css2 spec.
+ *statement : ruleset | at-rule;
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_statement_core (CRParser * a_this)
+{
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ switch (token->type) {
+ case ATKEYWORD_TK:
+ case IMPORT_SYM_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ status = cr_parser_parse_atrule_core (a_this);
+ CHECK_PARSING_STATUS (status, TRUE);
+ break;
+
+ default:
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ status = cr_parser_parse_ruleset_core (a_this);
+ cr_parser_clear_errors (a_this);
+ CHECK_PARSING_STATUS (status, TRUE);
+ }
+
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_ruleset:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses a "ruleset" as defined in the css2 spec at appendix D.1.
+ *ruleset ::= selector [ ',' S* selector ]*
+ *'{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ *
+ *This methods calls the SAC handler on the relevant SAC handler
+ *callbacks whenever it encounters some specific constructions.
+ *See the documentation of #CRDocHandler (the SAC handler) to know
+ *when which SAC handler is called.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_ruleset (CRParser * a_this)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ guint32 cur_char = 0,
+ next_char = 0;
+ CRString *property = NULL;
+ CRTerm *expr = NULL;
+ CRSimpleSel *simple_sels = NULL;
+ CRSelector *selector = NULL;
+ gboolean start_selector = FALSE,
+ is_important = FALSE;
+ CRParsingLocation end_parsing_location;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_parser_parse_selector (a_this, &selector);
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == '{',
+ (const guchar *) "while parsing rulset: current char should be '{'",
+ CR_SYNTAX_ERROR);
+
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_selector) {
+ /*
+ *the selector is ref counted so that the parser's user
+ *can choose to keep it.
+ */
+ if (selector) {
+ cr_selector_ref (selector);
+ }
+
+ PRIVATE (a_this)->sac_handler->start_selector
+ (PRIVATE (a_this)->sac_handler, selector);
+ start_selector = TRUE;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ PRIVATE (a_this)->state = TRY_PARSE_RULESET_STATE;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &expr,
+ &is_important);
+ if (expr) {
+ cr_term_ref (expr);
+ }
+ if (status == CR_OK
+ && PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property) {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler, property, expr,
+ is_important);
+ }
+ if (status == CR_OK) {
+ /*
+ *free the allocated
+ *'property' and 'term' before parsing
+ *next declarations.
+ */
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (expr) {
+ cr_term_unref (expr);
+ expr = NULL;
+ }
+ } else {/*status != CR_OK*/
+ guint32 c = 0 ;
+ /*
+ *test if we have reached '}', which
+ *would mean that we are parsing an empty ruleset (eg. x{ })
+ *In that case, goto end_of_ruleset.
+ */
+ status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, &c) ;
+ if (status == CR_OK && c == '}') {
+ status = CR_OK ;
+ goto end_of_ruleset ;
+ }
+ }
+ CHECK_PARSING_STATUS_ERR
+ (a_this, status, FALSE,
+ (const guchar *) "while parsing ruleset: next construction should be a declaration",
+ CR_SYNTAX_ERROR);
+
+ for (;;) {
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char != ';')
+ break;
+
+ /*consume the ';' char */
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &expr, &is_important);
+
+ if (expr) {
+ cr_term_ref (expr);
+ }
+ if (status == CR_OK
+ && PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property) {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, expr, is_important);
+ }
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (expr) {
+ cr_term_unref (expr);
+ expr = NULL;
+ }
+ }
+
+ end_of_ruleset:
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ cr_parser_get_parsing_location (a_this, &end_parsing_location);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ ENSURE_PARSING_COND_ERR
+ (a_this, cur_char == '}',
+ (const guchar *) "while parsing rulset: current char must be a '}'",
+ CR_SYNTAX_ERROR);
+
+ selector->location = end_parsing_location;
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_selector) {
+ PRIVATE (a_this)->sac_handler->end_selector
+ (PRIVATE (a_this)->sac_handler, selector);
+ start_selector = FALSE;
+ }
+
+ if (expr) {
+ cr_term_unref (expr);
+ expr = NULL;
+ }
+
+ if (simple_sels) {
+ cr_simple_sel_destroy (simple_sels);
+ simple_sels = NULL;
+ }
+
+ if (selector) {
+ cr_selector_unref (selector);
+ selector = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->state = RULESET_PARSED_STATE;
+
+ return CR_OK;
+
+ error:
+ if (start_selector == TRUE
+ && PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->error) {
+ PRIVATE (a_this)->sac_handler->error
+ (PRIVATE (a_this)->sac_handler);
+ }
+ if (expr) {
+ cr_term_unref (expr);
+ expr = NULL;
+ }
+ if (simple_sels) {
+ cr_simple_sel_destroy (simple_sels);
+ simple_sels = NULL;
+ }
+ if (property) {
+ cr_string_destroy (property);
+ }
+ if (selector) {
+ cr_selector_unref (selector);
+ selector = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_import:
+ *@a_this: the "this pointer" of the current instance
+ *of #CRParser.
+ *@a_media_list: out parameter. A linked list of
+ *#CRString
+ *Each CRString is a string that contains
+ *a 'medium' declaration part of the successfully
+ *parsed 'import' declaration.
+ *@a_import_string: out parameter.
+ *A string that contains the 'import
+ *string". The import string can be either an uri (if it starts with
+ *the substring "uri(") or a any other css2 string. Note that
+ * *a_import_string must be initially set to NULL or else, this function
+ *will return CR_BAD_PARAM_ERROR.
+ *@a_location: the location (line, column) where the import has been parsed
+ *
+ *Parses an 'import' declaration as defined in the css2 spec
+ *in appendix D.1:
+ *
+ *import ::=
+ *\@import [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_import (CRParser * a_this,
+ GList ** a_media_list,
+ CRString ** a_import_string,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ guint32 cur_char = 0,
+ next_char = 0;
+ CRString *medium = NULL;
+
+ g_return_val_if_fail (a_this
+ && a_import_string
+ && (*a_import_string == NULL),
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ if (BYTE (a_this, 1, NULL) == '@'
+ && BYTE (a_this, 2, NULL) == 'i'
+ && BYTE (a_this, 3, NULL) == 'm'
+ && BYTE (a_this, 4, NULL) == 'p'
+ && BYTE (a_this, 5, NULL) == 'o'
+ && BYTE (a_this, 6, NULL) == 'r'
+ && BYTE (a_this, 7, NULL) == 't') {
+ SKIP_CHARS (a_this, 1);
+ if (a_location) {
+ cr_parser_get_parsing_location
+ (a_this, a_location) ;
+ }
+ SKIP_CHARS (a_this, 6);
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ PRIVATE (a_this)->state = TRY_PARSE_IMPORT_STATE;
+
+ PEEK_NEXT_CHAR (a_this, &next_char);
+
+ if (next_char == '"' || next_char == '\'') {
+ status = cr_parser_parse_string (a_this, a_import_string);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+ } else {
+ status = cr_parser_parse_uri (a_this, a_import_string);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_ident (a_this, &medium);
+
+ if (status == CR_OK && medium) {
+ *a_media_list = g_list_append (*a_media_list, medium);
+ medium = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ for (; status == CR_OK;) {
+ if ((status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr,
+ &next_char)) != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ goto okay;
+ }
+ goto error;
+ }
+
+ if (next_char == ',') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ } else {
+ break;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_ident (a_this, &medium);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ if ((status == CR_OK) && medium) {
+ *a_media_list = g_list_append (*a_media_list, medium);
+
+ medium = NULL;
+ }
+
+ CHECK_PARSING_STATUS (status, FALSE);
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == ';');
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ okay:
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->state = IMPORT_PARSED_STATE;
+
+ return CR_OK;
+
+ error:
+
+ if (*a_media_list) {
+ GList *cur = NULL;
+
+ /*
+ *free each element of *a_media_list.
+ *Note that each element of *a_medium list *must*
+ *be a GString* or else, the code that is coming next
+ *will corrupt the memory and lead to hard to debug
+ *random crashes.
+ *This is where C++ and its compile time
+ *type checking mecanism (through STL containers) would
+ *have prevented us to go through this hassle.
+ */
+ for (cur = *a_media_list; cur; cur = cur->next) {
+ if (cur->data) {
+ cr_string_destroy (cur->data);
+ }
+ }
+
+ g_list_free (*a_media_list);
+ *a_media_list = NULL;
+ }
+
+ if (*a_import_string) {
+ cr_string_destroy (*a_import_string);
+ *a_import_string = NULL;
+ }
+
+ if (medium) {
+ cr_string_destroy (medium);
+ medium = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_media:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses a 'media' declaration as specified in the css2 spec at
+ *appendix D.1:
+ *
+ *media ::= \@media S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
+ *
+ *Note that this function calls the required sac handlers during the parsing
+ *to notify media productions. See #CRDocHandler to know the callback called
+ *during \@media parsing.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_media (CRParser * a_this)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ guint32 next_char = 0,
+ cur_char = 0;
+ CRString *medium = NULL;
+ GList *media_list = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this),
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == MEDIA_SYM_TK);
+ cr_parsing_location_copy (&location, &token->location) ;
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == IDENT_TK);
+
+ medium = token->u.str;
+ token->u.str = NULL;
+ cr_token_destroy (token);
+ token = NULL;
+
+ if (medium) {
+ media_list = g_list_append (media_list, medium);
+ medium = NULL;
+ }
+
+ for (; status == CR_OK;) {
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ PEEK_NEXT_CHAR (a_this, &next_char);
+
+ if (next_char == ',') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ } else {
+ break;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_ident (a_this, &medium);
+
+ CHECK_PARSING_STATUS (status, FALSE);
+
+ if (medium) {
+ media_list = g_list_append (media_list, medium);
+ medium = NULL;
+ }
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ ENSURE_PARSING_COND (cur_char == '{');
+
+ /*
+ *call the SAC handler api here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_media) {
+ PRIVATE (a_this)->sac_handler->start_media
+ (PRIVATE (a_this)->sac_handler, media_list,
+ &location);
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ PRIVATE (a_this)->state = TRY_PARSE_MEDIA_STATE;
+
+ for (; status == CR_OK;) {
+ status = cr_parser_parse_ruleset (a_this);
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ ENSURE_PARSING_COND (cur_char == '}');
+
+ /*
+ *call the right SAC handler api here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_media) {
+ PRIVATE (a_this)->sac_handler->end_media
+ (PRIVATE (a_this)->sac_handler, media_list);
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ /*
+ *Then, free the data structures passed to
+ *the last call to the SAC handler.
+ */
+ if (medium) {
+ cr_string_destroy (medium);
+ medium = NULL;
+ }
+
+ if (media_list) {
+ GList *cur = NULL;
+
+ for (cur = media_list; cur; cur = cur->next) {
+ cr_string_destroy (cur->data);
+ }
+
+ g_list_free (media_list);
+ media_list = NULL;
+ }
+
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->state = MEDIA_PARSED_STATE;
+
+ return CR_OK;
+
+ error:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (medium) {
+ cr_string_destroy (medium);
+ medium = NULL;
+ }
+
+ if (media_list) {
+ GList *cur = NULL;
+
+ for (cur = media_list; cur; cur = cur->next) {
+ cr_string_destroy (cur->data);
+ }
+
+ g_list_free (media_list);
+ media_list = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_page:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *
+ *Parses '\@page' rule as specified in the css2 spec in appendix D.1:
+ *page ::= PAGE_SYM S* IDENT? pseudo_page? S*
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function also calls the relevant SAC handlers whenever it
+ *encounters a construction that must
+ *be reported to the calling application.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_page (CRParser * a_this)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ CRTerm *css_expression = NULL;
+ CRString *page_selector = NULL,
+ *page_pseudo_class = NULL,
+ *property = NULL;
+ gboolean important = TRUE;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token) ;
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == PAGE_SYM_TK);
+
+ cr_parsing_location_copy (&location, &token->location) ;
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == IDENT_TK) {
+ page_selector = token->u.str;
+ token->u.str = NULL;
+ cr_token_destroy (token);
+ token = NULL;
+ } else {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ }
+
+ /*
+ *try to parse pseudo_page
+ */
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type == DELIM_TK && token->u.unichar == ':') {
+ cr_token_destroy (token);
+ token = NULL;
+ status = cr_parser_parse_ident (a_this, &page_pseudo_class);
+ CHECK_PARSING_STATUS (status, FALSE);
+ } else {
+ cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token);
+ token = NULL;
+ }
+
+ /*
+ *parse_block
+ *
+ */
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == CBO_TK);
+
+ cr_token_destroy (token);
+ token = NULL;
+
+ /*
+ *Call the appropriate SAC handler here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_page) {
+ PRIVATE (a_this)->sac_handler->start_page
+ (PRIVATE (a_this)->sac_handler,
+ page_selector, page_pseudo_class,
+ &location);
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ PRIVATE (a_this)->state = TRY_PARSE_PAGE_STATE;
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression,
+ &important);
+ ENSURE_PARSING_COND (status == CR_OK);
+
+ /*
+ *call the relevant SAC handler here...
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property) {
+ if (css_expression)
+ cr_term_ref (css_expression);
+
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression, important);
+ }
+ /*
+ *... and free the data structure passed to that last
+ *SAC handler.
+ */
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_unref (css_expression);
+ css_expression = NULL;
+ }
+
+ for (;;) {
+ /*parse the other ';' separated declarations */
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK && token);
+
+ if (token->type != SEMICOLON_TK) {
+ cr_tknzr_unget_token
+ (PRIVATE (a_this)->tknzr,
+ token);
+ token = NULL ;
+ break;
+ }
+
+ cr_token_destroy (token);
+ token = NULL;
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression,
+ &important);
+ if (status != CR_OK)
+ break ;
+
+ /*
+ *call the relevant SAC handler here...
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->property) {
+ cr_term_ref (css_expression);
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression, important);
+ }
+ /*
+ *... and free the data structure passed to that last
+ *SAC handler.
+ */
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_unref (css_expression);
+ css_expression = NULL;
+ }
+ }
+ cr_parser_try_to_skip_spaces_and_comments
+ (a_this) ;
+ if (token) {
+ cr_token_destroy (token) ;
+ token = NULL ;
+ }
+
+ status = cr_tknzr_get_next_token
+ (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == CBC_TK) ;
+ cr_token_destroy (token) ;
+ token = NULL ;
+ /*
+ *call the relevant SAC handler here.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->end_page) {
+ PRIVATE (a_this)->sac_handler->end_page
+ (PRIVATE (a_this)->sac_handler,
+ page_selector, page_pseudo_class);
+ }
+
+ if (page_selector) {
+ cr_string_destroy (page_selector);
+ page_selector = NULL;
+ }
+
+ if (page_pseudo_class) {
+ cr_string_destroy (page_pseudo_class);
+ page_pseudo_class = NULL;
+ }
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ /*here goes the former implem of this function ... */
+
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->state = PAGE_PARSED_STATE;
+
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ if (page_selector) {
+ cr_string_destroy (page_selector);
+ page_selector = NULL;
+ }
+ if (page_pseudo_class) {
+ cr_string_destroy (page_pseudo_class);
+ page_pseudo_class = NULL;
+ }
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_destroy (css_expression);
+ css_expression = NULL;
+ }
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+ return status;
+}
+
+/**
+ * cr_parser_parse_charset:
+ *@a_this: the "this pointer" of the current instance of #CRParser.
+ *@a_value: out parameter. The actual parsed value of the charset
+ *declararation. Note that for safety check reasons, *a_value must be
+ *set to NULL.
+ *@a_charset_sym_location: the parsing location of the charset rule
+ *
+ *Parses a charset declaration as defined implictly by the css2 spec in
+ *appendix D.1:
+ *charset ::= CHARSET_SYM S* STRING S* ';'
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_charset (CRParser * a_this, CRString ** a_value,
+ CRParsingLocation *a_charset_sym_location)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRToken *token = NULL;
+ CRString *charset_str = NULL;
+
+ g_return_val_if_fail (a_this && a_value
+ && (*a_value == NULL),
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == CHARSET_SYM_TK);
+ if (a_charset_sym_location) {
+ cr_parsing_location_copy (a_charset_sym_location,
+ &token->location) ;
+ }
+ cr_token_destroy (token);
+ token = NULL;
+
+ PRIVATE (a_this)->state = TRY_PARSE_CHARSET_STATE;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == STRING_TK);
+ charset_str = token->u.str;
+ token->u.str = NULL;
+ cr_token_destroy (token);
+ token = NULL;
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+
+ ENSURE_PARSING_COND (status == CR_OK
+ && token && token->type == SEMICOLON_TK);
+ cr_token_destroy (token);
+ token = NULL;
+
+ if (charset_str) {
+ *a_value = charset_str;
+ charset_str = NULL;
+ }
+
+ PRIVATE (a_this)->state = CHARSET_PARSED_STATE;
+ return CR_OK;
+
+ error:
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (*a_value) {
+ cr_string_destroy (*a_value);
+ *a_value = NULL;
+ }
+
+ if (charset_str) {
+ cr_string_destroy (charset_str);
+ charset_str = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+
+ return status;
+}
+
+/**
+ * cr_parser_parse_font_face:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses the "\@font-face" rule specified in the css1 spec in
+ *appendix D.1:
+ *
+ *font_face ::= FONT_FACE_SYM S*
+ *'{' S* declaration [ ';' S* declaration ]* '}' S*
+ *
+ *This function will call SAC handlers whenever it is necessary.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_font_face (CRParser * a_this)
+{
+ enum CRStatus status = CR_ERROR;
+ CRInputPos init_pos;
+ CRString *property = NULL;
+ CRTerm *css_expression = NULL;
+ CRToken *token = NULL;
+ gboolean important = FALSE;
+ guint32 next_char = 0,
+ cur_char = 0;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token);
+ ENSURE_PARSING_COND (status == CR_OK
+ && token
+ && token->type == FONT_FACE_SYM_TK);
+
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ if (token) {
+ cr_parsing_location_copy (&location,
+ &token->location) ;
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr,
+ &token);
+ ENSURE_PARSING_COND (status == CR_OK && token
+ && token->type == CBO_TK);
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ /*
+ *here, call the relevant SAC handler.
+ */
+ if (PRIVATE (a_this)->sac_handler
+ && PRIVATE (a_this)->sac_handler->start_font_face) {
+ PRIVATE (a_this)->sac_handler->start_font_face
+ (PRIVATE (a_this)->sac_handler, &location);
+ }
+ PRIVATE (a_this)->state = TRY_PARSE_FONT_FACE_STATE;
+ /*
+ *and resume the parsing.
+ */
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_declaration (a_this, &property,
+ &css_expression, &important);
+ if (status == CR_OK) {
+ /*
+ *here, call the relevant SAC handler.
+ */
+ cr_term_ref (css_expression);
+ if (PRIVATE (a_this)->sac_handler &&
+ PRIVATE (a_this)->sac_handler->property) {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression, important);
+ }
+ ENSURE_PARSING_COND (css_expression && property);
+ }
+ /*free the data structures allocated during last parsing. */
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_unref (css_expression);
+ css_expression = NULL;
+ }
+ for (;;) {
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char == ';') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ } else {
+ break;
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ status = cr_parser_parse_declaration (a_this,
+ &property,
+ &css_expression,
+ &important);
+ if (status != CR_OK)
+ break;
+ /*
+ *here, call the relevant SAC handler.
+ */
+ cr_term_ref (css_expression);
+ if (PRIVATE (a_this)->sac_handler->property) {
+ PRIVATE (a_this)->sac_handler->property
+ (PRIVATE (a_this)->sac_handler,
+ property, css_expression, important);
+ }
+ /*
+ *Then, free the data structures allocated during
+ *last parsing.
+ */
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_unref (css_expression);
+ css_expression = NULL;
+ }
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == '}');
+ /*
+ *here, call the relevant SAC handler.
+ */
+ if (PRIVATE (a_this)->sac_handler->end_font_face) {
+ PRIVATE (a_this)->sac_handler->end_font_face
+ (PRIVATE (a_this)->sac_handler);
+ }
+ cr_parser_try_to_skip_spaces_and_comments (a_this);
+
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->state = FONT_FACE_PARSED_STATE;
+ return CR_OK;
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+ if (property) {
+ cr_string_destroy (property);
+ property = NULL;
+ }
+ if (css_expression) {
+ cr_term_destroy (css_expression);
+ css_expression = NULL;
+ }
+ cr_tknzr_set_cur_pos (PRIVATE (a_this)->tknzr, &init_pos);
+ return status;
+}
+
+/**
+ * cr_parser_parse:
+ *@a_this: the current instance of #CRParser.
+ *
+ *Parses the data that comes from the
+ *input previously associated to the current instance of
+ *#CRParser.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse (CRParser * a_this)
+{
+ enum CRStatus status = CR_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->tknzr, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->use_core_grammar == FALSE) {
+ status = cr_parser_parse_stylesheet (a_this);
+ } else {
+ status = cr_parser_parse_stylesheet_core (a_this);
+ }
+
+ return status;
+}
+
+/**
+ * cr_parser_set_tknzr:
+ * @a_this: the current instance of #CRParser;
+ * @a_tknzr: the new tokenizer.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_set_tknzr (CRParser * a_this, CRTknzr * a_tknzr)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->tknzr) {
+ cr_tknzr_unref (PRIVATE (a_this)->tknzr);
+ }
+
+ PRIVATE (a_this)->tknzr = a_tknzr;
+
+ if (a_tknzr)
+ cr_tknzr_ref (a_tknzr);
+
+ return CR_OK;
+}
+
+/**
+ * cr_parser_get_tknzr:
+ *@a_this: the current instance of #CRParser
+ *@a_tknzr: out parameter. The returned tokenizer
+ *
+ *Getter of the parser's underlying tokenizer
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise
+ */
+enum CRStatus
+cr_parser_get_tknzr (CRParser * a_this, CRTknzr ** a_tknzr)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_tknzr, CR_BAD_PARAM_ERROR);
+
+ *a_tknzr = PRIVATE (a_this)->tknzr;
+ return CR_OK;
+}
+
+/**
+ * cr_parser_get_parsing_location:
+ *@a_this: the current instance of #CRParser
+ *@a_loc: the parsing location to get.
+ *
+ *Gets the current parsing location.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parser_get_parsing_location (CRParser const *a_this,
+ CRParsingLocation *a_loc)
+{
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && a_loc, CR_BAD_PARAM_ERROR) ;
+
+ return cr_tknzr_get_parsing_location
+ (PRIVATE (a_this)->tknzr, a_loc) ;
+}
+
+/**
+ * cr_parser_parse_buf:
+ *@a_this: the current instance of #CRparser
+ *@a_buf: the input buffer
+ *@a_len: the length of the input buffer
+ *@a_enc: the encoding of the buffer
+ *
+ *Parses a stylesheet from a buffer
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parser_parse_buf (CRParser * a_this,
+ const guchar * a_buf,
+ gulong a_len, enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_ERROR;
+ CRTknzr *tknzr = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_buf, CR_BAD_PARAM_ERROR);
+
+ tknzr = cr_tknzr_new_from_buf ((guchar*)a_buf, a_len, a_enc, FALSE);
+
+ g_return_val_if_fail (tknzr != NULL, CR_ERROR);
+
+ status = cr_parser_set_tknzr (a_this, tknzr);
+ g_return_val_if_fail (status == CR_OK, CR_ERROR);
+
+ status = cr_parser_parse (a_this);
+
+ return status;
+}
+
+/**
+ * cr_parser_destroy:
+ *@a_this: the current instance of #CRParser to
+ *destroy.
+ *
+ *Destroys the current instance
+ *of #CRParser.
+ */
+void
+cr_parser_destroy (CRParser * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ if (PRIVATE (a_this)->tknzr) {
+ if (cr_tknzr_unref (PRIVATE (a_this)->tknzr) == TRUE)
+ PRIVATE (a_this)->tknzr = NULL;
+ }
+
+ if (PRIVATE (a_this)->sac_handler) {
+ cr_doc_handler_unref (PRIVATE (a_this)->sac_handler);
+ PRIVATE (a_this)->sac_handler = NULL;
+ }
+
+ if (PRIVATE (a_this)->err_stack) {
+ cr_parser_clear_errors (a_this);
+ PRIVATE (a_this)->err_stack = NULL;
+ }
+
+ if (PRIVATE (a_this)) {
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-parser.h b/src/3rdparty/libcroco/cr-parser.h
new file mode 100644
index 000000000..24cf5dfe8
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-parser.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_PARSER_H__
+#define __CR_PARSER_H__
+
+#include <glib.h>
+#include "cr-input.h"
+#include "cr-tknzr.h"
+#include "cr-utils.h"
+#include "cr-doc-handler.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration file
+ *of the #CRParser class.
+ */
+typedef struct _CRParser CRParser ;
+typedef struct _CRParserPriv CRParserPriv ;
+
+
+/**
+ *The implementation of
+ *the SAC parser.
+ *The Class is opaque
+ *and must be manipulated through
+ *the provided methods.
+ */
+struct _CRParser {
+ CRParserPriv *priv ;
+} ;
+
+
+CRParser * cr_parser_new (CRTknzr *a_tknzr) ;
+
+CRParser * cr_parser_new_from_buf (guchar *a_buf, gulong a_len,
+ enum CREncoding a_enc,
+ gboolean a_free_buf) ;
+
+CRParser * cr_parser_new_from_file (const guchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+CRParser * cr_parser_new_from_input (CRInput *a_input) ;
+
+enum CRStatus cr_parser_set_tknzr (CRParser *a_this, CRTknzr *a_tknzr) ;
+
+enum CRStatus cr_parser_get_tknzr (CRParser *a_this, CRTknzr **a_tknzr) ;
+
+enum CRStatus cr_parser_get_parsing_location (CRParser const *a_this, CRParsingLocation *a_loc) ;
+
+enum CRStatus cr_parser_try_to_skip_spaces_and_comments (CRParser *a_this) ;
+
+
+enum CRStatus cr_parser_set_sac_handler (CRParser *a_this,
+ CRDocHandler *a_handler) ;
+
+enum CRStatus cr_parser_get_sac_handler (CRParser *a_this,
+ CRDocHandler **a_handler) ;
+
+enum CRStatus cr_parser_set_use_core_grammar (CRParser *a_this,
+ gboolean a_use_core_grammar) ;
+enum CRStatus cr_parser_get_use_core_grammar (CRParser const *a_this,
+ gboolean *a_use_core_grammar) ;
+
+enum CRStatus cr_parser_parse (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_file (CRParser *a_this,
+ const guchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+enum CRStatus cr_parser_parse_buf (CRParser *a_this, const guchar *a_buf,
+ gulong a_len, enum CREncoding a_enc) ;
+
+enum CRStatus cr_parser_set_default_sac_handler (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_term (CRParser *a_this, CRTerm **a_term) ;
+
+enum CRStatus cr_parser_parse_selector (CRParser * a_this, CRSelector ** a_selector) ;
+
+enum CRStatus cr_parser_parse_expr (CRParser *a_this, CRTerm **a_expr) ;
+
+enum CRStatus cr_parser_parse_prio (CRParser *a_this, CRString **a_prio) ;
+
+enum CRStatus cr_parser_parse_declaration (CRParser *a_this, CRString **a_property,
+ CRTerm **a_expr, gboolean *a_important) ;
+
+enum CRStatus cr_parser_parse_statement_core (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_ruleset (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_import (CRParser *a_this, GList ** a_media_list,
+ CRString **a_import_string,
+ CRParsingLocation *a_location) ;
+
+enum CRStatus cr_parser_parse_media (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_page (CRParser *a_this) ;
+
+enum CRStatus cr_parser_parse_charset (CRParser *a_this, CRString **a_value,
+ CRParsingLocation *a_charset_sym_location) ;
+
+enum CRStatus cr_parser_parse_font_face (CRParser *a_this) ;
+
+void cr_parser_destroy (CRParser *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PARSER_H__*/
diff --git a/src/3rdparty/libcroco/cr-parsing-location.c b/src/3rdparty/libcroco/cr-parsing-location.c
new file mode 100644
index 000000000..4fe4acc30
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-parsing-location.c
@@ -0,0 +1,172 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-parsing-location.h"
+
+/**
+ *@CRParsingLocation:
+ *
+ *Definition of the #CRparsingLocation class.
+ */
+
+
+/**
+ * cr_parsing_location_new:
+ *Instanciates a new parsing location.
+ *
+ *Returns the newly instanciated #CRParsingLocation.
+ *Must be freed by cr_parsing_location_destroy()
+ */
+CRParsingLocation *
+cr_parsing_location_new (void)
+{
+ CRParsingLocation * result = NULL ;
+
+ result = g_try_malloc (sizeof (CRParsingLocation)) ;
+ if (!result) {
+ cr_utils_trace_info ("Out of memory error") ;
+ return NULL ;
+ }
+ cr_parsing_location_init (result) ;
+ return result ;
+}
+
+/**
+ * cr_parsing_location_init:
+ *@a_this: the current instance of #CRParsingLocation.
+ *
+ *Initializes the an instance of #CRparsingLocation.
+ *
+ *Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_parsing_location_init (CRParsingLocation *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ memset (a_this, 0, sizeof (CRParsingLocation)) ;
+ return CR_OK ;
+}
+
+/**
+ * cr_parsing_location_copy:
+ *@a_to: the destination of the copy.
+ *Must be allocated by the caller.
+ *@a_from: the source of the copy.
+ *
+ *Copies an instance of CRParsingLocation into another one.
+ *
+ *Returns CR_OK upon succesful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_parsing_location_copy (CRParsingLocation *a_to,
+ CRParsingLocation const *a_from)
+{
+ g_return_val_if_fail (a_to && a_from, CR_BAD_PARAM_ERROR) ;
+
+ memcpy (a_to, a_from, sizeof (CRParsingLocation)) ;
+ return CR_OK ;
+}
+
+/**
+ * cr_parsing_location_to_string:
+ *@a_this: the current instance of #CRParsingLocation.
+ *@a_mask: a bitmap that defines which parts of the
+ *parsing location are to be serialized (line, column or byte offset)
+ *
+ *Returns the serialized string or NULL in case of an error.
+ */
+gchar *
+cr_parsing_location_to_string (CRParsingLocation const *a_this,
+ enum CRParsingLocationSerialisationMask a_mask)
+{
+ GString *result = NULL ;
+ gchar *str = NULL ;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ if (!a_mask) {
+ a_mask = DUMP_LINE | DUMP_COLUMN | DUMP_BYTE_OFFSET ;
+ }
+ result =g_string_new (NULL) ;
+ if (!result)
+ return NULL ;
+ if (a_mask & DUMP_LINE) {
+ g_string_append_printf (result, "line:%d ",
+ a_this->line) ;
+ }
+ if (a_mask & DUMP_COLUMN) {
+ g_string_append_printf (result, "column:%d ",
+ a_this->column) ;
+ }
+ if (a_mask & DUMP_BYTE_OFFSET) {
+ g_string_append_printf (result, "byte offset:%d ",
+ a_this->byte_offset) ;
+ }
+ if (result->len) {
+ str = result->str ;
+ g_string_free (result, FALSE) ;
+ } else {
+ g_string_free (result, TRUE) ;
+ }
+ return str ;
+}
+
+/**
+ * cr_parsing_location_dump:
+ * @a_this: current instance of #CRParsingLocation
+ * @a_mask: the serialization mask.
+ * @a_fp: the file pointer to dump the parsing location to.
+ */
+void
+cr_parsing_location_dump (CRParsingLocation const *a_this,
+ enum CRParsingLocationSerialisationMask a_mask,
+ FILE *a_fp)
+{
+ gchar *str = NULL ;
+
+ g_return_if_fail (a_this && a_fp) ;
+ str = cr_parsing_location_to_string (a_this, a_mask) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ * cr_parsing_location_destroy:
+ *@a_this: the current instance of #CRParsingLocation. Must
+ *have been allocated with cr_parsing_location_new().
+ *
+ *Destroys the current instance of #CRParsingLocation
+ */
+void
+cr_parsing_location_destroy (CRParsingLocation *a_this)
+{
+ g_return_if_fail (a_this) ;
+ g_free (a_this) ;
+}
+
diff --git a/src/3rdparty/libcroco/cr-parsing-location.h b/src/3rdparty/libcroco/cr-parsing-location.h
new file mode 100644
index 000000000..b8064a560
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-parsing-location.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See the COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_PARSING_LOCATION_H__
+#define __CR_PARSING_LOCATION_H__
+
+#include "cr-utils.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the CRParsingLocation
+ *object. This object keeps track of line/column/byte offset/
+ *at which the parsing of a given CSS construction appears.
+ */
+
+typedef struct _CRParsingLocation CRParsingLocation;
+struct _CRParsingLocation {
+ guint line ;
+ guint column ;
+ guint byte_offset ;
+} ;
+
+
+enum CRParsingLocationSerialisationMask {
+ DUMP_LINE = 1,
+ DUMP_COLUMN = 1 << 1,
+ DUMP_BYTE_OFFSET = 1 << 2
+} ;
+
+CRParsingLocation * cr_parsing_location_new (void) ;
+
+enum CRStatus cr_parsing_location_init (CRParsingLocation *a_this) ;
+
+enum CRStatus cr_parsing_location_copy (CRParsingLocation *a_to,
+ CRParsingLocation const *a_from) ;
+
+gchar * cr_parsing_location_to_string (CRParsingLocation const *a_this,
+ enum CRParsingLocationSerialisationMask a_mask) ;
+void cr_parsing_location_dump (CRParsingLocation const *a_this,
+ enum CRParsingLocationSerialisationMask a_mask,
+ FILE *a_fp) ;
+
+void cr_parsing_location_destroy (CRParsingLocation *a_this) ;
+
+
+
+G_END_DECLS
+#endif
diff --git a/src/3rdparty/libcroco/cr-prop-list.c b/src/3rdparty/libcroco/cr-prop-list.c
new file mode 100644
index 000000000..dc575d6ff
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-prop-list.c
@@ -0,0 +1,404 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include <string.h>
+#include "cr-prop-list.h"
+
+#define PRIVATE(a_obj) (a_obj)->priv
+
+struct _CRPropListPriv {
+ CRString *prop;
+ CRDeclaration *decl;
+ CRPropList *next;
+ CRPropList *prev;
+};
+
+static CRPropList *cr_prop_list_allocate (void);
+
+/**
+ *Default allocator of CRPropList
+ *@return the newly allocated CRPropList or NULL
+ *if an error arises.
+ */
+static CRPropList *
+cr_prop_list_allocate (void)
+{
+ CRPropList *result = NULL;
+
+ result = g_try_malloc (sizeof (CRPropList));
+ if (!result) {
+ cr_utils_trace_info ("could not allocate CRPropList");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRPropList));
+ PRIVATE (result) = g_try_malloc (sizeof (CRPropListPriv));
+ if (!PRIVATE (result)) {
+ cr_utils_trace_info ("could not allocate CRPropListPriv");
+ g_free (result);
+ return NULL;
+ }
+ memset (PRIVATE (result), 0, sizeof (CRPropListPriv));
+ return result;
+}
+
+/****************
+ *public methods
+ ***************/
+
+/**
+ * cr_prop_list_append:
+ *@a_this: the current instance of #CRPropList
+ *@a_to_append: the property list to append
+ *
+ *Appends a property list to the current one.
+ *
+ *Returns the resulting prop list, or NULL if an error
+ *occured
+ */
+CRPropList *
+cr_prop_list_append (CRPropList * a_this, CRPropList * a_to_append)
+{
+ CRPropList *cur = NULL;
+
+ g_return_val_if_fail (a_to_append, NULL);
+
+ if (!a_this)
+ return a_to_append;
+
+ /*go fetch the last element of the list */
+ for (cur = a_this;
+ cur && PRIVATE (cur) && PRIVATE (cur)->next;
+ cur = PRIVATE (cur)->next) ;
+ g_return_val_if_fail (cur, NULL);
+ PRIVATE (cur)->next = a_to_append;
+ PRIVATE (a_to_append)->prev = cur;
+ return a_this;
+}
+
+/**
+ * cr_prop_list_append2:
+ *Appends a pair of prop/declaration to
+ *the current prop list.
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to consider
+ *@a_decl: the declaration to consider
+ *
+ *Returns the resulting property list, or NULL in case
+ *of an error.
+ */
+CRPropList *
+cr_prop_list_append2 (CRPropList * a_this,
+ CRString * a_prop,
+ CRDeclaration * a_decl)
+{
+ CRPropList *list = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_prop && a_decl, NULL);
+
+ list = cr_prop_list_allocate ();
+ g_return_val_if_fail (list && PRIVATE (list), NULL);
+
+ PRIVATE (list)->prop = a_prop;
+ PRIVATE (list)->decl = a_decl;
+
+ result = cr_prop_list_append (a_this, list);
+ return result;
+}
+
+/**
+ * cr_prop_list_prepend:
+ *@a_this: the current instance of #CRPropList
+ *@a_to_prepend: the new list to prepend.
+ *
+ *Prepends a list to the current list
+ *Returns the new properties list.
+ */
+CRPropList *
+cr_prop_list_prepend (CRPropList * a_this, CRPropList * a_to_prepend)
+{
+ CRPropList *cur = NULL;
+
+ g_return_val_if_fail (a_to_prepend, NULL);
+
+ if (!a_this)
+ return a_to_prepend;
+
+ for (cur = a_to_prepend; cur && PRIVATE (cur)->next;
+ cur = PRIVATE (cur)->next) ;
+ g_return_val_if_fail (cur, NULL);
+ PRIVATE (cur)->next = a_this;
+ PRIVATE (a_this)->prev = cur;
+ return a_to_prepend;
+}
+
+/**
+ * cr_prop_list_prepend2:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop_name: property name to append
+ *@a_decl: the property value to append.
+ *
+ *Prepends a propertie to a list of properties
+ *
+ *Returns the new property list.
+ */
+CRPropList *
+cr_prop_list_prepend2 (CRPropList * a_this,
+ CRString * a_prop_name, CRDeclaration * a_decl)
+{
+ CRPropList *list = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_prop_name && a_decl, NULL);
+
+ list = cr_prop_list_allocate ();
+ g_return_val_if_fail (list, NULL);
+ PRIVATE (list)->prop = a_prop_name;
+ PRIVATE (list)->decl = a_decl;
+ result = cr_prop_list_prepend (a_this, list);
+ return result;
+}
+
+/**
+ * cr_prop_list_set_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to set
+ *
+ *Sets the property of a CRPropList
+ */
+enum CRStatus
+cr_prop_list_set_prop (CRPropList * a_this, CRString * a_prop)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_prop, CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->prop = a_prop;
+ return CR_OK;
+}
+
+/**
+ * cr_prop_list_get_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: out parameter. The returned property
+ *
+ *Getter of the property associated to the current instance
+ *of #CRPropList
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_prop_list_get_prop (CRPropList const * a_this, CRString ** a_prop)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_prop, CR_BAD_PARAM_ERROR);
+
+ *a_prop = PRIVATE (a_this)->prop;
+ return CR_OK;
+}
+
+/**
+ * cr_prop_list_set_decl:
+ * @a_this: the current instance of #CRPropList
+ * @a_decl: the new property value.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_prop_list_set_decl (CRPropList * a_this, CRDeclaration * a_decl)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_decl, CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->decl = a_decl;
+ return CR_OK;
+}
+
+/**
+ * cr_prop_list_get_decl:
+ * @a_this: the current instance of #CRPropList
+ * @a_decl: out parameter. The property value
+ *
+ * Returns CR_OK upon successful completion.
+ */
+enum CRStatus
+cr_prop_list_get_decl (CRPropList const * a_this, CRDeclaration ** a_decl)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_decl, CR_BAD_PARAM_ERROR);
+
+ *a_decl = PRIVATE (a_this)->decl;
+ return CR_OK;
+}
+
+/**
+ * cr_prop_list_lookup_prop:
+ *@a_this: the current instance of #CRPropList
+ *@a_prop: the property to lookup
+ *@a_prop_list: out parameter. The property/declaration
+ *pair found (if and only if the function returned code if CR_OK)
+ *
+ *Lookup a given property/declaration pair
+ *
+ *Returns CR_OK if a prop/decl pair has been found,
+ *CR_VALUE_NOT_FOUND_ERROR if not, or an error code if something
+ *bad happens.
+ */
+enum CRStatus
+cr_prop_list_lookup_prop (CRPropList * a_this,
+ CRString * a_prop, CRPropList ** a_pair)
+{
+ CRPropList *cur = NULL;
+
+ g_return_val_if_fail (a_prop && a_pair, CR_BAD_PARAM_ERROR);
+
+ if (!a_this)
+ return CR_VALUE_NOT_FOUND_ERROR;
+
+ g_return_val_if_fail (PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ for (cur = a_this; cur; cur = PRIVATE (cur)->next) {
+ if (PRIVATE (cur)->prop
+ && PRIVATE (cur)->prop->stryng
+ && PRIVATE (cur)->prop->stryng->str
+ && a_prop->stryng
+ && a_prop->stryng->str
+ && !strcmp (PRIVATE (cur)->prop->stryng->str,
+ a_prop->stryng->str))
+ break;
+ }
+
+ if (cur) {
+ *a_pair = cur;
+ return CR_OK;
+ }
+
+ return CR_VALUE_NOT_FOUND_ERROR;
+}
+
+/**
+ * cr_prop_list_get_next:
+ *@a_this: the current instance of CRPropList
+ *
+ *Gets the next prop/decl pair in the list
+ *
+ *Returns the next prop/declaration pair of the list,
+ *or NULL if we reached end of list (or if an error occurs)
+ */
+CRPropList *
+cr_prop_list_get_next (CRPropList * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+ return PRIVATE (a_this)->next;
+}
+
+/**
+ * cr_prop_list_get_prev:
+ *@a_this: the current instance of CRPropList
+ *
+ *Gets the previous prop/decl pair in the list
+ *
+ *Returns the previous prop/declaration pair of the list,
+ *or NULL if we reached end of list (or if an error occurs)
+ */
+CRPropList *
+cr_prop_list_get_prev (CRPropList * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), NULL);
+
+ return PRIVATE (a_this)->prev;
+}
+
+/**
+ * cr_prop_list_unlink:
+ *@a_this: the current list of prop/decl pairs
+ *@a_pair: the prop/decl pair to unlink.
+ *
+ *Unlinks a prop/decl pair from the list
+ *
+ *Returns the new list or NULL in case of an error.
+ */
+CRPropList *
+cr_prop_list_unlink (CRPropList * a_this, CRPropList * a_pair)
+{
+ CRPropList *prev = NULL,
+ *next = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_pair, NULL);
+
+ /*some sanity checks */
+ if (PRIVATE (a_pair)->next) {
+ next = PRIVATE (a_pair)->next;
+ g_return_val_if_fail (PRIVATE (next), NULL);
+ g_return_val_if_fail (PRIVATE (next)->prev == a_pair, NULL);
+ }
+ if (PRIVATE (a_pair)->prev) {
+ prev = PRIVATE (a_pair)->prev;
+ g_return_val_if_fail (PRIVATE (prev), NULL);
+ g_return_val_if_fail (PRIVATE (prev)->next == a_pair, NULL);
+ }
+ if (prev) {
+ PRIVATE (prev)->next = next;
+ }
+ if (next) {
+ PRIVATE (next)->prev = prev;
+ }
+ PRIVATE (a_pair)->prev = PRIVATE (a_pair)->next = NULL;
+ if (a_this == a_pair) {
+ if (next)
+ return next;
+ return NULL;
+ }
+ return a_this;
+}
+
+/**
+ * cr_prop_list_destroy:
+ * @a_this: the current instance of #CRPropList
+ */
+void
+cr_prop_list_destroy (CRPropList * a_this)
+{
+ CRPropList *tail = NULL,
+ *cur = NULL;
+
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ for (tail = a_this;
+ tail && PRIVATE (tail) && PRIVATE (tail)->next;
+ tail = cr_prop_list_get_next (tail)) ;
+ g_return_if_fail (tail);
+
+ cur = tail;
+
+ while (cur) {
+ tail = PRIVATE (cur)->prev;
+ if (tail && PRIVATE (tail))
+ PRIVATE (tail)->next = NULL;
+ PRIVATE (cur)->prev = NULL;
+ g_free (PRIVATE (cur));
+ PRIVATE (cur) = NULL;
+ g_free (cur);
+ cur = tail;
+ }
+}
diff --git a/src/3rdparty/libcroco/cr-prop-list.h b/src/3rdparty/libcroco/cr-prop-list.h
new file mode 100644
index 000000000..797ba43ea
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-prop-list.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_PROP_LIST_H__
+#define __CR_PROP_LIST_H__
+
+#include "cr-utils.h"
+#include "cr-declaration.h"
+#include "cr-string.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CRPropList CRPropList ;
+typedef struct _CRPropListPriv CRPropListPriv ;
+
+struct _CRPropList
+{
+ CRPropListPriv * priv;
+} ;
+
+CRPropList * cr_prop_list_append (CRPropList *a_this,
+ CRPropList *a_to_append) ;
+
+CRPropList * cr_prop_list_append2 (CRPropList *a_this,
+ CRString *a_prop,
+ CRDeclaration *a_decl) ;
+
+CRPropList * cr_prop_list_prepend (CRPropList *a_this,
+ CRPropList *a_to_append) ;
+
+CRPropList * cr_prop_list_prepend2 (CRPropList *a_this,
+ CRString *a_prop,
+ CRDeclaration *a_decl) ;
+
+enum CRStatus cr_prop_list_set_prop (CRPropList *a_this,
+ CRString *a_prop) ;
+
+enum CRStatus cr_prop_list_get_prop (CRPropList const *a_this,
+ CRString **a_prop) ;
+
+enum CRStatus cr_prop_list_lookup_prop (CRPropList *a_this,
+ CRString *a_prop,
+ CRPropList**a_pair) ;
+
+CRPropList * cr_prop_list_get_next (CRPropList *a_this) ;
+
+CRPropList * cr_prop_list_get_prev (CRPropList *a_this) ;
+
+enum CRStatus cr_prop_list_set_decl (CRPropList *a_this,
+ CRDeclaration *a_decl);
+
+enum CRStatus cr_prop_list_get_decl (CRPropList const *a_this,
+ CRDeclaration **a_decl) ;
+
+CRPropList * cr_prop_list_unlink (CRPropList *a_this,
+ CRPropList *a_pair) ;
+
+void cr_prop_list_destroy (CRPropList *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PROP_LIST_H__*/
diff --git a/src/3rdparty/libcroco/cr-pseudo.c b/src/3rdparty/libcroco/cr-pseudo.c
new file mode 100644
index 000000000..8715c19f1
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-pseudo.c
@@ -0,0 +1,167 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "cr-pseudo.h"
+
+/**
+ *@CRPseudo:
+ *The definition of the #CRPseudo class.
+ */
+
+/**
+ * cr_pseudo_new:
+ *Constructor of the #CRPseudo class.
+ *
+ *Returns the newly build instance.
+ */
+CRPseudo *
+cr_pseudo_new (void)
+{
+ CRPseudo *result = NULL;
+
+ result = g_malloc0 (sizeof (CRPseudo));
+
+ return result;
+}
+
+/**
+ * cr_pseudo_to_string:
+ * @a_this: the current instance of #CRPseud.
+ *
+ * Returns the serialized pseudo. Caller must free the returned
+ * string using g_free().
+ */
+guchar *
+cr_pseudo_to_string (CRPseudo const * a_this)
+{
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+
+ if (a_this->type == IDENT_PSEUDO) {
+ guchar *name = NULL;
+
+ if (a_this->name == NULL) {
+ goto error;
+ }
+
+ name = (guchar *) g_strndup (a_this->name->stryng->str,
+ a_this->name->stryng->len);
+
+ if (name) {
+ g_string_append (str_buf, (const gchar *) name);
+ g_free (name);
+ name = NULL;
+ }
+ } else if (a_this->type == FUNCTION_PSEUDO) {
+ guchar *name = NULL,
+ *arg = NULL;
+
+ if (a_this->name == NULL)
+ goto error;
+
+ name = (guchar *) g_strndup (a_this->name->stryng->str,
+ a_this->name->stryng->len);
+
+ if (name) {
+ g_string_append_printf (str_buf, "%s(", name);
+ g_free (name);
+ name = NULL;
+
+ if (arg) {
+ g_string_append (str_buf, (const gchar *) arg);
+ g_free (arg);
+ arg = NULL;
+ }
+
+ g_string_append_c (str_buf, ')');
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+
+ error:
+ g_string_free (str_buf, TRUE);
+ return NULL;
+}
+
+/**
+ * cr_pseudo_dump:
+ *@a_this: the current instance of pseudo
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the pseudo to a file.
+ *
+ */
+void
+cr_pseudo_dump (CRPseudo const * a_this, FILE * a_fp)
+{
+ guchar *tmp_str = NULL;
+
+ if (a_this) {
+ tmp_str = cr_pseudo_to_string (a_this);
+ if (tmp_str) {
+ fprintf (a_fp, "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+}
+
+/**
+ * cr_pseudo_destroy:
+ *@a_this: the current instance to destroy.
+ *
+ *destructor of the #CRPseudo class.
+ */
+void
+cr_pseudo_destroy (CRPseudo * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->name) {
+ cr_string_destroy (a_this->name);
+ a_this->name = NULL;
+ }
+
+ if (a_this->sel_name) {
+ cr_string_destroy (a_this->sel_name);
+ a_this->sel_name = NULL;
+ }
+
+ if (a_this->term) {
+ cr_term_destroy (a_this->term);
+ a_this->term = NULL;
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-pseudo.h b/src/3rdparty/libcroco/cr-pseudo.h
new file mode 100644
index 000000000..b78435014
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-pseudo.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyright information
+ */
+
+#ifndef __CR_PSEUDO_H__
+#define __CR_PSEUDO_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-attr-sel.h"
+#include "cr-parsing-location.h"
+#include "cr-term.h"
+
+G_BEGIN_DECLS
+
+enum CRPseudoType
+{
+ IDENT_PSEUDO = 0,
+ FUNCTION_PSEUDO
+} ;
+
+typedef struct _CRPseudo CRPseudo ;
+
+/**
+ *The CRPseudo Class.
+ *Abstract a "pseudo" as defined by the css2 spec
+ *in appendix D.1 .
+ */
+struct _CRPseudo
+{
+ enum CRPseudoType type ;
+ CRString *name ;
+ CRString *sel_name;
+ CRTerm *term ;
+ CRParsingLocation location ;
+} ;
+
+CRPseudo * cr_pseudo_new (void) ;
+
+guchar * cr_pseudo_to_string (CRPseudo const *a_this) ;
+
+void cr_pseudo_dump (CRPseudo const *a_this, FILE *a_fp) ;
+
+void cr_pseudo_destroy (CRPseudo *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_PSEUDO_H__*/
diff --git a/src/3rdparty/libcroco/cr-rgb.c b/src/3rdparty/libcroco/cr-rgb.c
new file mode 100644
index 000000000..889f248b6
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-rgb.c
@@ -0,0 +1,688 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "cr-rgb.h"
+#include "cr-term.h"
+#include "cr-parser.h"
+
+static const CRRgb gv_standard_colors[] = {
+ {(const guchar*)"aliceblue", 240, 248, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"antiquewhite", 250, 235, 215, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"aqua", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"aquamarine", 127, 255, 212, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"azure", 240, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"beige", 245, 245, 220, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"bisque", 255, 228, 196, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"black", 0, 0, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"blanchedalmond", 255, 235, 205, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"blue", 0, 0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"blueviolet", 138, 43, 226, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"brown", 165, 42, 42, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"burlywood", 222, 184, 135, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"cadetblue", 95, 158, 160, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"chartreuse", 127, 255, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"chocolate", 210, 105, 30, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"coral", 255, 127, 80, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"cornflowerblue", 100, 149, 237, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"cornsilk", 255, 248, 220, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"crimson", 220, 20, 60, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"cyan", 0, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkblue", 0, 0, 139, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkcyan", 0, 139, 139, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkgoldenrod", 184, 134, 11, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkgray", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkgreen", 0, 100, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkgrey", 169, 169, 169, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkkhaki", 189, 183, 107, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkmagenta", 139, 0, 139, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkolivegreen", 85, 107, 47, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkorange", 255, 140, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkorchid", 153, 50, 204, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkred", 139, 0, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darksalmon", 233, 150, 122, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkseagreen", 143, 188, 143, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkslateblue", 72, 61, 139, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkslategray", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkslategrey", 47, 79, 79, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkturquoise", 0, 206, 209, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"darkviolet", 148, 0, 211, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"deeppink", 255, 20, 147, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"deepskyblue", 0, 191, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"dimgray", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"dimgrey", 105, 105, 105, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"dodgerblue", 30, 144, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"firebrick", 178, 34, 34, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"floralwhite", 255, 250, 240, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"forestgreen", 34, 139, 34, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"fuchsia", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"gainsboro", 220, 220, 220, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"ghostwhite", 248, 248, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"gold", 255, 215, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"goldenrod", 218, 165, 32, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"gray", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"green", 0, 128, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"greenyellow", 173, 255, 47, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"grey", 128, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"honeydew", 240, 255, 240, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"hotpink", 255, 105, 180, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"indianred", 205, 92, 92, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"indigo", 75, 0, 130, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"ivory", 255, 255, 240, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"khaki", 240, 230, 140, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lavender", 230, 230, 250, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lavenderblush", 255, 240, 245, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lawngreen", 124, 252, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lemonchiffon", 255, 250, 205, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightblue", 173, 216, 230, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightcoral", 240, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightcyan", 224, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightgoldenrodyellow", 250, 250, 210, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightgray", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightgreen", 144, 238, 144, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightgrey", 211, 211, 211, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightpink", 255, 182, 193, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightsalmon", 255, 160, 122, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightseagreen", 32, 178, 170, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightskyblue", 135, 206, 250, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightslategray", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightslategrey", 119, 136, 153, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightsteelblue", 176, 196, 222, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lightyellow", 255, 255, 224, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"lime", 0, 255, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"limegreen", 50, 205, 50, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"linen", 250, 240, 230, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"magenta", 255, 0, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"maroon", 128, 0, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumaquamarine", 102, 205, 170, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumblue", 0, 0, 205, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumorchid", 186, 85, 211, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumpurple", 147, 112, 219, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumseagreen", 60, 179, 113, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumslateblue", 123, 104, 238, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumspringgreen", 0, 250, 154, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumturquoise", 72, 209, 204, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mediumvioletred", 199, 21, 133, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"midnightblue", 25, 25, 112, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mintcream", 245, 255, 250, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"mistyrose", 255, 228, 225, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"moccasin", 255, 228, 181, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"navajowhite", 255, 222, 173, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"navy", 0, 0, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"oldlace", 253, 245, 230, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"olive", 128, 128, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"olivedrab", 107, 142, 35, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"orange", 255, 165, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"orangered", 255, 69, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"orchid", 218, 112, 214, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"palegoldenrod", 238, 232, 170, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"palegreen", 152, 251, 152, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"paleturquoise", 175, 238, 238, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"palevioletred", 219, 112, 147, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"papayawhip", 255, 239, 213, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"peachpuff", 255, 218, 185, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"peru", 205, 133, 63, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"pink", 255, 192, 203, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"plum", 221, 160, 221, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"powderblue", 176, 224, 230, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"purple", 128, 0, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"rebeccapurple", 102, 51, 153, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"red", 255, 0, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"rosybrown", 188, 143, 143, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"royalblue", 65, 105, 225, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"saddlebrown", 139, 69, 19, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"salmon", 250, 128, 114, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"sandybrown", 244, 164, 96, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"seagreen", 46, 139, 87, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"seashell", 255, 245, 238, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"sienna", 160, 82, 45, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"silver", 192, 192, 192, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"skyblue", 135, 206, 235, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"slateblue", 106, 90, 205, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"slategray", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"slategrey", 112, 128, 144, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"snow", 255, 250, 250, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"springgreen", 0, 255, 127, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"steelblue", 70, 130, 180, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"tan", 210, 180, 140, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"teal", 0, 128, 128, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"thistle", 216, 191, 216, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"tomato", 255, 99, 71, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"transparent", 255, 255, 255, FALSE, FALSE, TRUE, {0,0,0}},
+ {(const guchar*)"turquoise", 64, 224, 208, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"violet", 238, 130, 238, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"wheat", 245, 222, 179, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"white", 255, 255, 255, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"whitesmoke", 245, 245, 245, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"yellow", 255, 255, 0, FALSE, FALSE, FALSE, {0,0,0}},
+ {(const guchar*)"yellowgreen", 154, 205, 50, FALSE, FALSE, FALSE, {0,0,0}}
+};
+
+/**
+ * cr_rgb_new:
+ *
+ *The default constructor of #CRRgb.
+ *
+ *Returns the newly built instance of #CRRgb
+ */
+CRRgb *
+cr_rgb_new (void)
+{
+ CRRgb *result = NULL;
+
+ result = g_try_malloc (sizeof (CRRgb));
+
+ if (result == NULL) {
+ cr_utils_trace_info ("No more memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRRgb));
+
+ return result;
+}
+
+/**
+ * cr_rgb_new_with_vals:
+ *@a_red: the red component of the color.
+ *@a_green: the green component of the color.
+ *@a_blue: the blue component of the color.
+ *@a_unit: the unit of the rgb values.
+ *(either percentage or integer values)
+ *
+ *A constructor of #CRRgb.
+ *
+ *Returns the newly built instance of #CRRgb.
+ */
+CRRgb *
+cr_rgb_new_with_vals (gulong a_red, gulong a_green,
+ gulong a_blue, gboolean a_is_percentage)
+{
+ CRRgb *result = NULL;
+
+ result = cr_rgb_new ();
+
+ g_return_val_if_fail (result, NULL);
+
+ result->red = a_red;
+ result->green = a_green;
+ result->blue = a_blue;
+ result->is_percentage = a_is_percentage;
+
+ return result;
+}
+
+/**
+ * cr_rgb_to_string:
+ *@a_this: the instance of #CRRgb to serialize.
+ *
+ *Serializes the rgb into a zero terminated string.
+ *
+ *Returns the zero terminated string containing the serialized
+ *rgb. MUST BE FREED by the caller using g_free().
+ */
+guchar *
+cr_rgb_to_string (CRRgb const * a_this)
+{
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+
+ str_buf = g_string_new (NULL);
+ g_return_val_if_fail (str_buf, NULL);
+
+ if (a_this->is_percentage == 1) {
+ g_string_append_printf (str_buf, "%ld", a_this->red);
+
+ g_string_append (str_buf, "%, ");
+
+ g_string_append_printf (str_buf, "%ld", a_this->green);
+ g_string_append (str_buf, "%, ");
+
+ g_string_append_printf (str_buf, "%ld", a_this->blue);
+ g_string_append_c (str_buf, '%');
+ } else {
+ g_string_append_printf (str_buf, "%ld", a_this->red);
+ g_string_append (str_buf, ", ");
+
+ g_string_append_printf (str_buf, "%ld", a_this->green);
+ g_string_append (str_buf, ", ");
+
+ g_string_append_printf (str_buf, "%ld", a_this->blue);
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ }
+
+ return result;
+}
+
+/**
+ * cr_rgb_dump:
+ *@a_this: the "this pointer" of
+ *the current instance of #CRRgb.
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the current instance of #CRRgb
+ *to a file.
+ */
+void
+cr_rgb_dump (CRRgb const * a_this, FILE * a_fp)
+{
+ guchar *str = NULL;
+
+ g_return_if_fail (a_this);
+
+ str = cr_rgb_to_string (a_this);
+
+ if (str) {
+ fprintf (a_fp, "%s", str);
+ g_free (str);
+ str = NULL;
+ }
+}
+
+/**
+ * cr_rgb_compute_from_percentage:
+ *@a_this: the current instance of #CRRgb
+ *
+ *If the rgb values are expressed in percentage,
+ *compute their real value.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_compute_from_percentage (CRRgb * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ if (a_this->is_percentage == FALSE)
+ return CR_OK;
+ a_this->red = a_this->red * 255 / 100;
+ a_this->green = a_this->green * 255 / 100;
+ a_this->blue = a_this->blue * 255 / 100;
+ a_this->is_percentage = FALSE;
+ return CR_OK;
+}
+
+/**
+ * cr_rgb_set:
+ *@a_this: the current instance of #CRRgb.
+ *@a_red: the red value.
+ *@a_green: the green value.
+ *@a_blue: the blue value.
+ *
+ *Sets rgb values to the RGB.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_rgb_set (CRRgb * a_this, gulong a_red,
+ gulong a_green, gulong a_blue, gboolean a_is_percentage)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ if (a_is_percentage != FALSE) {
+ g_return_val_if_fail (a_red <= 100
+ && a_green <= 100
+ && a_blue <= 100, CR_BAD_PARAM_ERROR);
+ }
+
+ a_this->is_percentage = a_is_percentage;
+
+ a_this->red = a_red;
+ a_this->green = a_green;
+ a_this->blue = a_blue;
+ a_this->inherit = FALSE ;
+ a_this->is_transparent = FALSE ;
+ return CR_OK;
+}
+
+/**
+ * cr_rgb_set_to_inherit:
+ *@a_this: the current instance of #CRRgb
+ *
+ *sets the value of the rgb to inherit.
+ *Look at the css spec from chapter 6.1 to 6.2 to understand
+ *the meaning of "inherit".
+ *
+ * Returns CR_OK upon succesful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ a_this->inherit = a_inherit ;
+
+ return CR_OK ;
+}
+
+/**
+ * cr_rgb_is_set_to_inherit:
+ *
+ * @a_this: the current instance of #CRRgb.
+ *
+ * Returns TRUE if the rgb is set to the value "inherit", FALSE otherwise.
+ */
+gboolean
+cr_rgb_is_set_to_inherit (CRRgb const *a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+
+ return a_this->inherit ;
+}
+
+/**
+ * cr_rgb_is_set_to_transparent:
+ *@a_this: the current instance of
+ *#CRRgb
+ *
+ *Tests if the rgb is set to the
+ *value "transparent" or not.
+ *
+ *Returns TRUE if the rgb has been set to
+ *transparent, FALSE otherwise.
+ */
+gboolean
+cr_rgb_is_set_to_transparent (CRRgb const *a_this)
+{
+ g_return_val_if_fail (a_this, FALSE) ;
+ return a_this->is_transparent ;
+}
+
+
+/**
+ * cr_rgb_set_to_transparent:
+ *@a_this: the current instance of #CRRgb
+ *@a_is_transparent: set to transparent or not.
+ *
+ *Sets the rgb to the "transparent" value (or not)
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_to_transparent (CRRgb *a_this,
+ gboolean a_is_transparent)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
+ a_this->is_transparent = a_is_transparent ;
+ return CR_OK ;
+}
+
+/**
+ * cr_rgb_set_from_rgb:
+ *@a_this: the current instance of #CRRgb.
+ *@a_rgb: the rgb to "copy"
+ *
+ *Sets the rgb from an other one.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_rgb (CRRgb * a_this, CRRgb const * a_rgb)
+{
+ g_return_val_if_fail (a_this && a_rgb, CR_BAD_PARAM_ERROR);
+
+ cr_rgb_copy (a_this, a_rgb) ;
+
+ return CR_OK;
+}
+
+static int
+cr_rgb_color_name_compare (const void *a,
+ const void *b)
+{
+ const char *a_color_name = a;
+ const CRRgb *rgb = b;
+
+ return g_ascii_strcasecmp (a_color_name, (const char *) rgb->name);
+}
+
+/**
+ * cr_rgb_set_from_name:
+ * @a_this: the current instance of #CRRgb
+ * @a_color_name: the color name
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_name (CRRgb * a_this, const guchar * a_color_name)
+{
+ enum CRStatus status = CR_OK;
+ CRRgb *result;
+
+ g_return_val_if_fail (a_this && a_color_name, CR_BAD_PARAM_ERROR);
+
+ result = bsearch (a_color_name,
+ gv_standard_colors,
+ G_N_ELEMENTS (gv_standard_colors),
+ sizeof (gv_standard_colors[0]),
+ cr_rgb_color_name_compare);
+ if (result != NULL)
+ cr_rgb_set_from_rgb (a_this, result);
+ else
+ status = CR_UNKNOWN_TYPE_ERROR;
+
+ return status;
+}
+
+/**
+ * cr_rgb_set_from_hex_str:
+ * @a_this: the current instance of #CRRgb
+ * @a_hex: the hexadecimal value to set.
+ *
+ * Returns CR_OK upon successful completion.
+ */
+enum CRStatus
+cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex)
+{
+ enum CRStatus status = CR_OK;
+ gulong i = 0;
+ guchar colors[3] = { 0 };
+
+ g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR);
+
+ if (strlen ((const char *) a_hex) == 3) {
+ for (i = 0; i < 3; i++) {
+ if (a_hex[i] >= '0' && a_hex[i] <= '9') {
+ colors[i] = a_hex[i] - '0';
+ colors[i] = (colors[i] << 4) | colors[i];
+ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') {
+ colors[i] = 10 + a_hex[i] - 'a';
+ colors[i] = (colors[i] << 4) | colors[i];
+ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') {
+ colors[i] = 10 + a_hex[i] - 'A';
+ colors[i] = (colors[i] << 4) | colors[i];
+ } else {
+ status = CR_UNKNOWN_TYPE_ERROR;
+ }
+ }
+ } else if (strlen ((const char *) a_hex) == 6) {
+ for (i = 0; i < 6; i++) {
+ if (a_hex[i] >= '0' && a_hex[i] <= '9') {
+ colors[i / 2] <<= 4;
+ colors[i / 2] |= a_hex[i] - '0';
+ status = CR_OK;
+ } else if (a_hex[i] >= 'a' && a_hex[i] <= 'z') {
+ colors[i / 2] <<= 4;
+ colors[i / 2] |= 10 + a_hex[i] - 'a';
+ status = CR_OK;
+ } else if (a_hex[i] >= 'A' && a_hex[i] <= 'Z') {
+ colors[i / 2] <<= 4;
+ colors[i / 2] |= 10 + a_hex[i] - 'A';
+ status = CR_OK;
+ } else {
+ status = CR_UNKNOWN_TYPE_ERROR;
+ }
+ }
+ } else {
+ status = CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ if (status == CR_OK) {
+ status = cr_rgb_set (a_this, colors[0],
+ colors[1], colors[2], FALSE);
+ cr_rgb_set_to_transparent (a_this, FALSE) ;
+ }
+ return status;
+}
+
+/**
+ * cr_rgb_set_from_term:
+ *@a_this: the instance of #CRRgb to set
+ *@a_value: the terminal from which to set
+ *
+ *Set the rgb from a terminal symbol
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value)
+{
+ enum CRStatus status = CR_OK ;
+ g_return_val_if_fail (a_this && a_value,
+ CR_BAD_PARAM_ERROR) ;
+
+ switch(a_value->type) {
+ case TERM_RGB:
+ if (a_value->content.rgb) {
+ cr_rgb_set_from_rgb
+ (a_this, a_value->content.rgb) ;
+ }
+ break ;
+ case TERM_IDENT:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strncmp ("inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ a_this->inherit = TRUE;
+ a_this->is_transparent = FALSE ;
+ } else {
+ status = cr_rgb_set_from_name
+ (a_this,
+ (const guchar *) a_value->content.str->stryng->str) ;
+ }
+ } else {
+ cr_utils_trace_info
+ ("a_value has NULL string value") ;
+ }
+ break ;
+ case TERM_HASH:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ status = cr_rgb_set_from_hex_str
+ (a_this,
+ (const guchar *) a_value->content.str->stryng->str) ;
+ } else {
+ cr_utils_trace_info
+ ("a_value has NULL string value") ;
+ }
+ break ;
+ default:
+ status = CR_UNKNOWN_TYPE_ERROR ;
+ }
+ return status ;
+}
+
+enum CRStatus
+cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src)
+{
+ g_return_val_if_fail (a_dest && a_src,
+ CR_BAD_PARAM_ERROR) ;
+
+ memcpy (a_dest, a_src, sizeof (CRRgb)) ;
+ return CR_OK ;
+}
+
+/**
+ * cr_rgb_destroy:
+ *@a_this: the "this pointer" of the
+ *current instance of #CRRgb.
+ *
+ *Destructor of #CRRgb.
+ */
+void
+cr_rgb_destroy (CRRgb * a_this)
+{
+ g_return_if_fail (a_this);
+ g_free (a_this);
+}
+
+/**
+ * cr_rgb_parse_from_buf:
+ *@a_str: a string that contains a color description
+ *@a_enc: the encoding of a_str
+ *
+ *Parses a text buffer that contains a rgb color
+ *
+ *Returns the parsed color, or NULL in case of error
+ */
+CRRgb *
+cr_rgb_parse_from_buf (const guchar *a_str,
+ enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_OK ;
+ CRTerm *value = NULL ;
+ CRParser * parser = NULL;
+ CRRgb *result = NULL;
+
+ g_return_val_if_fail (a_str, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE);
+
+ g_return_val_if_fail (parser, NULL);
+
+ status = cr_parser_try_to_skip_spaces_and_comments (parser) ;
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_term (parser, &value);
+ if (status != CR_OK)
+ goto cleanup;
+
+ result = cr_rgb_new ();
+ if (!result)
+ goto cleanup;
+
+ status = cr_rgb_set_from_term (result, value);
+
+cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+ if (value) {
+ cr_term_destroy(value);
+ value = NULL;
+ }
+ return result ;
+}
+
diff --git a/src/3rdparty/libcroco/cr-rgb.h b/src/3rdparty/libcroco/cr-rgb.h
new file mode 100644
index 000000000..a127a440e
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-rgb.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * see COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_RGB_H__
+#define __CR_RGB_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRRgb CRRgb ;
+struct _CRRgb
+{
+ /*
+ *the unit of the rgb.
+ *Either NO_UNIT (integer) or
+ *UNIT_PERCENTAGE (percentage).
+ */
+ const guchar *name ;
+ glong red ;
+ glong green ;
+ glong blue ;
+ gboolean is_percentage ;
+ gboolean inherit ;
+ gboolean is_transparent ;
+ CRParsingLocation location ;
+} ;
+
+CRRgb * cr_rgb_new (void) ;
+
+CRRgb * cr_rgb_new_with_vals (gulong a_red, gulong a_green,
+ gulong a_blue, gboolean a_is_percentage) ;
+
+CRRgb *cr_rgb_parse_from_buf(const guchar *a_str,
+ enum CREncoding a_enc);
+
+enum CRStatus cr_rgb_compute_from_percentage (CRRgb *a_this) ;
+
+enum CRStatus cr_rgb_set (CRRgb *a_this, gulong a_red,
+ gulong a_green, gulong a_blue,
+ gboolean a_is_percentage) ;
+
+enum CRStatus cr_rgb_copy (CRRgb *a_dest, CRRgb const *a_src) ;
+
+enum CRStatus cr_rgb_set_to_inherit (CRRgb *a_this, gboolean a_inherit) ;
+
+gboolean cr_rgb_is_set_to_inherit (CRRgb const *a_this) ;
+
+gboolean cr_rgb_is_set_to_transparent (CRRgb const *a_this) ;
+
+enum CRStatus cr_rgb_set_to_transparent (CRRgb *a_this,
+ gboolean a_is_transparent) ;
+enum CRStatus cr_rgb_set_from_rgb (CRRgb *a_this, CRRgb const *a_rgb) ;
+
+enum CRStatus cr_rgb_set_from_name (CRRgb *a_this, const guchar *a_color_name) ;
+
+enum CRStatus cr_rgb_set_from_hex_str (CRRgb *a_this, const guchar * a_hex_value) ;
+
+struct _CRTerm;
+
+enum CRStatus cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value);
+
+guchar * cr_rgb_to_string (CRRgb const *a_this) ;
+
+void cr_rgb_dump (CRRgb const *a_this, FILE *a_fp) ;
+
+void cr_rgb_destroy (CRRgb *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_RGB_H__*/
diff --git a/src/3rdparty/libcroco/cr-sel-eng.c b/src/3rdparty/libcroco/cr-sel-eng.c
new file mode 100644
index 000000000..9e35ad93f
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-sel-eng.c
@@ -0,0 +1,2294 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser
+ * General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyright informations.
+ */
+
+#include <string.h>
+#include "cr-sel-eng.h"
+#include "cr-node-iface.h"
+
+/**
+ *@CRSelEng:
+ *
+ *The definition of the #CRSelEng class.
+ *The #CRSelEng is actually the "Selection Engine"
+ *class. This is highly experimental for at the moment and
+ *its api is very likely to change in a near future.
+ */
+
+#define PRIVATE(a_this) (a_this)->priv
+
+struct CRPseudoClassSelHandlerEntry {
+ guchar *name;
+ enum CRPseudoType type;
+ CRPseudoClassSelectorHandler handler;
+};
+
+struct _CRSelEngPriv {
+ /*not used yet */
+ gboolean case_sensitive;
+
+ CRNodeIface const *node_iface;
+ CRStyleSheet *sheet;
+ /**
+ *where to store the next statement
+ *to be visited so that we can remember
+ *it from one method call to another.
+ */
+ CRStatement *cur_stmt;
+ GList *pcs_handlers;
+ gint pcs_handlers_size;
+} ;
+
+static gboolean class_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static gboolean id_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static gboolean attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static enum CRStatus sel_matches_node_real (CRSelEng * a_this,
+ CRSimpleSel * a_sel,
+ CRXMLNodePtr a_node,
+ gboolean * a_result,
+ gboolean a_eval_sel_list_from_end,
+ gboolean a_recurse);
+
+static enum CRStatus cr_sel_eng_get_matched_rulesets_real (CRSelEng * a_this,
+ CRStyleSheet *
+ a_stylesheet,
+ CRXMLNodePtr a_node,
+ CRStatement **
+ a_rulesets,
+ gulong * a_len);
+
+static enum CRStatus put_css_properties_in_props_list (CRPropList ** a_props,
+ CRStatement *
+ a_ruleset);
+
+static gboolean pseudo_class_add_sel_matches_node (CRSelEng * a_this,
+ CRAdditionalSel * a_add_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean empty_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean root_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean lang_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean only_child_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean first_child_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean first_of_type_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean last_child_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean last_of_type_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean nth_child_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean nth_of_type_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean nth_last_child_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static gboolean nth_last_of_type_pseudo_class_handler (CRSelEng * a_this,
+ CRAdditionalSel * a_sel,
+ CRXMLNodePtr a_node);
+
+static CRXMLNodePtr get_next_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static CRXMLNodePtr get_first_child_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static CRXMLNodePtr get_prev_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static CRXMLNodePtr get_next_parent_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node);
+
+static CRArguments get_arguments_from_function (CRAdditionalSel * a_sel);
+
+void
+cr_sel_eng_set_node_iface (CRSelEng *const a_this, CRNodeIface const *const a_node_iface)
+{
+ /* Allow NULL: the caller may be just ensuring that the previous node_iface
+ value doesn't get used until next cr_sel_eng_set_node_iface call. */
+ PRIVATE(a_this)->node_iface = a_node_iface;
+}
+
+/* Quick strcmp. Test only for == 0 or != 0, not < 0 or > 0. */
+#define strqcmp(str,lit,lit_len) \
+ (strlen (str) != (lit_len) || memcmp (str, lit, lit_len))
+
+static gboolean
+root_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "root")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :root only");
+ return FALSE;
+ }
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+
+ // libxml apears to set the parent of the root element to an
+ // element of type 'xml'.
+ return (parent == NULL || !strcmp(node_iface->getLocalName(parent),"xml") );
+}
+
+static gboolean
+empty_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "empty")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :empty only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+
+ CRXMLNodePtr cur_node = NULL;
+ cur_node = node_iface->getFirstChild (a_node);
+
+ return (cur_node == NULL);
+}
+
+static gboolean
+lang_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr a_node)
+{
+ CRNodeIface const *node_iface;
+ CRXMLNodePtr node = a_node;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ node_iface = PRIVATE(a_this)->node_iface;
+
+ /* "xml:lang" needed for SVG */
+ if ( (strqcmp (a_sel->content.pseudo->name->stryng->str, "lang", 4 ) &&
+ (strqcmp (a_sel->content.pseudo->name->stryng->str, "xml:lang", 8 ) ) )
+ || a_sel->content.pseudo->type != FUNCTION_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :lang only");
+ return FALSE;
+ }
+ /*lang code should exist and be at least of length 2 */
+ if (!a_sel->content.pseudo->term
+ || a_sel->content.pseudo->term->type != TERM_IDENT
+ || !a_sel->content.pseudo->term->content.str->stryng
+ || a_sel->content.pseudo->term->content.str->stryng->len < 2)
+ return FALSE;
+ for (; node; node = get_next_parent_element_node (node_iface, node)) {
+ char *val = node_iface->getProp (node, (const xmlChar *) "lang");
+ if (!val) val = node_iface->getProp (node, (const xmlChar *) "xml:lang");
+ if (val) {
+ if (!strcasecmp(val, a_sel->content.pseudo->term->content.str->stryng->str)) {
+ result = TRUE;
+ break;
+ }
+ node_iface->freePropVal (val);
+ val = NULL;
+ }
+ }
+
+ return result;
+}
+
+static gboolean
+only_child_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "only-child")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :only-child only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ CRXMLNodePtr cur_node = NULL;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+ return (cur_node == a_node &&
+ !get_next_element_node(node_iface, cur_node) );
+}
+
+static gboolean
+only_of_type_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "only-of-type")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :only-of-type selector only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ CRXMLNodePtr cur_node = NULL;
+ int m = 0;
+ int child = 0;
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ if (!strcmp(node_iface->getLocalName(cur_node), a_sel->content.pseudo->sel_name->stryng->str)) {
+ ++m;
+ }
+ if (cur_node == a_node) {
+ child = m;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+ return (child == m && child == 1);
+}
+
+static gboolean
+first_child_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr node = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "first-child")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :first-child only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+ node = get_first_child_element_node (node_iface, parent);
+ return (node == a_node);
+}
+
+static gboolean
+first_of_type_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "first-of-type")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :first-of-type only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ // Count which child no. of type
+ CRXMLNodePtr cur_node = NULL;
+ int child = 0;
+ int found = FALSE;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ if(!strcmp(node_iface->getLocalName(cur_node), a_sel->content.pseudo->sel_name->stryng->str)) {
+ child++;
+ }
+ if (cur_node == a_node) {
+ found = TRUE;
+ break;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+
+ if (!found)
+ return FALSE;
+
+ return (child == 1);
+}
+
+static gboolean
+last_child_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "last-child")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :last-child only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ CRXMLNodePtr cur_node = NULL;
+ int m = 0;
+ int child = 0;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+ while (cur_node) {
+ ++m;
+ if (cur_node == a_node) {
+ child = m;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+
+ }
+ return (m == child);
+}
+
+static gboolean
+last_of_type_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "last-of-type")
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :last-of-type only");
+ return FALSE;
+ }
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ CRXMLNodePtr cur_node = NULL;
+ int m = 0;
+ int child = 0;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ if (!strcmp(node_iface->getLocalName(cur_node), a_sel->content.pseudo->sel_name->stryng->str)) {
+ ++m;
+ }
+ if (cur_node == a_node) {
+ child = m;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+
+ return (m == child);
+}
+
+// See https://www.w3.org/TR/selectors/#nth-child-pseudo
+static gboolean
+nth_child_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "nth-child")
+ || a_sel->content.pseudo->type != FUNCTION_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :nth-child only");
+ return FALSE;
+ }
+
+ /*pseude code term should exist */
+ if (!a_sel->content.pseudo->term)
+ return FALSE;
+
+ CRArguments arg = get_arguments_from_function (a_sel);
+
+ if (arg.a == 0 && arg.b == 0)
+ return FALSE;
+
+ int a = arg.a;
+ int b = arg.b;
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ /* Count which child this is */
+ CRXMLNodePtr cur_node = NULL;
+ int child = 0;
+ int found = FALSE;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ ++child;
+ if (cur_node == a_node) {
+ found = TRUE;
+ break;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+
+ if (!found)
+ return FALSE;
+
+ if (a == 0)
+ return (b == child);
+
+ return ((child - b)%a == 0 && (child - b)/a > -1);
+}
+
+static gboolean
+nth_of_type_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "nth-of-type")
+ || a_sel->content.pseudo->type != FUNCTION_PSEUDO) {
+ cr_utils_trace_info ("This handler is for :nth-of-type only");
+ return FALSE;
+ }
+
+ // pseudo code term should exist
+ if (!a_sel->content.pseudo->term)
+ return FALSE;
+
+ CRArguments arg = get_arguments_from_function (a_sel);
+
+ if (arg.a == 0 && arg.b == 0)
+ return FALSE;
+
+ int a = arg.a;
+ int b = arg.b;
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent)
+ return FALSE;
+
+ // Count which child no. of required type
+ CRXMLNodePtr cur_node = NULL;
+ int child = 0;
+ int found = FALSE;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ // check if type match
+ if (!strcmp(node_iface->getLocalName(cur_node), a_sel->content.pseudo->sel_name->stryng->str))
+ ++child;
+ if (cur_node == a_node) {
+ found = TRUE;
+ break;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+
+ if (!found)
+ return FALSE;
+
+ if (a == 0)
+ return (b == child);
+
+ return ((child - b)%a == 0 && (child - b)/a > -1);
+}
+
+static gboolean
+nth_last_child_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "nth-last-child")) {
+ cr_utils_trace_info ("This handler is for :nth-last-child only");
+ return FALSE;
+ }
+
+ /*pseudo code term should exist */
+ if (!a_sel->content.pseudo->term)
+ return FALSE;
+
+ CRArguments arg = get_arguments_from_function (a_sel);
+
+ if (arg.a == 0 && arg.b == 0)
+ return FALSE;
+
+ int a = arg.a;
+ int b = arg.b;
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+
+ if (!parent) {
+ return FALSE;
+ }
+
+ /* Count which child this is (child) and total number of children (m). */
+
+ CRXMLNodePtr cur_node = NULL;
+ int m = 0;
+ int child = 0;
+ int found = FALSE;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ if (cur_node == a_node) {
+ found = TRUE;
+ child = m;
+ }
+ cur_node = get_next_element_node (node_iface,cur_node);
+ ++m;
+ }
+
+ if (!found)
+ return FALSE;
+
+ if (a == 0)
+ return ((m - b) == child);
+
+ return ((m - child - b)%a == 0 && (m - child - b)/a > -1);
+}
+
+static gboolean
+nth_last_of_type_pseudo_class_handler (CRSelEng *const a_this,
+ CRAdditionalSel * a_sel, CRXMLNodePtr const a_node)
+{
+ CRNodeIface const *node_iface = NULL;
+ CRXMLNodePtr parent = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_sel && a_sel->content.pseudo
+ && a_sel->content.pseudo
+ && a_sel->content.pseudo->name
+ && a_sel->content.pseudo->name->stryng
+ && a_node, FALSE);
+
+ if (strcmp (a_sel->content.pseudo->name->stryng->str, "nth-last-of-type")) {
+ cr_utils_trace_info ("This handler is for :nth-last-of-type only");
+ return FALSE;
+ }
+
+ /*pseude code term should exist */
+ if (!a_sel->content.pseudo->term)
+ return FALSE;
+
+ CRArguments arg = get_arguments_from_function (a_sel);
+
+ if (arg.a == 0 && arg.b == 0)
+ return FALSE;
+
+ int a = arg.a;
+ int b = arg.b;
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ parent = node_iface->getParentNode (a_node);
+ if (!parent) {
+ return FALSE;
+ }
+
+ CRXMLNodePtr cur_node = NULL;
+ int m = 0;
+ int child = 0;
+ int found = FALSE;
+
+ cur_node = get_first_child_element_node (node_iface, parent);
+
+ while (cur_node) {
+ if (!strcmp(node_iface->getLocalName(cur_node), a_sel->content.pseudo->sel_name->stryng->str))
+ ++m;
+ if (cur_node == a_node) {
+ found = TRUE;
+ child = m;
+ }
+ cur_node = get_next_element_node (node_iface, cur_node);
+ }
+
+ if (!found)
+ return FALSE;
+
+ if (a == 0)
+ return ((m - b) == child);
+
+ return ((m - child - b +1)%a == 0 && (m - child - b +1)/a > -1);
+
+}
+
+static gboolean
+pseudo_class_add_sel_matches_node (CRSelEng * a_this,
+ CRAdditionalSel * a_add_sel,
+ CRXMLNodePtr a_node)
+{
+ enum CRStatus status = CR_OK;
+ CRPseudoClassSelectorHandler handler = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_add_sel
+ && a_add_sel->content.pseudo
+ && a_add_sel->content.pseudo->name
+ && a_add_sel->content.pseudo->name->stryng
+ && a_add_sel->content.pseudo->name->stryng->str
+ && a_node, FALSE);
+
+ status = cr_sel_eng_get_pseudo_class_selector_handler
+ (a_this, (guchar *) a_add_sel->content.pseudo->name->stryng->str,
+ a_add_sel->content.pseudo->type, &handler);
+ if (status != CR_OK || !handler)
+ return FALSE;
+
+ return handler (a_this, a_add_sel, a_node);
+}
+
+/**
+ *@param a_add_sel the class additional selector to consider.
+ *@param a_node the xml node to consider.
+ *@return TRUE if the class additional selector matches
+ *the xml node given in argument, FALSE otherwise.
+ */
+static gboolean
+class_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ gboolean result = FALSE;
+ char *klass = NULL;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == CLASS_ADD_SELECTOR
+ && a_add_sel->content.class_name
+ && a_add_sel->content.class_name->stryng
+ && a_add_sel->content.class_name->stryng->str
+ && a_node, FALSE);
+
+ klass = a_node_iface->getProp (a_node, (const xmlChar *) "class");
+ if (klass) {
+ char const *cur;
+ for (cur = klass; cur && *cur; cur++) {
+ while (cur && *cur
+ && cr_utils_is_white_space (*cur)
+ == TRUE)
+ cur++;
+
+ if (!strncmp ((const char *) cur,
+ a_add_sel->content.class_name->stryng->str,
+ a_add_sel->content.class_name->stryng->len)) {
+ cur += a_add_sel->content.class_name->stryng->len;
+ if ((cur && !*cur)
+ || cr_utils_is_white_space (*cur) == TRUE)
+ result = TRUE;
+ } else { /* if it doesn't match, */
+ /* then skip to next whitespace character to try again */
+ while (cur && *cur && !(cr_utils_is_white_space(*cur) == TRUE))
+ cur++;
+ }
+ if (cur && !*cur)
+ break ;
+ }
+ a_node_iface->freePropVal (klass);
+ klass = NULL;
+ }
+ return result;
+
+}
+
+/**
+ *@return TRUE if the additional attribute selector matches
+ *the current xml node given in argument, FALSE otherwise.
+ *@param a_add_sel the additional attribute selector to consider.
+ *@param a_node the xml node to consider.
+ */
+static gboolean
+id_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ gboolean result = FALSE;
+ char *id = NULL;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ID_ADD_SELECTOR
+ && a_add_sel->content.id_name
+ && a_add_sel->content.id_name->stryng
+ && a_add_sel->content.id_name->stryng->str
+ && a_node, FALSE);
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ID_ADD_SELECTOR
+ && a_node, FALSE);
+
+ id = a_node_iface->getProp (a_node, (const xmlChar *) "id");
+ if (id) {
+ if (!strqcmp ((const char *) id, a_add_sel->content.id_name->stryng->str,
+ a_add_sel->content.id_name->stryng->len)) {
+ result = TRUE;
+ }
+ a_node_iface->freePropVal (id);
+ id = NULL;
+ }
+ return result;
+}
+
+/**
+ *Returns TRUE if the instance of #CRAdditional selector matches
+ *the node given in parameter, FALSE otherwise.
+ *@param a_add_sel the additional selector to evaluate.
+ *@param a_node the xml node against whitch the selector is to
+ *be evaluated
+ *return TRUE if the additional selector matches the current xml node
+ *FALSE otherwise.
+ */
+static gboolean
+attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
+ CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ CRAttrSel *cur_sel = NULL;
+
+ g_return_val_if_fail (a_add_sel
+ && a_add_sel->type == ATTRIBUTE_ADD_SELECTOR
+ && a_node, FALSE);
+
+ for (cur_sel = a_add_sel->content.attr_sel;
+ cur_sel; cur_sel = cur_sel->next) {
+ if (!cur_sel->name
+ || !cur_sel->name->stryng
+ || !cur_sel->name->stryng->str)
+ return FALSE;
+
+ char *const value = a_node_iface->getProp (a_node, cur_sel->name->stryng->str);
+ if (!value)
+ goto free_and_return_false;
+
+ switch (cur_sel->match_way) {
+ case SET:
+ break;
+
+ case EQUALS:
+ if (!cur_sel->value
+ || !cur_sel->value->stryng
+ || !cur_sel->value->stryng->str) {
+ goto free_and_return_false;
+ }
+ if (strcmp
+ (value,
+ cur_sel->value->stryng->str)) {
+ goto free_and_return_false;
+ }
+ break;
+
+ case INCLUDES:
+ {
+ char const *ptr1 = NULL,
+ *ptr2 = NULL,
+ *cur = NULL;
+ gboolean found = FALSE;
+
+ /*
+ *here, make sure value is a space
+ *separated list of "words", where one
+ *value is exactly cur_sel->value->str
+ */
+ for (cur = value; *cur; cur++) {
+ /*
+ *set ptr1 to the first non white space
+ *char addr.
+ */
+ while (cr_utils_is_white_space (*cur)
+ && *cur)
+ cur++;
+ if (!*cur)
+ break;
+ ptr1 = cur;
+
+ /*
+ *set ptr2 to the end the word.
+ */
+ while (!cr_utils_is_white_space (*cur)
+ && *cur)
+ cur++;
+ cur--;
+ ptr2 = cur;
+
+ if (!strncmp
+ ((const char *) ptr1,
+ cur_sel->value->stryng->str,
+ ptr2 - ptr1 + 1)) {
+ found = TRUE;
+ break;
+ }
+ ptr1 = ptr2 = NULL;
+ }
+
+ if (!found) {
+ goto free_and_return_false;
+ }
+ }
+ break;
+
+ case DASHMATCH:
+ {
+ char const *ptr1 = NULL,
+ *ptr2 = NULL,
+ *cur = NULL;
+ gboolean found = FALSE;
+
+ /*
+ *here, make sure value is an hyphen
+ *separated list of "words", each of which
+ *starting with "cur_sel->value->str"
+ */
+ for (cur = value; *cur; cur++) {
+ if (*cur == '-')
+ cur++;
+ ptr1 = cur;
+
+ while (*cur != '-' && *cur)
+ cur++;
+ cur--;
+ ptr2 = cur;
+
+ if (g_strstr_len
+ ((const gchar *) ptr1, ptr2 - ptr1 + 1,
+ cur_sel->value->stryng->str)
+ == ptr1) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ goto free_and_return_false;
+ }
+ }
+ break;
+ default:
+ goto free_and_return_false;
+ }
+
+ a_node_iface->freePropVal (value);
+ continue;
+
+ free_and_return_false:
+ a_node_iface->freePropVal (value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ *Evaluates if a given additional selector matches an xml node.
+ *@param a_add_sel the additional selector to consider.
+ *@param a_node the xml node to consider.
+ *@return TRUE is a_add_sel matches a_node, FALSE otherwise.
+ */
+static gboolean
+additional_selector_matches_node (CRSelEng * a_this,
+ CRAdditionalSel * a_add_sel,
+ CRXMLNodePtr a_node)
+{
+ CRAdditionalSel *cur_add_sel = NULL, *tail = NULL ;
+ gboolean evaluated = FALSE ;
+
+ for (tail = a_add_sel ;
+ tail && tail->next;
+ tail = tail->next) ;
+
+ g_return_val_if_fail (tail, FALSE) ;
+
+ for (cur_add_sel = tail ;
+ cur_add_sel ;
+ cur_add_sel = cur_add_sel->prev) {
+
+ evaluated = TRUE ;
+ if (cur_add_sel->type == NO_ADD_SELECTOR) {
+ return FALSE;
+ }
+
+ if (cur_add_sel->type == CLASS_ADD_SELECTOR
+ && cur_add_sel->content.class_name
+ && cur_add_sel->content.class_name->stryng
+ && cur_add_sel->content.class_name->stryng->str) {
+ if (!class_add_sel_matches_node (cur_add_sel,
+ PRIVATE(a_this)->node_iface,
+ a_node)) {
+ return FALSE;
+ }
+ continue ;
+ } else if (cur_add_sel->type == ID_ADD_SELECTOR
+ && cur_add_sel->content.id_name
+ && cur_add_sel->content.id_name->stryng
+ && cur_add_sel->content.id_name->stryng->str) {
+ if (!id_add_sel_matches_node (cur_add_sel,
+ PRIVATE(a_this)->node_iface,
+ a_node)) {
+ return FALSE;
+ }
+ continue ;
+ } else if (cur_add_sel->type == ATTRIBUTE_ADD_SELECTOR
+ && cur_add_sel->content.attr_sel) {
+ /*
+ *here, call a function that does the match
+ *against an attribute additionnal selector
+ *and an xml node.
+ */
+ if (!attr_add_sel_matches_node (cur_add_sel,
+ PRIVATE(a_this)->node_iface,
+ a_node)) {
+ return FALSE;
+ }
+ continue ;
+ } else if (cur_add_sel->type == PSEUDO_CLASS_ADD_SELECTOR
+ && cur_add_sel->content.pseudo) {
+ if (!pseudo_class_add_sel_matches_node
+ (a_this, cur_add_sel, a_node)) {
+ return FALSE;
+ }
+ continue ;
+ }
+ }
+ if (evaluated == TRUE)
+ return TRUE;
+ return FALSE ;
+}
+
+static CRXMLNodePtr
+get_next_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ CRXMLNodePtr cur_node = a_node;
+
+ g_return_val_if_fail (a_node, NULL);
+
+ do {
+ cur_node = a_node_iface->getNextSibling (cur_node);
+ } while (cur_node && !a_node_iface->isElementNode(cur_node));
+ return cur_node;
+}
+
+static CRXMLNodePtr
+get_first_child_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ CRXMLNodePtr cur_node = NULL;
+
+ g_return_val_if_fail (a_node, NULL);
+
+ cur_node = a_node_iface->getFirstChild (a_node);
+ if (!cur_node)
+ return cur_node;
+ if (a_node_iface->isElementNode (cur_node))
+ return cur_node;
+ return get_next_element_node (a_node_iface, cur_node);
+}
+
+static CRXMLNodePtr
+get_prev_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ CRXMLNodePtr cur_node = a_node;
+
+ g_return_val_if_fail (a_node, NULL);
+
+ do {
+ cur_node = a_node_iface->getPrevSibling (cur_node);
+ } while (cur_node && !a_node_iface->isElementNode(cur_node));
+ return cur_node;
+}
+
+static CRXMLNodePtr
+get_next_parent_element_node (CRNodeIface const * a_node_iface, CRXMLNodePtr a_node)
+{
+ CRXMLNodePtr cur_node = a_node;
+
+ g_return_val_if_fail (a_node, NULL);
+
+ do {
+ cur_node = a_node_iface->getParentNode (cur_node);
+ } while (cur_node && !a_node_iface->isElementNode (cur_node));
+ return cur_node;
+}
+
+static CRArguments
+get_arguments_from_function (CRAdditionalSel * a_sel)
+{
+ CRArguments arg;
+ arg.a = 0;
+ arg.b = 0;
+ switch (a_sel->content.pseudo->term->type) {
+ case TERM_NUMBER:
+ if (a_sel->content.pseudo->term->content.num) {
+ arg.b = a_sel->content.pseudo->term->content.num->val;
+ }
+ if (a_sel->content.pseudo->term->n) {
+ arg.a = arg.b;
+ arg.b = 0;
+ }
+ break;
+
+ case TERM_IDENT:
+ if (a_sel->content.pseudo->term->content.str) {
+ if (!strcmp(a_sel->content.pseudo->term->content.str->stryng->str, "even")) {
+ arg.a = 2;
+ arg.b = 0;
+ } else if (!strcmp(a_sel->content.pseudo->term->content.str->stryng->str, "odd")) {
+ arg.a = 2;
+ arg.b = 1;
+ } else if (!strcmp(a_sel->content.pseudo->term->content.str->stryng->str, "n")) {
+ /* 'n' without number */
+ arg.a = 1;
+ } else if (!strcmp(a_sel->content.pseudo->term->content.str->stryng->str, "-n")) {
+ /* '-n' without number */
+ arg.a = -1;
+ } else {
+ /* Unknown string */
+ arg.a = 0;
+ arg.b = 0;
+ return (arg);
+ }
+ }
+ break;
+
+ default:
+ cr_utils_trace_info ("Unknown term in nth style handler");
+ arg.a = 0;
+ arg.b = 0;
+ return (arg);
+ }
+
+ if (arg.a != 0 && a_sel->content.pseudo->term->next) {
+ /* check for b in 'an+b' */
+ if (a_sel->content.pseudo->term->next->type == TERM_NUMBER &&
+ a_sel->content.pseudo->term->next->content.num ) {
+ arg.b = a_sel->content.pseudo->term->next->content.num->val;
+ }
+ }
+
+ return (arg);
+}
+
+/**
+ *Evaluate a selector (a simple selectors list) and says
+ *if it matches the xml node given in parameter.
+ *The algorithm used here is the following:
+ *Walk the combinator separated list of simple selectors backward, starting
+ *from the end of the list. For each simple selector, looks if
+ *if matches the current node.
+ *
+ *@param a_this the selection engine.
+ *@param a_sel the simple selection list.
+ *@param a_node the xml node.
+ *@param a_result out parameter. Set to true if the
+ *selector matches the xml node, FALSE otherwise.
+ *@param a_recurse if set to TRUE, the function will walk to
+ *the next simple selector (after the evaluation of the current one)
+ *and recursively evaluate it. Must be usually set to TRUE unless you
+ *know what you are doing.
+ */
+static enum CRStatus
+sel_matches_node_real (CRSelEng * a_this, CRSimpleSel * a_sel,
+ CRXMLNodePtr a_node, gboolean * a_result,
+ gboolean a_eval_sel_list_from_end,
+ gboolean a_recurse)
+{
+ CRSimpleSel *cur_sel = NULL;
+ CRXMLNodePtr cur_node = NULL;
+ CRNodeIface const *node_iface = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_this && a_node
+ && a_result, CR_BAD_PARAM_ERROR);
+
+ node_iface = PRIVATE(a_this)->node_iface;
+ *a_result = FALSE;
+
+ if (!node_iface->isElementNode(a_node))
+ return CR_OK;
+
+ if (a_eval_sel_list_from_end == TRUE) {
+ /*go and get the last simple selector of the list */
+ for (cur_sel = a_sel;
+ cur_sel && cur_sel->next; cur_sel = cur_sel->next) ;
+ } else {
+ cur_sel = a_sel;
+ }
+
+ for (cur_node = a_node; cur_sel; cur_sel = cur_sel->prev) {
+ if (((cur_sel->type_mask & TYPE_SELECTOR)
+ && (cur_sel->name
+ && cur_sel->name->stryng
+ && cur_sel->name->stryng->str)
+ && (!strcmp (cur_sel->name->stryng->str,
+ (const char *) node_iface->getLocalName(cur_node))))
+ || (cur_sel->type_mask & UNIVERSAL_SELECTOR)) {
+ /*
+ *this simple selector
+ *matches the current xml node
+ *Let's see if the preceding
+ *simple selectors also match
+ *their xml node counterpart.
+ */
+ if (cur_sel->add_sel) {
+ if (additional_selector_matches_node (a_this, cur_sel->add_sel,
+ cur_node) == TRUE) {
+ goto walk_a_step_in_expr;
+ } else {
+ goto done;
+ }
+ } else {
+ goto walk_a_step_in_expr;
+ }
+ }
+ if (!(cur_sel->type_mask & TYPE_SELECTOR)
+ && !(cur_sel->type_mask & UNIVERSAL_SELECTOR)) {
+ if (!cur_sel->add_sel) {
+ goto done;
+ }
+ if (additional_selector_matches_node
+ (a_this, cur_sel->add_sel, cur_node)
+ == TRUE) {
+ goto walk_a_step_in_expr;
+ } else {
+ goto done;
+ }
+ } else {
+ goto done ;
+ }
+
+ walk_a_step_in_expr:
+ if (a_recurse == FALSE) {
+ *a_result = TRUE;
+ goto done;
+ }
+
+ /*
+ *here, depending on the combinator of cur_sel
+ *choose the axis of the xml tree traversal
+ *and walk one step in the xml tree.
+ */
+ if (!cur_sel->prev)
+ break;
+
+ switch (cur_sel->combinator) {
+ case NO_COMBINATOR:
+ break;
+
+ case COMB_WS: /*descendant selector */
+ {
+ CRXMLNodePtr n = NULL;
+ enum CRStatus status = CR_OK;
+ gboolean matches = FALSE;
+
+ /*
+ *walk the xml tree upward looking for a parent
+ *node that matches the preceding selector.
+ */
+ for (n = node_iface->getParentNode (cur_node);
+ n;
+ n = node_iface->getParentNode (n)) {
+ status = sel_matches_node_real
+ (a_this, cur_sel->prev,
+ n, &matches, FALSE, TRUE);
+
+ if (status != CR_OK)
+ goto done;
+
+ if (matches == TRUE) {
+ cur_node = n ;
+ break;
+ }
+ }
+
+ if (!n) {
+ /*
+ *didn't find any ancestor that matches
+ *the previous simple selector.
+ */
+ goto done;
+ }
+ /*
+ *in this case, the preceding simple sel
+ *will have been interpreted twice, which
+ *is a cpu and mem waste ... I need to find
+ *another way to do this. Anyway, this is
+ *my first attempt to write this function and
+ *I am a bit clueless.
+ */
+ break;
+ }
+
+ case COMB_PLUS:
+ cur_node = get_prev_element_node (node_iface, cur_node);
+ if (!cur_node)
+ goto done;
+ break;
+
+ case COMB_TILDE: /* General sibling selector. */
+ {
+ CRXMLNodePtr n = NULL;
+ enum CRStatus status = CR_OK;
+ gboolean matches = FALSE;
+
+ /*
+ * Walk through previous sibing nodes looking for a
+ * node that matches the preceding selector.
+ */
+ for (n = get_prev_element_node (node_iface, cur_node);
+ n;
+ n = get_prev_element_node (node_iface, n)) {
+ status = sel_matches_node_real
+ (a_this, cur_sel->prev,
+ n, &matches, FALSE, TRUE);
+
+ if (status != CR_OK)
+ goto done;
+
+ if (matches == TRUE) {
+ cur_node = n ;
+ break;
+ }
+ }
+
+ if (!n) {
+ /*
+ * Didn't find any previous sibling that matches
+ * the previous simple selector.
+ */
+ goto done;
+ }
+ /*
+ * See note above in COMB_WS section.
+ */
+ break;
+ }
+
+ case COMB_GT:
+ cur_node = get_next_parent_element_node (node_iface, cur_node);
+ if (!cur_node)
+ goto done;
+ break;
+
+ default:
+ goto done;
+ }
+ continue;
+ }
+
+ /*
+ *if we reached this point, it means the selector matches
+ *the xml node.
+ */
+ *a_result = TRUE;
+
+ done:
+ return CR_OK;
+}
+
+
+/**
+ *Returns array of the ruleset statements that matches the
+ *given xml node.
+ *The engine keeps in memory the last statement he
+ *visited during the match. So, the next call
+ *to this function will eventually return a rulesets list starting
+ *from the last ruleset statement visited during the previous call.
+ *The enable users to get matching rulesets in an incremental way.
+ *Note that for each statement returned,
+ *the engine calculates the specificity of the selector
+ *that matched the xml node and stores it in the "specifity" field
+ *of the statement structure.
+ *
+ *@param a_sel_eng the current selection engine
+ *@param a_node the xml node for which the request
+ *is being made.
+ *@param a_sel_list the list of selectors to perform the search in.
+ *@param a_rulesets in/out parameter. A pointer to the
+ *returned array of rulesets statements that match the xml node
+ *given in parameter. The caller allocates the array before calling this
+ *function.
+ *@param a_len in/out parameter the length (in sizeof (#CRStatement*))
+ *of the returned array.
+ *(the length of a_rulesets, more precisely).
+ *The caller must set it to the length of a_ruleset prior to calling this
+ *function. In return, the function sets it to the length
+ *(in sizeof (#CRStatement)) of the actually returned CRStatement array.
+ *@return CR_OUTPUT_TOO_SHORT_ERROR if found more rulesets than the size
+ *of the a_rulesets array. In this case, the first *a_len rulesets found
+ *are put in a_rulesets, and a further call will return the following
+ *ruleset(s) following the same principle.
+ *@return CR_OK if all the rulesets found have been returned. In this
+ *case, *a_len is set to the actual number of ruleset found.
+ *@return CR_BAD_PARAM_ERROR in case any of the given parameter are
+ *bad (e.g null pointer).
+ *@return CR_ERROR if any other error occured.
+ */
+static enum CRStatus
+cr_sel_eng_get_matched_rulesets_real (CRSelEng * a_this,
+ CRStyleSheet * a_stylesheet,
+ CRXMLNodePtr a_node,
+ CRStatement ** a_rulesets,
+ gulong * a_len)
+{
+ CRStatement *cur_stmt = NULL;
+ CRSelector *sel_list = NULL,
+ *cur_sel = NULL;
+ gboolean matches = FALSE;
+ enum CRStatus status = CR_OK;
+ gulong i = 0;
+
+ g_return_val_if_fail (a_this
+ && a_stylesheet
+ && a_node && a_rulesets, CR_BAD_PARAM_ERROR);
+
+ if (!a_stylesheet->statements) {
+ *a_rulesets = NULL;
+ *a_len = 0;
+ return CR_OK;
+ }
+
+ /*
+ *if this stylesheet is "new one"
+ *let's remember it for subsequent calls.
+ */
+ if (PRIVATE (a_this)->sheet != a_stylesheet) {
+ PRIVATE (a_this)->sheet = a_stylesheet;
+ PRIVATE (a_this)->cur_stmt = a_stylesheet->statements;
+ }
+
+ /*
+ *walk through the list of statements and,
+ *get the selectors list inside the statements that
+ *contain some, and try to match our xml node in these
+ *selectors lists.
+ */
+ for (cur_stmt = PRIVATE (a_this)->cur_stmt, i = 0;
+ (PRIVATE (a_this)->cur_stmt = cur_stmt);
+ cur_stmt = cur_stmt->next) {
+ /*
+ *initialyze the selector list in which we will
+ *really perform the search.
+ */
+ sel_list = NULL;
+
+ /*
+ *get the damn selector list in
+ *which we have to look
+ */
+ switch (cur_stmt->type) {
+ case RULESET_STMT:
+ if (cur_stmt->kind.ruleset
+ && cur_stmt->kind.ruleset->sel_list) {
+ sel_list = cur_stmt->kind.ruleset->sel_list;
+ }
+ break;
+
+ case AT_MEDIA_RULE_STMT:
+ if (cur_stmt->kind.media_rule
+ && cur_stmt->kind.media_rule->rulesets
+ && cur_stmt->kind.media_rule->rulesets->
+ kind.ruleset
+ && cur_stmt->kind.media_rule->rulesets->
+ kind.ruleset->sel_list) {
+ sel_list =
+ cur_stmt->kind.media_rule->
+ rulesets->kind.ruleset->sel_list;
+ }
+ break;
+
+ case AT_IMPORT_RULE_STMT:
+ /*
+ *some recursivity may be needed here.
+ *I don't like this :(
+ */
+ break;
+ default:
+ break;
+ }
+
+ if (!sel_list)
+ continue;
+
+ /*
+ *now, we have a comma separated selector list to look in.
+ *let's walk it and try to match the xml_node
+ *on each item of the list.
+ */
+ for (cur_sel = sel_list; cur_sel; cur_sel = cur_sel->next) {
+ if (!cur_sel->simple_sel)
+ continue;
+
+ status = cr_sel_eng_matches_node
+ (a_this, cur_sel->simple_sel,
+ a_node, &matches);
+
+ if (status == CR_OK && matches == TRUE) {
+ /*
+ *bingo!!! we found one ruleset that
+ *matches that fucking node.
+ *lets put it in the out array.
+ */
+
+ if (i < *a_len) {
+ a_rulesets[i] = cur_stmt;
+ i++;
+
+ /*
+ *For the cascade computing algorithm
+ *(which is gonna take place later)
+ *we must compute the specificity
+ *(css2 spec chap 6.4.1) of the selector
+ *that matched the current xml node
+ *and store it in the css2 statement
+ *(statement == ruleset here).
+ */
+ status = cr_simple_sel_compute_specificity (cur_sel->simple_sel);
+
+ g_return_val_if_fail (status == CR_OK,
+ CR_ERROR);
+ cur_stmt->specificity =
+ cur_sel->simple_sel->
+ specificity;
+ } else
+ {
+ *a_len = i;
+ return CR_OUTPUT_TOO_SHORT_ERROR;
+ }
+ }
+ }
+ }
+
+ /*
+ *if we reached this point, it means
+ *we reached the end of stylesheet.
+ *no need to store any info about the stylesheet
+ *anymore.
+ */
+ g_return_val_if_fail (!PRIVATE (a_this)->cur_stmt, CR_ERROR);
+ PRIVATE (a_this)->sheet = NULL;
+ *a_len = i;
+ return CR_OK;
+}
+
+static enum CRStatus
+put_css_properties_in_props_list (CRPropList ** a_props, CRStatement * a_stmt)
+{
+ CRPropList *props = NULL,
+ *pair = NULL,
+ *tmp_props = NULL;
+ CRDeclaration *cur_decl = NULL;
+
+ g_return_val_if_fail (a_props && a_stmt
+ && a_stmt->type == RULESET_STMT
+ && a_stmt->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ props = *a_props;
+
+ for (cur_decl = a_stmt->kind.ruleset->decl_list;
+ cur_decl; cur_decl = cur_decl->next) {
+ CRDeclaration *decl;
+
+ decl = NULL;
+ pair = NULL;
+
+ if (!cur_decl->property
+ || !cur_decl->property->stryng
+ || !cur_decl->property->stryng->str)
+ continue;
+ /*
+ *First, test if the property is not
+ *already present in our properties list
+ *If yes, apply the cascading rules to
+ *compute the precedence. If not, insert
+ *the property into the list
+ */
+ cr_prop_list_lookup_prop (props,
+ cur_decl->property,
+ &pair);
+
+ if (!pair) {
+ tmp_props = cr_prop_list_append2
+ (props, cur_decl->property, cur_decl);
+ if (tmp_props) {
+ props = tmp_props;
+ tmp_props = NULL;
+ }
+ continue;
+ }
+
+ /*
+ *A property with the same name already exists.
+ *We must apply here
+ *some cascading rules
+ *to compute the precedence.
+ */
+ cr_prop_list_get_decl (pair, &decl);
+ g_return_val_if_fail (decl, CR_ERROR);
+
+ /*
+ *first, look at the origin.
+ *6.4.1 says:
+ *"for normal declarations,
+ *author style sheets override user
+ *style sheets which override
+ *the default style sheet."
+ */
+ if (decl->parent_statement
+ && decl->parent_statement->parent_sheet
+ && (decl->parent_statement->parent_sheet->origin
+ < a_stmt->parent_sheet->origin)) {
+ /*
+ *if the already selected declaration
+ *is marked as being !important the current
+ *declaration must not overide it
+ *(unless the already selected declaration
+ *has an UA origin)
+ */
+ if (decl->important == TRUE && cur_decl->important != TRUE
+ && decl->parent_statement->parent_sheet->origin
+ != ORIGIN_UA) {
+ continue;
+ }
+ tmp_props = cr_prop_list_unlink (props, pair);
+ if (props) {
+ cr_prop_list_destroy (pair);
+ }
+ props = tmp_props;
+ tmp_props = NULL;
+ props = cr_prop_list_append2
+ (props, cur_decl->property, cur_decl);
+
+ continue;
+ } else if (decl->parent_statement
+ && decl->parent_statement->parent_sheet
+ && (decl->parent_statement->
+ parent_sheet->origin
+ > a_stmt->parent_sheet->origin)) {
+ cr_utils_trace_info
+ ("We should not reach this line\n");
+ continue;
+ }
+
+ /*
+ *A property with the same
+ *name and the same origin already exists.
+ *shit. This is lasting longer than expected ...
+ *Luckily, the spec says in 6.4.1:
+ *"more specific selectors will override
+ *more general ones"
+ *and
+ *"if two rules have the same weight,
+ *origin and specificity,
+ *the later specified wins"
+ */
+ if (a_stmt->specificity
+ >= decl->parent_statement->specificity) {
+ if (decl->important == TRUE && cur_decl->important != TRUE)
+ continue;
+ props = cr_prop_list_unlink (props, pair);
+ if (pair) {
+ cr_prop_list_destroy (pair);
+ pair = NULL;
+ }
+ props = cr_prop_list_append2 (props,
+ cur_decl->property,
+ cur_decl);
+ }
+ }
+ /*TODO: this may leak. Check this out */
+ *a_props = props;
+
+ return CR_OK;
+}
+
+static void
+set_style_from_props (CRStyle * a_style, CRPropList * a_props)
+{
+ CRPropList *cur = NULL;
+ CRDeclaration *decl = NULL;
+
+ for (cur = a_props; cur; cur = cr_prop_list_get_next (cur)) {
+ cr_prop_list_get_decl (cur, &decl);
+ cr_style_set_style_from_decl (a_style, decl);
+ decl = NULL;
+ }
+}
+
+/****************************************
+ *PUBLIC METHODS
+ ****************************************/
+
+/**
+ * cr_sel_eng_new:
+ *Creates a new instance of #CRSelEng.
+ *
+ *Returns the newly built instance of #CRSelEng of
+ *NULL if an error occurs.
+ */
+CRSelEng *
+cr_sel_eng_new (void)
+{
+ CRSelEng *result = NULL;
+
+ result = (CRSelEng *) g_try_malloc (sizeof (CRSelEng));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRSelEng));
+
+ PRIVATE (result) = (CRSelEngPriv *) g_try_malloc (sizeof (CRSelEngPriv));
+ if (!PRIVATE (result)) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (PRIVATE (result), 0, sizeof (CRSelEngPriv));
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "root",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ root_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "empty",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ empty_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "lang",
+ FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ lang_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "only-child",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ only_child_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "only-of-type",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ only_of_type_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "first-child",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ first_child_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "first-of-type",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ first_of_type_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "last-child",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ last_child_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "last-of-type",
+ IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ last_of_type_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "nth-child",
+ FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ nth_child_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "nth-of-type",
+ FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ nth_of_type_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "nth-last-child",
+ FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ nth_last_child_pseudo_class_handler);
+ cr_sel_eng_register_pseudo_class_sel_handler
+ (result, (guchar *) "nth-last-of-type",
+ FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
+ nth_last_of_type_pseudo_class_handler);
+
+ return result;
+}
+
+/**
+ * cr_sel_eng_register_pseudo_class_sel_handler:
+ *@a_this: the current instance of #CRSelEng
+ *@a_pseudo_class_sel_name: the name of the pseudo class selector.
+ *@a_pseudo_class_type: the type of the pseudo class selector.
+ *@a_handler: the actual handler or callback to be called during
+ *the selector evaluation process.
+ *
+ *Adds a new handler entry in the handlers entry table.
+ *
+ *Returns CR_OK, upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this,
+ guchar * a_name,
+ enum CRPseudoType a_type,
+ CRPseudoClassSelectorHandler
+ a_handler)
+{
+ struct CRPseudoClassSelHandlerEntry *handler_entry = NULL;
+ GList *list = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_handler && a_name, CR_BAD_PARAM_ERROR);
+
+ handler_entry = (struct CRPseudoClassSelHandlerEntry *) g_try_malloc
+ (sizeof (struct CRPseudoClassSelHandlerEntry));
+ if (!handler_entry) {
+ return CR_OUT_OF_MEMORY_ERROR;
+ }
+ memset (handler_entry, 0,
+ sizeof (struct CRPseudoClassSelHandlerEntry));
+ handler_entry->name = (guchar *) g_strdup ((const gchar *) a_name);
+ handler_entry->type = a_type;
+ handler_entry->handler = a_handler;
+ list = g_list_append (PRIVATE (a_this)->pcs_handlers, handler_entry);
+ if (!list) {
+ return CR_OUT_OF_MEMORY_ERROR;
+ }
+ PRIVATE (a_this)->pcs_handlers = list;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this,
+ guchar * a_name,
+ enum CRPseudoType a_type)
+{
+ GList *elem = NULL,
+ *deleted_elem = NULL;
+ gboolean found = FALSE;
+ struct CRPseudoClassSelHandlerEntry *entry = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ for (elem = PRIVATE (a_this)->pcs_handlers;
+ elem; elem = g_list_next (elem)) {
+ entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
+ if (!strcmp ((const char *) entry->name, (const char *) a_name)
+ && entry->type == a_type) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found == FALSE)
+ return CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR;
+ PRIVATE (a_this)->pcs_handlers = g_list_delete_link
+ (PRIVATE (a_this)->pcs_handlers, elem);
+ entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
+ if (entry->name) {
+ g_free (entry->name);
+ entry->name = NULL;
+ }
+ g_free (elem);
+ g_list_free (deleted_elem);
+
+ return CR_OK;
+}
+
+/**
+ * cr_sel_eng_unregister_all_pseudo_class_sel_handlers:
+ *@a_this: the current instance of #CRSelEng .
+ *
+ *Unregisters all the pseudo class sel handlers
+ *and frees all the associated allocated datastructures.
+ *
+ *Returns CR_OK upon succesful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng * a_this)
+{
+ GList *elem = NULL;
+ struct CRPseudoClassSelHandlerEntry *entry = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ if (!PRIVATE (a_this)->pcs_handlers)
+ return CR_OK;
+ for (elem = PRIVATE (a_this)->pcs_handlers;
+ elem; elem = g_list_next (elem)) {
+ entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
+ if (!entry)
+ continue;
+ if (entry->name) {
+ g_free (entry->name);
+ entry->name = NULL;
+ }
+ g_free (entry);
+ elem->data = NULL;
+ }
+ g_list_free (PRIVATE (a_this)->pcs_handlers);
+ PRIVATE (a_this)->pcs_handlers = NULL;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this,
+ guchar * a_name,
+ enum CRPseudoType a_type,
+ CRPseudoClassSelectorHandler *
+ a_handler)
+{
+ GList *elem = NULL;
+ struct CRPseudoClassSelHandlerEntry *entry = NULL;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_name, CR_BAD_PARAM_ERROR);
+
+ for (elem = PRIVATE (a_this)->pcs_handlers;
+ elem; elem = g_list_next (elem)) {
+ entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
+ if (!strcmp ((const char *) a_name, (const char *) entry->name)
+ && entry->type == a_type) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (found == FALSE)
+ return CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR;
+ *a_handler = entry->handler;
+ return CR_OK;
+}
+
+/**
+ * cr_sel_eng_matches_node:
+ *@a_this: the selection engine.
+ *@a_sel: the simple selector against which the xml node
+ *is going to be matched.
+ *@a_node: the node against which the selector is going to be matched.
+ *@a_result: out parameter. The result of the match. Is set to
+ *TRUE if the selector matches the node, FALSE otherwise. This value
+ *is considered if and only if this functions returns CR_OK.
+ *
+ *Evaluates a chained list of simple selectors (known as a css2 selector).
+ *Says wheter if this selector matches the xml node given in parameter or
+ *not.
+ *
+ *Returns the CR_OK if the selection ran correctly, an error code otherwise.
+ */
+enum CRStatus
+cr_sel_eng_matches_node (CRSelEng * a_this, CRSimpleSel * a_sel,
+ CRXMLNodePtr a_node, gboolean * a_result)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_this && a_node
+ && a_result, CR_BAD_PARAM_ERROR);
+
+ if (!PRIVATE(a_this)->node_iface->isElementNode (a_node)) {
+ *a_result = FALSE;
+ return CR_OK;
+ }
+
+ return sel_matches_node_real (a_this, a_sel,
+ a_node, a_result,
+ TRUE, TRUE);
+}
+
+/**
+ * cr_sel_eng_get_matched_rulesets:
+ *@a_this: the current instance of the selection engine.
+ *@a_sheet: the stylesheet that holds the selectors.
+ *@a_node: the xml node to consider during the walk thru
+ *the stylesheet.
+ *@a_rulesets: out parameter. A pointer to an array of
+ *rulesets statement pointers. *a_rulesets is allocated by
+ *this function and must be freed by the caller. However, the caller
+ *must not alter the rulesets statements pointer because they
+ *point to statements that are still in the css stylesheet.
+ *@a_len: the length of *a_ruleset.
+ *
+ *Returns an array of pointers to selectors that matches
+ *the xml node given in parameter.
+ *
+ *Returns CR_OK upon sucessfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_sel_eng_get_matched_rulesets (CRSelEng * a_this,
+ CRStyleSheet * a_sheet,
+ CRXMLNodePtr a_node,
+ CRStatement *** a_rulesets, gulong * a_len)
+{
+ CRStatement **stmts_tab = NULL;
+ enum CRStatus status = CR_OK;
+ gulong tab_size = 0,
+ tab_len = 0,
+ index = 0;
+ gushort stmts_chunck_size = 8;
+
+ g_return_val_if_fail (a_this
+ && a_sheet
+ && a_node
+ && a_rulesets && *a_rulesets == NULL
+ && a_len, CR_BAD_PARAM_ERROR);
+
+ stmts_tab = (CRStatement **) g_try_malloc (stmts_chunck_size * sizeof (CRStatement *));
+
+ if (!stmts_tab) {
+ cr_utils_trace_info ("Out of memory");
+ status = CR_ERROR;
+ goto error;
+ }
+ memset (stmts_tab, 0, stmts_chunck_size * sizeof (CRStatement *));
+
+ tab_size = stmts_chunck_size;
+ tab_len = tab_size;
+
+ while ((status = cr_sel_eng_get_matched_rulesets_real
+ (a_this, a_sheet, a_node, stmts_tab + index, &tab_len))
+ == CR_OUTPUT_TOO_SHORT_ERROR) {
+ stmts_tab = (CRStatement **) g_try_realloc (stmts_tab,
+ (tab_size + stmts_chunck_size)
+ * sizeof (CRStatement *));
+ if (!stmts_tab) {
+ cr_utils_trace_info ("Out of memory");
+ status = CR_ERROR;
+ goto error;
+ }
+ tab_size += stmts_chunck_size;
+ index += tab_len;
+ tab_len = tab_size - index;
+ }
+
+ tab_len = tab_size - stmts_chunck_size + tab_len;
+ *a_rulesets = stmts_tab;
+ *a_len = tab_len;
+
+ return CR_OK;
+
+ error:
+
+ if (stmts_tab) {
+ g_free (stmts_tab);
+ stmts_tab = NULL;
+
+ }
+
+ *a_len = 0;
+ return status;
+}
+
+enum CRStatus
+cr_sel_eng_process_stylesheet ( CRSelEng * a_eng,
+ CRXMLNodePtr a_node,
+ CRStyleSheet * a_stylesheet,
+ CRStatement *** stmts_tab,
+ gulong * tab_size,
+ gulong * tab_len,
+ gulong * index)
+{
+ enum CRStatus status = CR_OK;
+ CRStyleSheet *cur = NULL;
+ gushort stmts_chunck_size = 8;
+
+ // Process imported stylesheets first
+ for (cur = a_stylesheet->import ; cur ; cur = cur->next) {
+ cr_sel_eng_process_stylesheet( a_eng, a_node, cur, stmts_tab, tab_size, tab_len, index );
+ }
+
+ // Process this stylesheet
+ if (*tab_size - *index < 1) {
+ *stmts_tab = (CRStatement **) g_try_realloc
+ (*stmts_tab, (*tab_size + stmts_chunck_size)
+ * sizeof (CRStatement *));
+ if (!*stmts_tab) {
+ cr_utils_trace_info ("Out of memory");
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ *tab_size += stmts_chunck_size;
+ /*
+ *compute the max size left for
+ *cr_sel_eng_get_matched_rulesets_real()'s output tab
+ */
+ *tab_len = *tab_size - *index;
+ }
+ while ((status = cr_sel_eng_get_matched_rulesets_real
+ (a_eng, a_stylesheet, a_node, *stmts_tab + *index, tab_len))
+ == CR_OUTPUT_TOO_SHORT_ERROR) {
+ *stmts_tab = (CRStatement **) g_try_realloc
+ (*stmts_tab, (*tab_size + stmts_chunck_size)
+ * sizeof (CRStatement *));
+ if (!*stmts_tab) {
+ cr_utils_trace_info ("Out of memory");
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ *tab_size += stmts_chunck_size;
+ *index += *tab_len;
+ /*
+ *compute the max size left for
+ *cr_sel_eng_get_matched_rulesets_real()'s output tab
+ */
+ *tab_len = *tab_size - *index;
+ }
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Error while running "
+ "selector engine");
+ goto cleanup;
+ }
+ *index += *tab_len;
+ *tab_len = *tab_size - *index;
+
+ // Process other document stylesheets last
+ for (cur = a_stylesheet->next ; cur ; cur = cur->next) {
+ cr_sel_eng_process_stylesheet( a_eng, a_node, cur, stmts_tab, tab_size, tab_len, index );
+ }
+
+ return status;
+
+ cleanup:
+ if (*stmts_tab) {
+ g_free (*stmts_tab);
+ *stmts_tab = NULL;
+ }
+
+ return status;
+}
+
+enum CRStatus
+cr_sel_eng_get_matched_properties_from_cascade (CRSelEng * a_this,
+ CRCascade * a_cascade,
+ CRXMLNodePtr a_node,
+ CRPropList ** a_props)
+{
+ CRStatement **stmts_tab = NULL;
+ enum CRStatus status = CR_OK;
+ gulong tab_size = 0,
+ tab_len = 0,
+ i = 0,
+ index = 0;
+ enum CRStyleOrigin origin;
+ gushort stmts_chunck_size = 8;
+ CRStyleSheet *sheet = NULL;
+
+ g_return_val_if_fail (a_this
+ && a_cascade
+ && a_node && a_props, CR_BAD_PARAM_ERROR);
+
+ for (origin = ORIGIN_UA; origin < NB_ORIGINS; origin = (enum CRStyleOrigin) (origin + 1)) {
+ sheet = cr_cascade_get_sheet (a_cascade, origin);
+ if (!sheet)
+ continue;
+
+ status = cr_sel_eng_process_stylesheet (a_this, a_node, sheet, &stmts_tab, &tab_size, &tab_len, &index);
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Error while running "
+ "selector engine");
+ return status;
+ }
+ }
+
+ /*
+ *TODO, walk down the stmts_tab and build the
+ *property_name/declaration hashtable.
+ *Make sure one can walk from the declaration to
+ *the stylesheet.
+ */
+ for (i = 0; i < index; i++) {
+ CRStatement *stmt = stmts_tab[i];
+ if (!stmt)
+ continue;
+ switch (stmt->type) {
+ case RULESET_STMT:
+ if (!stmt->parent_sheet)
+ continue;
+ status = put_css_properties_in_props_list
+ (a_props, stmt);
+ break;
+ default:
+ break;
+ }
+
+ }
+ status = CR_OK ;
+
+ return status;
+}
+
+enum CRStatus
+cr_sel_eng_get_matched_style (CRSelEng * a_this,
+ CRCascade * a_cascade,
+ CRXMLNodePtr a_node,
+ CRStyle * a_parent_style,
+ CRStyle ** a_style,
+ gboolean a_set_props_to_initial_values)
+{
+ enum CRStatus status = CR_OK;
+
+ CRPropList *props = NULL;
+
+ g_return_val_if_fail (a_this && a_cascade
+ && a_node && a_style, CR_BAD_PARAM_ERROR);
+
+ status = cr_sel_eng_get_matched_properties_from_cascade
+ (a_this, a_cascade, a_node, &props);
+
+ g_return_val_if_fail (status == CR_OK, status);
+ if (props) {
+ if (!*a_style) {
+ *a_style = cr_style_new (a_set_props_to_initial_values) ;
+ g_return_val_if_fail (*a_style, CR_ERROR);
+ } else {
+ if (a_set_props_to_initial_values == TRUE) {
+ cr_style_set_props_to_initial_values (*a_style) ;
+ } else {
+ cr_style_set_props_to_default_values (*a_style);
+ }
+ }
+ (*a_style)->parent_style = a_parent_style;
+
+ set_style_from_props (*a_style, props);
+ if (props) {
+ cr_prop_list_destroy (props);
+ props = NULL;
+ }
+ }
+ return CR_OK;
+}
+
+/**
+ * cr_sel_eng_destroy:
+ *@a_this: the current instance of the selection engine.
+ *
+ *The destructor of #CRSelEng
+ */
+void
+cr_sel_eng_destroy (CRSelEng * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (!PRIVATE (a_this))
+ goto end ;
+ if (PRIVATE (a_this)->pcs_handlers) {
+ cr_sel_eng_unregister_all_pseudo_class_sel_handlers
+ (a_this) ;
+ PRIVATE (a_this)->pcs_handlers = NULL ;
+ }
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ end:
+ if (a_this) {
+ g_free (a_this);
+ }
+}
diff --git a/src/3rdparty/libcroco/cr-sel-eng.h b/src/3rdparty/libcroco/cr-sel-eng.h
new file mode 100644
index 000000000..206990eb6
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-sel-eng.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyrights information.
+ */
+
+#ifndef __CR_SEL_ENG_H__
+#define __CR_SEL_ENG_H__
+
+#include "cr-utils.h"
+#include "cr-stylesheet.h"
+#include "cr-cascade.h"
+#include "cr-style.h"
+#include "cr-prop-list.h"
+#include "cr-node-iface.h"
+
+#include <libxml/tree.h>
+
+/**
+ *@file:
+ *The declaration of the #CRSelEng class.
+ *The #CRSelEng is actually the "Selection Engine"
+ *class.
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CRSelEng CRSelEng ;
+typedef struct _CRSelEngPriv CRSelEngPriv ;
+typedef struct _CRArguments CRArguments ;
+
+//stores arguments of function of type an+b
+struct _CRArguments
+{
+ int a;
+ int b;
+} ;
+
+/**
+ *The Selection engine class.
+ *The main service provided by this class, is
+ *the ability to interpret a libcroco implementation
+ *of css2 selectors, and given an xml node, say if
+ *the selector matches the node or not.
+ */
+struct _CRSelEng
+{
+ CRSelEngPriv *priv ;
+} ;
+
+void cr_sel_eng_set_node_iface(CRSelEng *a_this, CRNodeIface const *);
+
+typedef gboolean (*CRPseudoClassSelectorHandler) (CRSelEng* a_this,
+ CRAdditionalSel *a_add_sel,
+ CRXMLNodePtr a_node) ;
+CRSelEng * cr_sel_eng_new (void) ;
+
+enum CRStatus cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng *a_this,
+ guchar *a_pseudo_class_sel_name,
+ enum CRPseudoType a_pseudo_class_type,
+ CRPseudoClassSelectorHandler a_handler) ;
+
+enum CRStatus cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng *a_this,
+ guchar *a_pseudo_class_sel_name,
+ enum CRPseudoType a_pseudo_class_type) ;
+
+enum CRStatus cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng *a_this) ;
+
+enum CRStatus cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng *a_this,
+ guchar *a_pseudo_class_sel_name,
+ enum CRPseudoType a_pseudo_class_type,
+ CRPseudoClassSelectorHandler *a_handler) ;
+
+enum CRStatus cr_sel_eng_matches_node (CRSelEng *a_this,
+ CRSimpleSel *a_sel,
+ CRXMLNodePtr a_node,
+ gboolean *a_result) ;
+
+enum CRStatus cr_sel_eng_get_matched_rulesets (CRSelEng *a_this,
+ CRStyleSheet *a_sheet,
+ CRXMLNodePtr a_node,
+ CRStatement ***a_rulesets,
+ gulong *a_len) ;
+
+enum CRStatus
+cr_sel_eng_get_matched_properties_from_cascade (CRSelEng *a_this,
+ CRCascade *a_cascade,
+ CRXMLNodePtr a_node,
+ CRPropList **a_props) ;
+
+enum CRStatus cr_sel_eng_get_matched_style (CRSelEng *a_this,
+ CRCascade *a_cascade,
+ CRXMLNodePtr a_node,
+ CRStyle *a_parent_style,
+ CRStyle **a_style,
+ gboolean a_set_props_to_initial_values) ;
+
+void cr_sel_eng_destroy (CRSelEng *a_this) ;
+
+G_END_DECLS
+
+
+#endif/*__CR_SEL_ENG_H__*/
diff --git a/src/3rdparty/libcroco/cr-selector.c b/src/3rdparty/libcroco/cr-selector.c
new file mode 100644
index 000000000..f9193feda
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-selector.c
@@ -0,0 +1,330 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-selector.h"
+#include "cr-parser.h"
+
+/**
+ * cr_selector_new:
+ *
+ *@a_simple_sel: the initial simple selector list
+ *of the current instance of #CRSelector.
+ *
+ *Creates a new instance of #CRSelector.
+ *
+ *Returns the newly built instance of #CRSelector, or
+ *NULL in case of failure.
+ */
+CRSelector *
+cr_selector_new (CRSimpleSel * a_simple_sel)
+{
+ CRSelector *result = NULL;
+
+ result = (CRSelector *) g_try_malloc (sizeof (CRSelector));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRSelector));
+ result->simple_sel = a_simple_sel;
+ return result;
+}
+
+/**
+ * cr_selector_parse_from_buf:
+ *
+ *@a_char_buf: the buffer to parse.
+ *@a_enc: the encoding of the input buffer a_char_buf.
+ *
+ *Parses a buf for selectors.
+ *
+ *Fix Me: parsing will fail for some cases if buf does not end with '{'.
+ *
+ *Returns the newly built instance of #CRSelector, or
+ *NULL in case of failure.
+ */
+CRSelector *
+cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc)
+{
+ CRParser *parser = NULL;
+
+ g_return_val_if_fail (a_char_buf, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf),
+ a_enc, FALSE);
+ g_return_val_if_fail (parser, NULL);
+
+ CRSelector *selector = NULL;
+ enum CRStatus status = CR_OK;
+ status = cr_parser_parse_selector (parser, &selector);
+
+ if (status != CR_OK) {
+ if (selector) {
+ cr_selector_unref (selector);
+ selector = NULL;
+ }
+ }
+ return selector;
+}
+
+/**
+ * cr_selector_append:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_new: the instance of #CRSelector to be appended.
+ *
+ *Appends a new instance of #CRSelector to the current selector list.
+ *
+ *Returns the new list.
+ */
+CRSelector *
+cr_selector_append (CRSelector * a_this, CRSelector * a_new)
+{
+ CRSelector *cur = NULL;
+
+ if (!a_this) {
+ return a_new;
+ }
+
+ /*walk forward the list headed by a_this to get the list tail */
+ for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+ cur->next = a_new;
+ a_new->prev = cur;
+
+ return a_this;
+}
+
+/**
+ * cr_selector_prepend:
+ *
+ *@a_this: the current instance of #CRSelector list.
+ *@a_new: the instance of #CRSelector.
+ *
+ *Prepends an element to the #CRSelector list.
+ *
+ *Returns the new list.
+ */
+CRSelector *
+cr_selector_prepend (CRSelector * a_this, CRSelector * a_new)
+{
+ CRSelector *cur = NULL;
+
+ a_new->next = a_this;
+ a_this->prev = a_new;
+
+ for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+ return cur;
+}
+
+/**
+ * cr_selector_append_simple_sel:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_simple_sel: the simple selector to append.
+ *
+ *append a simple selector to the current #CRSelector list.
+ *
+ *Returns the new list or NULL in case of failure.
+ */
+CRSelector *
+cr_selector_append_simple_sel (CRSelector * a_this,
+ CRSimpleSel * a_simple_sel)
+{
+ CRSelector *selector = NULL;
+
+ selector = cr_selector_new (a_simple_sel);
+ g_return_val_if_fail (selector, NULL);
+
+ return cr_selector_append (a_this, selector);
+}
+
+guchar *
+cr_selector_to_string (CRSelector const * a_this)
+{
+ guchar *result = NULL;
+ GString *str_buf = NULL;
+
+ str_buf = (GString *) g_string_new (NULL);
+ g_return_val_if_fail (str_buf, NULL);
+
+ if (a_this) {
+ CRSelector const *cur = NULL;
+
+ for (cur = a_this; cur; cur = cur->next) {
+ if (cur->simple_sel) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_simple_sel_to_string
+ (cur->simple_sel);
+
+ if (tmp_str) {
+ if (cur->prev)
+ g_string_append (str_buf,
+ ", ");
+
+ g_string_append (str_buf, (const gchar *) tmp_str);
+
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_selector_dump:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *@a_fp: the destination file.
+ *
+ *Serializes the current instance of #CRSelector to a file.
+ */
+void
+cr_selector_dump (CRSelector const * a_this, FILE * a_fp)
+{
+ guchar *tmp_buf = NULL;
+
+ if (a_this) {
+ tmp_buf = cr_selector_to_string (a_this);
+ if (tmp_buf) {
+ fprintf (a_fp, "%s", tmp_buf);
+ g_free (tmp_buf);
+ tmp_buf = NULL;
+ }
+ }
+}
+
+/**
+ * cr_selector_ref:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Increments the ref count of the current instance
+ *of #CRSelector.
+ */
+void
+cr_selector_ref (CRSelector * a_this)
+{
+ g_return_if_fail (a_this);
+
+ a_this->ref_count++;
+}
+
+/**
+ * cr_selector_unref:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Decrements the ref count of the current instance of
+ *#CRSelector.
+ *If the ref count reaches zero, the current instance of
+ *#CRSelector is destroyed.
+ *
+ *Returns TRUE if this function destroyed the current instance
+ *of #CRSelector, FALSE otherwise.
+ */
+gboolean
+cr_selector_unref (CRSelector * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count) {
+ a_this->ref_count--;
+ }
+
+ if (a_this->ref_count == 0) {
+ cr_selector_destroy (a_this);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * cr_selector_destroy:
+ *
+ *@a_this: the current instance of #CRSelector.
+ *
+ *Destroys the selector list.
+ */
+void
+cr_selector_destroy (CRSelector * a_this)
+{
+ CRSelector *cur = NULL;
+
+ g_return_if_fail (a_this);
+
+ /*
+ *go and get the list tail. In the same time, free
+ *all the simple selectors contained in the list.
+ */
+ for (cur = a_this; cur && cur->next; cur = cur->next) {
+ if (cur->simple_sel) {
+ cr_simple_sel_destroy (cur->simple_sel);
+ cur->simple_sel = NULL;
+ }
+ }
+
+ if (cur) {
+ if (cur->simple_sel) {
+ cr_simple_sel_destroy (cur->simple_sel);
+ cur->simple_sel = NULL;
+ }
+ }
+
+ /*in case the list has only one element */
+ if (cur && !cur->prev) {
+ g_free (cur);
+ return;
+ }
+
+ /*walk backward the list and free each "next element" */
+ for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
+ if (cur->next) {
+ g_free (cur->next);
+ cur->next = NULL;
+ }
+ }
+
+ if (!cur)
+ return;
+
+ if (cur->next) {
+ g_free (cur->next);
+ cur->next = NULL;
+ }
+
+ g_free (cur);
+}
diff --git a/src/3rdparty/libcroco/cr-selector.h b/src/3rdparty/libcroco/cr-selector.h
new file mode 100644
index 000000000..a7e029597
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-selector.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_SELECTOR_H__
+#define __CR_SELECTOR_H__
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-simple-sel.h"
+#include "cr-parsing-location.h"
+
+/**
+ *@file
+ *The declaration file of the #CRSelector file.
+ */
+
+G_BEGIN_DECLS
+
+typedef struct _CRSelector CRSelector ;
+
+/**
+ *Abstracts a CSS2 selector as defined in the right part
+ *of the 'ruleset' production in the appendix D.1 of the
+ *css2 spec.
+ *It is actually the abstraction of a comma separated list
+ *of simple selectors list.
+ *In a css2 file, a selector is a list of simple selectors
+ *separated by a comma.
+ *e.g: sel0, sel1, sel2 ...
+ *Each seln is a simple selector
+ */
+struct _CRSelector
+{
+ /**
+ *A Selection expression.
+ *It is a list of basic selectors.
+ *Each basic selector can be either an element
+ *selector, an id selector, a class selector, an
+ *attribute selector, an universal selector etc ...
+ */
+ CRSimpleSel *simple_sel ;
+
+ /**The next selector list element*/
+ CRSelector *next ;
+ CRSelector *prev ;
+ CRParsingLocation location ;
+ glong ref_count ;
+};
+
+CRSelector* cr_selector_new (CRSimpleSel *a_sel_expr) ;
+
+CRSelector * cr_selector_parse_from_buf (const guchar * a_char_buf,
+ enum CREncoding a_enc) ;
+
+CRSelector* cr_selector_append (CRSelector *a_this, CRSelector *a_new) ;
+
+CRSelector* cr_selector_append_simple_sel (CRSelector *a_this,
+ CRSimpleSel *a_simple_sel) ;
+
+CRSelector* cr_selector_prepend (CRSelector *a_this, CRSelector *a_new) ;
+
+guchar * cr_selector_to_string (CRSelector const *a_this) ;
+
+void cr_selector_dump (CRSelector const *a_this, FILE *a_fp) ;
+
+void cr_selector_ref (CRSelector *a_this) ;
+
+gboolean cr_selector_unref (CRSelector *a_this) ;
+
+void cr_selector_destroy (CRSelector *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_SELECTOR_H__*/
diff --git a/src/3rdparty/libcroco/cr-simple-sel.c b/src/3rdparty/libcroco/cr-simple-sel.c
new file mode 100644
index 000000000..3a4a3b2e2
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-simple-sel.c
@@ -0,0 +1,328 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "cr-simple-sel.h"
+
+/**
+ * cr_simple_sel_new:
+ *
+ *The constructor of #CRSimpleSel.
+ *
+ *Returns the new instance of #CRSimpleSel.
+ */
+CRSimpleSel *
+cr_simple_sel_new (void)
+{
+ CRSimpleSel *result = NULL;
+
+ result = (CRSimpleSel *) g_try_malloc (sizeof (CRSimpleSel));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRSimpleSel));
+
+ return result;
+}
+
+/**
+ * cr_simple_sel_append_simple_sel:
+ *
+ *Appends a simpe selector to the current list of simple selector.
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *@a_sel: the simple selector to append.
+ *
+ *Returns: the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_append_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
+{
+ CRSimpleSel *cur = NULL;
+
+ g_return_val_if_fail (a_sel, NULL);
+
+ if (a_this == NULL)
+ return a_sel;
+
+ for (cur = a_this; cur->next; cur = cur->next) ;
+
+ cur->next = a_sel;
+ a_sel->prev = cur;
+
+ return a_this;
+}
+
+/**
+ * cr_simple_sel_prepend_simple_sel:
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *@a_sel: the simple selector to prepend.
+ *
+ *Prepends a simple selector to the current list of simple selectors.
+ *
+ *Returns the new list upon successfull completion, an error code otherwise.
+ */
+CRSimpleSel *
+cr_simple_sel_prepend_simple_sel (CRSimpleSel * a_this, CRSimpleSel * a_sel)
+{
+ g_return_val_if_fail (a_sel, NULL);
+
+ if (a_this == NULL)
+ return a_sel;
+
+ a_sel->next = a_this;
+ a_this->prev = a_sel;
+
+ return a_sel;
+}
+
+guchar *
+cr_simple_sel_to_string (CRSimpleSel const * a_this)
+{
+ GString *str_buf = NULL;
+ guchar *result = NULL;
+
+ CRSimpleSel const *cur = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+ for (cur = a_this; cur; cur = cur->next) {
+ if (cur->name) {
+ guchar *str = (guchar *) g_strndup (cur->name->stryng->str,
+ cur->name->stryng->len);
+
+ if (str) {
+ switch (cur->combinator) {
+ case COMB_WS:
+ g_string_append (str_buf, " ");
+ break;
+
+ case COMB_PLUS:
+ g_string_append (str_buf, "+");
+ break;
+
+ case COMB_TILDE:
+ g_string_append (str_buf, "~");
+ break;
+
+ case COMB_GT:
+ g_string_append (str_buf, ">");
+ break;
+
+ default:
+ break;
+ }
+
+ g_string_append (str_buf, (const gchar *) str);
+ g_free (str);
+ str = NULL;
+ }
+ }
+
+ if (cur->add_sel) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_additional_sel_to_string (cur->add_sel);
+ if (tmp_str) {
+ g_string_append (str_buf, (const gchar *) tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+
+guchar *
+cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
+{
+ GString *str_buf = NULL;
+ guchar *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+ if (a_this->name) {
+ guchar *str = (guchar *) g_strndup (a_this->name->stryng->str,
+ a_this->name->stryng->len);
+
+ if (str) {
+ g_string_append_printf (str_buf, "%s", str);
+ g_free (str);
+ str = NULL;
+ }
+ }
+
+ if (a_this->add_sel) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_additional_sel_to_string (a_this->add_sel);
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf, "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_simple_sel_dump:
+ *@a_this: the current instance of #CRSimpleSel.
+ *@a_fp: the destination file pointer.
+ *
+ *Dumps the selector to a file.
+ *TODO: add the support of unicode in the dump.
+ *
+ *Returns CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_simple_sel_dump (CRSimpleSel const * a_this, FILE * a_fp)
+{
+ guchar *tmp_str = NULL;
+
+ g_return_val_if_fail (a_fp, CR_BAD_PARAM_ERROR);
+
+ if (a_this) {
+ tmp_str = cr_simple_sel_to_string (a_this);
+ if (tmp_str) {
+ fprintf (a_fp, "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+
+ return CR_OK;
+}
+
+/**
+ * cr_simple_sel_compute_specificity:
+ *
+ *@a_this: the current instance of #CRSimpleSel
+ *
+ *Computes the selector (combinator separated list of simple selectors)
+ *as defined in the css2 spec in chapter 6.4.3
+ *
+ *Returns CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
+{
+ CRAdditionalSel const *cur_add_sel = NULL;
+ CRSimpleSel const *cur_sel = NULL;
+ gulong a = 0,
+ b = 0,
+ c = 0;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
+ if (cur_sel->type_mask & TYPE_SELECTOR) {
+ c++; /*hmmh, is this a new language ? */
+ } else if (!cur_sel->name
+ || !cur_sel->name->stryng
+ || !cur_sel->name->stryng->str) {
+ if (cur_sel->add_sel->type ==
+ PSEUDO_CLASS_ADD_SELECTOR) {
+ /*
+ *this is a pseudo element, and
+ *the spec says, "ignore pseudo elements".
+ */
+ continue;
+ }
+ }
+
+ for (cur_add_sel = cur_sel->add_sel;
+ cur_add_sel; cur_add_sel = cur_add_sel->next) {
+ switch (cur_add_sel->type) {
+ case ID_ADD_SELECTOR:
+ a++;
+ break;
+
+ case NO_ADD_SELECTOR:
+ continue;
+
+ default:
+ b++;
+ break;
+ }
+ }
+ }
+
+ /*we suppose a, b and c have 1 to 3 digits */
+ a_this->specificity = a * 1000000 + b * 1000 + c;
+
+ return CR_OK;
+}
+
+/**
+ * cr_simple_sel_destroy:
+ *
+ *@a_this: the this pointer of the current instance of #CRSimpleSel.
+ *
+ *The destructor of the current instance of
+ *#CRSimpleSel. Recursively calls the destructor of #CRSimpleSel->next
+ */
+void
+cr_simple_sel_destroy (CRSimpleSel * const a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->name) {
+ cr_string_destroy (a_this->name);
+ a_this->name = NULL;
+ }
+
+ if (a_this->add_sel) {
+ cr_additional_sel_destroy (a_this->add_sel);
+ a_this->add_sel = NULL;
+ }
+
+ if (a_this->next) {
+ cr_simple_sel_destroy (a_this->next);
+ a_this->next = NULL;
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-simple-sel.h b/src/3rdparty/libcroco/cr-simple-sel.h
new file mode 100644
index 000000000..552e44f00
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-simple-sel.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_SEL_H__
+#define __CR_SEL_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-additional-sel.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *the declaration of the #CRSimpleSel class.
+ *
+ */
+enum Combinator
+{
+ NO_COMBINATOR,
+ COMB_WS, /*whitespace: descendent*/
+ COMB_PLUS, /*'+': immediately preceded by*/
+ COMB_TILDE, /*'~': preceded by, CSS 3*/
+ COMB_GT /*greater than ('>'): child*/
+} ;
+
+enum SimpleSelectorType
+{
+ NO_SELECTOR_TYPE = 0,
+ UNIVERSAL_SELECTOR = 1,
+ TYPE_SELECTOR = 1 << 1
+} ;
+
+typedef struct _CRSimpleSel CRSimpleSel ;
+
+/**
+ *The abstraction of a css2 simple selection list
+ *as defined by the right part of the "selector" production in the
+ *appendix D.1 of the css2 spec.
+ *It is basically a list of simple selector, each
+ *simple selector being separated by a combinator.
+ *
+ *In the libcroco's implementation, each simple selector
+ *is made of at most two parts:
+ *
+ *1/An element name or 'type selector' (which can hold a '*' and
+ *then been called 'universal selector')
+ *
+ *2/An additional selector that "specializes" the preceding type or
+ *universal selector. The additionnal selector can be either
+ *an id selector, or a class selector, or an attribute selector.
+ */
+struct _CRSimpleSel
+{
+ enum SimpleSelectorType type_mask ;
+ gboolean is_case_sentive ;
+ CRString * name ;
+ /**
+ *The combinator that separates
+ *this simple selector from the previous
+ *one.
+ */
+ enum Combinator combinator ;
+
+ /**
+ *The additional selector list of the
+ *current simple selector.
+ *An additional selector may
+ *be a class selector, an id selector,
+ *or an attribute selector.
+ *Note that this field is a linked list.
+ */
+ CRAdditionalSel *add_sel ;
+
+ /*
+ *the specificity as specified by
+ *chapter 6.4.3 of the spec.
+ */
+ gulong specificity ;
+
+ CRSimpleSel *next ;
+ CRSimpleSel *prev ;
+ CRParsingLocation location ;
+} ;
+
+CRSimpleSel * cr_simple_sel_new (void) ;
+
+CRSimpleSel * cr_simple_sel_append_simple_sel (CRSimpleSel *a_this,
+ CRSimpleSel *a_sel) ;
+
+CRSimpleSel * cr_simple_sel_prepend_simple_sel (CRSimpleSel *a_this,
+ CRSimpleSel *a_sel) ;
+
+guchar * cr_simple_sel_to_string (CRSimpleSel const *a_this) ;
+
+guchar * cr_simple_sel_one_to_string (CRSimpleSel const * a_this) ;
+
+enum CRStatus cr_simple_sel_dump (CRSimpleSel const *a_this, FILE *a_fp) ;
+
+enum CRStatus cr_simple_sel_dump_attr_sel_list (CRSimpleSel const *a_this) ;
+
+enum CRStatus cr_simple_sel_compute_specificity (CRSimpleSel *a_this) ;
+
+void cr_simple_sel_destroy (CRSimpleSel *a_this) ;
+
+G_END_DECLS
+
+
+#endif /*__CR_SIMPLE_SEL_H__*/
diff --git a/src/3rdparty/libcroco/cr-statement.c b/src/3rdparty/libcroco/cr-statement.c
new file mode 100644
index 000000000..e31123aec
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-statement.c
@@ -0,0 +1,2809 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS files for copyrights information.
+ */
+
+#include <string.h>
+#include "cr-statement.h"
+#include "cr-parser.h"
+
+/**
+ *@file
+ *Definition of the #CRStatement class.
+ */
+
+#define DECLARATION_INDENT_NB 2
+
+static void cr_statement_clear (CRStatement * a_this);
+
+static void
+parse_font_face_start_font_face_cb (CRDocHandler * a_this,
+ CRParsingLocation *a_location)
+{
+ CRStatement *stmt = NULL;
+ enum CRStatus status = CR_OK;
+
+ (void) a_location;
+
+ stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
+ g_return_if_fail (stmt);
+
+ status = cr_doc_handler_set_ctxt (a_this, stmt);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_font_face_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_if_fail (a_this);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Couldn't get parsing context. "
+ "This may lead to some memory leaks.");
+ return;
+ }
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ cr_doc_handler_set_ctxt (a_this, NULL);
+ return;
+ }
+}
+
+static void
+parse_font_face_property_cb (CRDocHandler * a_this,
+ CRString * a_name,
+ CRTerm * a_value, gboolean a_important)
+{
+ enum CRStatus status = CR_OK;
+ CRString *name = NULL;
+ CRDeclaration *decl = NULL;
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+
+ (void) a_important;
+
+ g_return_if_fail (a_this && a_name);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ g_return_if_fail (status == CR_OK && stmt);
+ g_return_if_fail (stmt->type == AT_FONT_FACE_RULE_STMT);
+
+ name = cr_string_dup (a_name) ;
+ g_return_if_fail (name);
+ decl = cr_declaration_new (stmt, name, a_value);
+ if (!decl) {
+ cr_utils_trace_info ("cr_declaration_new () failed.");
+ goto error;
+ }
+ name = NULL;
+
+ stmt->kind.font_face_rule->decl_list =
+ cr_declaration_append (stmt->kind.font_face_rule->decl_list,
+ decl);
+ if (!stmt->kind.font_face_rule->decl_list)
+ goto error;
+ decl = NULL;
+
+ error:
+ if (decl) {
+ cr_declaration_unref (decl);
+ decl = NULL;
+ }
+ if (name) {
+ cr_string_destroy (name);
+ name = NULL;
+ }
+}
+
+static void
+parse_font_face_end_font_face_cb (CRDocHandler * a_this)
+{
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_if_fail (a_this);
+
+ resultptr = &result;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) resultptr);
+ g_return_if_fail (status == CR_OK && result);
+ g_return_if_fail (result->type == AT_FONT_FACE_RULE_STMT);
+
+ status = cr_doc_handler_set_result (a_this, result);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_page_start_page_cb (CRDocHandler * a_this,
+ CRString * a_name,
+ CRString * a_pseudo_page,
+ CRParsingLocation *a_location)
+{
+ CRStatement *stmt = NULL;
+ enum CRStatus status = CR_OK;
+ CRString *page_name = NULL, *pseudo_name = NULL ;
+
+ (void) a_location;
+
+ if (a_name)
+ page_name = cr_string_dup (a_name) ;
+ if (a_pseudo_page)
+ pseudo_name = cr_string_dup (a_pseudo_page) ;
+
+ stmt = cr_statement_new_at_page_rule (NULL, NULL,
+ page_name,
+ pseudo_name);
+ page_name = NULL ;
+ pseudo_name = NULL ;
+ g_return_if_fail (stmt);
+ status = cr_doc_handler_set_ctxt (a_this, stmt);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_page_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_if_fail (a_this);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Couldn't get parsing context. "
+ "This may lead to some memory leaks.");
+ return;
+ }
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ stmt = NULL;
+ cr_doc_handler_set_ctxt (a_this, NULL);
+ }
+}
+
+static void
+parse_page_property_cb (CRDocHandler * a_this,
+ CRString * a_name,
+ CRTerm * a_expression, gboolean a_important)
+{
+ CRString *name = NULL;
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+ CRDeclaration *decl = NULL;
+ enum CRStatus status = CR_OK;
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ g_return_if_fail (status == CR_OK && stmt->type == AT_PAGE_RULE_STMT);
+
+ name = cr_string_dup (a_name);
+ g_return_if_fail (name);
+
+ decl = cr_declaration_new (stmt, name, a_expression);
+ g_return_if_fail (decl);
+ decl->important = a_important;
+ stmt->kind.page_rule->decl_list =
+ cr_declaration_append (stmt->kind.page_rule->decl_list, decl);
+ g_return_if_fail (stmt->kind.page_rule->decl_list);
+}
+
+static void
+parse_page_end_page_cb (CRDocHandler * a_this,
+ CRString * a_name,
+ CRString * a_pseudo_page)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+
+ (void) a_name;
+ (void) a_pseudo_page;
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ g_return_if_fail (status == CR_OK && stmt);
+ g_return_if_fail (stmt->type == AT_PAGE_RULE_STMT);
+
+ status = cr_doc_handler_set_result (a_this, stmt);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_start_media_cb (CRDocHandler * a_this,
+ GList * a_media_list,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *at_media = NULL;
+ GList *media_list = NULL;
+
+ (void) a_location;
+
+ g_return_if_fail (a_this && a_this->priv);
+
+ if (a_media_list) {
+ /*duplicate media list */
+ media_list = cr_utils_dup_glist_of_cr_string
+ (a_media_list);
+ }
+
+ g_return_if_fail (media_list);
+
+ /*make sure cr_statement_new_at_media_rule works in this case. */
+ at_media = cr_statement_new_at_media_rule (NULL, NULL, media_list);
+
+ status = cr_doc_handler_set_ctxt (a_this, at_media);
+ g_return_if_fail (status == CR_OK);
+ status = cr_doc_handler_set_result (a_this, at_media);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+
+ g_return_if_fail (a_this);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Couldn't get parsing context. "
+ "This may lead to some memory leaks.");
+ return;
+ }
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ stmt = NULL;
+ cr_doc_handler_set_ctxt (a_this, NULL);
+ cr_doc_handler_set_result (a_this, NULL);
+ }
+}
+
+static void
+parse_at_media_start_selector_cb (CRDocHandler * a_this,
+ CRSelector * a_sellist)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *at_media = NULL;
+ CRStatement **at_media_ptr = NULL;
+ CRStatement *ruleset = NULL;
+
+ g_return_if_fail (a_this && a_this->priv && a_sellist);
+
+ at_media_ptr = &at_media;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) at_media_ptr);
+ g_return_if_fail (status == CR_OK && at_media);
+ g_return_if_fail (at_media->type == AT_MEDIA_RULE_STMT);
+ ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, at_media);
+ g_return_if_fail (ruleset);
+ status = cr_doc_handler_set_ctxt (a_this, ruleset);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_property_cb (CRDocHandler * a_this,
+ CRString * a_name, CRTerm * a_value,
+ gboolean a_important)
+{
+ enum CRStatus status = CR_OK;
+
+ /*
+ *the current ruleset stmt, child of the
+ *current at-media being parsed.
+ */
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+ CRDeclaration *decl = NULL;
+ CRString *name = NULL;
+
+ g_return_if_fail (a_this && a_name);
+
+ name = cr_string_dup (a_name) ;
+ g_return_if_fail (name);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this,
+ (gpointer *) stmtptr);
+ g_return_if_fail (status == CR_OK && stmt);
+ g_return_if_fail (stmt->type == RULESET_STMT);
+
+ decl = cr_declaration_new (stmt, name, a_value);
+ g_return_if_fail (decl);
+ decl->important = a_important;
+ status = cr_statement_ruleset_append_decl (stmt, decl);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_end_selector_cb (CRDocHandler * a_this,
+ CRSelector * a_sellist)
+{
+ enum CRStatus status = CR_OK;
+
+ /*
+ *the current ruleset stmt, child of the
+ *current at-media being parsed.
+ */
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+
+ g_return_if_fail (a_this && a_sellist);
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
+ g_return_if_fail (status == CR_OK && stmt
+ && stmt->type == RULESET_STMT);
+ g_return_if_fail (stmt->kind.ruleset->parent_media_rule);
+
+ status = cr_doc_handler_set_ctxt
+ (a_this, stmt->kind.ruleset->parent_media_rule);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_at_media_end_media_cb (CRDocHandler * a_this,
+ GList * a_media_list)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *at_media = NULL;
+ CRStatement **at_media_ptr = NULL;
+
+ (void) a_media_list;
+
+ g_return_if_fail (a_this && a_this->priv);
+
+ at_media_ptr = &at_media;
+ status = cr_doc_handler_get_ctxt (a_this,
+ (gpointer *) at_media_ptr);
+ g_return_if_fail (status == CR_OK && at_media);
+ status = cr_doc_handler_set_result (a_this, at_media);
+}
+
+static void
+parse_ruleset_start_selector_cb (CRDocHandler * a_this,
+ CRSelector * a_sellist)
+{
+ CRStatement *ruleset = NULL;
+
+ g_return_if_fail (a_this && a_this->priv && a_sellist);
+
+ ruleset = cr_statement_new_ruleset (NULL, a_sellist, NULL, NULL);
+ g_return_if_fail (ruleset);
+
+ cr_doc_handler_set_result (a_this, ruleset);
+}
+
+static void
+parse_ruleset_unrecoverable_error_cb (CRDocHandler * a_this)
+{
+ CRStatement *stmt = NULL;
+ CRStatement **stmtptr = NULL;
+ enum CRStatus status = CR_OK;
+
+ stmtptr = &stmt;
+ status = cr_doc_handler_get_result (a_this, (gpointer *) stmtptr);
+ if (status != CR_OK) {
+ cr_utils_trace_info ("Couldn't get parsing context. "
+ "This may lead to some memory leaks.");
+ return;
+ }
+ if (stmt) {
+ cr_statement_destroy (stmt);
+ stmt = NULL;
+ cr_doc_handler_set_result (a_this, NULL);
+ }
+}
+
+static void
+parse_ruleset_property_cb (CRDocHandler * a_this,
+ CRString * a_name,
+ CRTerm * a_value, gboolean a_important)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *ruleset = NULL;
+ CRStatement **rulesetptr = NULL;
+ CRDeclaration *decl = NULL;
+ CRString *stringue = NULL;
+
+ g_return_if_fail (a_this && a_this->priv && a_name);
+
+ stringue = cr_string_dup (a_name);
+ g_return_if_fail (stringue);
+
+ rulesetptr = &ruleset;
+ status = cr_doc_handler_get_result (a_this, (gpointer *) rulesetptr);
+ g_return_if_fail (status == CR_OK
+ && ruleset
+ && ruleset->type == RULESET_STMT);
+
+ decl = cr_declaration_new (ruleset, stringue, a_value);
+ g_return_if_fail (decl);
+ decl->important = a_important;
+ status = cr_statement_ruleset_append_decl (ruleset, decl);
+ g_return_if_fail (status == CR_OK);
+}
+
+static void
+parse_ruleset_end_selector_cb (CRDocHandler * a_this,
+ CRSelector * a_sellist)
+{
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_if_fail (a_this && a_sellist);
+
+ resultptr = &result;
+ status = cr_doc_handler_get_result (a_this, (gpointer *) resultptr);
+
+ g_return_if_fail (status == CR_OK
+ && result
+ && result->type == RULESET_STMT);
+}
+
+static void
+cr_statement_clear (CRStatement * a_this)
+{
+ g_return_if_fail (a_this);
+
+ switch (a_this->type) {
+ case AT_RULE_STMT:
+ break;
+ case RULESET_STMT:
+ if (!a_this->kind.ruleset)
+ return;
+ if (a_this->kind.ruleset->sel_list) {
+ cr_selector_unref (a_this->kind.ruleset->sel_list);
+ a_this->kind.ruleset->sel_list = NULL;
+ }
+ if (a_this->kind.ruleset->decl_list) {
+ cr_declaration_destroy
+ (a_this->kind.ruleset->decl_list);
+ a_this->kind.ruleset->decl_list = NULL;
+ }
+ g_free (a_this->kind.ruleset);
+ a_this->kind.ruleset = NULL;
+ break;
+
+ case AT_IMPORT_RULE_STMT:
+ if (!a_this->kind.import_rule)
+ return;
+ if (a_this->kind.import_rule->url) {
+ cr_string_destroy
+ (a_this->kind.import_rule->url) ;
+ a_this->kind.import_rule->url = NULL;
+ }
+ g_free (a_this->kind.import_rule);
+ a_this->kind.import_rule = NULL;
+ break;
+
+ case AT_MEDIA_RULE_STMT:
+ if (!a_this->kind.media_rule)
+ return;
+ if (a_this->kind.media_rule->rulesets) {
+ cr_statement_destroy
+ (a_this->kind.media_rule->rulesets);
+ a_this->kind.media_rule->rulesets = NULL;
+ }
+ if (a_this->kind.media_rule->media_list) {
+ GList *cur = NULL;
+
+ for (cur = a_this->kind.media_rule->media_list;
+ cur; cur = cur->next) {
+ if (cur->data) {
+ cr_string_destroy ((CRString *) cur->data);
+ cur->data = NULL;
+ }
+
+ }
+ g_list_free (a_this->kind.media_rule->media_list);
+ a_this->kind.media_rule->media_list = NULL;
+ }
+ g_free (a_this->kind.media_rule);
+ a_this->kind.media_rule = NULL;
+ break;
+
+ case AT_PAGE_RULE_STMT:
+ if (!a_this->kind.page_rule)
+ return;
+
+ if (a_this->kind.page_rule->decl_list) {
+ cr_declaration_destroy
+ (a_this->kind.page_rule->decl_list);
+ a_this->kind.page_rule->decl_list = NULL;
+ }
+ if (a_this->kind.page_rule->name) {
+ cr_string_destroy
+ (a_this->kind.page_rule->name);
+ a_this->kind.page_rule->name = NULL;
+ }
+ if (a_this->kind.page_rule->pseudo) {
+ cr_string_destroy
+ (a_this->kind.page_rule->pseudo);
+ a_this->kind.page_rule->pseudo = NULL;
+ }
+ g_free (a_this->kind.page_rule);
+ a_this->kind.page_rule = NULL;
+ break;
+
+ case AT_CHARSET_RULE_STMT:
+ if (!a_this->kind.charset_rule)
+ return;
+
+ if (a_this->kind.charset_rule->charset) {
+ cr_string_destroy
+ (a_this->kind.charset_rule->charset);
+ a_this->kind.charset_rule->charset = NULL;
+ }
+ g_free (a_this->kind.charset_rule);
+ a_this->kind.charset_rule = NULL;
+ break;
+
+ case AT_FONT_FACE_RULE_STMT:
+ if (!a_this->kind.font_face_rule)
+ return;
+
+ if (a_this->kind.font_face_rule->decl_list) {
+ cr_declaration_unref
+ (a_this->kind.font_face_rule->decl_list);
+ a_this->kind.font_face_rule->decl_list = NULL;
+ }
+ g_free (a_this->kind.font_face_rule);
+ a_this->kind.font_face_rule = NULL;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * cr_statement_ruleset_to_string:
+ *
+ *@a_this: the current instance of #CRStatement
+ *@a_indent: the number of whitespace to use for indentation
+ *
+ *Serializes the ruleset statement into a string
+ *
+ *Returns the newly allocated serialised string. Must be freed
+ *by the caller, using g_free().
+ */
+static gchar *
+cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
+{
+ GString *stringue = NULL;
+ gchar *tmp_str = NULL,
+ *result = NULL;
+
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
+
+ stringue = (GString *) g_string_new (NULL);
+ if (!stringue) {
+ return result;
+ }
+
+ if (a_this->kind.ruleset->sel_list) {
+ if (a_indent)
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+
+ tmp_str =
+ (gchar *) cr_selector_to_string (a_this->kind.ruleset->
+ sel_list);
+ if (tmp_str) {
+ g_string_append (stringue, tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ g_string_append (stringue, " {\n");
+ if (a_this->kind.ruleset->decl_list) {
+ tmp_str = (gchar *) cr_declaration_list_to_string2
+ (a_this->kind.ruleset->decl_list,
+ a_indent + DECLARATION_INDENT_NB, TRUE);
+ if (tmp_str) {
+ g_string_append (stringue, tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ g_string_append (stringue, "\n");
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+ }
+ g_string_append (stringue, "}");
+ result = stringue->str;
+
+ g_string_free (stringue, FALSE);
+ stringue = NULL;
+
+ if (tmp_str) {
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ return result;
+}
+
+
+/**
+ * cr_statement_font_face_rule_to_string:
+ *
+ *@a_this: the current instance of #CRStatement to consider
+ *It must be a font face rule statement.
+ *@a_indent: the number of white spaces of indentation.
+ *
+ *Serializes a font face rule statement into a string.
+ *
+ *Returns the serialized string. Must be deallocated by the caller
+ *using g_free().
+ */
+static gchar *
+cr_statement_font_face_rule_to_string (CRStatement const * a_this,
+ glong a_indent)
+{
+ gchar *result = NULL, *tmp_str = NULL ;
+ GString *stringue = NULL ;
+
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT,
+ NULL);
+
+ if (a_this->kind.font_face_rule->decl_list) {
+ stringue = (GString *) g_string_new (NULL) ;
+ g_return_val_if_fail (stringue, NULL) ;
+ if (a_indent)
+ cr_utils_dump_n_chars2 (' ', stringue,
+ a_indent);
+ g_string_append (stringue, "@font-face {\n");
+ tmp_str = (gchar *) cr_declaration_list_to_string2
+ (a_this->kind.font_face_rule->decl_list,
+ a_indent + DECLARATION_INDENT_NB, TRUE) ;
+ if (tmp_str) {
+ g_string_append (stringue,
+ tmp_str) ;
+ g_free (tmp_str) ;
+ tmp_str = NULL ;
+ }
+ g_string_append (stringue, "\n}");
+ }
+ if (stringue) {
+ result = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ stringue = NULL ;
+ }
+ return result ;
+}
+
+
+/**
+ * cr_statement_charset_to_string:
+ *
+ *Serialises an \@charset statement into a string.
+ *@a_this: the statement to serialize.
+ *@a_indent: the number of indentation spaces
+ *
+ *Returns the serialized charset statement. Must be
+ *freed by the caller using g_free().
+ */
+static gchar *
+cr_statement_charset_to_string (CRStatement const *a_this,
+ gulong a_indent)
+{
+ gchar *str = NULL ;
+ GString *stringue = NULL ;
+
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT,
+ NULL) ;
+
+ if (a_this->kind.charset_rule
+ && a_this->kind.charset_rule->charset
+ && a_this->kind.charset_rule->charset->stryng
+ && a_this->kind.charset_rule->charset->stryng->str) {
+ str = g_strndup (a_this->kind.charset_rule->charset->stryng->str,
+ a_this->kind.charset_rule->charset->stryng->len);
+ g_return_val_if_fail (str, NULL);
+ stringue = g_string_new (NULL) ;
+ g_return_val_if_fail (stringue, NULL) ;
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+ g_string_append_printf (stringue,
+ "@charset \"%s\" ;", str);
+ if (str) {
+ g_free (str);
+ str = NULL;
+ }
+ }
+ if (stringue) {
+ str = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ }
+ return str ;
+}
+
+
+/**
+ * cr_statement_at_page_rule_to_string:
+ *
+ *Serialises the at page rule statement into a string
+ *@a_this: the current instance of #CRStatement. Must
+ *be an "\@page" rule statement.
+ *
+ *Returns the serialized string. Must be freed by the caller
+ */
+static gchar *
+cr_statement_at_page_rule_to_string (CRStatement const *a_this,
+ gulong a_indent)
+{
+ GString *stringue = NULL;
+ gchar *result = NULL ;
+
+ stringue = (GString *) g_string_new (NULL) ;
+
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
+ g_string_append (stringue, "@page");
+ if (a_this->kind.page_rule->name
+ && a_this->kind.page_rule->name->stryng) {
+ g_string_append_printf
+ (stringue, " %s",
+ a_this->kind.page_rule->name->stryng->str) ;
+ } else {
+ g_string_append (stringue, " ");
+ }
+ if (a_this->kind.page_rule->pseudo
+ && a_this->kind.page_rule->pseudo->stryng) {
+ g_string_append_printf
+ (stringue, " :%s",
+ a_this->kind.page_rule->pseudo->stryng->str) ;
+ }
+ if (a_this->kind.page_rule->decl_list) {
+ gchar *str = NULL ;
+ g_string_append (stringue, " {\n");
+ str = (gchar *) cr_declaration_list_to_string2
+ (a_this->kind.page_rule->decl_list,
+ a_indent + DECLARATION_INDENT_NB, TRUE) ;
+ if (str) {
+ g_string_append (stringue, str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ g_string_append (stringue, "\n}\n");
+ }
+ result = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ stringue = NULL ;
+ return result ;
+}
+
+
+/**
+ *Serializes an \@media statement.
+ *@param a_this the current instance of #CRStatement
+ *@param a_indent the number of spaces of indentation.
+ *@return the serialized \@media statement. Must be freed
+ *by the caller using g_free().
+ */
+static gchar *
+cr_statement_media_rule_to_string (CRStatement const *a_this,
+ gulong a_indent)
+{
+ gchar *str = NULL ;
+ GString *stringue = NULL ;
+ GList const *cur = NULL;
+
+ g_return_val_if_fail (a_this->type == AT_MEDIA_RULE_STMT,
+ NULL);
+
+ if (a_this->kind.media_rule) {
+ stringue = (GString *) g_string_new (NULL) ;
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+ g_string_append (stringue, "@media");
+
+ for (cur = a_this->kind.media_rule->media_list; cur;
+ cur = cur->next) {
+ if (cur->data) {
+ gchar *str2 = cr_string_dup2
+ ((CRString const *) cur->data);
+
+ if (str2) {
+ if (cur->prev) {
+ g_string_append
+ (stringue,
+ ",");
+ }
+ g_string_append_printf
+ (stringue,
+ " %s", str2);
+ g_free (str2);
+ str2 = NULL;
+ }
+ }
+ }
+ g_string_append (stringue, " {\n");
+ str = cr_statement_list_to_string
+ (a_this->kind.media_rule->rulesets,
+ a_indent + DECLARATION_INDENT_NB) ;
+ if (str) {
+ g_string_append (stringue, str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ g_string_append (stringue, "\n}");
+ }
+ if (stringue) {
+ str = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ }
+ return str ;
+}
+
+
+static gchar *
+cr_statement_import_rule_to_string (CRStatement const *a_this,
+ gulong a_indent)
+{
+ GString *stringue = NULL ;
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ NULL) ;
+
+ if (a_this->kind.import_rule->url
+ && a_this->kind.import_rule->url->stryng) {
+ stringue = (GString *) g_string_new (NULL) ;
+ g_return_val_if_fail (stringue, NULL) ;
+ str = g_strndup (a_this->kind.import_rule->url->stryng->str,
+ a_this->kind.import_rule->url->stryng->len);
+ cr_utils_dump_n_chars2 (' ', stringue, a_indent);
+ if (str) {
+ g_string_append_printf (stringue,
+ "@import url(\"%s\")",
+ str);
+ g_free (str);
+ str = NULL ;
+ } else /*there is no url, so no import rule, get out! */
+ return NULL;
+
+ if (a_this->kind.import_rule->media_list) {
+ GList const *cur = NULL;
+
+ for (cur = a_this->kind.import_rule->media_list;
+ cur; cur = cur->next) {
+ if (cur->data) {
+ CRString const *crstr = cur->data;
+
+ if (cur->prev) {
+ g_string_append
+ (stringue, ", ");
+ }
+ if (crstr
+ && crstr->stryng
+ && crstr->stryng->str) {
+ g_string_append_len
+ (stringue,
+ crstr->stryng->str,
+ crstr->stryng->len) ;
+ }
+ }
+ }
+ }
+ g_string_append (stringue, " ;");
+ }
+ if (stringue) {
+ str = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ stringue = NULL ;
+ }
+ return str ;
+}
+
+
+/*******************
+ *public functions
+ ******************/
+
+/**
+ * cr_statement_does_buf_parses_against_core:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Tries to parse a buffer and says whether if the content of the buffer
+ *is a css statement as defined by the "Core CSS Grammar" (chapter 4 of the
+ *css spec) or not.
+ *
+ *Returns TRUE if the buffer parses against the core grammar, false otherwise.
+ */
+gboolean
+cr_statement_does_buf_parses_against_core (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ CRParser *parser = NULL;
+ enum CRStatus status = CR_OK;
+ gboolean result = FALSE;
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ g_return_val_if_fail (parser, FALSE);
+
+ status = cr_parser_set_use_core_grammar (parser, TRUE);
+ if (status != CR_OK) {
+ goto cleanup;
+ }
+
+ status = cr_parser_parse_statement_core (parser);
+ if (status == CR_OK) {
+ result = TRUE;
+ }
+
+ cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ }
+
+ return result;
+}
+
+/**
+ * cr_statement_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains a css statement and returns
+ *an instance of #CRStatement in case of successful parsing.
+ *TODO: at support of "\@import" rules.
+ *
+ *Returns the newly built instance of #CRStatement in case
+ *of successful parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding)
+{
+ CRStatement *result = NULL;
+
+ /*
+ *The strategy of this function is "brute force".
+ *It tries to parse all the types of CRStatement it knows about.
+ *I could do this a smarter way but I don't have the time now.
+ *I think I will revisit this when time of performances and
+ *pull based incremental parsing comes.
+ */
+
+ result = cr_statement_ruleset_parse_from_buf (a_buf, a_encoding);
+ if (!result) {
+ result = cr_statement_at_charset_rule_parse_from_buf
+ (a_buf, a_encoding);
+ } else {
+ goto out;
+ }
+
+ if (!result) {
+ result = cr_statement_at_media_rule_parse_from_buf
+ (a_buf, a_encoding);
+ } else {
+ goto out;
+ }
+
+ if (!result) {
+ result = cr_statement_at_charset_rule_parse_from_buf
+ (a_buf, a_encoding);
+ } else {
+ goto out;
+ }
+
+ if (!result) {
+ result = cr_statement_font_face_rule_parse_from_buf
+ (a_buf, a_encoding);
+
+ } else {
+ goto out;
+ }
+
+ if (!result) {
+ result = cr_statement_at_page_rule_parse_from_buf
+ (a_buf, a_encoding);
+ } else {
+ goto out;
+ }
+
+ if (!result) {
+ result = cr_statement_at_import_rule_parse_from_buf
+ (a_buf, a_encoding);
+ } else {
+ goto out;
+ }
+
+ out:
+ return result;
+}
+
+/**
+ * cr_statement_ruleset_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_enc: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains a ruleset statement and instanciates
+ *a #CRStatement of type RULESET_STMT.
+ *
+ *Returns the newly built instance of #CRStatement in case of successful parsing,
+ *NULL otherwise.
+ */
+CRStatement *
+cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_enc)
+{
+ enum CRStatus status = CR_OK;
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+ CRParser *parser = NULL;
+ CRDocHandler *sac_handler = NULL;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_enc, FALSE);
+
+ g_return_val_if_fail (parser, NULL);
+
+ sac_handler = cr_doc_handler_new ();
+ g_return_val_if_fail (sac_handler, NULL);
+
+ sac_handler->start_selector = parse_ruleset_start_selector_cb;
+ sac_handler->end_selector = parse_ruleset_end_selector_cb;
+ sac_handler->property = parse_ruleset_property_cb;
+ sac_handler->unrecoverable_error =
+ parse_ruleset_unrecoverable_error_cb;
+
+ cr_parser_set_sac_handler (parser, sac_handler);
+ cr_parser_try_to_skip_spaces_and_comments (parser);
+ status = cr_parser_parse_ruleset (parser);
+ if (status != CR_OK) {
+ goto cleanup;
+ }
+
+ resultptr = &result;
+ status = cr_doc_handler_get_result (sac_handler,
+ (gpointer *) resultptr);
+ if (!((status == CR_OK) && result)) {
+ if (result) {
+ cr_statement_destroy (result);
+ result = NULL;
+ }
+ }
+
+ cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ sac_handler = NULL ;
+ }
+ if (sac_handler) {
+ cr_doc_handler_unref (sac_handler);
+ sac_handler = NULL;
+ }
+ return result;
+}
+
+/**
+ * cr_statement_new_ruleset:
+ *
+ *@a_sel_list: the list of #CRSimpleSel (selectors)
+ *the rule applies to.
+ *@a_decl_list: the list of instances of #CRDeclaration
+ *that composes the ruleset.
+ *@a_media_types: a list of instances of GString that
+ *describe the media list this ruleset applies to.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRRulSet.
+ *
+ *Returns the new instance of #CRStatement or NULL if something
+ *went wrong.
+ */
+CRStatement *
+cr_statement_new_ruleset (CRStyleSheet * a_sheet,
+ CRSelector * a_sel_list,
+ CRDeclaration * a_decl_list,
+ CRStatement * a_parent_media_rule)
+{
+ CRStatement *result = NULL;
+
+ g_return_val_if_fail (a_sel_list, NULL);
+
+ if (a_parent_media_rule) {
+ g_return_val_if_fail
+ (a_parent_media_rule->type == AT_MEDIA_RULE_STMT,
+ NULL);
+ g_return_val_if_fail (a_parent_media_rule->kind.media_rule,
+ NULL);
+ }
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStatement));
+ result->type = RULESET_STMT;
+ result->kind.ruleset = (CRRuleSet *) g_try_malloc (sizeof (CRRuleSet));
+
+ if (!result->kind.ruleset) {
+ cr_utils_trace_info ("Out of memory");
+ if (result)
+ g_free (result);
+ return NULL;
+ }
+
+ memset (result->kind.ruleset, 0, sizeof (CRRuleSet));
+ result->kind.ruleset->sel_list = a_sel_list;
+ if (a_sel_list)
+ cr_selector_ref (a_sel_list);
+ result->kind.ruleset->decl_list = a_decl_list;
+
+ if (a_parent_media_rule) {
+ result->kind.ruleset->parent_media_rule = a_parent_media_rule;
+ a_parent_media_rule->kind.media_rule->rulesets =
+ cr_statement_append
+ (a_parent_media_rule->kind.media_rule->rulesets,
+ result);
+ }
+
+ cr_statement_set_parent_sheet (result, a_sheet);
+
+ return result;
+}
+
+/**
+ * cr_statement_at_media_rule_parse_from_buf:
+ *
+ *@a_buf: the input to parse.
+ *@a_enc: the encoding of the buffer.
+ *
+ *Parses a buffer that contains an "\@media" declaration
+ *and builds an \@media css statement.
+ *
+ *Returns the \@media statement, or NULL if the buffer could not
+ *be successfully parsed.
+ */
+CRStatement *
+cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_enc)
+{
+ CRParser *parser = NULL;
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+ CRDocHandler *sac_handler = NULL;
+ enum CRStatus status = CR_OK;
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_enc, FALSE);
+ if (!parser) {
+ cr_utils_trace_info ("Instanciation of the parser failed");
+ goto cleanup;
+ }
+
+ sac_handler = cr_doc_handler_new ();
+ if (!sac_handler) {
+ cr_utils_trace_info
+ ("Instanciation of the sac handler failed");
+ goto cleanup;
+ }
+
+ sac_handler->start_media = parse_at_media_start_media_cb;
+ sac_handler->start_selector = parse_at_media_start_selector_cb;
+ sac_handler->property = parse_at_media_property_cb;
+ sac_handler->end_selector = parse_at_media_end_selector_cb;
+ sac_handler->end_media = parse_at_media_end_media_cb;
+ sac_handler->unrecoverable_error =
+ parse_at_media_unrecoverable_error_cb;
+
+ status = cr_parser_set_sac_handler (parser, sac_handler);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_media (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ resultptr = &result;
+ status = cr_doc_handler_get_result (sac_handler,
+ (gpointer *) resultptr);
+ if (status != CR_OK)
+ goto cleanup;
+
+ cleanup:
+
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ sac_handler = NULL ;
+ }
+ if (sac_handler) {
+ cr_doc_handler_unref (sac_handler);
+ sac_handler = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_statement_new_at_media_rule:
+ *
+ *@a_ruleset: the ruleset statements contained
+ *in the \@media rule.
+ *@a_media: the media string list. A list of GString pointers.
+ *
+ *Instanciates an instance of #CRStatement of type
+ *AT_MEDIA_RULE_STMT (\@media ruleset).
+ *
+ */
+CRStatement *
+cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
+ CRStatement * a_rulesets, GList * a_media)
+{
+ CRStatement *result = NULL,
+ *cur = NULL;
+
+ if (a_rulesets)
+ g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStatement));
+ result->type = AT_MEDIA_RULE_STMT;
+
+ result->kind.media_rule = (CRAtMediaRule *) g_try_malloc (sizeof (CRAtMediaRule));
+ if (!result->kind.media_rule) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (result->kind.media_rule, 0, sizeof (CRAtMediaRule));
+ result->kind.media_rule->rulesets = a_rulesets;
+ for (cur = a_rulesets; cur; cur = cur->next) {
+ if (cur->type != RULESET_STMT || !cur->kind.ruleset) {
+ cr_utils_trace_info ("Bad parameter a_rulesets. "
+ "It should be a list of "
+ "correct ruleset statement only !");
+ goto error;
+ }
+ cur->kind.ruleset->parent_media_rule = result;
+ }
+
+ result->kind.media_rule->media_list = a_media;
+ if (a_sheet) {
+ cr_statement_set_parent_sheet (result, a_sheet);
+ }
+
+ return result;
+
+ error:
+ return NULL;
+}
+
+/**
+ * cr_statement_new_at_import_rule:
+ *
+ *@a_url: the url to connect to the get the file
+ *to be imported.
+ *@a_sheet: the imported parsed stylesheet.
+ *
+ *Creates a new instance of #CRStatment of type
+ *#CRAtImportRule.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
+ CRString * a_url,
+ GList * a_media_list,
+ CRStyleSheet * a_imported_sheet)
+{
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStatement));
+ result->type = AT_IMPORT_RULE_STMT;
+
+ result->kind.import_rule = (CRAtImportRule *) g_try_malloc (sizeof (CRAtImportRule));
+
+ if (!result->kind.import_rule) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+
+ memset (result->kind.import_rule, 0, sizeof (CRAtImportRule));
+ result->kind.import_rule->url = a_url;
+ result->kind.import_rule->media_list = a_media_list;
+ result->kind.import_rule->sheet = a_imported_sheet;
+ if (a_container_sheet)
+ cr_statement_set_parent_sheet (result, a_container_sheet);
+
+ return result;
+}
+
+/**
+ * cr_statement_at_import_rule_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@import" rule and
+ *instanciate a #CRStatement of type AT_IMPORT_RULE_STMT
+ *
+ *Returns the newly built instance of #CRStatement in case of
+ *a successful parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ enum CRStatus status = CR_OK;
+ CRParser *parser = NULL;
+ CRStatement *result = NULL;
+ GList *media_list = NULL;
+ CRString *import_string = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ if (!parser) {
+ cr_utils_trace_info ("Instanciation of parser failed.");
+ goto cleanup;
+ }
+
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_import (parser,
+ &media_list,
+ &import_string,
+ &location);
+ if (status != CR_OK || !import_string)
+ goto cleanup;
+
+ result = cr_statement_new_at_import_rule (NULL, import_string,
+ media_list, NULL);
+ if (result) {
+ cr_parsing_location_copy (&result->location,
+ &location) ;
+ import_string = NULL;
+ media_list = NULL;
+ }
+
+ cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+ if (media_list) {
+ for (; media_list;
+ media_list = g_list_next (media_list)) {
+ if (media_list->data) {
+ cr_string_destroy ((CRString*)media_list->data);
+ media_list->data = NULL;
+ }
+ }
+ g_list_free (media_list);
+ media_list = NULL;
+ }
+ if (import_string) {
+ cr_string_destroy (import_string);
+ import_string = NULL;
+ }
+
+ return result;
+}
+
+/**
+ * cr_statement_new_at_page_rule:
+ *
+ *@a_decl_list: a list of instances of #CRDeclarations
+ *which is actually the list of declarations that applies to
+ *this page rule.
+ *@a_selector: the page rule selector.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRAtPageRule.
+ *
+ *Returns the newly built instance of #CRStatement or NULL
+ *in case of error.
+ */
+CRStatement *
+cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
+ CRDeclaration * a_decl_list,
+ CRString * a_name, CRString * a_pseudo)
+{
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStatement));
+ result->type = AT_PAGE_RULE_STMT;
+
+ result->kind.page_rule = (CRAtPageRule *) g_try_malloc (sizeof (CRAtPageRule));
+
+ if (!result->kind.page_rule) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+
+ memset (result->kind.page_rule, 0, sizeof (CRAtPageRule));
+ if (a_decl_list) {
+ result->kind.page_rule->decl_list = a_decl_list;
+ cr_declaration_ref (a_decl_list);
+ }
+ result->kind.page_rule->name = a_name;
+ result->kind.page_rule->pseudo = a_pseudo;
+ if (a_sheet)
+ cr_statement_set_parent_sheet (result, a_sheet);
+
+ return result;
+}
+
+/**
+ * cr_statement_at_page_rule_parse_from_buf:
+ *
+ *@a_buf: the character buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@page" production and,
+ *if the parsing succeeds, builds the page statement.
+ *
+ *Returns the newly built at page statement in case of successful parsing,
+ *NULL otherwise.
+ */
+CRStatement *
+cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ enum CRStatus status = CR_OK;
+ CRParser *parser = NULL;
+ CRDocHandler *sac_handler = NULL;
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ if (!parser) {
+ cr_utils_trace_info ("Instanciation of the parser failed.");
+ goto cleanup;
+ }
+
+ sac_handler = cr_doc_handler_new ();
+ if (!sac_handler) {
+ cr_utils_trace_info
+ ("Instanciation of the sac handler failed.");
+ goto cleanup;
+ }
+
+ sac_handler->start_page = parse_page_start_page_cb;
+ sac_handler->property = parse_page_property_cb;
+ sac_handler->end_page = parse_page_end_page_cb;
+ sac_handler->unrecoverable_error = parse_page_unrecoverable_error_cb;
+
+ status = cr_parser_set_sac_handler (parser, sac_handler);
+ if (status != CR_OK)
+ goto cleanup;
+
+ /*Now, invoke the parser to parse the "@page production" */
+ cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+ status = cr_parser_parse_page (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ resultptr = &result;
+ status = cr_doc_handler_get_result (sac_handler,
+ (gpointer *) resultptr);
+
+ cleanup:
+
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ sac_handler = NULL ;
+ }
+ if (sac_handler) {
+ cr_doc_handler_unref (sac_handler);
+ sac_handler = NULL;
+ }
+ return result;
+}
+
+/**
+ * cr_statement_new_at_charset_rule:
+ *
+ *@a_charset: the string representing the charset.
+ *Note that the newly built instance of #CRStatement becomes
+ *the owner of a_charset. The caller must not free a_charset !!!.
+ *
+ *Creates a new instance of #CRStatement of type
+ *#CRAtCharsetRule.
+ *
+ *Returns the newly built instance of #CRStatement or NULL
+ *if an error arises.
+ */
+CRStatement *
+cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet,
+ CRString * a_charset)
+{
+ CRStatement *result = NULL;
+
+ g_return_val_if_fail (a_charset, NULL);
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStatement));
+ result->type = AT_CHARSET_RULE_STMT;
+
+ result->kind.charset_rule = (CRAtCharsetRule *) g_try_malloc (sizeof (CRAtCharsetRule));
+
+ if (!result->kind.charset_rule) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (result->kind.charset_rule, 0, sizeof (CRAtCharsetRule));
+ result->kind.charset_rule->charset = a_charset;
+ cr_statement_set_parent_sheet (result, a_sheet);
+
+ return result;
+}
+
+/**
+ * cr_statement_at_charset_rule_parse_from_buf:
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of the buffer.
+ *
+ *Parses a buffer that contains an '\@charset' rule and
+ *creates an instance of #CRStatement of type AT_CHARSET_RULE_STMT.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ enum CRStatus status = CR_OK;
+ CRParser *parser = NULL;
+ CRStatement *result = NULL;
+ CRString *charset = NULL;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ if (!parser) {
+ cr_utils_trace_info ("Instanciation of the parser failed.");
+ goto cleanup;
+ }
+
+ /*Now, invoke the parser to parse the "@charset production" */
+ cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+ status = cr_parser_parse_charset (parser, &charset, NULL);
+ if (status != CR_OK || !charset)
+ goto cleanup;
+
+ result = cr_statement_new_at_charset_rule (NULL, charset);
+ if (result)
+ charset = NULL;
+
+ cleanup:
+
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+ if (charset) {
+ cr_string_destroy (charset);
+ }
+
+ return result;
+}
+
+/**
+ * cr_statement_new_at_font_face_rule:
+ *
+ *@a_font_decls: a list of instances of #CRDeclaration. Each declaration
+ *is actually a font declaration.
+ *
+ *Creates an instance of #CRStatement of type #CRAtFontFaceRule.
+ *
+ *Returns the newly built instance of #CRStatement.
+ */
+CRStatement *
+cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
+ CRDeclaration * a_font_decls)
+{
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
+
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRStatement));
+ result->type = AT_FONT_FACE_RULE_STMT;
+
+ result->kind.font_face_rule = (CRAtFontFaceRule *) g_try_malloc
+ (sizeof (CRAtFontFaceRule));
+
+ if (!result->kind.font_face_rule) {
+ cr_utils_trace_info ("Out of memory");
+ g_free (result);
+ return NULL;
+ }
+ memset (result->kind.font_face_rule, 0, sizeof (CRAtFontFaceRule));
+
+ result->kind.font_face_rule->decl_list = a_font_decls;
+ if (a_sheet)
+ cr_statement_set_parent_sheet (result, a_sheet);
+
+ return result;
+}
+
+/**
+ * cr_statement_font_face_rule_parse_from_buf:
+ *
+ *
+ *@a_buf: the buffer to parse.
+ *@a_encoding: the character encoding of a_buf.
+ *
+ *Parses a buffer that contains an "\@font-face" rule and builds
+ *an instance of #CRStatement of type AT_FONT_FACE_RULE_STMT out of it.
+ *
+ *Returns the newly built instance of #CRStatement in case of successufull
+ *parsing, NULL otherwise.
+ */
+CRStatement *
+cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ CRStatement *result = NULL;
+ CRStatement **resultptr = NULL;
+ CRParser *parser = NULL;
+ CRDocHandler *sac_handler = NULL;
+ enum CRStatus status = CR_OK;
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ if (!parser)
+ goto cleanup;
+
+ sac_handler = cr_doc_handler_new ();
+ if (!sac_handler)
+ goto cleanup;
+
+ /*
+ *set sac callbacks here
+ */
+ sac_handler->start_font_face = parse_font_face_start_font_face_cb;
+ sac_handler->property = parse_font_face_property_cb;
+ sac_handler->end_font_face = parse_font_face_end_font_face_cb;
+ sac_handler->unrecoverable_error =
+ parse_font_face_unrecoverable_error_cb;
+
+ status = cr_parser_set_sac_handler (parser, sac_handler);
+ if (status != CR_OK)
+ goto cleanup;
+
+ /*
+ *cleanup spaces of comment that may be there before the real
+ *"@font-face" thing.
+ */
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ status = cr_parser_parse_font_face (parser);
+ if (status != CR_OK)
+ goto cleanup;
+
+ resultptr = &result;
+ status = cr_doc_handler_get_result (sac_handler,
+ (gpointer *) resultptr);
+ if (status != CR_OK || !result)
+ goto cleanup;
+
+ cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ sac_handler = NULL ;
+ }
+ if (sac_handler) {
+ cr_doc_handler_unref (sac_handler);
+ sac_handler = NULL;
+ }
+ return result;
+}
+
+/**
+ * cr_statement_set_parent_sheet:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_sheet: the sheet that contains the current statement.
+ *
+ *Sets the container stylesheet.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_set_parent_sheet (CRStatement * a_this, CRStyleSheet * a_sheet)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ a_this->parent_sheet = a_sheet;
+ return CR_OK;
+}
+
+/**
+ * cr_statement_get_parent_sheet:
+ *
+ *@a_this: the current #CRStatement.
+ *@a_sheet: out parameter. A pointer to the sheets that
+ *
+ *Gets the sheets that contains the current statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_get_parent_sheet (CRStatement * a_this, CRStyleSheet ** a_sheet)
+{
+ g_return_val_if_fail (a_this && a_sheet, CR_BAD_PARAM_ERROR);
+ *a_sheet = a_this->parent_sheet;
+ return CR_OK;
+}
+
+/**
+ * cr_statement_append:
+ *
+ *@a_this: the current instance of the statement list.
+ *@a_new: a_new the new instance of #CRStatement to append.
+ *
+ *Appends a new statement to the statement list.
+ *
+ *Returns the new list statement list, or NULL in cas of failure.
+ */
+CRStatement *
+cr_statement_append (CRStatement * a_this, CRStatement * a_new)
+{
+ CRStatement *cur = NULL;
+
+ g_return_val_if_fail (a_new, NULL);
+
+ if (!a_this) {
+ return a_new;
+ }
+
+ /*walk forward in the current list to find the tail list element */
+ for (cur = a_this; cur && cur->next; cur = cur->next) ;
+
+ cur->next = a_new;
+ a_new->prev = cur;
+
+ return a_this;
+}
+
+/**
+ * cr_statement_prepend:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_new: the new statement to prepend.
+ *
+ *Prepends the an instance of #CRStatement to
+ *the current statement list.
+ *
+ *Returns the new list with the new statement prepended,
+ *or NULL in case of an error.
+ */
+CRStatement *
+cr_statement_prepend (CRStatement * a_this, CRStatement * a_new)
+{
+ CRStatement *cur = NULL;
+
+ g_return_val_if_fail (a_new, NULL);
+
+ if (!a_this)
+ return a_new;
+
+ a_new->next = a_this;
+ a_this->prev = a_new;
+
+ /*walk backward in the prepended list to find the head list element */
+ for (cur = a_new; cur && cur->prev; cur = cur->prev) ;
+
+ return cur;
+}
+
+/**
+ * cr_statement_unlink:
+ *
+ *@a_this: the current statements list.
+ *@a_to_unlink: the statement to unlink from the list.
+ *
+ *Unlinks a statement from the statements list.
+ *
+ *Returns the new list where a_to_unlink has been unlinked
+ *from, or NULL in case of error.
+ */
+CRStatement *
+cr_statement_unlink (CRStatement * a_stmt)
+{
+ CRStatement *result = a_stmt;
+
+ g_return_val_if_fail (result, NULL);
+
+ /**
+ *Some sanity checks first
+ */
+ if (a_stmt->next) {
+ g_return_val_if_fail (a_stmt->next->prev == a_stmt, NULL);
+ }
+ if (a_stmt->prev) {
+ g_return_val_if_fail (a_stmt->prev->next == a_stmt, NULL);
+ }
+
+ /**
+ *Now, the real unlinking job.
+ */
+ if (a_stmt->next) {
+ a_stmt->next->prev = a_stmt->prev;
+ }
+ if (a_stmt->prev) {
+ a_stmt->prev->next = a_stmt->next;
+ }
+
+ if (a_stmt->parent_sheet
+ && a_stmt->parent_sheet->statements == a_stmt) {
+ a_stmt->parent_sheet->statements =
+ a_stmt->parent_sheet->statements->next;
+ }
+
+ a_stmt->next = NULL;
+ a_stmt->prev = NULL;
+ a_stmt->parent_sheet = NULL;
+
+ return result;
+}
+
+/**
+ * cr_statement_nr_rules:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *
+ *Gets the number of rules in the statement list;
+ *
+ *Returns number of rules in the statement list.
+ */
+gint
+cr_statement_nr_rules (CRStatement const * a_this)
+{
+ CRStatement const *cur = NULL;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, -1);
+
+ for (cur = a_this; cur; cur = cur->next)
+ nr++;
+ return nr;
+}
+
+/**
+ * cr_statement_get_from_list:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@itemnr: the index into the statement list.
+ *
+ *Use an index to get a CRStatement from the statement list.
+ *
+ *Returns CRStatement at position itemnr, if itemnr > number of statements - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_statement_get_from_list (CRStatement * a_this, int itemnr)
+{
+ CRStatement *cur = NULL;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ for (cur = a_this; cur; cur = cur->next)
+ if (nr++ == itemnr)
+ return cur;
+ return NULL;
+}
+
+/**
+ * cr_statement_ruleset_set_sel_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_sel_list: the selector list to set. Note
+ *that this function increments the ref count of a_sel_list.
+ *The sel list will be destroyed at the destruction of the
+ *current instance of #CRStatement.
+ *
+ *Sets a selector list to a ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement * a_this,
+ CRSelector * a_sel_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT,
+ CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.ruleset->sel_list)
+ cr_selector_unref (a_this->kind.ruleset->sel_list);
+
+ a_this->kind.ruleset->sel_list = a_sel_list;
+
+ if (a_sel_list)
+ cr_selector_ref (a_sel_list);
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_get_declarations:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_decl_list: out parameter. A pointer to the returned
+ *list of declaration. Must not be NULL.
+ *
+ *Gets a pointer to the list of declaration contained
+ *in the ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code if something
+ *bad happened.
+ */
+enum CRStatus
+cr_statement_ruleset_get_declarations (CRStatement * a_this,
+ CRDeclaration ** a_decl_list)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset
+ && a_decl_list, CR_BAD_PARAM_ERROR);
+
+ *a_decl_list = a_this->kind.ruleset->decl_list;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_get_sel_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_list: out parameter. The returned selector list,
+ *if and only if the function returned CR_OK.
+ *
+ *Gets a pointer to the selector list contained in
+ *the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement const * a_this, CRSelector ** a_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ *a_list = a_this->kind.ruleset->sel_list;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_set_decl_list:
+ *
+ *@a_this: the current ruleset statement.
+ *@a_list: the declaration list to be added to the current
+ *ruleset statement.
+ *
+ *Sets a declaration list to the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement * a_this,
+ CRDeclaration * a_list)
+{
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.ruleset->decl_list == a_list)
+ return CR_OK;
+
+ if (a_this->kind.ruleset->sel_list) {
+ cr_declaration_destroy (a_this->kind.ruleset->decl_list);
+ }
+
+ a_this->kind.ruleset->sel_list = NULL;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_append_decl2:
+ *
+ *@a_this: the current statement.
+ *@a_prop: the property of the declaration.
+ *@a_value: the value of the declaration.
+ *
+ *Appends a declaration to the current ruleset statement.
+ *
+ *Returns CR_OK upon successful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement * a_this,
+ CRString * a_prop,
+ CRTerm * a_value)
+{
+ CRDeclaration *new_decls = NULL;
+
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ new_decls = cr_declaration_append2
+ (a_this->kind.ruleset->decl_list,
+ a_prop, a_value);
+ g_return_val_if_fail (new_decls, CR_ERROR);
+ a_this->kind.ruleset->decl_list = new_decls;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_ruleset_append_decl:
+ *
+ *Appends a declaration to the current statement.
+ *
+ *@a_this: the current statement.
+ *@a_declaration: the declaration to append.
+ *
+ *Returns CR_OK upon sucessful completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement * a_this,
+ CRDeclaration * a_decl)
+{
+ CRDeclaration *new_decls = NULL;
+
+ g_return_val_if_fail (a_this && a_this->type == RULESET_STMT
+ && a_this->kind.ruleset, CR_BAD_PARAM_ERROR);
+
+ new_decls = cr_declaration_append
+ (a_this->kind.ruleset->decl_list, a_decl);
+ g_return_val_if_fail (new_decls, CR_ERROR);
+ a_this->kind.ruleset->decl_list = new_decls;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_set_imported_sheet:
+ *
+ *Sets a stylesheet to the current \@import rule.
+ *@a_this: the current \@import rule.
+ *@a_sheet: the stylesheet. The stylesheet is owned
+ *by the current instance of #CRStatement, that is, the
+ *stylesheet will be destroyed when the current instance
+ *of #CRStatement is destroyed.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_imported_sheet (CRStatement * a_this,
+ CRStyleSheet * a_sheet)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR);
+
+ a_this->kind.import_rule->sheet = a_sheet;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_get_imported_sheet:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_sheet: out parameter. The returned stylesheet if and
+ *only if the function returns CR_OK.
+ *
+ *Gets the stylesheet contained by the \@import rule statement.
+ *Returns CR_OK upon sucessful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_imported_sheet (CRStatement * a_this,
+ CRStyleSheet ** a_sheet)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR);
+ *a_sheet = a_this->kind.import_rule->sheet;
+ return CR_OK;
+
+}
+
+/**
+ * cr_statement_at_import_rule_set_url:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_url: the url to set.
+ *
+ *Sets an url to the current \@import rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement * a_this,
+ CRString * a_url)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.import_rule->url) {
+ cr_string_destroy (a_this->kind.import_rule->url);
+ }
+
+ a_this->kind.import_rule->url = a_url;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_import_rule_get_url:
+ *
+ *@a_this: the current \@import rule statement.
+ *@a_url: out parameter. The returned url if
+ *and only if the function returned CR_OK.
+ *
+ *Gets the url of the \@import rule statement.
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement const * a_this,
+ CRString ** a_url)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_this->kind.import_rule,
+ CR_BAD_PARAM_ERROR);
+
+ *a_url = a_this->kind.import_rule->url;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_media_nr_rules:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *
+ *Returns the number of rules in the media rule;
+ */
+int
+cr_statement_at_media_nr_rules (CRStatement const * a_this)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_MEDIA_RULE_STMT
+ && a_this->kind.media_rule, CR_BAD_PARAM_ERROR);
+
+ return cr_statement_nr_rules (a_this->kind.media_rule->rulesets);
+}
+
+/**
+ * cr_statement_at_media_get_from_list:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@itemnr: the index into the media rule list of rules.
+ *
+ *Use an index to get a CRStatement from the media rule list of rules.
+ *
+ *Returns CRStatement at position itemnr, if itemnr > number of rules - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_statement_at_media_get_from_list (CRStatement * a_this, int itemnr)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_MEDIA_RULE_STMT
+ && a_this->kind.media_rule, NULL);
+
+ return cr_statement_get_from_list (a_this->kind.media_rule->rulesets,
+ itemnr);
+}
+
+/**
+ * cr_statement_at_page_rule_set_declarations:
+ *
+ *@a_this: the current \@page rule statement.
+ *@a_decl_list: the declaration list to add. Will be freed
+ *by the current instance of #CRStatement when it is destroyed.
+ *
+ *Sets a declaration list to the current \@page rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement * a_this,
+ CRDeclaration * a_decl_list)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.page_rule->decl_list) {
+ cr_declaration_unref (a_this->kind.page_rule->decl_list);
+ }
+
+ a_this->kind.page_rule->decl_list = a_decl_list;
+
+ if (a_decl_list) {
+ cr_declaration_ref (a_decl_list);
+ }
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_page_rule_get_declarations:
+ *
+ *@a_this: the current \@page rule statement.
+ *@a_decl_list: out parameter. The returned declaration list.
+ *
+ *Gets the declaration list associated to the current \@page rule
+ *statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement * a_this,
+ CRDeclaration ** a_decl_list)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule, CR_BAD_PARAM_ERROR);
+
+ *a_decl_list = a_this->kind.page_rule->decl_list;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_charset_rule_set_charset:
+ *
+ *
+ *@a_this: the current \@charset rule statement.
+ *@a_charset: the charset to set.
+ *
+ *Sets the charset of the current \@charset rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement * a_this,
+ CRString * a_charset)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT
+ && a_this->kind.charset_rule,
+ CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.charset_rule->charset) {
+ cr_string_destroy (a_this->kind.charset_rule->charset);
+ }
+ a_this->kind.charset_rule->charset = a_charset;
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_charset_rule_get_charset:
+ *@a_this: the current \@charset rule statement.
+ *@a_charset: out parameter. The returned charset string if
+ *and only if the function returned CR_OK.
+ *
+ *Gets the charset string associated to the current
+ *\@charset rule statement.
+ *
+ * Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement const * a_this,
+ CRString ** a_charset)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_CHARSET_RULE_STMT
+ && a_this->kind.charset_rule,
+ CR_BAD_PARAM_ERROR);
+
+ *a_charset = a_this->kind.charset_rule->charset;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_set_decls:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_decls: the declarations list to set.
+ *
+ *Sets a declaration list to the current \@font-face rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement * a_this,
+ CRDeclaration * a_decls)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR);
+
+ if (a_this->kind.font_face_rule->decl_list) {
+ cr_declaration_unref (a_this->kind.font_face_rule->decl_list);
+ }
+
+ a_this->kind.font_face_rule->decl_list = a_decls;
+ cr_declaration_ref (a_decls);
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_get_decls:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_decls: out parameter. The returned declaration list if
+ *and only if this function returns CR_OK.
+ *
+ *Gets the declaration list associated to the current instance
+ *of \@font-face rule statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement * a_this,
+ CRDeclaration ** a_decls)
+{
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR);
+
+ *a_decls = a_this->kind.font_face_rule->decl_list;
+
+ return CR_OK;
+}
+
+/**
+ * cr_statement_at_font_face_rule_add_decl:
+ *
+ *@a_this: the current \@font-face rule statement.
+ *@a_prop: the property of the declaration.
+ *@a_value: the value of the declaration.
+ *
+ *Adds a declaration to the current \@font-face rule
+ *statement.
+ *
+ *Returns CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement * a_this,
+ CRString * a_prop, CRTerm * a_value)
+{
+ CRDeclaration *decls = NULL;
+
+ g_return_val_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT
+ && a_this->kind.font_face_rule,
+ CR_BAD_PARAM_ERROR);
+
+ decls = cr_declaration_append2
+ (a_this->kind.font_face_rule->decl_list,
+ a_prop, a_value);
+
+ g_return_val_if_fail (decls, CR_ERROR);
+
+ if (a_this->kind.font_face_rule->decl_list == NULL)
+ cr_declaration_ref (decls);
+
+ a_this->kind.font_face_rule->decl_list = decls;
+
+ return CR_OK;
+}
+
+
+/**
+ * cr_statement_to_string:
+ *
+ *@a_this: the current statement to serialize
+ *@a_indent: the number of white space of indentation.
+ *
+ *Serializes a css statement into a string
+ *
+ *Returns the serialized statement. Must be freed by the caller
+ *using g_free().
+ */
+gchar *
+cr_statement_to_string (CRStatement const * a_this, gulong a_indent)
+{
+ gchar *str = NULL ;
+
+ if (!a_this)
+ return NULL;
+
+ switch (a_this->type) {
+ case RULESET_STMT:
+ str = cr_statement_ruleset_to_string
+ (a_this, a_indent);
+ break;
+
+ case AT_FONT_FACE_RULE_STMT:
+ str = cr_statement_font_face_rule_to_string
+ (a_this, a_indent) ;
+ break;
+
+ case AT_CHARSET_RULE_STMT:
+ str = cr_statement_charset_to_string
+ (a_this, a_indent);
+ break;
+
+ case AT_PAGE_RULE_STMT:
+ str = cr_statement_at_page_rule_to_string
+ (a_this, a_indent);
+ break;
+
+ case AT_MEDIA_RULE_STMT:
+ str = cr_statement_media_rule_to_string
+ (a_this, a_indent);
+ break;
+
+ case AT_IMPORT_RULE_STMT:
+ str = cr_statement_import_rule_to_string
+ (a_this, a_indent);
+ break;
+
+ default:
+ cr_utils_trace_info ("Statement unrecognized");
+ break;
+ }
+ return str ;
+}
+
+gchar*
+cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent)
+{
+ CRStatement const *cur_stmt = NULL ;
+ GString *stringue = NULL ;
+ gchar *str = NULL ;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ stringue = g_string_new (NULL) ;
+ if (!stringue) {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ for (cur_stmt = a_this ; cur_stmt;
+ cur_stmt = cur_stmt->next) {
+ str = cr_statement_to_string (cur_stmt, a_indent) ;
+ if (str) {
+ if (!cur_stmt->prev) {
+ g_string_append (stringue, str) ;
+ } else {
+ g_string_append_printf
+ (stringue, "\n%s", str) ;
+ }
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+ str = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ return str ;
+}
+
+/**
+ * cr_statement_dump:
+ *
+ *@a_this: the current css2 statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentation characters.
+ *
+ *Dumps the css2 statement to a file.
+ */
+void
+cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+ gchar *str = NULL ;
+
+ if (!a_this)
+ return;
+
+ str = cr_statement_to_string (a_this, a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s",str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ * cr_statement_dump_ruleset:
+ *
+ *@a_this: the current instance of #CRStatement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces to add.
+ *
+ *Dumps a ruleset statement to a file.
+ */
+void
+cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
+{
+ gchar *str = NULL;
+
+ g_return_if_fail (a_fp && a_this);
+ str = cr_statement_ruleset_to_string (a_this, a_indent);
+ if (str) {
+ fprintf (a_fp, "%s", str);
+ g_free (str);
+ str = NULL;
+ }
+}
+
+/**
+ * cr_statement_dump_font_face_rule:
+ *
+ *@a_this: the current instance of font face rule statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentation.
+ *
+ *Dumps a font face rule statement to a file.
+ */
+void
+cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
+ glong a_indent)
+{
+ gchar *str = NULL ;
+ g_return_if_fail (a_this
+ && a_this->type == AT_FONT_FACE_RULE_STMT);
+
+ str = cr_statement_font_face_rule_to_string (a_this,
+ a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ * cr_statement_dump_charset:
+ *
+ *@a_this: the current instance of the \@charset rule statement.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces.
+ *
+ *Dumps an \@charset rule statement to a file.
+ */
+void
+cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+ gchar *str = NULL;
+
+ g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
+
+ str = cr_statement_charset_to_string (a_this,
+ a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+
+/**
+ * cr_statement_dump_page:
+ *
+ *@a_this: the statement to dump on stdout.
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of indentation white spaces.
+ *
+ *Dumps an \@page rule statement on stdout.
+ */
+void
+cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
+{
+ gchar *str = NULL;
+
+ g_return_if_fail (a_this
+ && a_this->type == AT_PAGE_RULE_STMT
+ && a_this->kind.page_rule);
+
+ str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s", str);
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+
+/**
+ * cr_statement_dump_media_rule:
+ *
+ *@a_this: the statement to dump.
+ *@a_fp: the destination file pointer
+ *@a_indent: the number of white spaces indentation.
+ *
+ *Dumps an \@media rule statement to a file.
+ */
+void
+cr_statement_dump_media_rule (CRStatement const * a_this,
+ FILE * a_fp,
+ gulong a_indent)
+{
+ gchar *str = NULL ;
+ g_return_if_fail (a_this->type == AT_MEDIA_RULE_STMT);
+
+ str = cr_statement_media_rule_to_string (a_this, a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ * cr_statement_dump_import_rule:
+ *
+ *@a_fp: the destination file pointer.
+ *@a_indent: the number of white space indentations.
+ *
+ *Dumps an \@import rule statement to a file.
+ */
+void
+cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
+ gulong a_indent)
+{
+ gchar *str = NULL ;
+ g_return_if_fail (a_this
+ && a_this->type == AT_IMPORT_RULE_STMT
+ && a_fp
+ && a_this->kind.import_rule);
+
+ str = cr_statement_import_rule_to_string (a_this, a_indent) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ * cr_statement_destroy:
+ *
+ * @a_this: the current instance of #CRStatement.
+ *
+ *Destructor of #CRStatement.
+ */
+void
+cr_statement_destroy (CRStatement * a_this)
+{
+ CRStatement *cur = NULL;
+
+ g_return_if_fail (a_this);
+
+ /*go get the tail of the list */
+ for (cur = a_this; cur && cur->next; cur = cur->next) {
+ cr_statement_clear (cur);
+ }
+
+ if (cur)
+ cr_statement_clear (cur);
+
+ if (cur->prev == NULL) {
+ g_free (a_this);
+ return;
+ }
+
+ /*walk backward and free next element */
+ for (cur = cur->prev; cur && cur->prev; cur = cur->prev) {
+ if (cur->next) {
+ g_free (cur->next);
+ cur->next = NULL;
+ }
+ }
+
+ if (!cur)
+ return;
+
+ /*free the one remaining list */
+ if (cur->next) {
+ g_free (cur->next);
+ cur->next = NULL;
+ }
+
+ g_free (cur);
+ cur = NULL;
+}
diff --git a/src/3rdparty/libcroco/cr-statement.h b/src/3rdparty/libcroco/cr-statement.h
new file mode 100644
index 000000000..74a233055
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-statement.h
@@ -0,0 +1,440 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include "cr-utils.h"
+#include "cr-term.h"
+#include "cr-selector.h"
+#include "cr-declaration.h"
+
+#ifndef __CR_STATEMENT_H__
+#define __CR_STATEMENT_H__
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRStatement class.
+ */
+
+/*
+ *forward declaration of CRStyleSheet which is defined in
+ *cr-stylesheet.h
+ */
+
+struct _CRStatement ;
+
+/*
+ *typedef struct _CRStatement CRStatement ;
+ *this is forward declared in
+ *cr-declaration.h already.
+ */
+
+struct _CRAtMediaRule ;
+typedef struct _CRAtMediaRule CRAtMediaRule ;
+
+typedef struct _CRRuleSet CRRuleSet ;
+
+/**
+ *The abstraction of a css ruleset.
+ *A ruleset is made of a list of selectors,
+ *followed by a list of declarations.
+ */
+struct _CRRuleSet
+{
+ /**A list of instances of #CRSimpeSel*/
+ CRSelector *sel_list ;
+
+ /**A list of instances of #CRDeclaration*/
+ CRDeclaration *decl_list ;
+
+ /**
+ *The parent media rule, or NULL if
+ *no parent media rule exists.
+ */
+ CRStatement *parent_media_rule ;
+} ;
+
+/*
+ *a forward declaration of CRStylesheet.
+ *CRStylesheet is actually declared in
+ *cr-stylesheet.h
+ */
+struct _CRStyleSheet ;
+typedef struct _CRStyleSheet CRStyleSheet;
+
+
+/**The \@import rule abstraction.*/
+typedef struct _CRAtImportRule CRAtImportRule ;
+struct _CRAtImportRule
+{
+ /**the url of the import rule*/
+ CRString *url ;
+
+ GList *media_list ;
+
+ /**
+ *the stylesheet fetched from the url, if any.
+ *this is not "owned" by #CRAtImportRule which means
+ *it is not destroyed by the destructor of #CRAtImportRule.
+ */
+ CRStyleSheet * sheet;
+};
+
+
+/**abstraction of an \@media rule*/
+struct _CRAtMediaRule
+{
+ GList *media_list ;
+ CRStatement *rulesets ;
+} ;
+
+
+typedef struct _CRAtPageRule CRAtPageRule ;
+/**The \@page rule abstraction*/
+struct _CRAtPageRule
+{
+ /**a list of instances of #CRDeclaration*/
+ CRDeclaration *decl_list ;
+
+ /**page selector. Is a pseudo selector*/
+ CRString *name ;
+ CRString *pseudo ;
+} ;
+
+/**The \@charset rule abstraction*/
+typedef struct _CRAtCharsetRule CRAtCharsetRule ;
+struct _CRAtCharsetRule
+{
+ CRString * charset ;
+};
+
+/**The abstaction of the \@font-face rule.*/
+typedef struct _CRAtFontFaceRule CRAtFontFaceRule ;
+struct _CRAtFontFaceRule
+{
+ /*a list of instanaces of #CRDeclaration*/
+ CRDeclaration *decl_list ;
+} ;
+
+
+/**
+ *The possible types of css2 statements.
+ */
+enum CRStatementType
+{
+ /**
+ *A generic css at-rule
+ *each unknown at-rule will
+ *be of this type.
+ */
+
+ /**A css at-rule*/
+ AT_RULE_STMT = 0,
+
+ /*A css ruleset*/
+ RULESET_STMT,
+
+ /**A css2 import rule*/
+ AT_IMPORT_RULE_STMT,
+
+ /**A css2 media rule*/
+ AT_MEDIA_RULE_STMT,
+
+ /**A css2 page rule*/
+ AT_PAGE_RULE_STMT,
+
+ /**A css2 charset rule*/
+ AT_CHARSET_RULE_STMT,
+
+ /**A css2 font face rule*/
+ AT_FONT_FACE_RULE_STMT
+} ;
+
+
+/**
+ *The abstraction of css statement as defined
+ *in the chapter 4 and appendix D.1 of the css2 spec.
+ *A statement is actually a double chained list of
+ *statements.A statement can be a ruleset, an \@import
+ *rule, an \@page rule etc ...
+ */
+struct _CRStatement
+{
+ /**
+ *The type of the statement.
+ */
+ enum CRStatementType type ;
+
+ union
+ {
+ CRRuleSet *ruleset ;
+ CRAtImportRule *import_rule ;
+ CRAtMediaRule *media_rule ;
+ CRAtPageRule *page_rule ;
+ CRAtCharsetRule *charset_rule ;
+ CRAtFontFaceRule *font_face_rule ;
+ } kind ;
+
+ /*
+ *the specificity of the selector
+ *that matched this statement.
+ *This is only used by the cascading
+ *order determination algorithm.
+ */
+ gulong specificity ;
+
+ /*
+ *the style sheet that contains
+ *this css statement.
+ */
+ CRStyleSheet *parent_sheet ;
+ CRStatement *next ;
+ CRStatement *prev ;
+
+ CRParsingLocation location ;
+
+ /**
+ *a custom pointer useable by
+ *applications that use libcroco.
+ *libcroco itself will never modify
+ *this pointer.
+ */
+ gpointer app_data ;
+
+ /**
+ *a custom pointer used
+ *by the upper layers of libcroco.
+ *application should never use this
+ *pointer.
+ */
+ gpointer croco_data ;
+
+} ;
+
+
+gboolean
+cr_statement_does_buf_parses_against_core (const guchar *a_buf,
+ enum CREncoding a_encoding) ;
+CRStatement *
+cr_statement_parse_from_buf (const guchar *a_buf,
+ enum CREncoding a_encoding) ;
+CRStatement*
+cr_statement_new_ruleset (CRStyleSheet *a_sheet,
+ CRSelector *a_sel_list,
+ CRDeclaration *a_decl_list,
+ CRStatement *a_media_rule) ;
+CRStatement *
+cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_enc) ;
+
+CRStatement*
+cr_statement_new_at_import_rule (CRStyleSheet *a_container_sheet,
+ CRString *a_url,
+ GList *a_media_list,
+ CRStyleSheet *a_imported_sheet) ;
+
+CRStatement *
+cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding) ;
+
+CRStatement *
+cr_statement_new_at_media_rule (CRStyleSheet *a_sheet,
+ CRStatement *a_ruleset,
+ GList *a_media) ;
+CRStatement *
+cr_statement_at_media_rule_parse_from_buf (const guchar *a_buf,
+ enum CREncoding a_enc) ;
+
+CRStatement *
+cr_statement_new_at_charset_rule (CRStyleSheet *a_sheet,
+ CRString *a_charset) ;
+CRStatement *
+cr_statement_at_charset_rule_parse_from_buf (const guchar *a_buf,
+ enum CREncoding a_encoding);
+
+
+CRStatement *
+cr_statement_new_at_font_face_rule (CRStyleSheet *a_sheet,
+ CRDeclaration *a_font_decls) ;
+CRStatement *
+cr_statement_font_face_rule_parse_from_buf (const guchar *a_buf,
+ enum CREncoding a_encoding) ;
+
+CRStatement *
+cr_statement_new_at_page_rule (CRStyleSheet *a_sheet,
+ CRDeclaration *a_decl_list,
+ CRString *a_name,
+ CRString *a_pseudo) ;
+CRStatement *
+cr_statement_at_page_rule_parse_from_buf (const guchar *a_buf,
+ enum CREncoding a_encoding) ;
+
+enum CRStatus
+cr_statement_set_parent_sheet (CRStatement *a_this,
+ CRStyleSheet *a_sheet) ;
+
+enum CRStatus
+cr_statement_get_parent_sheet (CRStatement *a_this,
+ CRStyleSheet **a_sheet) ;
+
+CRStatement *
+cr_statement_append (CRStatement *a_this,
+ CRStatement *a_new) ;
+
+CRStatement*
+cr_statement_prepend (CRStatement *a_this,
+ CRStatement *a_new) ;
+
+CRStatement *
+cr_statement_unlink (CRStatement *a_stmt) ;
+
+enum CRStatus
+cr_statement_ruleset_set_sel_list (CRStatement *a_this,
+ CRSelector *a_sel_list) ;
+
+enum CRStatus
+cr_statement_ruleset_get_sel_list (CRStatement const *a_this,
+ CRSelector **a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_set_decl_list (CRStatement *a_this,
+ CRDeclaration *a_list) ;
+
+enum CRStatus
+cr_statement_ruleset_get_declarations (CRStatement *a_this,
+ CRDeclaration **a_decl_list) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl2 (CRStatement *a_this,
+ CRString *a_prop, CRTerm *a_value) ;
+
+enum CRStatus
+cr_statement_ruleset_append_decl (CRStatement *a_this,
+ CRDeclaration *a_decl) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_imported_sheet (CRStatement *a_this,
+ CRStyleSheet *a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_imported_sheet (CRStatement *a_this,
+ CRStyleSheet **a_sheet) ;
+
+enum CRStatus
+cr_statement_at_import_rule_set_url (CRStatement *a_this,
+ CRString *a_url) ;
+
+enum CRStatus
+cr_statement_at_import_rule_get_url (CRStatement const *a_this,
+ CRString **a_url) ;
+
+gint
+cr_statement_at_media_nr_rules (CRStatement const *a_this) ;
+
+CRStatement *
+cr_statement_at_media_get_from_list (CRStatement *a_this, int itemnr) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_sel (CRStatement *a_this,
+ CRSelector *a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_sel (CRStatement const *a_this,
+ CRSelector **a_sel) ;
+
+enum CRStatus
+cr_statement_at_page_rule_set_declarations (CRStatement *a_this,
+ CRDeclaration *a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_page_rule_get_declarations (CRStatement *a_this,
+ CRDeclaration **a_decl_list) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_set_charset (CRStatement *a_this,
+ CRString *a_charset) ;
+
+enum CRStatus
+cr_statement_at_charset_rule_get_charset (CRStatement const *a_this,
+ CRString **a_charset) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_set_decls (CRStatement *a_this,
+ CRDeclaration *a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_get_decls (CRStatement *a_this,
+ CRDeclaration **a_decls) ;
+
+enum CRStatus
+cr_statement_at_font_face_rule_add_decl (CRStatement *a_this,
+ CRString *a_prop,
+ CRTerm *a_value) ;
+
+gchar *
+cr_statement_to_string (CRStatement const * a_this, gulong a_indent) ;
+
+gchar*
+cr_statement_list_to_string (CRStatement const *a_this, gulong a_indent) ;
+
+void
+cr_statement_dump (CRStatement const *a_this, FILE *a_fp, gulong a_indent) ;
+
+void
+cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp,
+ glong a_indent) ;
+
+void
+cr_statement_dump_font_face_rule (CRStatement const * a_this,
+ FILE * a_fp,
+ glong a_indent) ;
+
+void
+cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp,
+ gulong a_indent) ;
+
+
+void
+cr_statement_dump_media_rule (CRStatement const * a_this,
+ FILE * a_fp,
+ gulong a_indent) ;
+
+void
+cr_statement_dump_import_rule (CRStatement const * a_this, FILE * a_fp,
+ gulong a_indent) ;
+void
+cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp,
+ gulong a_indent) ;
+gint
+cr_statement_nr_rules (CRStatement const *a_this) ;
+
+CRStatement *
+cr_statement_get_from_list (CRStatement *a_this, int itemnr) ;
+
+void
+cr_statement_destroy (CRStatement *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_STATEMENT_H__*/
diff --git a/src/3rdparty/libcroco/cr-string.c b/src/3rdparty/libcroco/cr-string.c
new file mode 100644
index 000000000..86ad3432c
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-string.c
@@ -0,0 +1,168 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <string.h>
+#include "cr-string.h"
+
+/**
+ *Instanciates a #CRString
+ *@return the newly instanciated #CRString
+ *Must be freed with cr_string_destroy().
+ */
+CRString *
+cr_string_new (void)
+{
+ CRString *result = NULL ;
+
+ result = (CRString *) g_try_malloc (sizeof (CRString)) ;
+ if (!result) {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ memset (result, 0, sizeof (CRString)) ;
+ result->stryng = g_string_new (NULL) ;
+ return result ;
+}
+
+/**
+ *Instanciate a string and initialise it to
+ *a_string.
+ *@param a_string the initial string
+ *@return the newly instanciated string.
+ */
+CRString *
+cr_string_new_from_string (const gchar * a_string)
+{
+ CRString *result = NULL ;
+
+ result = cr_string_new () ;
+ if (!result) {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ if (a_string)
+ g_string_append (result->stryng, a_string) ;
+ return result ;
+}
+
+/**
+ *Instanciates a #CRString from an instance of GString.
+ *@param a_string the input string that will be copied into
+ *the newly instanciated #CRString
+ *@return the newly instanciated #CRString.
+ */
+CRString *
+cr_string_new_from_gstring (GString const *a_string)
+{
+ CRString *result = NULL ;
+
+ result = cr_string_new () ;
+ if (!result) {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ if (a_string) {
+ g_string_append_len (result->stryng,
+ a_string->str,
+ a_string->len);
+
+ }
+ return result ;
+}
+
+CRString *
+cr_string_dup (CRString const *a_this)
+{
+ CRString *result = NULL ;
+ g_return_val_if_fail (a_this, NULL) ;
+
+ result = cr_string_new_from_gstring (a_this->stryng) ;
+ if (!result) {
+ cr_utils_trace_info ("Out of memory") ;
+ return NULL ;
+ }
+ cr_parsing_location_copy (&result->location,
+ &a_this->location) ;
+ return result ;
+}
+
+gchar *
+cr_string_dup2 (CRString const *a_this)
+{
+ gchar *result = NULL ;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ if (a_this
+ && a_this->stryng
+ && a_this->stryng->str) {
+ result = g_strndup (a_this->stryng->str,
+ a_this->stryng->len) ;
+ }
+ return result ;
+}
+
+/**
+ *Returns a pointer to the internal raw NULL terminated string
+ *of the current instance of #CRString.
+ *@param a_this the current instance of #CRString
+ */
+const gchar *
+cr_string_peek_raw_str (CRString const *a_this)
+{
+ g_return_val_if_fail (a_this, NULL) ;
+
+ if (a_this->stryng && a_this->stryng->str)
+ return a_this->stryng->str ;
+ return NULL ;
+}
+
+/**
+ *Returns the length of the internal raw NULL terminated
+ *string of the current instance of #CRString.
+ *@param a_this the current instance of #CRString.
+ *@return the len of the internal raw NULL termninated string,
+ *of -1 if no length can be returned.
+ */
+gint
+cr_string_peek_raw_str_len (CRString const *a_this)
+{
+ g_return_val_if_fail (a_this && a_this->stryng,
+ -1) ;
+ return a_this->stryng->len ;
+}
+
+/**
+ *@param a_this the #CRString to destroy.
+ */
+void
+cr_string_destroy (CRString *a_this)
+{
+ g_return_if_fail (a_this) ;
+
+ if (a_this->stryng) {
+ g_string_free (a_this->stryng, TRUE) ;
+ a_this->stryng = NULL ;
+ }
+ g_free (a_this) ;
+}
diff --git a/src/3rdparty/libcroco/cr-string.h b/src/3rdparty/libcroco/cr-string.h
new file mode 100644
index 000000000..2700f0e2e
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-string.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * See COPYRIGHTS file for copyright information.
+ */
+
+/**
+ *@file
+ *Declaration file of the #CRString class.
+ */
+
+#ifndef __CR_STRING_H__
+#define __CR_STRING_H__
+
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+typedef struct _CRString CRString ;
+
+/**
+ *This is a ship implementation of string based on GString.
+ *Actually, the aim of CRString is to store the parsing location
+ *(line,column,byte offset) at which a given string has been parsed
+ *in the input CSS.
+ *So this class has a gstring field of type GString that users can
+ *freely manipulate, and also a CRParginLocation type where the
+ *parsing location is store. If you don't want to deal with parsing
+ *location stuffs, then use GString instead. If we were in C++ for example,
+ *CRString would just inherit GString and just add accessors to
+ *the CRParsingLocation data ... but we are not and we still have
+ *to provide the parsing location information.
+ */
+struct _CRString {
+ /**
+ *The GString where all the string
+ *operation happen.
+ */
+ GString *stryng ;
+ /**
+ *The parsing location storage area.
+ */
+ CRParsingLocation location ;
+} ;
+
+CRString * cr_string_new (void) ;
+
+CRString *cr_string_new_from_string (const gchar * a_string) ;
+CRString * cr_string_new_from_gstring (GString const *a_string) ;
+CRString *cr_string_dup (CRString const *a_this) ;
+gchar *cr_string_dup2 (CRString const *a_this) ;
+const gchar *cr_string_peek_raw_str (CRString const *a_this) ;
+gint cr_string_peek_raw_str_len (CRString const *a_this) ;
+void cr_string_destroy (CRString *a_this) ;
+
+G_END_DECLS
+
+#endif
diff --git a/src/3rdparty/libcroco/cr-style.c b/src/3rdparty/libcroco/cr-style.c
new file mode 100644
index 000000000..2b865c248
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-style.c
@@ -0,0 +1,2850 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of
+ * the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the
+ * GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * see COPYRIGTHS file for copyright information
+ */
+
+#include <string.h>
+#include "cr-style.h"
+
+/**
+ *@file
+ *The definition of the #CRStyle class.
+ */
+
+/**
+ *A property ID.
+ *Each supported css property has an ID which is
+ *an entry into a property "population" jump table.
+ *each entry of the property population jump table
+ *contains code to transform the literal form of
+ *a property value into a strongly typed value.
+ */
+enum CRPropertyID {
+ PROP_ID_NOT_KNOWN = 0,
+ PROP_ID_PADDING_TOP,
+ PROP_ID_PADDING_RIGHT,
+ PROP_ID_PADDING_BOTTOM,
+ PROP_ID_PADDING_LEFT,
+ PROP_ID_PADDING,
+ PROP_ID_BORDER_TOP_WIDTH,
+ PROP_ID_BORDER_RIGHT_WIDTH,
+ PROP_ID_BORDER_BOTTOM_WIDTH,
+ PROP_ID_BORDER_LEFT_WIDTH,
+ PROP_ID_BORDER_WIDTH,
+ PROP_ID_BORDER_TOP_STYLE,
+ PROP_ID_BORDER_RIGHT_STYLE,
+ PROP_ID_BORDER_BOTTOM_STYLE,
+ PROP_ID_BORDER_LEFT_STYLE,
+ PROP_ID_BORDER_STYLE,
+ PROP_ID_BORDER_TOP_COLOR,
+ PROP_ID_BORDER_RIGHT_COLOR,
+ PROP_ID_BORDER_BOTTOM_COLOR,
+ PROP_ID_BORDER_LEFT_COLOR,
+ PROP_ID_BORDER_TOP,
+ PROP_ID_BORDER_RIGHT,
+ PROP_ID_BORDER_BOTTOM,
+ PROP_ID_BORDER_LEFT,
+ PROP_ID_BORDER,
+ PROP_ID_MARGIN_TOP,
+ PROP_ID_MARGIN_RIGHT,
+ PROP_ID_MARGIN_BOTTOM,
+ PROP_ID_MARGIN_LEFT,
+ PROP_ID_MARGIN,
+ PROP_ID_DISPLAY,
+ PROP_ID_POSITION,
+ PROP_ID_TOP,
+ PROP_ID_RIGHT,
+ PROP_ID_BOTTOM,
+ PROP_ID_LEFT,
+ PROP_ID_FLOAT,
+ PROP_ID_WIDTH,
+ PROP_ID_COLOR,
+ PROP_ID_BACKGROUND_COLOR,
+ PROP_ID_FONT_FAMILY,
+ PROP_ID_FONT_SIZE,
+ PROP_ID_FONT_STYLE,
+ PROP_ID_FONT_WEIGHT,
+ PROP_ID_WHITE_SPACE,
+ /*should be the last one. */
+ NB_PROP_IDS
+};
+
+typedef struct _CRPropertyDesc CRPropertyDesc;
+
+struct _CRPropertyDesc {
+ const gchar *name;
+ enum CRPropertyID prop_id;
+};
+
+static CRPropertyDesc gv_prop_table[] = {
+ {"padding-top", PROP_ID_PADDING_TOP},
+ {"padding-right", PROP_ID_PADDING_RIGHT},
+ {"padding-bottom", PROP_ID_PADDING_BOTTOM},
+ {"padding-left", PROP_ID_PADDING_LEFT},
+ {"padding", PROP_ID_PADDING},
+ {"border-top-width", PROP_ID_BORDER_TOP_WIDTH},
+ {"border-right-width", PROP_ID_BORDER_RIGHT_WIDTH},
+ {"border-bottom-width", PROP_ID_BORDER_BOTTOM_WIDTH},
+ {"border-left-width", PROP_ID_BORDER_LEFT_WIDTH},
+ {"border-width", PROP_ID_BORDER_WIDTH},
+ {"border-top-style", PROP_ID_BORDER_TOP_STYLE},
+ {"border-right-style", PROP_ID_BORDER_RIGHT_STYLE},
+ {"border-bottom-style", PROP_ID_BORDER_BOTTOM_STYLE},
+ {"border-left-style", PROP_ID_BORDER_LEFT_STYLE},
+ {"border-style", PROP_ID_BORDER_STYLE},
+ {"border-top", PROP_ID_BORDER_TOP},
+ {"border-right", PROP_ID_BORDER_RIGHT},
+ {"border-bottom", PROP_ID_BORDER_BOTTOM},
+ {"border-left", PROP_ID_BORDER_LEFT},
+ {"border", PROP_ID_BORDER},
+ {"margin-top", PROP_ID_MARGIN_TOP},
+ {"margin-right", PROP_ID_MARGIN_RIGHT},
+ {"margin-bottom", PROP_ID_MARGIN_BOTTOM},
+ {"margin-left", PROP_ID_MARGIN_LEFT},
+ {"margin", PROP_ID_MARGIN},
+ {"display", PROP_ID_DISPLAY},
+ {"position", PROP_ID_POSITION},
+ {"top", PROP_ID_TOP},
+ {"right", PROP_ID_RIGHT},
+ {"bottom", PROP_ID_BOTTOM},
+ {"left", PROP_ID_LEFT},
+ {"float", PROP_ID_FLOAT},
+ {"width", PROP_ID_WIDTH},
+ {"color", PROP_ID_COLOR},
+ {"border-top-color", PROP_ID_BORDER_TOP_COLOR},
+ {"border-right-color", PROP_ID_BORDER_RIGHT_COLOR},
+ {"border-bottom-color", PROP_ID_BORDER_BOTTOM_COLOR},
+ {"border-left-color", PROP_ID_BORDER_LEFT_COLOR},
+ {"background-color", PROP_ID_BACKGROUND_COLOR},
+ {"font-family", PROP_ID_FONT_FAMILY},
+ {"font-size", PROP_ID_FONT_SIZE},
+ {"font-style", PROP_ID_FONT_STYLE},
+ {"font-weight", PROP_ID_FONT_WEIGHT},
+ {"white-space", PROP_ID_WHITE_SPACE},
+ /*must be the last one */
+ {NULL, (enum CRPropertyID) 0}
+};
+
+/**
+ *A the key/value pair of this hash table
+ *are:
+ *key => name of the css property found in gv_prop_table
+ *value => matching property id found in gv_prop_table.
+ *So this hash table is here just to retrieval of a property id
+ *from a property name.
+ */
+static GHashTable *gv_prop_hash = NULL;
+
+/**
+ *incremented by each new instance of #CRStyle
+ *and decremented at the it destroy time.
+ *When this reaches zero, gv_prop_hash is destroyed.
+ */
+static gulong gv_prop_hash_ref_count = 0;
+
+struct CRNumPropEnumDumpInfo {
+ enum CRNumProp code;
+ const gchar *str;
+};
+
+static struct CRNumPropEnumDumpInfo gv_num_props_dump_infos[] = {
+ {NUM_PROP_TOP, "top"},
+ {NUM_PROP_RIGHT, "right"},
+ {NUM_PROP_BOTTOM, "bottom"},
+ {NUM_PROP_LEFT, "left"},
+ {NUM_PROP_PADDING_TOP, "padding-top"},
+ {NUM_PROP_PADDING_RIGHT, "padding-right"},
+ {NUM_PROP_PADDING_BOTTOM, "padding-bottom"},
+ {NUM_PROP_PADDING_LEFT, "padding-left"},
+ {NUM_PROP_BORDER_TOP, "border-top"},
+ {NUM_PROP_BORDER_RIGHT, "border-right"},
+ {NUM_PROP_BORDER_BOTTOM, "border-bottom"},
+ {NUM_PROP_BORDER_LEFT, "border-left"},
+ {NUM_PROP_MARGIN_TOP, "margin-top"},
+ {NUM_PROP_MARGIN_RIGHT, "margin-right"},
+ {NUM_PROP_MARGIN_BOTTOM, "margin-bottom"},
+ {NUM_PROP_MARGIN_LEFT, "margin-left"},
+ {NUM_PROP_WIDTH, "width"},
+ {(enum CRNumProp) 0, NULL}
+};
+
+struct CRRgbPropEnumDumpInfo {
+ enum CRRgbProp code;
+ const gchar *str;
+};
+
+static struct CRRgbPropEnumDumpInfo gv_rgb_props_dump_infos[] = {
+ {RGB_PROP_BORDER_TOP_COLOR, "border-top-color"},
+ {RGB_PROP_BORDER_RIGHT_COLOR, "border-right-color"},
+ {RGB_PROP_BORDER_BOTTOM_COLOR, "bottom-color"},
+ {RGB_PROP_BORDER_LEFT_COLOR, "left-color"},
+ {RGB_PROP_COLOR, "color"},
+ {RGB_PROP_BACKGROUND_COLOR, "background-color"},
+ {(enum CRRgbProp) 0, NULL}
+};
+
+struct CRBorderStylePropEnumDumpInfo {
+ enum CRBorderStyleProp code;
+ const gchar *str;
+
+};
+
+static struct CRBorderStylePropEnumDumpInfo gv_border_style_props_dump_infos[]
+ = {
+ {BORDER_STYLE_PROP_TOP, "border-style-top"},
+ {BORDER_STYLE_PROP_RIGHT, "border-style-right"},
+ {BORDER_STYLE_PROP_BOTTOM, "boder-style-bottom"},
+ {BORDER_STYLE_PROP_LEFT, "border-style-left"},
+ {(enum CRBorderStyleProp) 0, NULL}
+};
+
+static enum CRStatus
+ cr_style_init_properties (void);
+
+enum CRDirection {
+ DIR_TOP = 0,
+ DIR_RIGHT,
+ DIR_BOTTOM,
+ DIR_LEFT,
+
+ /*must be the last one */
+ NB_DIRS
+};
+
+static const gchar *num_prop_code_to_string (enum CRNumProp a_code);
+
+static const gchar *rgb_prop_code_to_string (enum CRRgbProp a_code);
+
+static const gchar *border_style_prop_code_to_string (enum CRBorderStyleProp
+ a_code);
+
+static enum CRStatus
+set_prop_padding_x_from_value (CRStyle * a_style,
+ CRTerm * a_value, enum CRDirection a_dir);
+
+static enum CRStatus
+set_prop_border_x_width_from_value (CRStyle * a_style,
+ CRTerm * a_value,
+ enum CRDirection a_dir);
+static enum CRStatus
+set_prop_border_width_from_value (CRStyle *a_style,
+ CRTerm *a_value) ;
+
+static enum CRStatus
+set_prop_border_x_style_from_value (CRStyle * a_style,
+ CRTerm * a_value,
+ enum CRDirection a_dir);
+static enum CRStatus
+set_prop_border_style_from_value (CRStyle *a_style,
+ CRTerm *a_value) ;
+
+static enum CRStatus
+set_prop_margin_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir);
+
+static enum CRStatus
+set_prop_display_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir);
+
+static enum CRStatus
+set_prop_float (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_width (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_color (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_background_color (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir);
+
+static enum CRStatus
+set_prop_border_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir);
+
+static enum CRStatus
+set_prop_border_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_padding_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_margin_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+init_style_font_size_field (CRStyle * a_style);
+
+static enum CRStatus
+set_prop_font_size_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_font_style_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static enum CRStatus
+set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value);
+
+static const gchar *
+num_prop_code_to_string (enum CRNumProp a_code)
+{
+ guint len = sizeof (gv_num_props_dump_infos) /
+ sizeof (struct CRNumPropEnumDumpInfo);
+ if (a_code >= len) {
+ cr_utils_trace_info ("A field has been added "
+ "to 'enum CRNumProp' and no matching"
+ " entry has been "
+ "added to gv_num_prop_dump_infos table.\n"
+ "Please add the missing matching entry");
+ return NULL;
+ }
+ if (gv_num_props_dump_infos[a_code].code != a_code) {
+ cr_utils_trace_info ("mismatch between the order of fields in"
+ " 'enum CRNumProp' and "
+ "the order of entries in "
+ "the gv_num_prop_dump_infos table");
+ return NULL;
+ }
+ return gv_num_props_dump_infos[a_code].str;
+}
+
+static const gchar *
+rgb_prop_code_to_string (enum CRRgbProp a_code)
+{
+ guint len = sizeof (gv_rgb_props_dump_infos) /
+ sizeof (struct CRRgbPropEnumDumpInfo);
+
+ if (a_code >= len) {
+ cr_utils_trace_info ("A field has been added "
+ "to 'enum CRRgbProp' and no matching"
+ " entry has been "
+ "added to gv_rgb_prop_dump_infos table.\n"
+ "Please add the missing matching entry");
+ return NULL;
+ }
+ if (gv_rgb_props_dump_infos[a_code].code != a_code) {
+ cr_utils_trace_info ("mismatch between the order of fields in"
+ " 'enum CRRgbProp' and "
+ "the order of entries in "
+ "the gv_rgb_props_dump_infos table");
+ return NULL;
+ }
+ return gv_rgb_props_dump_infos[a_code].str;
+}
+
+static const gchar *
+border_style_prop_code_to_string (enum CRBorderStyleProp a_code)
+{
+ guint len = sizeof (gv_border_style_props_dump_infos) /
+ sizeof (struct CRBorderStylePropEnumDumpInfo);
+
+ if (a_code >= len) {
+ cr_utils_trace_info ("A field has been added "
+ "to 'enum CRBorderStyleProp' and no matching"
+ " entry has been "
+ "added to gv_border_style_prop_dump_infos table.\n"
+ "Please add the missing matching entry");
+ return NULL;
+ }
+ if (gv_border_style_props_dump_infos[a_code].code != a_code) {
+ cr_utils_trace_info ("mismatch between the order of fields in"
+ " 'enum CRBorderStyleProp' and "
+ "the order of entries in "
+ "the gv_border_style_props_dump_infos table");
+ return NULL;
+ }
+ return gv_border_style_props_dump_infos[a_code].str;
+}
+
+static enum CRStatus
+cr_style_init_properties (void)
+{
+
+ if (!gv_prop_hash) {
+ gulong i = 0;
+
+ gv_prop_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ if (!gv_prop_hash) {
+ cr_utils_trace_info ("Out of memory");
+ return CR_ERROR;
+ }
+
+ /*load gv_prop_hash from gv_prop_table */
+ for (i = 0; gv_prop_table[i].name; i++) {
+ g_hash_table_insert
+ (gv_prop_hash,
+ (gpointer) gv_prop_table[i].name,
+ GINT_TO_POINTER (gv_prop_table[i].prop_id));
+ }
+ }
+
+ return CR_OK;
+}
+
+static enum CRPropertyID
+cr_style_get_prop_id (const guchar * a_prop)
+{
+ gpointer *raw_id = NULL;
+
+ if (!gv_prop_hash) {
+ cr_style_init_properties ();
+ }
+
+ raw_id = (gpointer *) g_hash_table_lookup (gv_prop_hash, a_prop);
+ if (!raw_id) {
+ return PROP_ID_NOT_KNOWN;
+ }
+ return (enum CRPropertyID)GPOINTER_TO_INT (raw_id);
+}
+
+static enum CRStatus
+set_prop_padding_x_from_value (CRStyle * a_style,
+ CRTerm * a_value, enum CRDirection a_dir)
+{
+ enum CRStatus status = CR_OK;
+ CRNum *num_val = NULL;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ if (a_value->type != TERM_NUMBER && a_value->type != TERM_IDENT)
+ return CR_BAD_PARAM_ERROR;
+
+ switch (a_dir) {
+ case DIR_TOP:
+ num_val = &a_style->num_props[NUM_PROP_PADDING_TOP].sv;
+ break;
+
+ case DIR_RIGHT:
+ num_val = &a_style->num_props[NUM_PROP_PADDING_RIGHT].sv;
+ break;
+
+ case DIR_BOTTOM:
+ num_val = &a_style->num_props[NUM_PROP_PADDING_BOTTOM].sv;
+ break;
+
+ case DIR_LEFT:
+ num_val = &a_style->num_props[NUM_PROP_PADDING_LEFT].sv;
+ break;
+
+ default:
+ return CR_BAD_PARAM_ERROR;
+ }
+
+ if (a_value->type == TERM_IDENT) {
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strncmp ((const char *) "inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ status = cr_num_set (num_val, 0.0, NUM_INHERIT);
+ return CR_OK;
+ } else
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ g_return_val_if_fail (a_value->type == TERM_NUMBER
+ && a_value->content.num, CR_UNKNOWN_TYPE_ERROR);
+
+ switch (a_value->content.num->type) {
+ case NUM_LENGTH_EM:
+ case NUM_LENGTH_EX:
+ case NUM_LENGTH_PX:
+ case NUM_LENGTH_IN:
+ case NUM_LENGTH_CM:
+ case NUM_LENGTH_MM:
+ case NUM_LENGTH_PT:
+ case NUM_LENGTH_PC:
+ case NUM_PERCENTAGE:
+ status = cr_num_copy (num_val, a_value->content.num);
+ break;
+ default:
+ status = CR_UNKNOWN_TYPE_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_border_x_width_from_value (CRStyle * a_style,
+ CRTerm * a_value,
+ enum CRDirection a_dir)
+{
+ enum CRStatus status = CR_OK;
+ CRNum *num_val = NULL;
+
+ g_return_val_if_fail (a_value && a_style, CR_BAD_PARAM_ERROR);
+
+ switch (a_dir) {
+ case DIR_TOP:
+ num_val = &a_style->num_props[NUM_PROP_BORDER_TOP].sv;
+ break;
+
+ case DIR_RIGHT:
+ num_val = &a_style->num_props[NUM_PROP_BORDER_RIGHT].sv;
+ break;
+
+ case DIR_BOTTOM:
+ num_val = &a_style->num_props[NUM_PROP_BORDER_BOTTOM].sv;
+ break;
+
+ case DIR_LEFT:
+ num_val = &a_style->num_props[NUM_PROP_BORDER_LEFT].sv;
+ break;
+
+ default:
+ return CR_BAD_PARAM_ERROR;
+ break;
+ }
+
+ if (a_value->type == TERM_IDENT) {
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strncmp ("thin",
+ a_value->content.str->stryng->str,
+ sizeof ("thin")-1)) {
+ cr_num_set (num_val, BORDER_THIN,
+ NUM_LENGTH_PX);
+ } else if (!strncmp
+ ("medium",
+ a_value->content.str->stryng->str,
+ sizeof ("medium")-1)) {
+ cr_num_set (num_val, BORDER_MEDIUM,
+ NUM_LENGTH_PX);
+ } else if (!strncmp ("thick",
+ a_value->content.str->stryng->str,
+ sizeof ("thick")-1)) {
+ cr_num_set (num_val, BORDER_THICK,
+ NUM_LENGTH_PX);
+ } else {
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+ }
+ } else if (a_value->type == TERM_NUMBER) {
+ if (a_value->content.num) {
+ cr_num_copy (num_val, a_value->content.num);
+ }
+ } else if (a_value->type != TERM_NUMBER
+ || a_value->content.num == NULL) {
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_border_width_from_value (CRStyle *a_style,
+ CRTerm *a_value)
+{
+ CRTerm *cur_term = NULL ;
+ g_return_val_if_fail (a_style && a_value,
+ CR_BAD_PARAM_ERROR) ;
+ cur_term = a_value ;
+
+ if (!cur_term)
+ return CR_ERROR ;
+
+ int dir;
+ for (dir = (int) DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
+ enum CRDirection direction = (enum CRDirection)dir;
+ set_prop_border_x_width_from_value (a_style,
+ cur_term,
+ direction) ;
+ }
+
+ cur_term = cur_term->next ;
+ if (!cur_term)
+ return CR_OK ;
+ set_prop_border_x_width_from_value (a_style, cur_term,
+ DIR_RIGHT) ;
+ set_prop_border_x_width_from_value (a_style, cur_term,
+ DIR_LEFT) ;
+
+ cur_term = cur_term->next ;
+ if (!cur_term)
+ return CR_OK ;
+ set_prop_border_x_width_from_value (a_style, cur_term,
+ DIR_BOTTOM) ;
+
+ cur_term = cur_term->next ;
+ if (!cur_term)
+ return CR_OK ;
+ set_prop_border_x_width_from_value (a_style, cur_term,
+ DIR_LEFT) ;
+
+ return CR_OK ;
+}
+
+static enum CRStatus
+set_prop_border_x_style_from_value (CRStyle * a_style,
+ CRTerm * a_value, enum CRDirection a_dir)
+{
+ enum CRStatus status = CR_OK;
+ enum CRBorderStyle *border_style_ptr = NULL;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_dir) {
+ case DIR_TOP:
+ border_style_ptr = &a_style->
+ border_style_props[BORDER_STYLE_PROP_TOP];
+ break;
+
+ case DIR_RIGHT:
+ border_style_ptr =
+ &a_style->border_style_props[BORDER_STYLE_PROP_RIGHT];
+ break;
+
+ case DIR_BOTTOM:
+ border_style_ptr = &a_style->
+ border_style_props[BORDER_STYLE_PROP_BOTTOM];
+ break;
+
+ case DIR_LEFT:
+ border_style_ptr = &a_style->
+ border_style_props[BORDER_STYLE_PROP_LEFT];
+ break;
+
+ default:
+ break;
+ }
+
+ if (a_value->type != TERM_IDENT || !a_value->content.str) {
+ return CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ if (!strncmp ("none",
+ a_value->content.str->stryng->str,
+ sizeof ("none")-1)) {
+ *border_style_ptr = BORDER_STYLE_NONE;
+ } else if (!strncmp ("hidden",
+ a_value->content.str->stryng->str,
+ sizeof ("hidden")-1)) {
+ *border_style_ptr = BORDER_STYLE_HIDDEN;
+ } else if (!strncmp ("dotted",
+ a_value->content.str->stryng->str,
+ sizeof ("dotted")-1)) {
+ *border_style_ptr = BORDER_STYLE_DOTTED;
+ } else if (!strncmp ("dashed",
+ a_value->content.str->stryng->str, sizeof ("dashed")-1)) {
+ *border_style_ptr = BORDER_STYLE_DASHED;
+ } else if (!strncmp ("solid",
+ a_value->content.str->stryng->str, sizeof ("solid")-1)) {
+ *border_style_ptr = BORDER_STYLE_SOLID;
+ } else if (!strncmp ("double",
+ a_value->content.str->stryng->str, sizeof ("double")-1)) {
+ *border_style_ptr = BORDER_STYLE_DOUBLE;
+ } else if (!strncmp ("groove",
+ a_value->content.str->stryng->str, sizeof ("groove")-1)) {
+ *border_style_ptr = BORDER_STYLE_GROOVE;
+ } else if (!strncmp ("ridge",
+ a_value->content.str->stryng->str,
+ sizeof ("ridge")-1)) {
+ *border_style_ptr = BORDER_STYLE_RIDGE;
+ } else if (!strncmp ("inset",
+ a_value->content.str->stryng->str,
+ sizeof ("inset")-1)) {
+ *border_style_ptr = BORDER_STYLE_INSET;
+ } else if (!strncmp ("outset",
+ a_value->content.str->stryng->str,
+ sizeof ("outset")-1)) {
+ *border_style_ptr = BORDER_STYLE_OUTSET;
+ } else if (!strncmp ("inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ *border_style_ptr = BORDER_STYLE_INHERIT;
+ } else {
+ status = CR_UNKNOWN_TYPE_ERROR;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_border_style_from_value (CRStyle *a_style,
+ CRTerm *a_value)
+{
+ CRTerm *cur_term = NULL ;
+
+ g_return_val_if_fail (a_style && a_value,
+ CR_BAD_PARAM_ERROR) ;
+
+ cur_term = a_value ;
+ if (!cur_term || cur_term->type != TERM_IDENT) {
+ return CR_ERROR ;
+ }
+
+ int dir;
+ for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
+ enum CRDirection direction = (enum CRDirection)dir;
+ set_prop_border_x_style_from_value (a_style,
+ cur_term,
+ direction) ;
+ }
+
+ cur_term = cur_term->next ;
+ if (!cur_term || cur_term->type != TERM_IDENT) {
+ return CR_OK ;
+ }
+
+ set_prop_border_x_style_from_value (a_style, cur_term,
+ DIR_RIGHT) ;
+ set_prop_border_x_style_from_value (a_style, cur_term,
+ DIR_LEFT) ;
+
+ cur_term = cur_term->next ;
+ if (!cur_term || cur_term->type != TERM_IDENT) {
+ return CR_OK ;
+ }
+ set_prop_border_x_style_from_value (a_style, cur_term,
+ DIR_BOTTOM) ;
+
+ cur_term = cur_term->next ;
+ if (!cur_term || cur_term->type != TERM_IDENT) {
+ return CR_OK ;
+ }
+ set_prop_border_x_style_from_value (a_style, cur_term,
+ DIR_LEFT) ;
+ return CR_OK ;
+}
+
+static enum CRStatus
+set_prop_margin_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir)
+{
+ enum CRStatus status = CR_OK;
+ CRNum *num_val = NULL;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_dir) {
+ case DIR_TOP:
+ num_val = &a_style->num_props[NUM_PROP_MARGIN_TOP].sv;
+ break;
+
+ case DIR_RIGHT:
+ num_val = &a_style->num_props[NUM_PROP_MARGIN_RIGHT].sv;
+ break;
+
+ case DIR_BOTTOM:
+ num_val = &a_style->num_props[NUM_PROP_MARGIN_BOTTOM].sv;
+ break;
+
+ case DIR_LEFT:
+ num_val = &a_style->num_props[NUM_PROP_MARGIN_LEFT].sv;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "inherit")) {
+ status = cr_num_set (num_val, 0.0, NUM_INHERIT);
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && !strcmp (a_value->content.str->stryng->str,
+ "auto")) {
+ status = cr_num_set (num_val, 0.0, NUM_AUTO);
+ } else {
+ status = CR_UNKNOWN_TYPE_ERROR;
+ }
+ break ;
+
+ case TERM_NUMBER:
+ status = cr_num_copy (num_val, a_value->content.num);
+ break;
+
+ default:
+ status = CR_UNKNOWN_TYPE_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+struct CRPropDisplayValPair {
+ const gchar *prop_name;
+ enum CRDisplayType type;
+};
+
+static enum CRStatus
+set_prop_display_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ static const struct CRPropDisplayValPair disp_vals_map[] = {
+ {"none", DISPLAY_NONE},
+ {"inline", DISPLAY_INLINE},
+ {"block", DISPLAY_BLOCK},
+ {"run-in", DISPLAY_RUN_IN},
+ {"compact", DISPLAY_COMPACT},
+ {"marker", DISPLAY_MARKER},
+ {"table", DISPLAY_TABLE},
+ {"inline-table", DISPLAY_INLINE_TABLE},
+ {"table-row-group", DISPLAY_TABLE_ROW_GROUP},
+ {"table-header-group", DISPLAY_TABLE_HEADER_GROUP},
+ {"table-footer-group", DISPLAY_TABLE_FOOTER_GROUP},
+ {"table-row", DISPLAY_TABLE_ROW},
+ {"table-column-group", DISPLAY_TABLE_COLUMN_GROUP},
+ {"table-column", DISPLAY_TABLE_COLUMN},
+ {"table-cell", DISPLAY_TABLE_CELL},
+ {"table-caption", DISPLAY_TABLE_CAPTION},
+ {"inherit", DISPLAY_INHERIT},
+ {NULL, DISPLAY_NONE}
+ };
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ {
+ int i = 0;
+
+ if (!a_value->content.str
+ || !a_value->content.str->stryng
+ || !a_value->content.str->stryng->str)
+ break;
+
+ for (i = 0; disp_vals_map[i].prop_name; i++) {
+ if (!strncmp
+ (disp_vals_map[i].prop_name,
+ a_value->content.str->stryng->str,
+ strlen (disp_vals_map[i].prop_name))) {
+ a_style->display =
+ disp_vals_map[i].type;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return CR_OK;
+}
+
+struct CRPropPositionValPair {
+ const gchar *name;
+ enum CRPositionType type;
+};
+
+static enum CRStatus
+set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_UNKNOWN_PROP_VAL_ERROR;
+ static const struct CRPropPositionValPair position_vals_map[] = {
+ {"static", POSITION_STATIC},
+ {"relative", POSITION_RELATIVE},
+ {"absolute", POSITION_ABSOLUTE},
+ {"fixed", POSITION_FIXED},
+ {"inherit", POSITION_INHERIT},
+ {NULL, POSITION_STATIC}
+ /*must alwas be the last one */
+ };
+
+ g_return_val_if_fail (a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ {
+ int i = 0;
+
+ if (!a_value->content.str
+ || !a_value->content.str->stryng
+ || !a_value->content.str->stryng->str)
+ break;
+
+ for (i = 0; position_vals_map[i].name; i++) {
+ if (!strncmp (position_vals_map[i].name,
+ a_value->content.str->stryng->str,
+ strlen (position_vals_map[i].
+ name))) {
+ a_style->position =
+ position_vals_map[i].type;
+ status = CR_OK;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir)
+{
+ CRNum *box_offset = NULL;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ if (!(a_value->type == TERM_NUMBER)
+ && !(a_value->type == TERM_IDENT)) {
+ return CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+
+ switch (a_dir) {
+ case DIR_TOP:
+ box_offset = &a_style->num_props[NUM_PROP_TOP].sv;
+ break;
+
+ case DIR_RIGHT:
+ box_offset = &a_style->num_props[NUM_PROP_RIGHT].sv;
+ break;
+
+ case DIR_BOTTOM:
+ box_offset = &a_style->num_props[NUM_PROP_BOTTOM].sv;
+ break;
+ case DIR_LEFT:
+ box_offset = &a_style->num_props[NUM_PROP_LEFT].sv;
+ break;
+
+ default:
+ break;
+ }
+
+ box_offset->type = NUM_AUTO;
+
+ if (a_value->type == TERM_NUMBER && a_value->content.num) {
+ cr_num_copy (box_offset, a_value->content.num);
+ } else if (a_value->type == TERM_IDENT
+ && a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strncmp ("inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ cr_num_set (box_offset, 0.0, NUM_INHERIT);
+ } else if (!strncmp ("auto",
+ a_value->content.str->stryng->str,
+ sizeof ("auto")-1)) {
+ box_offset->type = NUM_AUTO;
+ }
+ }
+
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_float (CRStyle * a_style, CRTerm * a_value)
+{
+ g_return_val_if_fail (a_style && a_value,
+ CR_BAD_PARAM_ERROR);
+
+ /*the default float type as specified by the css2 spec */
+ a_style->float_type = FLOAT_NONE;
+
+ if (a_value->type != TERM_IDENT
+ || !a_value->content.str
+ || !a_value->content.str->stryng
+ || !a_value->content.str->stryng->str) {
+ /*unknow type, the float type is set to it's default value */
+ return CR_OK;
+ }
+
+ if (!strncmp ("none",
+ a_value->content.str->stryng->str,
+ sizeof ("none")-1)) {
+ a_style->float_type = FLOAT_NONE;
+ } else if (!strncmp ("left",
+ a_value->content.str->stryng->str,
+ sizeof ("left")-1)) {
+ a_style->float_type = FLOAT_LEFT;
+ } else if (!strncmp ("right",
+ a_value->content.str->stryng->str,
+ sizeof ("right")-1)) {
+ a_style->float_type = FLOAT_RIGHT;
+ } else if (!strncmp ("inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ a_style->float_type = FLOAT_INHERIT;
+ }
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_width (CRStyle * a_style, CRTerm * a_value)
+{
+ CRNum *width = NULL;
+ g_return_val_if_fail (a_style
+ && a_value,
+ CR_BAD_PARAM_ERROR);
+
+ width = &a_style->num_props[NUM_PROP_WIDTH].sv;
+ cr_num_set (width, 0.0, NUM_AUTO);
+
+ if (a_value->type == TERM_IDENT) {
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strncmp ("auto",
+ a_value->content.str->stryng->str,
+ sizeof ("auto")-1)) {
+ cr_num_set (width, 0.0, NUM_AUTO);
+ } else if (!strncmp ("inherit",
+ a_value->content.str->stryng->str,
+ sizeof ("inherit")-1)) {
+ cr_num_set (width, 0.0, NUM_INHERIT);
+ }
+ }
+ } else if (a_value->type == TERM_NUMBER) {
+ if (a_value->content.num) {
+ cr_num_copy (&a_style->num_props[NUM_PROP_WIDTH].sv,
+ a_value->content.num);
+ }
+ }
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_color (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+ CRRgb *a_rgb = &a_style->rgb_props[RGB_PROP_COLOR].sv;
+
+ g_return_val_if_fail (a_style
+ && a_value, CR_BAD_PARAM_ERROR);
+
+ status = cr_rgb_set_from_term (a_rgb, a_value);
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_background_color (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+ CRRgb *rgb = &a_style->rgb_props[RGB_PROP_BACKGROUND_COLOR].sv;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ status = cr_rgb_set_from_term (rgb, a_value);
+ return status;
+}
+
+/**
+ *Sets border-top-color, border-right-color,
+ *border-bottom-color or border-left-color properties
+ *in the style structure. The value is taken from a
+ *css2 term of type IDENT or RGB.
+ *@param a_style the style structure to set.
+ *@param a_value the css2 term to take the color information from.
+ *@param a_dir the direction (TOP, LEFT, RIGHT, or BOTTOM).
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir)
+{
+ CRRgb *rgb_color = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_dir) {
+ case DIR_TOP:
+ rgb_color = &a_style->rgb_props[RGB_PROP_BORDER_TOP_COLOR].sv;
+ break;
+
+ case DIR_RIGHT:
+ rgb_color =
+ &a_style->rgb_props[RGB_PROP_BORDER_RIGHT_COLOR].sv;
+ break;
+
+ case DIR_BOTTOM:
+ rgb_color =
+ &a_style->rgb_props[RGB_PROP_BORDER_BOTTOM_COLOR].sv;
+ break;
+
+ case DIR_LEFT:
+ rgb_color =
+ &a_style->rgb_props[RGB_PROP_BORDER_LEFT_COLOR].sv;
+ break;
+
+ default:
+ cr_utils_trace_info ("unknown DIR type");
+ return CR_BAD_PARAM_ERROR;
+ }
+
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+
+ if (a_value->type == TERM_IDENT) {
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ status = cr_rgb_set_from_name
+ (rgb_color,
+ (const guchar *) a_value->content.str->stryng->str);
+
+ }
+ if (status != CR_OK) {
+ cr_rgb_set_from_name (rgb_color, (const guchar *) "black");
+ }
+ } else if (a_value->type == TERM_RGB) {
+ if (a_value->content.rgb) {
+ status = cr_rgb_set_from_rgb
+ (rgb_color, a_value->content.rgb);
+ }
+ }
+ return status;
+}
+
+static enum CRStatus
+set_prop_border_x_from_value (CRStyle * a_style, CRTerm * a_value,
+ enum CRDirection a_dir)
+{
+ CRTerm *cur_term = NULL;
+
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ for (cur_term = a_value;
+ cur_term;
+ cur_term = cur_term->next) {
+ status = set_prop_border_x_width_from_value (a_style,
+ cur_term, a_dir);
+
+ if (status != CR_OK) {
+ status = set_prop_border_x_style_from_value
+ (a_style, cur_term, a_dir);
+ }
+ if (status != CR_OK) {
+ status = set_prop_border_x_color_from_value
+ (a_style, cur_term, a_dir);
+ }
+ }
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_border_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ int dir;
+ for (dir = 0; dir < (int)NB_DIRS; dir++) {
+ set_prop_border_x_from_value (a_style,
+ a_value,
+ (enum CRDirection)dir);
+ }
+
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_padding_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ CRTerm *cur_term = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ cur_term = a_value;
+
+ /*filter the eventual non NUMBER terms some user can have written here*/
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_ERROR ;
+
+ int dir;
+ for (dir = 0; dir < (int)NB_DIRS; dir++) {
+ set_prop_padding_x_from_value (a_style,
+ cur_term, (enum CRDirection)dir);
+ }
+ cur_term = cur_term->next;
+
+ /*filter non NUMBER terms that some users can have written here...*/
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ /*the user can have just written padding: 1px*/
+ if (!cur_term)
+ return CR_OK;
+
+ set_prop_padding_x_from_value (a_style, cur_term, DIR_RIGHT);
+ set_prop_padding_x_from_value (a_style, cur_term, DIR_LEFT);
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_OK;
+
+ set_prop_padding_x_from_value (a_style, cur_term, DIR_BOTTOM);
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_OK;
+ status = set_prop_padding_x_from_value (a_style, cur_term, DIR_LEFT);
+ return status;
+}
+
+static enum CRStatus
+set_prop_margin_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ CRTerm *cur_term = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ cur_term = a_value;
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+
+ if (!cur_term)
+ return CR_OK;
+
+ int dir;
+ for (dir = 0; dir < (int)NB_DIRS; dir++) {
+ set_prop_margin_x_from_value(a_style,
+ cur_term, (enum CRDirection)dir);
+ }
+ cur_term = cur_term->next;
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_OK;
+
+ set_prop_margin_x_from_value (a_style, cur_term, DIR_RIGHT);
+ set_prop_margin_x_from_value (a_style, cur_term, DIR_LEFT);
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_OK;
+
+ set_prop_margin_x_from_value (a_style, cur_term, DIR_BOTTOM);
+
+ while (cur_term && cur_term->type != TERM_NUMBER) {
+ cur_term = cur_term->next;
+ }
+ if (!cur_term)
+ return CR_OK;
+
+ status = set_prop_margin_x_from_value (a_style, cur_term, DIR_LEFT);
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ CRTerm *cur_term = NULL;
+ CRFontFamily *font_family = NULL,
+ *cur_ff = NULL,
+ *cur_ff2 = NULL;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ if (a_value->type == TERM_IDENT &&
+ a_value->content.str &&
+ a_value->content.str->stryng &&
+ a_value->content.str->stryng->str &&
+ !strcmp ("inherit", a_value->content.str->stryng->str))
+ {
+ font_family = cr_font_family_new (FONT_FAMILY_INHERIT, NULL);
+ goto out;
+ }
+
+ for (cur_term = a_value; cur_term; cur_term = cur_term->next) {
+ switch (cur_term->type) {
+ case TERM_IDENT:
+ {
+ enum CRFontFamilyType font_type;
+
+ if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str
+ && !strcmp
+ (cur_term->content.str->stryng->str,
+ "sans-serif")) {
+ font_type = FONT_FAMILY_SANS_SERIF;
+ } else if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str
+ && !strcmp
+ (cur_term->content.str->stryng->str,
+ "serif")) {
+ font_type = FONT_FAMILY_SERIF;
+ } else if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str
+ && !strcmp (cur_term->content.str->stryng->str,
+ "cursive")) {
+ font_type = FONT_FAMILY_CURSIVE;
+ } else if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str
+ && !strcmp (cur_term->content.str->stryng->str,
+ "fantasy")) {
+ font_type = FONT_FAMILY_FANTASY;
+ } else if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str
+ && !strcmp (cur_term->content.str->stryng->str,
+ "monospace")) {
+ font_type = FONT_FAMILY_MONOSPACE;
+ } else {
+ /*
+ *unknown property value.
+ *ignore it.
+ */
+ continue;
+ }
+
+ cur_ff = cr_font_family_new (font_type, NULL);
+ }
+ break;
+
+ case TERM_STRING:
+ {
+ if (cur_term->content.str
+ && cur_term->content.str->stryng
+ && cur_term->content.str->stryng->str) {
+ cur_ff = cr_font_family_new
+ (FONT_FAMILY_NON_GENERIC,
+ (guchar *) cur_term->content.str->stryng->str);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ cur_ff2 = cr_font_family_append (font_family, cur_ff);
+ if (cur_ff2) {
+ font_family = cur_ff2;
+ }
+ }
+
+ out:
+ if (font_family) {
+ if (a_style->font_family) {
+ cr_font_family_destroy (a_style->font_family);
+ a_style->font_family = NULL ;
+ }
+ a_style->font_family = font_family;
+ font_family = NULL ;
+ }
+
+ return CR_OK;
+}
+
+static enum CRStatus
+init_style_font_size_field (CRStyle * a_style)
+{
+ g_return_val_if_fail (a_style, CR_BAD_PARAM_ERROR);
+
+ memset (&a_style->font_size, 0,
+ sizeof (CRFontSizeVal)) ;
+ /*
+ if (!a_style->font_size) {
+ a_style->font_size = cr_font_size_new ();
+ if (!a_style->font_size) {
+ return CR_INSTANCIATION_FAILED_ERROR;
+ }
+ } else {
+ cr_font_size_clear (a_style->font_size);
+ }
+ */
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_font_size_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "xx-small")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_XX_SMALL;
+
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "x-small")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_X_SMALL;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "small")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_SMALL;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str, "medium")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_MEDIUM;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "large")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_LARGE;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "x-large")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_X_LARGE;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "xx-large")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type =
+ PREDEFINED_ABSOLUTE_FONT_SIZE;
+ a_style->font_size.sv.value.predefined =
+ FONT_SIZE_XX_LARGE;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "larger")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type = RELATIVE_FONT_SIZE;
+ a_style->font_size.sv.value.relative = FONT_SIZE_LARGER;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str,
+ "smaller")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type = RELATIVE_FONT_SIZE;
+ a_style->font_size.sv.value.relative =
+ FONT_SIZE_SMALLER;
+ } else if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str
+ && !strcmp (a_value->content.str->stryng->str, "inherit")) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+ a_style->font_size.sv.type = INHERITED_FONT_SIZE;
+
+ } else {
+ cr_utils_trace_info ("Unknow value of font-size") ;
+ status = init_style_font_size_field (a_style);
+ return CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+ break;
+
+ case TERM_NUMBER:
+ if (a_value->content.num) {
+ status = init_style_font_size_field (a_style);
+ g_return_val_if_fail (status == CR_OK, status);
+
+ a_style->font_size.sv.type = ABSOLUTE_FONT_SIZE;
+ cr_num_copy (&a_style->font_size.sv.value.absolute,
+ a_value->content.num) ;
+ }
+ break;
+
+ default:
+ status = init_style_font_size_field (a_style);
+ return CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+ return CR_OK;
+}
+
+static enum CRStatus
+set_prop_font_style_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strcmp (a_value->content.str->stryng->str, "normal")) {
+ a_style->font_style = FONT_STYLE_NORMAL;
+ } else if (!strcmp
+ (a_value->content.str->stryng->str,
+ "italic")) {
+ a_style->font_style = FONT_STYLE_ITALIC;
+ } else if (!strcmp
+ (a_value->content.str->stryng->str,
+ "oblique")) {
+ a_style->font_style = FONT_STYLE_OBLIQUE;
+ } else if (!strcmp
+ (a_value->content.str->stryng->str,
+ "inherit")) {
+ a_style->font_style = FONT_STYLE_INHERIT;
+ } else {
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+ }
+ break;
+
+ default:
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ if (a_value->content.str
+ && a_value->content.str->stryng
+ && a_value->content.str->stryng->str) {
+ if (!strcmp (a_value->content.str->stryng->str,
+ "normal")) {
+ a_style->font_weight = FONT_WEIGHT_NORMAL;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "bold")) {
+ a_style->font_weight = FONT_WEIGHT_BOLD;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "bolder")) {
+ a_style->font_weight = FONT_WEIGHT_BOLDER;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "lighter")) {
+ a_style->font_weight = FONT_WEIGHT_LIGHTER;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "inherit")) {
+ a_style->font_weight = FONT_WEIGHT_INHERIT;
+
+ } else {
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+
+ }
+ break;
+
+ case TERM_NUMBER:
+ if (a_value->content.num
+ && (a_value->content.num->type == NUM_GENERIC
+ || a_value->content.num->type == NUM_AUTO)) {
+ if (a_value->content.num->val <= 150) {
+ a_style->font_weight = FONT_WEIGHT_100;
+ } else if (a_value->content.num->val <= 250) {
+ a_style->font_weight = FONT_WEIGHT_200;
+ } else if (a_value->content.num->val <= 350) {
+ a_style->font_weight = FONT_WEIGHT_300;
+ } else if (a_value->content.num->val <= 450) {
+ a_style->font_weight = FONT_WEIGHT_400;
+ } else if (a_value->content.num->val <= 550) {
+ a_style->font_weight = FONT_WEIGHT_500;
+ } else if (a_value->content.num->val <= 650) {
+ a_style->font_weight = FONT_WEIGHT_600;
+ } else if (a_value->content.num->val <= 750) {
+ a_style->font_weight = FONT_WEIGHT_700;
+ } else if (a_value->content.num->val <= 850) {
+ a_style->font_weight = FONT_WEIGHT_800;
+ } else {
+ a_style->font_weight = FONT_WEIGHT_900;
+ }
+ }
+ break;
+
+ default:
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+static enum CRStatus
+set_prop_white_space_from_value (CRStyle * a_style, CRTerm * a_value)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
+
+ switch (a_value->type) {
+ case TERM_IDENT:
+ if (a_value->content.str && a_value->content.str->stryng) {
+ if (!strcmp (a_value->content.str->stryng->str, "normal")) {
+ a_style->white_space = WHITE_SPACE_NORMAL;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "pre")) {
+ a_style->white_space = WHITE_SPACE_PRE;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "nowrap")) {
+ a_style->white_space = WHITE_SPACE_NOWRAP;
+ } else if (!strcmp (a_value->content.str->stryng->str,
+ "inherit")) {
+ a_style->white_space = WHITE_SPACE_INHERIT;
+ } else {
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ }
+ }
+ break;
+ default:
+ status = CR_UNKNOWN_PROP_VAL_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+/******************
+ *Public methods
+ ******************/
+
+/**
+ *Default constructor of #CRStyle.
+ *@param a_set_props_to_initial_values if TRUE, the style properties
+ *will be set to the default values. Only the style properties of the
+ *root box should be set to their initial values.
+ *Otherwise, the style values are set to their default value.
+ *Read the CSS2 spec, chapters 6.1.1 to 6.2.
+ */
+CRStyle *
+cr_style_new (gboolean a_set_props_to_initial_values)
+{
+ CRStyle *result = NULL;
+
+ result = (CRStyle *) g_try_malloc (sizeof (CRStyle));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRStyle));
+ gv_prop_hash_ref_count++;
+
+ if (a_set_props_to_initial_values == TRUE) {
+ cr_style_set_props_to_initial_values (result);
+ } else {
+ cr_style_set_props_to_default_values (result);
+ }
+
+ return result;
+}
+
+/**
+ *Sets the style properties to their default values according to the css2 spec
+ * i.e inherit if the property is inherited, its initial value otherwise.
+ *@param a_this the current instance of #CRStyle.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_style_set_props_to_default_values (CRStyle * a_this)
+{
+ glong i = 0;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ for (i = 0; i < NB_NUM_PROPS; i++)
+ {
+ switch (i)
+ {
+ case NUM_PROP_WIDTH:
+ case NUM_PROP_TOP:
+ case NUM_PROP_RIGHT:
+ case NUM_PROP_BOTTOM:
+ case NUM_PROP_LEFT:
+ cr_num_set (&a_this->num_props[i].sv, 0, NUM_AUTO);
+ break;
+
+ case NUM_PROP_PADDING_TOP:
+ case NUM_PROP_PADDING_RIGHT:
+ case NUM_PROP_PADDING_BOTTOM:
+ case NUM_PROP_PADDING_LEFT:
+ case NUM_PROP_BORDER_TOP:
+ case NUM_PROP_BORDER_RIGHT:
+ case NUM_PROP_BORDER_BOTTOM:
+ case NUM_PROP_BORDER_LEFT:
+ case NUM_PROP_MARGIN_TOP:
+ case NUM_PROP_MARGIN_RIGHT:
+ case NUM_PROP_MARGIN_BOTTOM:
+ case NUM_PROP_MARGIN_LEFT:
+ cr_num_set (&a_this->num_props[i].sv,
+ 0, NUM_LENGTH_PX);
+ break;
+
+ default:
+ cr_utils_trace_info ("Unknown property");
+ break;
+ }
+ }
+
+ for (i = 0; i < NB_RGB_PROPS; i++) {
+
+ switch (i) {
+ /*default foreground color is black */
+ case RGB_PROP_COLOR:
+ /*
+ *REVIEW: color is inherited and the default value is
+ *ua dependant.
+ */
+ cr_rgb_set_to_inherit (&a_this->rgb_props[i].sv,
+ TRUE) ;
+ break;
+
+ /*default background color is white */
+ case RGB_PROP_BACKGROUND_COLOR:
+ /* TODO: the default value should be transparent */
+ cr_rgb_set (&a_this->rgb_props[i].sv,
+ 255, 255, 255, FALSE);
+ cr_rgb_set_to_transparent (&a_this->rgb_props[i].sv,
+ TRUE) ;
+ break;
+
+ default:
+ /*
+ *TODO: for BORDER_COLOR the initial value should
+ * be the same as COLOR
+ */
+ cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0,
+ FALSE);
+ break;
+ }
+ }
+
+ for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
+ a_this->border_style_props[i] = BORDER_STYLE_NONE;
+ }
+
+ a_this->display = DISPLAY_INLINE;
+ a_this->position = POSITION_STATIC;
+ a_this->float_type = FLOAT_NONE;
+ a_this->parent_style = NULL;
+ a_this->font_style = FONT_STYLE_INHERIT;
+ a_this->font_variant = FONT_VARIANT_INHERIT;
+ a_this->font_weight = FONT_WEIGHT_INHERIT;
+ a_this->font_family = NULL;
+
+ cr_font_size_set_to_inherit (&a_this->font_size.sv) ;
+ cr_font_size_clear (&a_this->font_size.cv) ;
+ cr_font_size_clear (&a_this->font_size.av) ;
+
+ /* To make the inheritance resolution possible and efficient */
+ a_this->inherited_props_resolved = FALSE ;
+ return CR_OK;
+}
+
+/**
+ *Sets the style properties to their initial value according to the css2 spec.
+ *This function should be used to initialize the style of the root element
+ *of an xml tree.
+ *Some properties are user agent dependant like font-family, and
+ *are not initialized, read the spec to make you renderer compliant.
+ *@param a_this the current instance of #CRStyle.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_style_set_props_to_initial_values (CRStyle *a_this)
+{
+ glong i = 0;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ for (i = 0; i < NB_NUM_PROPS; i++) {
+ switch (i) {
+ case NUM_PROP_WIDTH:
+ cr_num_set (&a_this->num_props[i].sv, 800,
+ NUM_LENGTH_PX) ;
+ break ;
+ case NUM_PROP_TOP:
+ case NUM_PROP_RIGHT:
+ case NUM_PROP_BOTTOM:
+ case NUM_PROP_LEFT:
+ cr_num_set (&a_this->num_props[i].sv, 0, NUM_AUTO);
+ break;
+
+ case NUM_PROP_PADDING_TOP:
+ case NUM_PROP_PADDING_RIGHT:
+ case NUM_PROP_PADDING_BOTTOM:
+ case NUM_PROP_PADDING_LEFT:
+ case NUM_PROP_BORDER_TOP:
+ case NUM_PROP_BORDER_RIGHT:
+ case NUM_PROP_BORDER_BOTTOM:
+ case NUM_PROP_BORDER_LEFT:
+ case NUM_PROP_MARGIN_TOP:
+ case NUM_PROP_MARGIN_RIGHT:
+ case NUM_PROP_MARGIN_BOTTOM:
+ case NUM_PROP_MARGIN_LEFT:
+ cr_num_set (&a_this->num_props[i].sv,
+ 0, NUM_LENGTH_PX);
+ break;
+
+ default:
+ cr_utils_trace_info ("Unknown property");
+ break;
+ }
+ }
+
+ for (i = 0; i < NB_RGB_PROPS; i++) {
+
+ switch (i) {
+ /*default foreground color is black */
+ case RGB_PROP_COLOR:
+ cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0, FALSE);
+ break;
+
+ /*default background color is white */
+ case RGB_PROP_BACKGROUND_COLOR:
+ cr_rgb_set (&a_this->rgb_props[i].sv,
+ 255, 255, 255, FALSE);
+ cr_rgb_set_to_transparent (&a_this->rgb_props[i].sv,
+ TRUE) ;
+ break;
+ default:
+ cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0, FALSE);
+ break;
+ }
+ }
+
+ for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
+ a_this->border_style_props[i] = BORDER_STYLE_NONE;
+ }
+
+ a_this->display = DISPLAY_BLOCK;
+ a_this->position = POSITION_STATIC;
+ a_this->float_type = FLOAT_NONE;
+ a_this->font_style = FONT_STYLE_NORMAL;
+ a_this->font_variant = FONT_VARIANT_NORMAL;
+ a_this->font_weight = FONT_WEIGHT_NORMAL;
+ a_this->font_stretch = FONT_STRETCH_NORMAL;
+ a_this->white_space = WHITE_SPACE_NORMAL;
+ cr_font_size_set_predefined_absolute_font_size
+ (&a_this->font_size.sv, FONT_SIZE_MEDIUM) ;
+ a_this->inherited_props_resolved = FALSE ;
+
+ return CR_OK;
+}
+
+/**
+ *Resolves the inherited properties.
+ *The function sets the "inherited" properties to either the value of
+ *their parent properties.
+ *This function is *NOT* recursive. So the inherited properties of
+ *the parent style must have been resolved prior to calling this function.
+ *@param a_this the instance where
+ *@return CR_OK if a root node is found and the propagation is successful,
+ *an error code otherwise
+ */
+enum CRStatus
+cr_style_resolve_inherited_properties (CRStyle *a_this)
+{
+ enum CRStatus ret = CR_OK;
+ glong i = 0;
+
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ g_return_val_if_fail (a_this->parent_style, CR_BAD_PARAM_ERROR) ;
+
+ if (a_this->inherited_props_resolved == TRUE)
+ return CR_OK ;
+
+ for (i=0 ; i < NB_NUM_PROPS ;i++) {
+ if (a_this->num_props[i].sv.type == NUM_INHERIT) {
+ cr_num_copy (&a_this->num_props[i].cv,
+ &a_this->parent_style->num_props[i].cv);
+ }
+ }
+ for (i=0; i < NB_RGB_PROPS; i++) {
+ if (cr_rgb_is_set_to_inherit (&a_this->rgb_props[i].sv) == TRUE) {
+ cr_rgb_copy (
+ &a_this->rgb_props[i].cv,
+ &a_this->parent_style->rgb_props[i].cv);
+ }
+ }
+ for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
+ if (a_this->border_style_props[i] == BORDER_STYLE_INHERIT) {
+ a_this->border_style_props[i] =
+ a_this->parent_style->border_style_props[i];
+ }
+ }
+
+ if (a_this->display == DISPLAY_INHERIT) {
+ a_this->display = a_this->parent_style->display;
+ }
+ if (a_this->position == POSITION_INHERIT) {
+ a_this->position = a_this->parent_style->position;
+ }
+ if (a_this->float_type == FLOAT_INHERIT) {
+ a_this->float_type = a_this->parent_style->float_type;
+ }
+ if (a_this->font_style == FONT_STYLE_INHERIT) {
+ a_this->font_style = a_this->parent_style->font_style;
+ }
+ if (a_this->font_variant == FONT_VARIANT_INHERIT) {
+ a_this->font_variant = a_this->parent_style->font_variant;
+ }
+ if (a_this->font_weight == FONT_WEIGHT_INHERIT) {
+ a_this->font_weight = a_this->parent_style->font_weight;
+ }
+ if (a_this->font_stretch == FONT_STRETCH_INHERIT) {
+ a_this->font_stretch = a_this->parent_style->font_stretch;
+ }
+ /*NULL is inherit marker for font_famiy*/
+ if (a_this->font_family == NULL) {
+ a_this->font_family = a_this->parent_style->font_family;
+ }
+ if (a_this->font_size.sv.type == INHERITED_FONT_SIZE) {
+ cr_font_size_copy (&a_this->font_size.cv,
+ &a_this->parent_style->font_size.cv) ;
+ }
+ a_this->inherited_props_resolved = TRUE ;
+ return ret;
+}
+
+/**
+ *Walks through a css2 property declaration, and populated the
+ *according field(s) in the #CRStyle structure.
+ *If the properties or their value(s) are/is not known,
+ *sets the corresponding field(s) of #CRStyle to its/their default
+ *value(s)
+ *@param a_this the instance of #CRStyle to set.
+ *@param a_decl the declaration from which the #CRStyle fields are set.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_style_set_style_from_decl (CRStyle * a_this, CRDeclaration * a_decl)
+{
+ CRTerm *value = NULL;
+ enum CRStatus status = CR_OK;
+
+ enum CRPropertyID prop_id = PROP_ID_NOT_KNOWN;
+
+ g_return_val_if_fail (a_this && a_decl
+ && a_decl
+ && a_decl->property
+ && a_decl->property->stryng
+ && a_decl->property->stryng->str,
+ CR_BAD_PARAM_ERROR);
+
+ prop_id = cr_style_get_prop_id
+ ((const guchar *) a_decl->property->stryng->str);
+
+ value = a_decl->value;
+ switch (prop_id) {
+ case PROP_ID_PADDING_TOP:
+ status = set_prop_padding_x_from_value
+ (a_this, value, DIR_TOP);
+ break;
+
+ case PROP_ID_PADDING_RIGHT:
+ status = set_prop_padding_x_from_value
+ (a_this, value, DIR_RIGHT);
+ break;
+ case PROP_ID_PADDING_BOTTOM:
+ status = set_prop_padding_x_from_value
+ (a_this, value, DIR_BOTTOM);
+ break;
+
+ case PROP_ID_PADDING_LEFT:
+ status = set_prop_padding_x_from_value
+ (a_this, value, DIR_LEFT);
+ break;
+
+ case PROP_ID_PADDING:
+ status = set_prop_padding_from_value (a_this, value) ;
+ break;
+
+ case PROP_ID_BORDER_TOP_WIDTH:
+ status = set_prop_border_x_width_from_value (a_this, value,
+ DIR_TOP);
+ break;
+
+ case PROP_ID_BORDER_RIGHT_WIDTH:
+ status = set_prop_border_x_width_from_value (a_this, value,
+ DIR_RIGHT);
+ break;
+
+ case PROP_ID_BORDER_BOTTOM_WIDTH:
+ status = set_prop_border_x_width_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_BORDER_LEFT_WIDTH:
+ status = set_prop_border_x_width_from_value (a_this, value,
+ DIR_LEFT);
+ break;
+
+ case PROP_ID_BORDER_WIDTH:
+ status = set_prop_border_width_from_value (a_this, value) ;
+ break ;
+
+ case PROP_ID_BORDER_TOP_STYLE:
+ status = set_prop_border_x_style_from_value (a_this, value,
+ DIR_TOP);
+ break;
+
+ case PROP_ID_BORDER_RIGHT_STYLE:
+ status = set_prop_border_x_style_from_value (a_this, value,
+ DIR_RIGHT);
+ break;
+
+ case PROP_ID_BORDER_BOTTOM_STYLE:
+ status = set_prop_border_x_style_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_BORDER_LEFT_STYLE:
+ status = set_prop_border_x_style_from_value (a_this, value,
+ DIR_LEFT);
+ break;
+
+ case PROP_ID_BORDER_STYLE:
+ status = set_prop_border_style_from_value (a_this, value) ;
+ break ;
+
+ case PROP_ID_BORDER_TOP_COLOR:
+ status = set_prop_border_x_color_from_value (a_this, value,
+ DIR_TOP);
+ break;
+
+ case PROP_ID_BORDER_RIGHT_COLOR:
+ status = set_prop_border_x_color_from_value (a_this, value,
+ DIR_RIGHT);
+ break;
+
+ case PROP_ID_BORDER_BOTTOM_COLOR:
+ status = set_prop_border_x_color_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_BORDER_LEFT_COLOR:
+ status = set_prop_border_x_color_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_BORDER_TOP:
+ status = set_prop_border_x_from_value (a_this, value,
+ DIR_TOP);
+ break;
+
+ case PROP_ID_BORDER_RIGHT:
+ status = set_prop_border_x_from_value (a_this, value,
+ DIR_RIGHT);
+ break;
+
+ case PROP_ID_BORDER_BOTTOM:
+ status = set_prop_border_x_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_BORDER_LEFT:
+ status = set_prop_border_x_from_value (a_this, value,
+ DIR_LEFT);
+ break;
+
+ case PROP_ID_MARGIN_TOP:
+ status = set_prop_margin_x_from_value (a_this, value,
+ DIR_TOP);
+ break;
+
+ case PROP_ID_BORDER:
+ status = set_prop_border_from_value (a_this, value);
+ break;
+
+ case PROP_ID_MARGIN_RIGHT:
+ status = set_prop_margin_x_from_value (a_this, value,
+ DIR_RIGHT);
+ break;
+
+ case PROP_ID_MARGIN_BOTTOM:
+ status = set_prop_margin_x_from_value (a_this, value,
+ DIR_BOTTOM);
+ break;
+
+ case PROP_ID_MARGIN_LEFT:
+ status = set_prop_margin_x_from_value (a_this, value,
+ DIR_LEFT);
+ break;
+
+ case PROP_ID_MARGIN:
+ status = set_prop_margin_from_value (a_this, value);
+ break;
+
+ case PROP_ID_DISPLAY:
+ status = set_prop_display_from_value (a_this, value);
+ break;
+
+ case PROP_ID_POSITION:
+ status = set_prop_position_from_value (a_this, value);
+ break;
+
+ case PROP_ID_TOP:
+ status = set_prop_x_from_value (a_this, value, DIR_TOP);
+ break;
+
+ case PROP_ID_RIGHT:
+ status = set_prop_x_from_value (a_this, value, DIR_RIGHT);
+ break;
+
+ case PROP_ID_BOTTOM:
+ status = set_prop_x_from_value (a_this, value, DIR_BOTTOM);
+ break;
+
+ case PROP_ID_LEFT:
+ status = set_prop_x_from_value (a_this, value, DIR_LEFT);
+ break;
+
+ case PROP_ID_FLOAT:
+ status = set_prop_float (a_this, value);
+ break;
+
+ case PROP_ID_WIDTH:
+ status = set_prop_width (a_this, value);
+ break;
+
+ case PROP_ID_COLOR:
+ status = set_prop_color (a_this, value);
+ break;
+
+ case PROP_ID_BACKGROUND_COLOR:
+ status = set_prop_background_color (a_this, value);
+ break;
+
+ case PROP_ID_FONT_FAMILY:
+ status = set_prop_font_family_from_value (a_this, value);
+ break;
+
+ case PROP_ID_FONT_SIZE:
+ status = set_prop_font_size_from_value (a_this, value);
+ break;
+
+ case PROP_ID_FONT_STYLE:
+ status = set_prop_font_style_from_value (a_this, value);
+ break;
+
+ case PROP_ID_FONT_WEIGHT:
+ status = set_prop_font_weight_from_value (a_this, value);
+ break;
+
+ case PROP_ID_WHITE_SPACE:
+ status = set_prop_white_space_from_value(a_this, value);
+ break;
+
+ default:
+ return CR_UNKNOWN_TYPE_ERROR;
+
+ }
+
+ return status;
+}
+
+/**
+ *Increases the reference count
+ *of the current instance of #CRStyle.
+ *@param a_this the current instance of #CRStyle.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_style_ref (CRStyle * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ a_this->ref_count++;
+ return CR_OK;
+}
+
+/**
+ *Decreases the reference count of
+ *the current instance of #CRStyle.
+ *If the reference count reaches 0, the
+ *instance of #CRStyle is destoyed.
+ *@param a_this the current instance of #CRStyle.
+ *@return TRUE if the instance has been destroyed, FALSE
+ *otherwise.
+ */
+gboolean
+cr_style_unref (CRStyle * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count)
+ a_this->ref_count--;
+
+ if (!a_this->ref_count) {
+ cr_style_destroy (a_this);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ *Duplicates the current instance of #CRStyle .
+ *The newly created instance of #CRStyle must be
+ *freed using cr_style_destroy ().
+ *@param a_this the current instance of #CRStyle.
+ *@return the newly duplicated instance of #CRStyle.
+ */
+CRStyle *
+cr_style_dup (CRStyle * a_this)
+{
+ CRStyle *result = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ result = cr_style_new (FALSE);
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ cr_style_copy (result, a_this);
+ return result;
+}
+
+/**
+ *Copies a style data structure into another.
+ *TODO: this is actually broken because it's based
+ *on memcpy although some data stuctures of CRStyle should
+ *be properly duplicated.
+ *@param a_dest the destination style datastructure
+ *@param a_src the source style datastructure.
+ *@return CR_OK upon succesfull completion, an error code otherwise
+ */
+enum CRStatus
+cr_style_copy (CRStyle * a_dest, CRStyle * a_src)
+{
+ g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);
+
+ memcpy (a_dest, a_src, sizeof (CRStyle));
+ return CR_OK;
+}
+
+/**
+ *dump a CRNumpPropVal in a string.
+ *@param a_prop_val the numerical property value to dump
+ *@param a_str the string to dump the numerical propertie into.
+ *Note that the string value is appended to a_str.
+ *@param a_nb_indent the number white chars of indentation.
+ */
+enum CRStatus
+cr_style_num_prop_val_to_string (CRNumPropVal * a_prop_val,
+ GString * a_str, guint a_nb_indent)
+{
+ enum CRStatus status = CR_OK;
+ guchar *tmp_str = NULL;
+ GString *str = NULL;
+
+ g_return_val_if_fail (a_prop_val && a_str, CR_BAD_PARAM_ERROR);
+
+ str = g_string_new (NULL);
+ cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
+ g_string_append (str, "NumPropVal {");
+ tmp_str = cr_num_to_string (&a_prop_val->sv);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "sv: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+
+ tmp_str = cr_num_to_string (&a_prop_val->cv);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "cv: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+
+ tmp_str = cr_num_to_string (&a_prop_val->av);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "av: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ g_string_append (str, "}");
+ g_string_append (a_str, str->str);
+ status = CR_OK;
+ cleanup:
+
+ if (tmp_str) {
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ if (str) {
+ g_string_free (str, TRUE);
+ }
+ return status;
+}
+
+enum CRStatus
+cr_style_rgb_prop_val_to_string (CRRgbPropVal * a_prop_val,
+ GString * a_str, guint a_nb_indent)
+{
+ enum CRStatus status = CR_OK;
+ guchar *tmp_str = NULL;
+ GString *str = NULL;
+
+ g_return_val_if_fail (a_prop_val && a_str, CR_BAD_PARAM_ERROR);
+
+ str = g_string_new (NULL);
+
+ cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
+ g_string_append (str, "RGBPropVal {");
+ tmp_str = cr_rgb_to_string (&a_prop_val->sv);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "sv: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ tmp_str = cr_rgb_to_string (&a_prop_val->cv);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "cv: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ tmp_str = cr_rgb_to_string (&a_prop_val->av);
+ if (!tmp_str) {
+ status = CR_ERROR;
+ goto cleanup;
+ }
+ g_string_append_printf (str, "av: %s ", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+
+ g_string_append (str, "}");
+ g_string_append (a_str, str->str);
+ status = CR_OK;
+ cleanup:
+
+ if (tmp_str) {
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ if (str) {
+ g_string_free (str, TRUE);
+ }
+ return status;
+}
+
+enum CRStatus
+cr_style_border_style_to_string (enum CRBorderStyle a_prop,
+ GString * a_str, guint a_nb_indent)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);
+
+ switch (a_prop) {
+ case BORDER_STYLE_NONE:
+ str = (gchar *) "border-style-none";
+ break;
+ case BORDER_STYLE_HIDDEN:
+ str = (gchar *) "border-style-hidden";
+ break;
+ case BORDER_STYLE_DOTTED:
+ str = (gchar *) "border-style-dotted";
+ break;
+ case BORDER_STYLE_DASHED:
+ str = (gchar *) "border-style-dashed";
+ break;
+ case BORDER_STYLE_SOLID:
+ str = (gchar *) "border-style-solid";
+ break;
+ case BORDER_STYLE_DOUBLE:
+ str = (gchar *) "border-style-double";
+ break;
+ case BORDER_STYLE_GROOVE:
+ str = (gchar *) "border-style-groove";
+ break;
+ case BORDER_STYLE_RIDGE:
+ str = (gchar *) "border-style-ridge";
+ break;
+ case BORDER_STYLE_INSET:
+ str = (gchar *) "border-style-inset";
+ break;
+ case BORDER_STYLE_OUTSET:
+ str = (gchar *) "border-style-outset";
+ break;
+ default:
+ str = (gchar *) "unknown border style";
+ break;
+ }
+ cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
+ g_string_append (a_str, str);
+ return CR_OK;
+}
+
+enum CRStatus
+cr_style_display_type_to_string (enum CRDisplayType a_code,
+ GString * a_str, guint a_nb_indent)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);
+
+ switch (a_code) {
+ case DISPLAY_NONE:
+ str = (gchar *) "display-none";
+ break;
+ case DISPLAY_INLINE:
+ str = (gchar *) "display-inline";
+ break;
+ case DISPLAY_BLOCK:
+ str = (gchar *) "display-block";
+ break;
+ case DISPLAY_LIST_ITEM:
+ str = (gchar *) "display-list-item";
+ break;
+ case DISPLAY_RUN_IN:
+ str = (gchar *) "display-run-in";
+ break;
+ case DISPLAY_COMPACT:
+ str = (gchar *) "display-compact";
+ break;
+ case DISPLAY_MARKER:
+ str = (gchar *) "display-marker";
+ break;
+ case DISPLAY_TABLE:
+ str = (gchar *) "display-table";
+ break;
+ case DISPLAY_INLINE_TABLE:
+ str = (gchar *) "display-inline-table";
+ break;
+ case DISPLAY_TABLE_ROW_GROUP:
+ str = (gchar *) "display-table-row-group";
+ break;
+ case DISPLAY_TABLE_HEADER_GROUP:
+ str = (gchar *) "display-table-header-group";
+ break;
+ case DISPLAY_TABLE_FOOTER_GROUP:
+ str = (gchar *) "display-table-footer-group";
+ break;
+ case DISPLAY_TABLE_ROW:
+ str = (gchar *) "display-table-row";
+ break;
+ case DISPLAY_TABLE_COLUMN_GROUP:
+ str = (gchar *) "display-table-column-group";
+ break;
+ case DISPLAY_TABLE_COLUMN:
+ str = (gchar *) "display-table-column";
+ break;
+ case DISPLAY_TABLE_CELL:
+ str = (gchar *) "display-table-cell";
+ break;
+ case DISPLAY_TABLE_CAPTION:
+ str = (gchar *) "display-table-caption";
+ break;
+ case DISPLAY_INHERIT:
+ str = (gchar *) "display-inherit";
+ break;
+ default:
+ str = (gchar *) "unknown display property";
+ break;
+ }
+ cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
+ g_string_append (a_str, str);
+ return CR_OK;
+
+}
+
+enum CRStatus
+cr_style_position_type_to_string (enum CRPositionType a_code,
+ GString * a_str, guint a_nb_indent)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);
+
+ switch (a_code) {
+ case POSITION_STATIC:
+ str = (gchar *) "position-static";
+ break;
+ case POSITION_RELATIVE:
+ str = (gchar *) "position-relative";
+ break;
+ case POSITION_ABSOLUTE:
+ str = (gchar *) "position-absolute";
+ break;
+ case POSITION_FIXED:
+ str = (gchar *) "position-fixed";
+ break;
+ case POSITION_INHERIT:
+ str = (gchar *) "position-inherit";
+ break;
+ default:
+ str = (gchar *) "unknown static property";
+ }
+ cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
+ g_string_append (a_str, str);
+ return CR_OK;
+}
+
+enum CRStatus
+cr_style_float_type_to_string (enum CRFloatType a_code,
+ GString * a_str, guint a_nb_indent)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);
+
+ switch (a_code) {
+ case FLOAT_NONE:
+ str = (gchar *) "float-none";
+ break;
+ case FLOAT_LEFT:
+ str = (gchar *) "float-left";
+ break;
+ case FLOAT_RIGHT:
+ str = (gchar *) "float-right";
+ break;
+ case FLOAT_INHERIT:
+ str = (gchar *) "float-inherit";
+ break;
+ default:
+ str = (gchar *) "unknown float property value";
+ break;
+ }
+ cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
+ g_string_append (a_str, str);
+ return CR_OK;
+}
+
+enum CRStatus
+cr_style_white_space_type_to_string (enum CRWhiteSpaceType a_code,
+ GString * a_str, guint a_nb_indent)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);
+
+ switch (a_code) {
+ case WHITE_SPACE_NORMAL:
+ str = (gchar *) "normal";
+ break;
+ case WHITE_SPACE_PRE:
+ str = (gchar *) "pre";
+ break;
+ case WHITE_SPACE_NOWRAP:
+ str = (gchar *) "nowrap";
+ break;
+ case WHITE_SPACE_INHERIT:
+ str = (gchar *) "inherited";
+ break;
+ default:
+ str = (gchar *) "unknow white space property value";
+ break;
+ }
+ cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
+ g_string_append (a_str, str);
+ return CR_OK;
+}
+
+/**
+ *Serializes in instance of #CRStyle into
+ *a string
+ *@param a_this the instance of #CRStyle to serialize
+ *@param a_str the string to serialise the style into.
+ *if *a_str is NULL, a new GString is instanciated, otherwise
+ *the style serialisation is appended to the existed *a_str
+ *@param the number of white space char to use for indentation.
+ *@return CR_OK upon successful completion, an error code otherwise.
+ */
+enum CRStatus
+cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
+{
+ const gint INTERNAL_INDENT = 2;
+ gint indent = a_nb_indent + INTERNAL_INDENT;
+ gchar *tmp_str = NULL;
+ GString *str = NULL;
+ gint i = 0;
+
+ g_return_val_if_fail (a_this && a_str, CR_BAD_PARAM_ERROR);
+
+ if (!*a_str) {
+ str = g_string_new (NULL);
+ } else {
+ str = *a_str;
+ }
+ cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
+ g_string_append (str, "style {\n");
+
+ /*loop over the num_props and to_string() them */
+ for (i = NUM_PROP_TOP; i < NB_NUM_PROPS; i++) {
+ /*
+ *to_string() the name of the num_prop
+ *(using num_prop_code_to_string)
+ *before outputing it value
+ */
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp) i);
+ if (tmp_str) {
+ g_string_append_printf (str, "%s: ", tmp_str);
+ } else {
+ g_string_append (str, "NULL");
+ }
+ tmp_str = NULL;
+ cr_style_num_prop_val_to_string (&a_this->num_props[i], str,
+ a_nb_indent +
+ INTERNAL_INDENT);
+ g_string_append (str, "\n");
+ }
+ /*loop over the rgb_props and to_string() them all */
+ for (i = RGB_PROP_BORDER_TOP_COLOR; i < NB_RGB_PROPS; i++) {
+ tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp) i);
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ if (tmp_str) {
+ g_string_append_printf (str, "%s: ", tmp_str);
+ } else {
+ g_string_append (str, "NULL: ");
+ }
+ tmp_str = NULL;
+ cr_style_rgb_prop_val_to_string (&a_this->rgb_props[i], str,
+ a_nb_indent +
+ INTERNAL_INDENT);
+ g_string_append (str, "\n");
+ }
+ /*loop over the border_style_props and to_string() them */
+ for (i = BORDER_STYLE_PROP_TOP; i < NB_BORDER_STYLE_PROPS; i++) {
+ tmp_str = (gchar *) border_style_prop_code_to_string ((enum CRBorderStyleProp) i);
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ if (tmp_str) {
+ g_string_append_printf (str, "%s: ", tmp_str);
+ } else {
+ g_string_append (str, "NULL: ");
+ }
+ tmp_str = NULL;
+ cr_style_border_style_to_string (a_this->
+ border_style_props[i], str,
+ 0);
+ g_string_append (str, "\n");
+ }
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ g_string_append (str, "display: ");
+ cr_style_display_type_to_string (a_this->display, str, 0);
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ g_string_append (str, "position: ");
+ cr_style_position_type_to_string (a_this->position, str, 0);
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ g_string_append (str, "float-type: ");
+ cr_style_float_type_to_string (a_this->float_type, str, 0);
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ g_string_append (str, "white-space: ");
+ cr_style_white_space_type_to_string (a_this->white_space, str, 0);
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ g_string_append (str, "font-family: ");
+ tmp_str = (gchar *) cr_font_family_to_string (a_this->font_family, TRUE);
+ if (tmp_str) {
+ g_string_append (str, tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ } else {
+ g_string_append (str, "NULL");
+ }
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = cr_font_size_to_string (&a_this->font_size.sv);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-size {sv:%s, ",
+ tmp_str) ;
+ } else {
+ g_string_append (str, "font-size {sv:NULL, ");
+ }
+ tmp_str = cr_font_size_to_string (&a_this->font_size.cv);
+ if (tmp_str) {
+ g_string_append_printf (str, "cv:%s, ", tmp_str);
+ } else {
+ g_string_append (str, "cv:NULL, ");
+ }
+ tmp_str = cr_font_size_to_string (&a_this->font_size.av);
+ if (tmp_str) {
+ g_string_append_printf (str, "av:%s}", tmp_str);
+ } else {
+ g_string_append (str, "av:NULL}");
+ }
+
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = cr_font_size_adjust_to_string (a_this->font_size_adjust);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-size-adjust: %s", tmp_str);
+ } else {
+ g_string_append (str, "font-size-adjust: NULL");
+ }
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = (gchar *) cr_font_style_to_string (a_this->font_style);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-style: %s", tmp_str);
+ } else {
+ g_string_append (str, "font-style: NULL");
+ }
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = (gchar *) cr_font_variant_to_string (a_this->font_variant);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-variant: %s", tmp_str);
+ } else {
+ g_string_append (str, "font-variant: NULL");
+ }
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = (gchar *) cr_font_weight_to_string (a_this->font_weight);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-weight: %s", tmp_str);
+ } else {
+ g_string_append (str, "font-weight: NULL");
+ }
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+ cr_utils_dump_n_chars2 (' ', str, indent);
+ tmp_str = (gchar *) cr_font_stretch_to_string (a_this->font_stretch);
+ if (tmp_str) {
+ g_string_append_printf (str, "font-stretch: %s", tmp_str);
+ } else {
+ g_string_append (str, "font-stretch: NULL");
+ }
+ tmp_str = NULL;
+ g_string_append (str, "\n");
+
+
+ cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
+ g_string_append (str, "}");
+
+ return CR_OK;
+}
+
+/**
+ *Destructor of the #CRStyle class.
+ *@param a_this the instance to destroy.
+ */
+void
+cr_style_destroy (CRStyle * a_this)
+{
+ g_return_if_fail (a_this);
+
+ g_free (a_this);
+}
+
diff --git a/src/3rdparty/libcroco/cr-style.h b/src/3rdparty/libcroco/cr-style.h
new file mode 100644
index 000000000..18aeaad09
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-style.h
@@ -0,0 +1,339 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli.
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_STYLE_H__
+#define __CR_STYLE_H__
+
+#include "cr-utils.h"
+#include "cr-statement.h"
+#include "cr-fonts.h"
+
+/**
+ *@file
+ *The declaration of the #CRStyle class.
+ */
+G_BEGIN_DECLS
+
+typedef struct _CRStyle CRStyle ;
+
+enum CRBorderStyle
+{
+ BORDER_STYLE_NONE = 0,
+ BORDER_STYLE_HIDDEN,
+ BORDER_STYLE_DOTTED,
+ BORDER_STYLE_DASHED,
+ BORDER_STYLE_SOLID,
+ BORDER_STYLE_DOUBLE,
+ BORDER_STYLE_GROOVE,
+ BORDER_STYLE_RIDGE,
+ BORDER_STYLE_INSET,
+ BORDER_STYLE_OUTSET,
+ BORDER_STYLE_INHERIT
+} ;
+
+enum CRDisplayType
+{
+ DISPLAY_NONE,
+ DISPLAY_INLINE,
+ DISPLAY_BLOCK,
+ DISPLAY_LIST_ITEM,
+ DISPLAY_RUN_IN,
+ DISPLAY_COMPACT,
+ DISPLAY_MARKER,
+ DISPLAY_TABLE,
+ DISPLAY_INLINE_TABLE,
+ DISPLAY_TABLE_ROW_GROUP,
+ DISPLAY_TABLE_HEADER_GROUP,
+ DISPLAY_TABLE_FOOTER_GROUP,
+ DISPLAY_TABLE_ROW,
+ DISPLAY_TABLE_COLUMN_GROUP,
+ DISPLAY_TABLE_COLUMN,
+ DISPLAY_TABLE_CELL,
+ DISPLAY_TABLE_CAPTION,
+ DISPLAY_INHERIT
+} ;
+
+enum CRPositionType
+{
+ POSITION_STATIC,
+ POSITION_RELATIVE,
+ POSITION_ABSOLUTE,
+ POSITION_FIXED,
+ POSITION_INHERIT
+} ;
+
+enum CRFloatType
+{
+ FLOAT_NONE,
+ FLOAT_LEFT,
+ FLOAT_RIGHT,
+ FLOAT_INHERIT
+} ;
+
+enum CRWhiteSpaceType
+{
+ WHITE_SPACE_NORMAL,
+ WHITE_SPACE_PRE,
+ WHITE_SPACE_NOWRAP,
+ WHITE_SPACE_INHERIT
+} ;
+
+
+#define BORDER_THIN 2
+#define BORDER_MEDIUM 4
+#define BORDER_THICK 6
+
+
+/**
+ *A numerical css property value.
+ *This data type is actually split in 3 parts:
+ *1/the specified value
+ *2/the computed value
+ *3/the actual value.
+ *To understand the semantic of these three parts,
+ *see css2 spec chap 6.1 ("Specified, computed and actual values.").
+ */
+typedef struct _CRNumPropVal CRNumPropVal ;
+struct _CRNumPropVal
+{
+ /**specified value*/
+ CRNum sv ;
+ /**computed value*/
+ CRNum cv ;
+ /**actual value*/
+ CRNum av ;
+} ;
+
+/**
+ *An rgb css property value.
+ *This data type is actually split in 3 parts:
+ *1/the specified value
+ *2/the computed value
+ *3/the actual value.
+ *To understand the semantic of these three parts,
+ *see css2 spec chap 6.1 ("Specified, computed and actual values.").
+ */
+typedef struct _CRRgbPropVal CRRgbPropVal ;
+struct _CRRgbPropVal
+{
+ /**specified value*/
+ CRRgb sv ;
+ /**computed value*/
+ CRRgb cv ;
+ /**actual value*/
+ CRRgb av ;
+} ;
+
+
+enum CRNumProp
+{
+ NUM_PROP_TOP=0,
+ NUM_PROP_RIGHT,
+ NUM_PROP_BOTTOM,
+ NUM_PROP_LEFT,/*3*/
+
+ NUM_PROP_PADDING_TOP,
+ NUM_PROP_PADDING_RIGHT,
+ NUM_PROP_PADDING_BOTTOM,
+ NUM_PROP_PADDING_LEFT,/*7*/
+
+ NUM_PROP_BORDER_TOP,
+ NUM_PROP_BORDER_RIGHT,
+ NUM_PROP_BORDER_BOTTOM,
+ NUM_PROP_BORDER_LEFT,/*11*/
+
+ NUM_PROP_MARGIN_TOP,
+ NUM_PROP_MARGIN_RIGHT,
+ NUM_PROP_MARGIN_BOTTOM,
+ NUM_PROP_MARGIN_LEFT,/*15*/
+
+ NUM_PROP_WIDTH,
+
+ /*must be last*/
+ NB_NUM_PROPS
+} ;
+
+enum CRRgbProp
+{
+ RGB_PROP_BORDER_TOP_COLOR = 0,
+ RGB_PROP_BORDER_RIGHT_COLOR,
+ RGB_PROP_BORDER_BOTTOM_COLOR,
+ RGB_PROP_BORDER_LEFT_COLOR,
+ RGB_PROP_COLOR,
+ RGB_PROP_BACKGROUND_COLOR,
+
+ /*must be last*/
+ NB_RGB_PROPS
+} ;
+
+
+enum CRBorderStyleProp
+{
+ BORDER_STYLE_PROP_TOP = 0,
+ BORDER_STYLE_PROP_RIGHT,
+ BORDER_STYLE_PROP_BOTTOM,
+ BORDER_STYLE_PROP_LEFT,
+
+ /*must be last*/
+ NB_BORDER_STYLE_PROPS
+} ;
+
+enum CRBoxOffsetProp
+{
+ BOX_OFFSET_PROP_TOP = 0,
+ BOX_OFFSET_PROP_RIGHT,
+ BOX_OFFSET_PROP_BOTTOM,
+ BOX_OFFSET_PROP_LEFT,
+
+ /*must be last*/
+ NB_BOX_OFFSET_PROPS
+} ;
+
+typedef struct _CRFontSizeVal CRFontSizeVal ;
+struct _CRFontSizeVal {
+ /*specified value*/
+ CRFontSize sv ;
+ /*computed value*/
+ CRFontSize cv ;
+ /*actual value*/
+ CRFontSize av ;
+} ;
+
+/**
+ *The css2 style class.
+ *Contains computed and actual values
+ *inferred from the declarations found
+ *in the stylesheets.
+ *See css2 spec chapter 6.
+ */
+struct _CRStyle
+{
+ /**
+ *numerical properties.
+ *the properties are indexed by
+ *enum #CRNumProp.
+ */
+ CRNumPropVal num_props[NB_NUM_PROPS] ;
+
+ /**
+ *color properties.
+ *They are indexed by enum #CRRgbProp .
+ */
+ CRRgbPropVal rgb_props[NB_RGB_PROPS] ;
+
+ /**
+ *border style properties.
+ *They are indexed by enum #CRBorderStyleProp .
+ */
+ enum CRBorderStyle border_style_props[NB_BORDER_STYLE_PROPS] ;
+
+ /**box display type*/
+ enum CRDisplayType display ;
+
+ /**the positioning scheme*/
+ enum CRPositionType position ;
+
+ /**the float property*/
+ enum CRFloatType float_type ;
+
+ /*
+ *the 'font-family' property.
+ */
+ CRFontFamily *font_family ;
+
+ /**
+ *the 'font-size' property.
+ */
+ CRFontSizeVal font_size ;
+ CRFontSizeAdjust *font_size_adjust ;
+ enum CRFontStyle font_style ;
+ enum CRFontVariant font_variant ;
+ enum CRFontWeight font_weight ;
+ enum CRFontStretch font_stretch ;
+
+ /**
+ * the 'tex' properties
+ */
+ enum CRWhiteSpaceType white_space;
+
+ gboolean inherited_props_resolved ;
+ CRStyle *parent_style ;
+ gulong ref_count ;
+} ;
+
+enum CRStatus cr_style_white_space_type_to_string (enum CRWhiteSpaceType a_code,
+ GString * a_str, guint a_nb_indent) ;
+
+enum CRStatus cr_style_num_prop_val_to_string (CRNumPropVal *a_prop_val,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+enum CRStatus cr_style_rgb_prop_val_to_string (CRRgbPropVal *a_prop_val,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+enum CRStatus cr_style_border_style_to_string (enum CRBorderStyle a_prop,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+enum CRStatus cr_style_display_type_to_string (enum CRDisplayType a_code,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+enum CRStatus cr_style_position_type_to_string (enum CRPositionType a_code,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+enum CRStatus cr_style_float_type_to_string (enum CRFloatType a_code,
+ GString *a_str,
+ guint a_nb_indent) ;
+
+CRStyle * cr_style_new (gboolean a_set_props_to_initial_values) ;
+
+enum CRStatus cr_style_set_props_to_default_values (CRStyle *a_this) ;
+enum CRStatus cr_style_set_props_to_initial_values (CRStyle *a_this) ;
+enum CRStatus cr_style_resolve_inherited_properties (CRStyle *a_this) ;
+enum CRStatus cr_style_propagate_from_parent (CRStyle *a_this);
+
+enum CRStatus cr_style_set_style_from_decl (CRStyle *a_this,
+ CRDeclaration *a_decl) ;
+
+
+enum CRStatus cr_style_copy (CRStyle *a_dest, CRStyle *a_src) ;
+
+enum CRStatus cr_style_ref (CRStyle *a_this) ;
+
+gboolean cr_style_unref (CRStyle *a_this) ;
+
+void cr_style_destroy (CRStyle *a_this) ;
+
+CRStyle * cr_style_dup (CRStyle *a_this) ;
+
+enum CRStatus cr_style_to_string (CRStyle *a_this,
+ GString **a_str,
+ guint a_nb_indent) ;
+
+G_END_DECLS
+
+#endif /*__CR_STYLE_H__*/
diff --git a/src/3rdparty/libcroco/cr-stylesheet.c b/src/3rdparty/libcroco/cr-stylesheet.c
new file mode 100644
index 000000000..a2cfc20c9
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-stylesheet.c
@@ -0,0 +1,261 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2004 Dodji Seketeli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "string.h"
+#include "cr-stylesheet.h"
+
+/**
+ *@file
+ *The definition of the #CRStyleSheet class
+ */
+
+/**
+ *Constructor of the #CRStyleSheet class.
+ *@param the initial list of css statements.
+ *@return the newly built css2 stylesheet, or NULL in case of error.
+ */
+CRStyleSheet *
+cr_stylesheet_new (CRStatement * a_stmts)
+{
+ CRStyleSheet *result;
+
+ result = (CRStyleSheet *) g_try_malloc (sizeof (CRStyleSheet));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRStyleSheet));
+
+ if (a_stmts)
+ result->statements = a_stmts;
+
+ return result;
+}
+
+/**
+ *@param a_this the current instance of #CRStyleSheet
+ *@return the serialized stylesheet.
+ */
+gchar *
+cr_stylesheet_to_string (CRStyleSheet const *a_this)
+{
+ gchar *str = NULL;
+ GString *stringue = NULL;
+ CRStatement const *cur_stmt = NULL;
+ CRStyleSheet *cur = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ stringue = g_string_new (NULL) ;
+ g_return_val_if_fail (stringue, NULL) ;
+
+ if (a_this->import) {
+ str = cr_stylesheet_to_string (a_this->import);
+ if (str) {
+ g_string_append (stringue, str) ;
+ g_free (str) ;
+ g_string_append (stringue, "\n") ;
+ str = NULL ;
+ }
+ }
+
+ for (cur_stmt = a_this->statements;
+ cur_stmt; cur_stmt = cur_stmt->next) {
+ if (cur_stmt->prev) {
+ g_string_append (stringue, "\n\n") ;
+ }
+ str = cr_statement_to_string (cur_stmt, 0) ;
+ if (str) {
+ g_string_append (stringue, str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+
+ if (a_this->next) {
+ str = cr_stylesheet_to_string (a_this->next);
+ if (str) {
+ g_string_append (stringue, "\n") ;
+ g_string_append (stringue, str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+ }
+
+ if (stringue) {
+ str = stringue->str ;
+ g_string_free (stringue, FALSE) ;
+ stringue = NULL ;
+ }
+ return str ;
+}
+
+/**
+ *Dumps the current css2 stylesheet to a file.
+ *@param a_this the current instance of #CRStyleSheet.
+ *@param a_fp the destination file
+ */
+void
+cr_stylesheet_dump (CRStyleSheet const * a_this, FILE * a_fp)
+{
+ gchar *str = NULL ;
+
+ g_return_if_fail (a_this);
+
+ str = cr_stylesheet_to_string (a_this) ;
+ if (str) {
+ fprintf (a_fp, "%s", str) ;
+ g_free (str) ;
+ str = NULL ;
+ }
+}
+
+/**
+ *Return the number of rules in the stylesheet.
+ *@param a_this the current instance of #CRStyleSheet.
+ *@return number of rules in the stylesheet.
+ */
+gint
+cr_stylesheet_nr_rules (CRStyleSheet const * a_this)
+{
+ g_return_val_if_fail (a_this, -1);
+
+ return cr_statement_nr_rules (a_this->statements);
+}
+
+/**
+ *Use an index to get a CRStatement from the rules in a given stylesheet.
+ *@param a_this the current instance of #CRStatement.
+ *@param itemnr the index into the rules.
+ *@return CRStatement at position itemnr, if itemnr > number of rules - 1,
+ *it will return NULL.
+ */
+CRStatement *
+cr_stylesheet_statement_get_from_list (CRStyleSheet * a_this, int itemnr)
+{
+ g_return_val_if_fail (a_this, NULL);
+
+ return cr_statement_get_from_list (a_this->statements, itemnr);
+}
+
+/**
+ *Appends a new stylesheet to the current list of #CRStylesheet.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRStylesheet .
+ *@param a_new_stylesheet the stylesheet to append.
+ *@return the list of stylesheets with the a_new_stylesheet appended to it.
+ */
+CRStyleSheet *
+cr_stylesheet_append_stylesheet (CRStyleSheet * a_this, CRStyleSheet * a_new_stylesheet)
+{
+ CRStyleSheet *cur = NULL;
+
+ g_return_val_if_fail (a_new_stylesheet, NULL);
+
+ if (a_this == NULL)
+ return a_new_stylesheet;
+
+ for (cur = a_this; cur->next; cur = cur->next) ;
+
+ cur->next = a_new_stylesheet;
+
+ return a_this;
+}
+
+
+/**
+ *Appends a new import stylesheet to the current list of imports.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRStylesheet .
+ *@param a_new_stylesheet the import stylesheet to append.
+ *@return the list of stylesheets with the a_new_import appended to it.
+ */
+CRStyleSheet *
+cr_stylesheet_append_import (CRStyleSheet * a_this, CRStyleSheet * a_new_import)
+{
+ CRStyleSheet *cur = NULL;
+
+ g_return_val_if_fail (a_new_import, NULL);
+
+ if (a_this->import == NULL)
+ a_this->import = a_new_import;
+ return a_this;
+
+ for (cur = a_this->import; cur->next; cur = cur->next) ;
+
+ cur->next = a_new_import;
+
+ return a_this;
+}
+
+
+void
+cr_stylesheet_ref (CRStyleSheet * a_this)
+{
+ g_return_if_fail (a_this);
+
+ a_this->ref_count++;
+}
+
+gboolean
+cr_stylesheet_unref (CRStyleSheet * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count)
+ a_this->ref_count--;
+
+ if (!a_this->ref_count) {
+ cr_stylesheet_destroy (a_this);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ *Destructor of the #CRStyleSheet class.
+ *@param a_this the current instance of the #CRStyleSheet class.
+ */
+void
+cr_stylesheet_destroy (CRStyleSheet * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (a_this->statements) {
+ cr_statement_destroy (a_this->statements);
+ a_this->statements = NULL;
+ }
+
+ if (a_this->import) {
+ cr_stylesheet_destroy (a_this->import);
+ }
+
+ if (a_this->next) {
+ cr_stylesheet_destroy (a_this->next);
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-stylesheet.h b/src/3rdparty/libcroco/cr-stylesheet.h
new file mode 100644
index 000000000..7ebaf7a60
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-stylesheet.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * see COPYRIGHTS file for copyright information.
+ */
+
+
+#ifndef __CR_STYLESHEET_H__
+#define __CR_STYLESHEET_H__
+
+#include "cr-utils.h"
+#include "cr-statement.h"
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The declaration of the #CRStyleSheet class.
+ */
+
+
+enum CRStyleOrigin
+{
+ /*Please don't change the order of
+ *the values enumerated here ...
+ *New values should be added at the end,
+ *just before ORIGIN_END.
+ */
+ ORIGIN_UA = 0,
+ ORIGIN_USER,
+ ORIGIN_AUTHOR,
+
+ /*must always be the last one*/
+ NB_ORIGINS
+} ;
+
+/**
+ *An abstraction of a css stylesheet as defined
+ *by the css2 spec in chapter 4.
+ */
+struct _CRStyleSheet
+{
+ /**The css statements list*/
+ CRStatement *statements ;
+
+ enum CRStyleOrigin origin ;
+
+ /*the parent import rule, if any.*/
+ CRStatement *parent_import_rule ;
+
+ /**custom data used by libcroco*/
+ gpointer croco_data ;
+
+ /**
+ *custom application data pointer
+ *Can be used by applications.
+ */
+ gpointer app_data ;
+
+ /**
+ *the reference count of this insance
+ *Please, don't never ever modify it
+ *directly. Use cr_stylesheet_ref()
+ *and cr_stylesheet_unref() instead.
+ */
+ gulong ref_count ;
+
+ /**
+ * A link to an imported stylesheet
+ * (can have more than one).
+ */
+ CRStyleSheet *import;
+
+ /**
+ * A link to the next stylesheet.
+ */
+ CRStyleSheet *next;
+} ;
+
+CRStyleSheet * cr_stylesheet_new (CRStatement *a_stmts) ;
+
+gchar * cr_stylesheet_to_string (CRStyleSheet const *a_this) ;
+
+void cr_stylesheet_dump (CRStyleSheet const *a_this, FILE *a_fp) ;
+
+gint cr_stylesheet_nr_rules (CRStyleSheet const *a_this) ;
+
+CRStatement * cr_stylesheet_statement_get_from_list (CRStyleSheet *a_this, int itemnr) ;
+
+CRStyleSheet * cr_stylesheet_append_import (CRStyleSheet *a_this, CRStyleSheet *a_new_import) ;
+
+CRStyleSheet * cr_stylesheet_append_stylesheet (CRStyleSheet *a_this, CRStyleSheet *a_new_stylesheet) ;
+
+void cr_stylesheet_ref (CRStyleSheet *a_this) ;
+
+gboolean cr_stylesheet_unref (CRStyleSheet *a_this) ;
+
+void cr_stylesheet_destroy (CRStyleSheet *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_STYLESHEET_H__*/
diff --git a/src/3rdparty/libcroco/cr-term.c b/src/3rdparty/libcroco/cr-term.c
new file mode 100644
index 000000000..aec524b0b
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-term.c
@@ -0,0 +1,788 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "cr-term.h"
+#include "cr-num.h"
+#include "cr-parser.h"
+
+/**
+ *@file
+ *Definition of the #CRTem class.
+ */
+
+static void
+cr_term_clear (CRTerm * a_this)
+{
+ g_return_if_fail (a_this);
+
+ switch (a_this->type) {
+ case TERM_NUMBER:
+ if (a_this->content.num) {
+ cr_num_destroy (a_this->content.num);
+ a_this->content.num = NULL;
+ }
+ break;
+
+ case TERM_FUNCTION:
+ if (a_this->ext_content.func_param) {
+ cr_term_destroy (a_this->ext_content.func_param);
+ a_this->ext_content.func_param = NULL;
+ }
+ case TERM_STRING:
+ case TERM_IDENT:
+ case TERM_URI:
+ case TERM_HASH:
+ if (a_this->content.str) {
+ cr_string_destroy (a_this->content.str);
+ a_this->content.str = NULL;
+ }
+ break;
+
+ case TERM_RGB:
+ if (a_this->content.rgb) {
+ cr_rgb_destroy (a_this->content.rgb);
+ a_this->content.rgb = NULL;
+ }
+ break;
+
+ case TERM_UNICODERANGE:
+ case TERM_NO_TYPE:
+ default:
+ break;
+ }
+
+ a_this->type = TERM_NO_TYPE;
+ a_this->n = FALSE;
+}
+
+/**
+ *Instanciate a #CRTerm.
+ *@return the newly build instance
+ *of #CRTerm.
+ */
+CRTerm *
+cr_term_new (void)
+{
+ CRTerm *result = NULL;
+
+ result = (CRTerm *) g_try_malloc (sizeof (CRTerm));
+ if (!result) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+ memset (result, 0, sizeof (CRTerm));
+ return result;
+}
+
+/**
+ *Parses an expresion as defined by the css2 spec
+ *and builds the expression as a list of terms.
+ *@param a_buf the buffer to parse.
+ *@return a pointer to the first term of the expression or
+ *NULL if parsing failed.
+ */
+CRTerm *
+cr_term_parse_expression_from_buf (const guchar * a_buf,
+ enum CREncoding a_encoding)
+{
+ CRParser *parser = NULL;
+ CRTerm *result = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_buf, NULL);
+
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
+ g_return_val_if_fail (parser, NULL);
+
+ status = cr_parser_try_to_skip_spaces_and_comments (parser);
+ if (status != CR_OK) {
+ goto cleanup;
+ }
+ status = cr_parser_parse_expr (parser, &result);
+ if (status != CR_OK) {
+ if (result) {
+ cr_term_destroy (result);
+ result = NULL;
+ }
+ }
+
+ cleanup:
+ if (parser) {
+ cr_parser_destroy (parser);
+ parser = NULL;
+ }
+
+ return result;
+}
+
+enum CRStatus
+cr_term_set_number (CRTerm * a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_NUMBER;
+ a_this->content.num = a_num;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_function (CRTerm * a_this, CRString * a_func_name,
+ CRTerm * a_func_param)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_FUNCTION;
+ a_this->content.str = a_func_name;
+ a_this->ext_content.func_param = a_func_param;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_string (CRTerm * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_STRING;
+ a_this->content.str = a_str;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_ident (CRTerm * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_IDENT;
+ a_this->content.str = a_str;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_uri (CRTerm * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_URI;
+ a_this->content.str = a_str;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_rgb (CRTerm * a_this, CRRgb * a_rgb)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_RGB;
+ a_this->content.rgb = a_rgb;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_term_set_hash (CRTerm * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_term_clear (a_this);
+
+ a_this->type = TERM_HASH;
+ a_this->content.str = a_str;
+ return CR_OK;
+}
+
+/**
+ *Appends a new term to the current list of #CRTerm.
+ *
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm .
+ *@param a_new_term the term to append.
+ *@return the list of terms with the a_new_term appended to it.
+ */
+CRTerm *
+cr_term_append_term (CRTerm * a_this, CRTerm * a_new_term)
+{
+ CRTerm *cur = NULL;
+
+ g_return_val_if_fail (a_new_term, NULL);
+
+ if (a_this == NULL)
+ return a_new_term;
+
+ for (cur = a_this; cur->next; cur = cur->next) ;
+
+ cur->next = a_new_term;
+ a_new_term->prev = cur;
+
+ return a_this;
+}
+
+/**
+ *Prepends a term to the list of terms represented by a_this.
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTerm .
+ *@param a_new_term the term to prepend.
+ *@return the head of the new list.
+ */
+CRTerm *
+cr_term_prepend_term (CRTerm * a_this, CRTerm * a_new_term)
+{
+ g_return_val_if_fail (a_this && a_new_term, NULL);
+
+ a_new_term->next = a_this;
+ a_this->prev = a_new_term;
+
+ return a_new_term;
+}
+
+/**
+ *Serializes the expression represented by
+ *the chained instances of #CRterm.
+ *@param a_this the current instance of #CRTerm
+ *@return the zero terminated string containing the serialized
+ *form of #CRTerm. MUST BE FREED BY THE CALLER using g_free().
+ */
+guchar *
+cr_term_to_string (CRTerm const * a_this)
+{
+ GString *str_buf = NULL;
+ CRTerm const *cur = NULL;
+ guchar *result = NULL,
+ *content = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+ g_return_val_if_fail (str_buf, NULL);
+
+ for (cur = a_this; cur; cur = cur->next) {
+ if ((cur->content.str == NULL)
+ && (cur->content.num == NULL)
+ && (cur->content.str == NULL)
+ && (cur->content.rgb == NULL))
+ continue;
+
+ switch (cur->the_operator) {
+ case DIVIDE:
+ g_string_append (str_buf, " / ");
+ break;
+
+ case COMMA:
+ g_string_append (str_buf, ", ");
+ break;
+
+ case NO_OP:
+ if (cur->prev) {
+ g_string_append (str_buf, " ");
+ }
+ break;
+ default:
+
+ break;
+ }
+
+ switch (cur->unary_op) {
+ case PLUS_UOP:
+ g_string_append (str_buf, "+");
+ break;
+
+ case MINUS_UOP:
+ g_string_append (str_buf, "-");
+ break;
+
+ default:
+ break;
+ }
+
+ switch (cur->type) {
+ case TERM_NUMBER:
+ if (cur->content.num) {
+ content = cr_num_to_string (cur->content.num);
+ }
+
+ if (content) {
+ g_string_append (str_buf, (const gchar *) content);
+ g_free (content);
+ content = NULL;
+ }
+
+ break;
+
+ case TERM_FUNCTION:
+ if (cur->content.str) {
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf, "%s(",
+ content);
+
+ if (cur->ext_content.func_param) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_term_to_string
+ (cur->
+ ext_content.func_param);
+
+ if (tmp_str) {
+ g_string_append (str_buf,
+ (const gchar *) tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ }
+ g_string_append (str_buf, ")");
+ g_free (content);
+ content = NULL;
+ }
+
+ break;
+
+ case TERM_STRING:
+ if (cur->content.str) {
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf,
+ "\"%s\"", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_IDENT:
+ if (cur->content.str) {
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append (str_buf, (const gchar *) content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_URI:
+ if (cur->content.str) {
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf
+ (str_buf, "url(%s)", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_RGB:
+ if (cur->content.rgb) {
+ guchar *tmp_str = NULL;
+
+ g_string_append (str_buf, "rgb(");
+ tmp_str = cr_rgb_to_string (cur->content.rgb);
+
+ if (tmp_str) {
+ g_string_append (str_buf, (const gchar *) tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ g_string_append (str_buf, ")");
+ }
+
+ break;
+
+ case TERM_UNICODERANGE:
+ g_string_append
+ (str_buf,
+ "?found unicoderange: dump not supported yet?");
+ break;
+
+ case TERM_HASH:
+ if (cur->content.str) {
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf,
+ "#%s", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ default:
+ g_string_append (str_buf,
+ "Unrecognized Term type");
+ break;
+ }
+ }
+
+ if (str_buf) {
+ result =(guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+guchar *
+cr_term_one_to_string (CRTerm const * a_this)
+{
+ GString *str_buf = NULL;
+ guchar *result = NULL,
+ *content = NULL;
+
+ g_return_val_if_fail (a_this, NULL);
+
+ str_buf = g_string_new (NULL);
+ g_return_val_if_fail (str_buf, NULL);
+
+ if ((a_this->content.str == NULL)
+ && (a_this->content.num == NULL)
+ && (a_this->content.str == NULL)
+ && (a_this->content.rgb == NULL))
+ return NULL ;
+
+ switch (a_this->the_operator) {
+ case DIVIDE:
+ g_string_append_printf (str_buf, " / ");
+ break;
+
+ case COMMA:
+ g_string_append_printf (str_buf, ", ");
+ break;
+
+ case NO_OP:
+ if (a_this->prev) {
+ g_string_append_printf (str_buf, " ");
+ }
+ break;
+ default:
+
+ break;
+ }
+
+ switch (a_this->unary_op) {
+ case PLUS_UOP:
+ g_string_append_printf (str_buf, "+");
+ break;
+
+ case MINUS_UOP:
+ g_string_append_printf (str_buf, "-");
+ break;
+
+ default:
+ break;
+ }
+
+ switch (a_this->type) {
+ case TERM_NUMBER:
+ if (a_this->content.num) {
+ content = cr_num_to_string (a_this->content.num);
+ }
+
+ if (content) {
+ g_string_append (str_buf, (const gchar *) content);
+ g_free (content);
+ content = NULL;
+ }
+
+ break;
+
+ case TERM_FUNCTION:
+ if (a_this->content.str) {
+ content = (guchar *) g_strndup
+ (a_this->content.str->stryng->str,
+ a_this->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf, "%s(",
+ content);
+
+ if (a_this->ext_content.func_param) {
+ guchar *tmp_str = NULL;
+
+ tmp_str = cr_term_to_string
+ (a_this->
+ ext_content.func_param);
+
+ if (tmp_str) {
+ g_string_append_printf
+ (str_buf,
+ "%s", tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+
+ g_string_append_printf (str_buf, ")");
+ g_free (content);
+ content = NULL;
+ }
+ }
+
+ break;
+
+ case TERM_STRING:
+ if (a_this->content.str) {
+ content = (guchar *) g_strndup
+ (a_this->content.str->stryng->str,
+ a_this->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf,
+ "\"%s\"", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_IDENT:
+ if (a_this->content.str) {
+ content = (guchar *) g_strndup
+ (a_this->content.str->stryng->str,
+ a_this->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append (str_buf, (const gchar *) content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_URI:
+ if (a_this->content.str) {
+ content = (guchar *) g_strndup
+ (a_this->content.str->stryng->str,
+ a_this->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf
+ (str_buf, "url(%s)", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ case TERM_RGB:
+ if (a_this->content.rgb) {
+ guchar *tmp_str = NULL;
+
+ g_string_append_printf (str_buf, "rgb(");
+ tmp_str = cr_rgb_to_string (a_this->content.rgb);
+
+ if (tmp_str) {
+ g_string_append (str_buf, (const gchar *) tmp_str);
+ g_free (tmp_str);
+ tmp_str = NULL;
+ }
+ g_string_append_printf (str_buf, ")");
+ }
+
+ break;
+
+ case TERM_UNICODERANGE:
+ g_string_append_printf
+ (str_buf,
+ "?found unicoderange: dump not supported yet?");
+ break;
+
+ case TERM_HASH:
+ if (a_this->content.str) {
+ content = (guchar *) g_strndup
+ (a_this->content.str->stryng->str,
+ a_this->content.str->stryng->len);
+ }
+
+ if (content) {
+ g_string_append_printf (str_buf,
+ "#%s", content);
+ g_free (content);
+ content = NULL;
+ }
+ break;
+
+ default:
+ g_string_append_printf (str_buf,
+ "%s",
+ "Unrecognized Term type");
+ break;
+ }
+
+ if (str_buf) {
+ result = (guchar *) str_buf->str;
+ g_string_free (str_buf, FALSE);
+ str_buf = NULL;
+ }
+
+ return result;
+}
+
+/**
+ *Dumps the expression (a list of terms connected by operators)
+ *to a file.
+ *TODO: finish the dump. The dump of some type of terms have not yet been
+ *implemented.
+ *@param a_this the current instance of #CRTerm.
+ *@param a_fp the destination file pointer.
+ */
+void
+cr_term_dump (CRTerm const * a_this, FILE * a_fp)
+{
+ guchar *content = NULL;
+
+ g_return_if_fail (a_this);
+
+ content = cr_term_to_string (a_this);
+
+ if (content) {
+ fprintf (a_fp, "%s", content);
+ g_free (content);
+ }
+}
+
+/**
+ *Return the number of terms in the expression.
+ *@param a_this the current instance of #CRTerm.
+ *@return number of terms in the expression.
+ */
+int
+cr_term_nr_values (CRTerm const *a_this)
+{
+ CRTerm const *cur = NULL ;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, -1) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ nr ++;
+ return nr;
+}
+
+/**
+ *Use an index to get a CRTerm from the expression.
+ *@param a_this the current instance of #CRTerm.
+ *@param itemnr the index into the expression.
+ *@return CRTerm at position itemnr, if itemnr > number of terms - 1,
+ *it will return NULL.
+ */
+CRTerm *
+cr_term_get_from_list (CRTerm *a_this, int itemnr)
+{
+ CRTerm *cur = NULL ;
+ int nr = 0;
+
+ g_return_val_if_fail (a_this, NULL) ;
+
+ for (cur = a_this ; cur ; cur = cur->next)
+ if (nr++ == itemnr)
+ return cur;
+ return NULL;
+}
+
+/**
+ *Increments the reference counter of the current instance
+ *of #CRTerm.*
+ *@param a_this the current instance of #CRTerm.
+ */
+void
+cr_term_ref (CRTerm * a_this)
+{
+ g_return_if_fail (a_this);
+
+ a_this->ref_count++;
+}
+
+/**
+ *Decrements the ref count of the current instance of
+ *#CRTerm. If the ref count reaches zero, the instance is
+ *destroyed.
+ *@param a_this the current instance of #CRTerm.
+ *@return TRUE if the current instance has been destroyed, FALSE otherwise.
+ */
+gboolean
+cr_term_unref (CRTerm * a_this)
+{
+ g_return_val_if_fail (a_this, FALSE);
+
+ if (a_this->ref_count) {
+ a_this->ref_count--;
+ }
+
+ if (a_this->ref_count == 0) {
+ cr_term_destroy (a_this);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ *The destructor of the #CRTerm class.
+ *@param a_this the "this pointer" of the current instance
+ *of #CRTerm.
+ */
+void
+cr_term_destroy (CRTerm * const a_this)
+{
+ g_return_if_fail (a_this);
+
+ cr_term_clear (a_this);
+
+ if (a_this->next) {
+ cr_term_destroy (a_this->next);
+ a_this->next = NULL;
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-term.h b/src/3rdparty/libcroco/cr-term.h
new file mode 100644
index 000000000..39b9c6a8b
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-term.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "cr-utils.h"
+#include "cr-rgb.h"
+#include "cr-num.h"
+#include "cr-string.h"
+
+#ifndef __CR_TERM_H__
+#define __CR_TERM_H__
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *Declaration of the #CRTerm class.
+ */
+
+enum CRTermType
+{
+ TERM_NO_TYPE = 0,
+ TERM_NUMBER,
+ TERM_FUNCTION,
+ TERM_STRING,
+ TERM_IDENT,
+ TERM_URI,
+ TERM_RGB,
+ TERM_UNICODERANGE,
+ TERM_HASH
+} ;
+
+
+enum UnaryOperator
+{
+ NO_UNARY_UOP = 0,
+ PLUS_UOP,
+ MINUS_UOP,
+ EMPTY_UNARY_UOP
+} ;
+
+enum Operator
+{
+ NO_OP = 0,
+ DIVIDE,
+ COMMA
+} ;
+
+struct _CRTerm ;
+typedef struct _CRTerm CRTerm ;
+
+/**
+ *An abstraction of a css2 term as
+ *defined in the CSS2 spec in appendix D.1:
+ *term ::=
+ *[ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S*
+ *| ANGLE S* | TIME S* | FREQ S* | function ]
+ * | STRING S* | IDENT S* | URI S* | RGB S*
+ *| UNICODERANGE S* | hexcolor
+ */
+struct _CRTerm
+{
+ /**
+ *The type of the term.
+ */
+ enum CRTermType type ;
+
+ /**
+ *The unary operator associated to
+ *the current term.
+ */
+ enum UnaryOperator unary_op ;
+
+ /**
+ *The operator associated to the current term.
+ */
+ enum Operator the_operator ;
+
+
+ /**
+ *The content of the term.
+ *Depending of the type of the term,
+ *this holds either a number, a percentage ...
+ */
+ union
+ {
+ CRNum *num ;
+ CRString * str ;
+ CRRgb * rgb ;
+ } content ;
+
+ /**
+ *If the term is of type UNICODERANGE,
+ *this field holds the upper bound of the range.
+ *if the term is of type FUNCTION, this holds
+ *an instance of CRTerm that represents
+ * the expression which is the argument of the function.
+ */
+ union
+ {
+ CRTerm *func_param ;
+ } ext_content ;
+
+ /**
+ *A flag to indicate if there is an n as in the nth child expression 'an+b'.
+ */
+ gboolean n;
+
+ /**
+ *A spare pointer, just in case.
+ *Can be used by the application.
+ */
+ gpointer app_data ;
+
+ glong ref_count ;
+
+ /**
+ *A pointer to the next term,
+ *just in case this term is part of
+ *an expression.
+ */
+ CRTerm *next ;
+
+ /**
+ *A pointer to the previous
+ *term.
+ */
+ CRTerm *prev ;
+ CRParsingLocation location ;
+} ;
+
+CRTerm * cr_term_parse_expression_from_buf (const guchar *a_buf,
+ enum CREncoding a_encoding) ;
+CRTerm * cr_term_new (void) ;
+
+enum CRStatus cr_term_set_number (CRTerm *a_this, CRNum *a_num) ;
+
+enum CRStatus cr_term_set_function (CRTerm *a_this,
+ CRString *a_func_name,
+ CRTerm *a_func_param) ;
+
+enum CRStatus cr_term_set_string (CRTerm *a_this, CRString *a_str) ;
+
+enum CRStatus cr_term_set_ident (CRTerm *a_this, CRString *a_str) ;
+
+enum CRStatus cr_term_set_uri (CRTerm *a_this, CRString *a_str) ;
+
+enum CRStatus cr_term_set_rgb (CRTerm *a_this, CRRgb *a_rgb) ;
+
+enum CRStatus cr_term_set_hash (CRTerm *a_this, CRString *a_str) ;
+
+CRTerm * cr_term_append_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+CRTerm * cr_term_prepend_term (CRTerm *a_this, CRTerm *a_new_term) ;
+
+guchar * cr_term_to_string (CRTerm const *a_this) ;
+
+guchar * cr_term_one_to_string (CRTerm const * a_this) ;
+
+void cr_term_dump (CRTerm const *a_this, FILE *a_fp) ;
+
+int cr_term_nr_values (CRTerm const *a_this) ;
+
+CRTerm * cr_term_get_from_list (CRTerm *a_this, int itemnr) ;
+
+void cr_term_ref (CRTerm *a_this) ;
+
+gboolean cr_term_unref (CRTerm *a_this) ;
+
+void cr_term_destroy (CRTerm * a_term) ;
+
+G_END_DECLS
+
+#endif /*__CR_TERM_H__*/
diff --git a/src/3rdparty/libcroco/cr-tknzr.c b/src/3rdparty/libcroco/cr-tknzr.c
new file mode 100644
index 000000000..83f6ab3c0
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-tknzr.c
@@ -0,0 +1,2754 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See the COPYRIGHTS file for copyrights information.
+ */
+
+/**
+ *@file
+ *The definition of the #CRTknzr (tokenizer)
+ *class.
+ */
+
+#include "string.h"
+#include "cr-tknzr.h"
+#include "cr-doc-handler.h"
+
+struct _CRTknzrPriv {
+ /**The parser input stream of bytes*/
+ CRInput *input;
+
+ /**
+ *A cache where tknzr_unget_token()
+ *puts back the token. tknzr_get_next_token()
+ *first look in this cache, and if and
+ *only if it's empty, fetches the next token
+ *from the input stream.
+ */
+ CRToken *token_cache;
+
+ /**
+ *The position of the end of the previous token
+ *or char fetched.
+ */
+ CRInputPos prev_pos;
+
+ CRDocHandler *sac_handler;
+
+ /**
+ *The reference count of the current instance
+ *of #CRTknzr. Is manipulated by cr_tknzr_ref()
+ *and cr_tknzr_unref().
+ */
+ glong ref_count;
+};
+
+#define PRIVATE(obj) ((obj)->priv)
+
+/**
+ *return TRUE if the character is a number ([0-9]), FALSE otherwise
+ *@param a_char the char to test.
+ */
+#define IS_NUM(a_char) (((a_char) >= '0' && (a_char) <= '9')?TRUE:FALSE)
+
+/**
+ *Checks if 'status' equals CR_OK. If not, goto the 'error' label.
+ *
+ *@param status the status (of type enum CRStatus) to test.
+ *@param is_exception if set to FALSE, the final status returned the
+ *current function will be CR_PARSING_ERROR. If set to TRUE, the
+ *current status will be the current value of the 'status' variable.
+ *
+ */
+#define CHECK_PARSING_STATUS(status, is_exception) \
+if ((status) != CR_OK) \
+{ \
+ if (is_exception == FALSE) \
+ { \
+ status = CR_PARSING_ERROR ; \
+ } \
+ goto error ; \
+}
+
+/**
+ *Peeks the next char from the input stream of the current tokenizer.
+ *invokes CHECK_PARSING_STATUS on the status returned by
+ *cr_tknzr_input_peek_char().
+ *
+ *@param the current instance of #CRTkzr.
+ *@param to_char a pointer to the char where to store the
+ *char peeked.
+ */
+#define PEEK_NEXT_CHAR(a_tknzr, a_to_char) \
+{\
+status = cr_tknzr_peek_char (a_tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (status, TRUE) \
+}
+
+/**
+ *Reads the next char from the input stream of the current parser.
+ *In case of error, jumps to the "error:" label located in the
+ *function where this macro is called.
+ *@param parser the curent instance of #CRTknzr
+ *@param to_char a pointer to the guint32 char where to store
+ *the character read.
+ */
+#define READ_NEXT_CHAR(a_tknzr, to_char) \
+status = cr_tknzr_read_char (a_tknzr, to_char) ;\
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Gets information about the current position in
+ *the input of the parser.
+ *In case of failure, this macro returns from the
+ *calling function and
+ *returns a status code of type enum #CRStatus.
+ *@param parser the current instance of #CRTknzr.
+ *@param pos out parameter. A pointer to the position
+ *inside the current parser input. Must
+ */
+#define RECORD_INITIAL_POS(a_tknzr, a_pos) \
+status = cr_input_get_cur_pos (PRIVATE \
+(a_tknzr)->input, a_pos) ; \
+g_return_val_if_fail (status == CR_OK, status)
+
+/**
+ *Gets the address of the current byte inside the
+ *parser input.
+ *@param parser the current instance of #CRTknzr.
+ *@param addr out parameter a pointer (guchar*)
+ *to where the address must be put.
+ */
+#define RECORD_CUR_BYTE_ADDR(a_tknzr, a_addr) \
+status = cr_input_get_cur_byte_addr \
+ (PRIVATE (a_tknzr)->input, a_addr) ; \
+CHECK_PARSING_STATUS (status, TRUE)
+
+/**
+ *Peeks a byte from the topmost parser input at
+ *a given offset from the current position.
+ *If it fails, goto the "error:" label.
+ *
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_offset the offset of the byte to peek, the
+ *current byte having the offset '0'.
+ *@param a_byte_ptr out parameter a pointer (guchar*) to
+ *where the peeked char is to be stored.
+ */
+#define PEEK_BYTE(a_tknzr, a_offset, a_byte_ptr) \
+status = cr_tknzr_peek_byte (a_tknzr, \
+ a_offset, \
+ a_byte_ptr) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+#define BYTE(a_input, a_n, a_eof) \
+cr_input_peek_byte2 (a_input, a_n, a_eof)
+
+/**
+ *Reads a byte from the topmost parser input
+ *steam.
+ *If it fails, goto the "error" label.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_byte_ptr the guchar * where to put the read char.
+ */
+#define READ_NEXT_BYTE(a_tknzr, a_byte_ptr) \
+status = \
+cr_input_read_byte (PRIVATE (a_tknzr)->input, a_byte_ptr) ;\
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skips a given number of byte in the topmost
+ *parser input. Don't update line and column number.
+ *In case of error, jumps to the "error:" label
+ *of the surrounding function.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_bytes the number of bytes to skip.
+ */
+#define SKIP_BYTES(a_tknzr, a_nb_bytes) \
+status = cr_input_seek_index (PRIVATE (a_tknzr)->input, \
+ CR_SEEK_CUR, a_nb_bytes) ; \
+CHECK_PARSING_STATUS (status, TRUE) ;
+
+/**
+ *Skip utf8 encoded characters.
+ *Updates line and column numbers.
+ *@param a_parser the current instance of #CRTknzr.
+ *@param a_nb_chars the number of chars to skip. Must be of
+ *type glong.
+ */
+#define SKIP_CHARS(a_tknzr, a_nb_chars) \
+{ \
+gulong nb_chars = a_nb_chars ; \
+status = cr_input_consume_chars \
+ (PRIVATE (a_tknzr)->input,0, &nb_chars) ; \
+CHECK_PARSING_STATUS (status, TRUE) ; \
+}
+
+/**
+ *Tests the condition and if it is false, sets
+ *status to "CR_PARSING_ERROR" and goto the 'error'
+ *label.
+ *@param condition the condition to test.
+ */
+#define ENSURE_PARSING_COND(condition) \
+if (! (condition)) {status = CR_PARSING_ERROR; goto error ;}
+
+static enum CRStatus cr_tknzr_parse_nl (CRTknzr * a_this,
+ guchar ** a_start,
+ guchar ** a_end,
+ CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_w (CRTknzr * a_this,
+ guchar ** a_start,
+ guchar ** a_end,
+ CRParsingLocation *a_location) ;
+
+static enum CRStatus cr_tknzr_parse_unicode_escape (CRTknzr * a_this,
+ guint32 * a_unicode,
+ CRParsingLocation *a_location) ;
+
+static enum CRStatus cr_tknzr_parse_escape (CRTknzr * a_this,
+ guint32 * a_esc_code,
+ CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_string (CRTknzr * a_this,
+ CRString ** a_str);
+
+static enum CRStatus cr_tknzr_parse_comment (CRTknzr * a_this,
+ CRString ** a_comment);
+
+static enum CRStatus cr_tknzr_parse_nmstart (CRTknzr * a_this,
+ guint32 * a_char,
+ CRParsingLocation *a_location);
+
+static enum CRStatus cr_tknzr_parse_num (CRTknzr * a_this,
+ CRNum ** a_num);
+
+/**********************************
+ *PRIVATE methods
+ **********************************/
+
+/**
+ *Parses a "w" as defined by the css spec at [4.1.1]:
+ * w ::= [ \t\r\n\f]*
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. Upon successfull completion, points
+ *to the beginning of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ *@param a_end out param. Upon successfull completion, points
+ *to the end of the parsed white space, points to NULL otherwise.
+ *Can also point to NULL is there is no white space actually.
+ */
+static enum CRStatus
+cr_tknzr_parse_w (CRTknzr * a_this,
+ guchar ** a_start,
+ guchar ** a_end,
+ CRParsingLocation *a_location)
+{
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_start && a_end,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ *a_start = NULL;
+ *a_end = NULL;
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cr_utils_is_white_space (cur_char) == FALSE) {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ if (a_location) {
+ cr_tknzr_get_parsing_location (a_this,
+ a_location) ;
+ }
+ RECORD_CUR_BYTE_ADDR (a_this, a_start);
+ *a_end = *a_start;
+
+ for (;;) {
+ gboolean is_eof = FALSE;
+
+ cr_input_get_end_of_file (PRIVATE (a_this)->input, &is_eof);
+ if (is_eof)
+ break;
+
+ status = cr_tknzr_peek_char (a_this, &cur_char);
+ if (status == CR_END_OF_INPUT_ERROR) {
+ status = CR_OK;
+ break;
+ } else if (status != CR_OK) {
+ goto error;
+ }
+
+ if (cr_utils_is_white_space (cur_char) == TRUE) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ RECORD_CUR_BYTE_ADDR (a_this, a_end);
+ } else {
+ break;
+ }
+ }
+
+ return CR_OK;
+
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a newline as defined in the css2 spec:
+ * nl ::= \n|\r\n|\r|\f
+ *
+ *@param a_this the "this pointer" of the current instance of #CRTknzr.
+ *@param a_start a pointer to the first character of the successfully
+ *parsed string.
+ *@param a_end a pointer to the last character of the successfully parsed
+ *string.
+ *@result CR_OK uppon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nl (CRTknzr * a_this,
+ guchar ** a_start,
+ guchar ** a_end,
+ CRParsingLocation *a_location)
+{
+ CRInputPos init_pos;
+ guchar next_chars[2] = { 0 };
+ enum CRStatus status = CR_PARSING_ERROR;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_start && a_end, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]);
+ PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+ if ((next_chars[0] == '\r' && next_chars[1] == '\n')) {
+ SKIP_BYTES (a_this, 1);
+ if (a_location) {
+ cr_tknzr_get_parsing_location
+ (a_this, a_location) ;
+ }
+ SKIP_CHARS (a_this, 1);
+
+ RECORD_CUR_BYTE_ADDR (a_this, a_end);
+
+ status = CR_OK;
+ } else if (next_chars[0] == '\n'
+ || next_chars[0] == '\r' || next_chars[0] == '\f') {
+ SKIP_CHARS (a_this, 1);
+ if (a_location) {
+ cr_tknzr_get_parsing_location
+ (a_this, a_location) ;
+ }
+ RECORD_CUR_BYTE_ADDR (a_this, a_start);
+ *a_end = *a_start;
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ return CR_OK ;
+
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos) ;
+ return status;
+}
+
+/**
+ *Go ahead in the parser input, skipping all the spaces.
+ *If the next char if not a white space, this function does nothing.
+ *In any cases, it stops when it encounters a non white space character.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_try_to_skip_spaces (CRTknzr * a_this)
+{
+ enum CRStatus status = CR_ERROR;
+ guint32 cur_char = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+ status = cr_input_peek_char (PRIVATE (a_this)->input, &cur_char);
+
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR)
+ return CR_OK;
+ return status;
+ }
+
+ if (cr_utils_is_white_space (cur_char) == TRUE) {
+ gulong nb_chars = -1; /*consume all spaces */
+
+ status = cr_input_consume_white_spaces
+ (PRIVATE (a_this)->input, &nb_chars);
+ }
+
+ return status;
+}
+
+/**
+ *Parses a "comment" as defined in the css spec at [4.1.1]:
+ *COMMENT ::= \/\*[^*]*\*+([^/][^*]*\*+)*\/ .
+ *This complex regexp is just to say that comments start
+ *with the two chars '/''*' and ends with the two chars '*''/'.
+ *It also means that comments cannot be nested.
+ *So based on that, I've just tried to implement the parsing function
+ *simply and in a straight forward manner.
+ */
+static enum CRStatus
+cr_tknzr_parse_comment (CRTknzr * a_this,
+ CRString ** a_comment)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ guint32 cur_char = 0, next_char= 0;
+ CRString *comment = NULL;
+ CRParsingLocation loc = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ READ_NEXT_CHAR (a_this, &cur_char) ;
+ ENSURE_PARSING_COND (cur_char == '/');
+ cr_tknzr_get_parsing_location (a_this, &loc) ;
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == '*');
+ comment = cr_string_new ();
+ for (;;) { /* [^*]* */
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char == '*')
+ break;
+ READ_NEXT_CHAR (a_this, &cur_char);
+ g_string_append_unichar (comment->stryng, cur_char);
+ }
+ /* Stop condition: next_char == '*' */
+ for (;;) { /* \*+ */
+ READ_NEXT_CHAR(a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == '*');
+ g_string_append_unichar (comment->stryng, cur_char);
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char != '*')
+ break;
+ }
+ /* Stop condition: next_char != '*' */
+ for (;;) { /* ([^/][^*]*\*+)* */
+ if (next_char == '/')
+ break;
+ READ_NEXT_CHAR(a_this, &cur_char);
+ g_string_append_unichar (comment->stryng, cur_char);
+ for (;;) { /* [^*]* */
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char == '*')
+ break;
+ READ_NEXT_CHAR (a_this, &cur_char);
+ g_string_append_unichar (comment->stryng, cur_char);
+ }
+ /* Stop condition: next_char = '*', no need to verify, because peek and read exit to error anyway */
+ for (;;) { /* \*+ */
+ READ_NEXT_CHAR(a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == '*');
+ g_string_append_unichar (comment->stryng, cur_char);
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char != '*')
+ break;
+ }
+ /* Continue condition: next_char != '*' */
+ }
+ /* Stop condition: next_char == '\/' */
+ READ_NEXT_CHAR(a_this, &cur_char);
+ g_string_append_unichar (comment->stryng, cur_char);
+
+ if (status == CR_OK) {
+ cr_parsing_location_copy (&comment->location,
+ &loc) ;
+ *a_comment = comment;
+ return CR_OK;
+ }
+ error:
+
+ if (comment) {
+ cr_string_destroy (comment);
+ comment = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses an 'unicode' escape sequence defined
+ *in css spec at chap 4.1.1:
+ *unicode ::= \\[0-9a-f]{1,6}[ \n\r\t\f]?
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. A pointer to the start
+ *of the unicode escape sequence. Must *NOT* be deleted by
+ *the caller.
+ *@param a_end out parameter. A pointer to the last character
+ *of the unicode escape sequence. Must *NOT* be deleted by the caller.
+ *@return CR_OK if parsing succeded, an error code otherwise.
+ *Error code can be either CR_PARSING_ERROR if the string
+ *parsed just doesn't
+ *respect the production or another error if a
+ *lower level error occured.
+ */
+static enum CRStatus
+cr_tknzr_parse_unicode_escape (CRTknzr * a_this,
+ guint32 * a_unicode,
+ CRParsingLocation *a_location)
+{
+ guint32 cur_char;
+ CRInputPos init_pos;
+ glong occur = 0;
+ guint32 unicode = 0;
+ guchar *tmp_char_ptr1 = NULL,
+ *tmp_char_ptr2 = NULL;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_unicode, CR_BAD_PARAM_ERROR);
+
+ /*first, let's backup the current position pointer */
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char != '\\') {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ if (a_location) {
+ cr_tknzr_get_parsing_location
+ (a_this, a_location) ;
+ }
+ PEEK_NEXT_CHAR (a_this, &cur_char);
+
+ for (occur = 0, unicode = 0; ((cur_char >= '0' && cur_char <= '9')
+ || (cur_char >= 'a' && cur_char <= 'f')
+ || (cur_char >= 'A' && cur_char <= 'F'))
+ && occur < 6; occur++) {
+ gint cur_char_val = 0;
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if ((cur_char >= '0' && cur_char <= '9')) {
+ cur_char_val = (cur_char - '0');
+ } else if ((cur_char >= 'a' && cur_char <= 'f')) {
+ cur_char_val = 10 + (cur_char - 'a');
+ } else if ((cur_char >= 'A' && cur_char <= 'F')) {
+ cur_char_val = 10 + (cur_char - 'A');
+ }
+
+ unicode = unicode * 16 + cur_char_val;
+
+ PEEK_NEXT_CHAR (a_this, &cur_char);
+ }
+
+ /* Eat a whitespace if possible. */
+ cr_tknzr_parse_w (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2, NULL);
+ *a_unicode = unicode;
+ return CR_OK;
+
+ error:
+ /*
+ *restore the initial position pointer backuped at
+ *the beginning of this function.
+ */
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+}
+
+/**
+ *parses an escape sequence as defined by the css spec:
+ *escape ::= {unicode}|\\[ -~\200-\4177777]
+ *@param a_this the current instance of #CRTknzr .
+ */
+static enum CRStatus
+cr_tknzr_parse_escape (CRTknzr * a_this, guint32 * a_esc_code,
+ CRParsingLocation *a_location)
+{
+ enum CRStatus status = CR_OK;
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ guchar next_chars[2];
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_esc_code, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]);
+ PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+ if (next_chars[0] != '\\') {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ if ((next_chars[1] >= '0' && next_chars[1] <= '9')
+ || (next_chars[1] >= 'a' && next_chars[1] <= 'f')
+ || (next_chars[1] >= 'A' && next_chars[1] <= 'F')) {
+ status = cr_tknzr_parse_unicode_escape (a_this, a_esc_code,
+ a_location);
+ } else {
+ /*consume the '\' char */
+ READ_NEXT_CHAR (a_this, &cur_char);
+ if (a_location) {
+ cr_tknzr_get_parsing_location (a_this,
+ a_location) ;
+ }
+ /*then read the char after the '\' */
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char != ' ' && (cur_char < 200 || cur_char > 4177777)) {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ *a_esc_code = cur_char;
+
+ }
+ if (status == CR_OK) {
+ return CR_OK;
+ }
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+/**
+ *Parses a string type as defined in css spec [4.1.1]:
+ *
+ *string ::= {string1}|{string2}
+ *string1 ::= \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
+ *string2 ::= \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out parameter. Upon successfull completion,
+ *points to the beginning of the string, points to an undefined value
+ *otherwise.
+ *@param a_end out parameter. Upon successfull completion, points to
+ *the beginning of the string, points to an undefined value otherwise.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_string (CRTknzr * a_this, CRString ** a_str)
+{
+ guint32 cur_char = 0,
+ delim = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ CRString *str = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char == '"')
+ delim = '"';
+ else if (cur_char == '\'')
+ delim = '\'';
+ else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ str = cr_string_new ();
+ if (str) {
+ cr_tknzr_get_parsing_location
+ (a_this, &str->location) ;
+ }
+ for (;;) {
+ guchar next_chars[2] = { 0 };
+
+ PEEK_BYTE (a_this, 1, &next_chars[0]);
+
+ if (next_chars[0] == '\\') {
+ guchar *tmp_char_ptr1 = NULL,
+ *tmp_char_ptr2 = NULL;
+ guint32 esc_code = 0;
+
+ PEEK_BYTE (a_this, 2, &next_chars[1]);
+
+ if (next_chars[1] == '\'' || next_chars[1] == '"') {
+ g_string_append_unichar (str->stryng,
+ next_chars[1]);
+ SKIP_BYTES (a_this, 2);
+ status = CR_OK;
+ } else {
+ status = cr_tknzr_parse_escape
+ (a_this, &esc_code, NULL);
+
+ if (status == CR_OK) {
+ g_string_append_unichar
+ (str->stryng,
+ esc_code);
+ }
+ }
+
+ if (status != CR_OK) {
+ /*
+ *consume the '\' char, and try to parse
+ *a newline.
+ */
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ status = cr_tknzr_parse_nl
+ (a_this, &tmp_char_ptr1,
+ &tmp_char_ptr2, NULL);
+ }
+
+ CHECK_PARSING_STATUS (status, FALSE);
+ } else if (strchr ("\t !#$%&", next_chars[0])
+ || (next_chars[0] >= '(' && next_chars[0] <= '~')) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ g_string_append_unichar (str->stryng,
+ cur_char);
+ status = CR_OK;
+ }
+
+ else if (cr_utils_is_nonascii (next_chars[0])) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ g_string_append_unichar (str->stryng, cur_char);
+ } else if (next_chars[0] == delim) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ break;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ }
+
+ if (status == CR_OK) {
+ if (*a_str == NULL) {
+ *a_str = str;
+ str = NULL;
+ } else {
+ (*a_str)->stryng = g_string_append_len
+ ((*a_str)->stryng,
+ str->stryng->str,
+ str->stryng->len);
+ cr_string_destroy (str);
+ }
+ return CR_OK;
+ }
+
+ error:
+
+ if (str) {
+ cr_string_destroy (str) ;
+ str = NULL;
+ }
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+/**
+ *Parses the an nmstart as defined by the css2 spec [4.1.1]:
+ * nmstart [a-zA-Z]|{nonascii}|{escape}
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmstart (CRTknzr * a_this,
+ guint32 * a_char,
+ CRParsingLocation *a_location)
+{
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ guint32 cur_char = 0,
+ next_char = 0;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PEEK_NEXT_CHAR (a_this, &next_char);
+
+ if (next_char == '\\') {
+ status = cr_tknzr_parse_escape (a_this, a_char,
+ a_location);
+
+ if (status != CR_OK)
+ goto error;
+
+ } else if (cr_utils_is_nonascii (next_char) == TRUE
+ || ((next_char >= 'a') && (next_char <= 'z'))
+ || ((next_char >= 'A') && (next_char <= 'Z'))
+ ) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ if (a_location) {
+ cr_tknzr_get_parsing_location (a_this,
+ a_location) ;
+ }
+ *a_char = cur_char;
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ return CR_OK;
+
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+
+}
+
+/**
+ *Parses an nmchar as described in the css spec at
+ *chap 4.1.1:
+ *nmchar ::= [a-z0-9-]|{nonascii}|{escape}
+ *
+ *Humm, I have added the possibility for nmchar to
+ *contain upper case letters.
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_start out param. A pointer to the starting point of
+ *the token.
+ *@param a_end out param. A pointer to the ending point of the
+ *token.
+ *@param a_char out param. The actual parsed nmchar.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_nmchar (CRTknzr * a_this, guint32 * a_char,
+ CRParsingLocation *a_location)
+{
+ guint32 cur_char = 0,
+ next_char = 0;
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this) && a_char,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_input_peek_char (PRIVATE (a_this)->input,
+ &next_char) ;
+ if (status != CR_OK)
+ goto error;
+
+ if (next_char == '\\') {
+ status = cr_tknzr_parse_escape (a_this, a_char,
+ a_location);
+
+ if (status != CR_OK)
+ goto error;
+
+ } else if (cr_utils_is_nonascii (next_char) == TRUE
+ || ((next_char >= 'a') && (next_char <= 'z'))
+ || ((next_char >= 'A') && (next_char <= 'Z'))
+ || ((next_char >= '0') && (next_char <= '9'))
+ || (next_char == '-')
+ || (next_char == '_') /*'_' not allowed by the spec. */
+ ) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ *a_char = cur_char;
+ status = CR_OK;
+ if (a_location) {
+ cr_tknzr_get_parsing_location
+ (a_this, a_location) ;
+ }
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ return CR_OK;
+
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+/**
+ *Parses an "ident" as defined in css spec [4.1.1]:
+ *ident ::= {nmstart}{nmchar}*
+ *
+ *Actually parses it using the css3 grammar:
+ *ident ::= -?{nmstart}{nmchar}*
+ *@param a_this the currens instance of #CRTknzr.
+ *
+ *@param a_str a pointer to parsed ident. If *a_str is NULL,
+ *this function allocates a new instance of CRString. If not,
+ *the function just appends the parsed string to the one passed.
+ *In both cases it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_ident (CRTknzr * a_this, CRString ** a_str)
+{
+ guint32 tmp_char = 0;
+ CRString *stringue = NULL ;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ gboolean location_is_set = FALSE ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ PEEK_NEXT_CHAR (a_this, &tmp_char) ;
+ stringue = cr_string_new () ;
+ g_return_val_if_fail (stringue,
+ CR_OUT_OF_MEMORY_ERROR) ;
+
+ if (tmp_char == '-') {
+ READ_NEXT_CHAR (a_this, &tmp_char) ;
+ cr_tknzr_get_parsing_location
+ (a_this, &stringue->location) ;
+ location_is_set = TRUE ;
+ g_string_append_unichar (stringue->stryng,
+ tmp_char) ;
+ }
+ status = cr_tknzr_parse_nmstart (a_this, &tmp_char, NULL);
+ if (status != CR_OK) {
+ status = CR_PARSING_ERROR;
+ goto end ;
+ }
+ if (location_is_set == FALSE) {
+ cr_tknzr_get_parsing_location
+ (a_this, &stringue->location) ;
+ location_is_set = TRUE ;
+ }
+ g_string_append_unichar (stringue->stryng, tmp_char);
+ for (;;) {
+ status = cr_tknzr_parse_nmchar (a_this,
+ &tmp_char,
+ NULL);
+ if (status != CR_OK) {
+ status = CR_OK ;
+ break;
+ }
+ g_string_append_unichar (stringue->stryng, tmp_char);
+ }
+ if (status == CR_OK) {
+ if (!*a_str) {
+ *a_str = stringue ;
+
+ } else {
+ g_string_append_len ((*a_str)->stryng,
+ stringue->stryng->str,
+ stringue->stryng->len) ;
+ cr_string_destroy (stringue) ;
+ }
+ stringue = NULL ;
+ }
+
+ error:
+ end:
+ if (stringue) {
+ cr_string_destroy (stringue) ;
+ stringue = NULL ;
+ }
+ if (status != CR_OK ) {
+ cr_tknzr_set_cur_pos (a_this, &init_pos) ;
+ }
+ return status ;
+}
+
+
+/**
+ *Parses a "name" as defined by css spec [4.1.1]:
+ *name ::= {nmchar}+
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *
+ *@param a_str out parameter. A pointer to the successfully parsed
+ *name. If *a_str is set to NULL, this function allocates a new instance
+ *of CRString. If not, it just appends the parsed name to the passed *a_str.
+ *In both cases, it is up to the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_name (CRTknzr * a_this,
+ CRString ** a_str)
+{
+ guint32 tmp_char = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ gboolean str_needs_free = FALSE,
+ is_first_nmchar=TRUE ;
+ glong i = 0;
+ CRParsingLocation loc = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str,
+ CR_BAD_PARAM_ERROR) ;
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ if (*a_str == NULL) {
+ *a_str = cr_string_new ();
+ str_needs_free = TRUE;
+ }
+ for (i = 0;; i++) {
+ if (is_first_nmchar == TRUE) {
+ status = cr_tknzr_parse_nmchar
+ (a_this, &tmp_char,
+ &loc) ;
+ is_first_nmchar = FALSE ;
+ } else {
+ status = cr_tknzr_parse_nmchar
+ (a_this, &tmp_char, NULL) ;
+ }
+ if (status != CR_OK)
+ break;
+ g_string_append_unichar ((*a_str)->stryng,
+ tmp_char);
+ }
+ if (i > 0) {
+ cr_parsing_location_copy
+ (&(*a_str)->location, &loc) ;
+ return CR_OK;
+ }
+ if (str_needs_free == TRUE && *a_str) {
+ cr_string_destroy (*a_str);
+ *a_str = NULL;
+ }
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return CR_PARSING_ERROR;
+}
+
+/**
+ *Parses a "hash" as defined by the css spec in [4.1.1]:
+ *HASH ::= #{name}
+ */
+static enum CRStatus
+cr_tknzr_parse_hash (CRTknzr * a_this, CRString ** a_str)
+{
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+ gboolean str_needs_free = FALSE;
+ CRParsingLocation loc = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ if (cur_char != '#') {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ if (*a_str == NULL) {
+ *a_str = cr_string_new ();
+ str_needs_free = TRUE;
+ }
+ cr_tknzr_get_parsing_location (a_this,
+ &loc) ;
+ status = cr_tknzr_parse_name (a_this, a_str);
+ cr_parsing_location_copy (&(*a_str)->location, &loc) ;
+ if (status != CR_OK) {
+ goto error;
+ }
+ return CR_OK;
+
+ error:
+ if (str_needs_free == TRUE && *a_str) {
+ cr_string_destroy (*a_str);
+ *a_str = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+/**
+ *Parses an uri as defined by the css spec [4.1.1]:
+ * URI ::= url\({w}{string}{w}\)
+ * |url\({w}([!#$%&*-~]|{nonascii}|{escape})*{w}\)
+ *
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_str the successfully parsed url.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_uri (CRTknzr * a_this,
+ CRString ** a_str)
+{
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_PARSING_ERROR;
+ guchar tab[4] = { 0 }, *tmp_ptr1 = NULL, *tmp_ptr2 = NULL;
+ CRString *str = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PEEK_BYTE (a_this, 1, &tab[0]);
+ PEEK_BYTE (a_this, 2, &tab[1]);
+ PEEK_BYTE (a_this, 3, &tab[2]);
+ PEEK_BYTE (a_this, 4, &tab[3]);
+
+ if (tab[0] != 'u' || tab[1] != 'r' || tab[2] != 'l' || tab[3] != '(') {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ /*
+ *Here, we want to skip 4 bytes ('u''r''l''(').
+ *But we also need to keep track of the parsing location
+ *of the 'u'. So, we skip 1 byte, we record the parsing
+ *location, then we skip the 3 remaining bytes.
+ */
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this, &location) ;
+ SKIP_CHARS (a_this, 3);
+ cr_tknzr_try_to_skip_spaces (a_this);
+ status = cr_tknzr_parse_string (a_this, a_str);
+
+ if (status == CR_OK) {
+ guint32 next_char = 0;
+ status = cr_tknzr_parse_w (a_this, &tmp_ptr1,
+ &tmp_ptr2, NULL);
+ cr_tknzr_try_to_skip_spaces (a_this);
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (next_char == ')') {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ }
+ }
+ if (status != CR_OK) {
+ str = cr_string_new ();
+ for (;;) {
+ guint32 next_char = 0;
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ if (strchr ("!#$%&", next_char)
+ || (next_char >= '*' && next_char <= '~')
+ || (cr_utils_is_nonascii (next_char) == TRUE)) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ g_string_append_unichar
+ (str->stryng, cur_char);
+ status = CR_OK;
+ } else {
+ guint32 esc_code = 0;
+ status = cr_tknzr_parse_escape
+ (a_this, &esc_code, NULL);
+ if (status == CR_OK) {
+ g_string_append_unichar
+ (str->stryng,
+ esc_code);
+ } else {
+ status = CR_OK;
+ break;
+ }
+ }
+ }
+ cr_tknzr_try_to_skip_spaces (a_this);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ if (cur_char == ')') {
+ status = CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ if (str) {
+ if (*a_str == NULL) {
+ *a_str = str;
+ str = NULL;
+ } else {
+ g_string_append_len
+ ((*a_str)->stryng,
+ str->stryng->str,
+ str->stryng->len);
+ cr_string_destroy (str);
+ }
+ }
+ }
+
+ cr_parsing_location_copy
+ (&(*a_str)->location,
+ &location) ;
+ return CR_OK ;
+ error:
+ if (str) {
+ cr_string_destroy (str);
+ str = NULL;
+ }
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+/**
+ *parses an RGB as defined in the css2 spec.
+ *rgb: rgb '('S*{num}%?S* ',' {num}#?S*,S*{num}#?S*')'
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *@param a_rgb out parameter the parsed rgb.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_rgb (CRTknzr * a_this, CRRgb ** a_rgb)
+{
+ enum CRStatus status = CR_OK;
+ CRInputPos init_pos;
+ CRNum *num = NULL;
+ guchar next_bytes[3] = { 0 }, cur_byte = 0;
+ glong red = 0,
+ green = 0,
+ blue = 0,
+ i = 0;
+ gboolean is_percentage = FALSE;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]);
+ PEEK_BYTE (a_this, 2, &next_bytes[1]);
+ PEEK_BYTE (a_this, 3, &next_bytes[2]);
+
+ if (((next_bytes[0] == 'r') || (next_bytes[0] == 'R'))
+ && ((next_bytes[1] == 'g') || (next_bytes[1] == 'G'))
+ && ((next_bytes[2] == 'b') || (next_bytes[2] == 'B'))) {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this, &location) ;
+ SKIP_CHARS (a_this, 2);
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ READ_NEXT_BYTE (a_this, &cur_byte);
+ ENSURE_PARSING_COND (cur_byte == '(');
+
+ cr_tknzr_try_to_skip_spaces (a_this);
+ status = cr_tknzr_parse_num (a_this, &num);
+ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
+
+ red = (glong)num->val;
+ cr_num_destroy (num);
+ num = NULL;
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]);
+ if (next_bytes[0] == '%') {
+ SKIP_CHARS (a_this, 1);
+ is_percentage = TRUE;
+ }
+ cr_tknzr_try_to_skip_spaces (a_this);
+
+ for (i = 0; i < 2; i++) {
+ READ_NEXT_BYTE (a_this, &cur_byte);
+ ENSURE_PARSING_COND (cur_byte == ',');
+
+ cr_tknzr_try_to_skip_spaces (a_this);
+ status = cr_tknzr_parse_num (a_this, &num);
+ ENSURE_PARSING_COND ((status == CR_OK) && (num != NULL));
+
+ PEEK_BYTE (a_this, 1, &next_bytes[0]);
+ if (next_bytes[0] == '%') {
+ SKIP_CHARS (a_this, 1);
+ is_percentage = 1;
+ }
+
+ if (i == 0) {
+ green = (glong)num->val;
+ } else if (i == 1) {
+ blue = (glong)num->val;
+ }
+
+ if (num) {
+ cr_num_destroy (num);
+ num = NULL;
+ }
+ cr_tknzr_try_to_skip_spaces (a_this);
+ }
+
+ READ_NEXT_BYTE (a_this, &cur_byte);
+ if (*a_rgb == NULL) {
+ *a_rgb = cr_rgb_new_with_vals (red, green, blue,
+ is_percentage);
+
+ if (*a_rgb == NULL) {
+ status = CR_ERROR;
+ goto error;
+ }
+ status = CR_OK;
+ } else {
+ (*a_rgb)->red = red;
+ (*a_rgb)->green = green;
+ (*a_rgb)->blue = blue;
+ (*a_rgb)->is_percentage = is_percentage;
+
+ status = CR_OK;
+ }
+
+ if (status == CR_OK) {
+ if (a_rgb && *a_rgb) {
+ cr_parsing_location_copy
+ (&(*a_rgb)->location,
+ &location) ;
+ }
+ return CR_OK;
+ }
+
+ error:
+ if (num) {
+ cr_num_destroy (num);
+ num = NULL;
+ }
+
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return CR_OK;
+}
+
+/**
+ *Parses a atkeyword as defined by the css spec in [4.1.1]:
+ *ATKEYWORD ::= @{ident}
+ *
+ *@param a_this the "this pointer" of the current instance of
+ *#CRTknzr.
+ *
+ *@param a_str out parameter. The parsed atkeyword. If *a_str is
+ *set to NULL this function allocates a new instance of CRString and
+ *sets it to the parsed atkeyword. If not, this function just appends
+ *the parsed atkeyword to the end of *a_str. In both cases it is up to
+ *the caller to free *a_str.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+static enum CRStatus
+cr_tknzr_parse_atkeyword (CRTknzr * a_this,
+ CRString ** a_str)
+{
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ gboolean str_needs_free = FALSE;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_str, CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char != '@') {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ if (*a_str == NULL) {
+ *a_str = cr_string_new ();
+ str_needs_free = TRUE;
+ }
+ status = cr_tknzr_parse_ident (a_this, a_str);
+ if (status != CR_OK) {
+ goto error;
+ }
+ return CR_OK;
+ error:
+
+ if (str_needs_free == TRUE && *a_str) {
+ cr_string_destroy (*a_str);
+ *a_str = NULL;
+ }
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+}
+
+static enum CRStatus
+cr_tknzr_parse_important (CRTknzr * a_this,
+ CRParsingLocation *a_location)
+{
+ guint32 cur_char = 0;
+ CRInputPos init_pos;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ READ_NEXT_CHAR (a_this, &cur_char);
+ ENSURE_PARSING_COND (cur_char == '!');
+ if (a_location) {
+ cr_tknzr_get_parsing_location (a_this,
+ a_location) ;
+ }
+ cr_tknzr_try_to_skip_spaces (a_this);
+
+ if (BYTE (PRIVATE (a_this)->input, 1, NULL) == 'i'
+ && BYTE (PRIVATE (a_this)->input, 2, NULL) == 'm'
+ && BYTE (PRIVATE (a_this)->input, 3, NULL) == 'p'
+ && BYTE (PRIVATE (a_this)->input, 4, NULL) == 'o'
+ && BYTE (PRIVATE (a_this)->input, 5, NULL) == 'r'
+ && BYTE (PRIVATE (a_this)->input, 6, NULL) == 't'
+ && BYTE (PRIVATE (a_this)->input, 7, NULL) == 'a'
+ && BYTE (PRIVATE (a_this)->input, 8, NULL) == 'n'
+ && BYTE (PRIVATE (a_this)->input, 9, NULL) == 't') {
+ SKIP_BYTES (a_this, 9);
+ if (a_location) {
+ cr_tknzr_get_parsing_location (a_this,
+ a_location) ;
+ }
+ return CR_OK;
+ } else {
+ status = CR_PARSING_ERROR;
+ }
+
+ error:
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+}
+
+/**
+ *Parses a num as defined in the css spec [4.1.1]:
+ *[0-9]+|[0-9]*\.[0-9]+
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_num out parameter. The parsed number.
+ *@return CR_OK upon successfull completion,
+ *an error code otherwise.
+ *
+ *The CSS specification says that numbers may be
+ *preceeded by '+' or '-' to indicate the sign.
+ *Technically, the "num" construction as defined
+ *by the tokenizer doesn't allow this, but we parse
+ *it here for simplicity.
+ */
+static enum CRStatus
+cr_tknzr_parse_num (CRTknzr * a_this,
+ CRNum ** a_num)
+{
+ enum CRStatus status = CR_PARSING_ERROR;
+ enum CRNumType val_type = NUM_GENERIC;
+ gboolean parsing_dec, /* true iff seen decimal point. */
+ parsed; /* true iff the substring seen so far is a valid CSS
+ number, i.e. `[0-9]+|[0-9]*\.[0-9]+'. */
+ guint32 cur_char = 0,
+ next_char = 0;
+ gdouble numerator, denominator = 1;
+ CRInputPos init_pos;
+ CRParsingLocation location = {0,0,0} ;
+ int sign = 1;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR);
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+ READ_NEXT_CHAR (a_this, &cur_char);
+
+ if (cur_char == '+' || cur_char == '-') {
+ if (cur_char == '-') {
+ sign = -1;
+ }
+ READ_NEXT_CHAR (a_this, &cur_char);
+ }
+
+ if (IS_NUM (cur_char)) {
+ numerator = (cur_char - '0');
+ parsing_dec = FALSE;
+ parsed = TRUE;
+ } else if (cur_char == '.') {
+ numerator = 0;
+ parsing_dec = TRUE;
+ parsed = FALSE;
+ } else {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+ cr_tknzr_get_parsing_location (a_this, &location) ;
+
+ for (;;) {
+ status = cr_tknzr_peek_char (a_this, &next_char);
+ if (status != CR_OK) {
+ if (status == CR_END_OF_INPUT_ERROR)
+ status = CR_OK;
+ break;
+ }
+ if (next_char == '.') {
+ if (parsing_dec) {
+ status = CR_PARSING_ERROR;
+ goto error;
+ }
+
+ READ_NEXT_CHAR (a_this, &cur_char);
+ parsing_dec = TRUE;
+ parsed = FALSE; /* In CSS, there must be at least
+ one digit after `.'. */
+ } else if (IS_NUM (next_char)) {
+ READ_NEXT_CHAR (a_this, &cur_char);
+ parsed = TRUE;
+
+ numerator = numerator * 10 + (cur_char - '0');
+ if (parsing_dec) {
+ denominator *= 10;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (!parsed) {
+ status = CR_PARSING_ERROR;
+ }
+
+ /*
+ *Now, set the output param values.
+ */
+ if (status == CR_OK) {
+ gdouble val = (numerator / denominator) * sign;
+ if (*a_num == NULL) {
+ *a_num = cr_num_new_with_val (val, val_type);
+
+ if (*a_num == NULL) {
+ status = CR_ERROR;
+ goto error;
+ }
+ } else {
+ (*a_num)->val = val;
+ (*a_num)->type = val_type;
+ }
+ cr_parsing_location_copy (&(*a_num)->location,
+ &location) ;
+ return CR_OK;
+ }
+
+ error:
+
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+
+ return status;
+}
+
+/*********************************************
+ *PUBLIC methods
+ ********************************************/
+
+CRTknzr *
+cr_tknzr_new (CRInput * a_input)
+{
+ CRTknzr *result = NULL;
+
+ result = (CRTknzr *) g_try_malloc (sizeof (CRTknzr));
+
+ if (result == NULL) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRTknzr));
+
+ result->priv = (CRTknzrPriv *)g_try_malloc (sizeof (CRTknzrPriv));
+
+ if (result->priv == NULL) {
+ cr_utils_trace_info ("Out of memory");
+
+ if (result) {
+ g_free (result);
+ result = NULL;
+ }
+
+ return NULL;
+ }
+ memset (result->priv, 0, sizeof (CRTknzrPriv));
+ if (a_input)
+ cr_tknzr_set_input (result, a_input);
+ return result;
+}
+
+CRTknzr *
+cr_tknzr_new_from_buf (guchar * a_buf, gulong a_len,
+ enum CREncoding a_enc,
+ gboolean a_free_at_destroy)
+{
+ CRTknzr *result = NULL;
+ CRInput *input = NULL;
+
+ input = cr_input_new_from_buf (a_buf, a_len, a_enc,
+ a_free_at_destroy);
+
+ g_return_val_if_fail (input != NULL, NULL);
+
+ result = cr_tknzr_new (input);
+
+ return result;
+}
+
+CRTknzr *
+cr_tknzr_new_from_uri (const guchar * a_file_uri,
+ enum CREncoding a_enc)
+{
+ CRTknzr *result = NULL;
+ CRInput *input = NULL;
+
+ input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc);
+ g_return_val_if_fail (input != NULL, NULL);
+
+ result = cr_tknzr_new (input);
+
+ return result;
+}
+
+void
+cr_tknzr_ref (CRTknzr * a_this)
+{
+ g_return_if_fail (a_this && PRIVATE (a_this));
+
+ PRIVATE (a_this)->ref_count++;
+}
+
+gboolean
+cr_tknzr_unref (CRTknzr * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), FALSE);
+
+ if (PRIVATE (a_this)->ref_count > 0) {
+ PRIVATE (a_this)->ref_count--;
+ }
+
+ if (PRIVATE (a_this)->ref_count == 0) {
+ cr_tknzr_destroy (a_this);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+enum CRStatus
+cr_tknzr_set_input (CRTknzr * a_this, CRInput * a_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->input) {
+ cr_input_unref (PRIVATE (a_this)->input);
+ }
+
+ PRIVATE (a_this)->input = a_input;
+
+ cr_input_ref (PRIVATE (a_this)->input);
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_tknzr_get_input (CRTknzr * a_this, CRInput ** a_input)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ *a_input = PRIVATE (a_this)->input;
+
+ return CR_OK;
+}
+
+/*********************************
+ *Tokenizer input handling routines
+ *********************************/
+
+/**
+ *Reads the next byte from the parser input stream.
+ *@param a_this the "this pointer" of the current instance of
+ *#CRParser.
+ *@param a_byte out parameter the place where to store the byte
+ *read.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_byte (CRTknzr * a_this, guchar * a_byte)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR);
+
+ return cr_input_read_byte (PRIVATE (a_this)->input, a_byte);
+
+}
+
+/**
+ *Reads the next char from the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The read char.
+ *@return CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_tknzr_read_char (CRTknzr * a_this, guint32 * a_char)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_read_char (PRIVATE (a_this)->input, a_char);
+}
+
+/**
+ *Peeks a char from the parser input stream.
+ *To "peek a char" means reads the next char without consuming it.
+ *Subsequent calls to this function return the same char.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_char out parameter. The peeked char uppon successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_char (CRTknzr * a_this, guint32 * a_char)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_char, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_peek_char (PRIVATE (a_this)->input, a_char);
+}
+
+/**
+ *Peeks a byte ahead at a given postion in the parser input stream.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_offset the offset of the peeked byte starting from the current
+ *byte in the parser input stream.
+ *@param a_byte out parameter. The peeked byte upon
+ *successfull completion.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_tknzr_peek_byte (CRTknzr * a_this, gulong a_offset, guchar * a_byte)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input && a_byte,
+ CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_peek_byte (PRIVATE (a_this)->input,
+ CR_SEEK_CUR, a_offset, a_byte);
+}
+
+/**
+ *Same as cr_tknzr_peek_byte() but this api returns the byte peeked.
+ *@param a_this the current instance of #CRTknzr.
+ *@param a_offset the offset of the peeked byte starting from the current
+ *byte in the parser input stream.
+ *@param a_eof out parameter. If not NULL, is set to TRUE if we reached end of
+ *file, FALE otherwise. If the caller sets it to NULL, this parameter
+ *is just ignored.
+ *@return the peeked byte.
+ */
+guchar
+cr_tknzr_peek_byte2 (CRTknzr * a_this, gulong a_offset, gboolean * a_eof)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, 0);
+
+ return cr_input_peek_byte2 (PRIVATE (a_this)->input, a_offset, a_eof);
+}
+
+/**
+ *Gets the number of bytes left in the topmost input stream
+ *associated to this parser.
+ *@param a_this the current instance of #CRTknzr
+ *@return the number of bytes left or -1 in case of error.
+ */
+glong
+cr_tknzr_get_nb_bytes_left (CRTknzr * a_this)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_get_nb_bytes_left (PRIVATE (a_this)->input);
+}
+
+enum CRStatus
+cr_tknzr_get_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_pos, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_get_cur_pos (PRIVATE (a_this)->input, a_pos);
+}
+
+enum CRStatus
+cr_tknzr_get_parsing_location (CRTknzr *a_this,
+ CRParsingLocation *a_loc)
+{
+ g_return_val_if_fail (a_this
+ && PRIVATE (a_this)
+ && a_loc,
+ CR_BAD_PARAM_ERROR) ;
+
+ return cr_input_get_parsing_location
+ (PRIVATE (a_this)->input, a_loc) ;
+}
+
+enum CRStatus
+cr_tknzr_get_cur_byte_addr (CRTknzr * a_this, guchar ** a_addr)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_get_cur_byte_addr (PRIVATE (a_this)->input, a_addr);
+}
+
+enum CRStatus
+cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_seek_index (PRIVATE (a_this)->input, a_origin, a_pos);
+}
+
+enum CRStatus
+cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
+{
+ gulong consumed = *(gulong *) a_nb_char;
+ enum CRStatus status;
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_input_set_cur_pos (PRIVATE (a_this)->input,
+ &PRIVATE (a_this)->prev_pos);
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ status = cr_input_consume_chars (PRIVATE (a_this)->input,
+ a_char, &consumed);
+ *a_nb_char = (glong) consumed;
+ return status;
+}
+
+enum CRStatus
+cr_tknzr_set_cur_pos (CRTknzr * a_this, CRInputPos * a_pos)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ return cr_input_set_cur_pos (PRIVATE (a_this)->input, a_pos);
+}
+
+enum CRStatus
+cr_tknzr_unget_token (CRTknzr * a_this, CRToken * a_token)
+{
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->token_cache == NULL,
+ CR_BAD_PARAM_ERROR);
+
+ PRIVATE (a_this)->token_cache = a_token;
+
+ return CR_OK;
+}
+
+/**
+ *Returns the next token of the input stream.
+ *This method is really central. Each parsing
+ *method calls it.
+ *@param a_this the current tokenizer.
+ *@param a_tk out parameter. The returned token.
+ *for the sake of mem leak avoidance, *a_tk must
+ *be NULL.
+ *@param CR_OK upon successfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk)
+{
+ enum CRStatus status = CR_OK;
+ CRToken *token = NULL;
+ CRInputPos init_pos;
+ guint32 next_char = 0;
+ guchar next_bytes[4] = { 0 };
+ gboolean reached_eof = FALSE;
+ CRInput *input = NULL;
+ CRString *str = NULL;
+ CRRgb *rgb = NULL;
+ CRParsingLocation location = {0,0,0} ;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && a_tk && *a_tk == NULL
+ && PRIVATE (a_this)->input,
+ CR_BAD_PARAM_ERROR);
+
+ if (PRIVATE (a_this)->token_cache) {
+ *a_tk = PRIVATE (a_this)->token_cache;
+ PRIVATE (a_this)->token_cache = NULL;
+ return CR_OK;
+ }
+
+ RECORD_INITIAL_POS (a_this, &init_pos);
+
+ status = cr_input_get_end_of_file
+ (PRIVATE (a_this)->input, &reached_eof);
+ ENSURE_PARSING_COND (status == CR_OK);
+
+ if (reached_eof == TRUE) {
+ status = CR_END_OF_INPUT_ERROR;
+ goto error;
+ }
+
+ input = PRIVATE (a_this)->input;
+
+ PEEK_NEXT_CHAR (a_this, &next_char);
+ token = cr_token_new ();
+ ENSURE_PARSING_COND (token);
+
+ switch (next_char) {
+ case '@':
+ {
+ if (BYTE (input, 2, NULL) == 'f'
+ && BYTE (input, 3, NULL) == 'o'
+ && BYTE (input, 4, NULL) == 'n'
+ && BYTE (input, 5, NULL) == 't'
+ && BYTE (input, 6, NULL) == '-'
+ && BYTE (input, 7, NULL) == 'f'
+ && BYTE (input, 8, NULL) == 'a'
+ && BYTE (input, 9, NULL) == 'c'
+ && BYTE (input, 10, NULL) == 'e') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location
+ (a_this, &location) ;
+ SKIP_CHARS (a_this, 9);
+ status = cr_token_set_font_face_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+
+ if (BYTE (input, 2, NULL) == 'c'
+ && BYTE (input, 3, NULL) == 'h'
+ && BYTE (input, 4, NULL) == 'a'
+ && BYTE (input, 5, NULL) == 'r'
+ && BYTE (input, 6, NULL) == 's'
+ && BYTE (input, 7, NULL) == 'e'
+ && BYTE (input, 8, NULL) == 't') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location
+ (a_this, &location) ;
+ SKIP_CHARS (a_this, 7);
+ status = cr_token_set_charset_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+
+ if (BYTE (input, 2, NULL) == 'i'
+ && BYTE (input, 3, NULL) == 'm'
+ && BYTE (input, 4, NULL) == 'p'
+ && BYTE (input, 5, NULL) == 'o'
+ && BYTE (input, 6, NULL) == 'r'
+ && BYTE (input, 7, NULL) == 't') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location
+ (a_this, &location) ;
+ SKIP_CHARS (a_this, 6);
+ status = cr_token_set_import_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+
+ if (BYTE (input, 2, NULL) == 'm'
+ && BYTE (input, 3, NULL) == 'e'
+ && BYTE (input, 4, NULL) == 'd'
+ && BYTE (input, 5, NULL) == 'i'
+ && BYTE (input, 6, NULL) == 'a') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 5);
+ status = cr_token_set_media_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+
+ if (BYTE (input, 2, NULL) == 'p'
+ && BYTE (input, 3, NULL) == 'a'
+ && BYTE (input, 4, NULL) == 'g'
+ && BYTE (input, 5, NULL) == 'e') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 4);
+ status = cr_token_set_page_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+ status = cr_tknzr_parse_atkeyword (a_this, &str);
+ if (status == CR_OK) {
+ status = cr_token_set_atkeyword (token, str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ goto done;
+ }
+ }
+ break;
+
+ case 'u':
+
+ if (BYTE (input, 2, NULL) == 'r'
+ && BYTE (input, 3, NULL) == 'l'
+ && BYTE (input, 4, NULL) == '(') {
+ CRString *str2 = NULL;
+
+ status = cr_tknzr_parse_uri (a_this, &str2);
+ if (status == CR_OK) {
+ status = cr_token_set_uri (token, str2);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str2) {
+ cr_parsing_location_copy (&token->location,
+ &str2->location) ;
+ }
+ goto done;
+ }
+ }
+ goto fallback;
+ break;
+
+ case 'r':
+ if (BYTE (input, 2, NULL) == 'g'
+ && BYTE (input, 3, NULL) == 'b'
+ && BYTE (input, 4, NULL) == '(') {
+ status = cr_tknzr_parse_rgb (a_this, &rgb);
+ if (status == CR_OK && rgb) {
+ status = cr_token_set_rgb (token, rgb);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (rgb) {
+ cr_parsing_location_copy (&token->location,
+ &rgb->location) ;
+ }
+ rgb = NULL;
+ goto done;
+ }
+
+ }
+ goto fallback;
+ break;
+
+ case '<':
+ if (BYTE (input, 2, NULL) == '!'
+ && BYTE (input, 3, NULL) == '-'
+ && BYTE (input, 4, NULL) == '-') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 3);
+ status = cr_token_set_cdo (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+ break;
+
+ case '-':
+ if (BYTE (input, 2, NULL) == '-'
+ && BYTE (input, 3, NULL) == '>') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 2);
+ status = cr_token_set_cdc (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ } else {
+ status = cr_tknzr_parse_ident
+ (a_this, &str);
+ if (status == CR_OK) {
+ cr_token_set_ident
+ (token, str);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ goto done;
+ } else {
+ goto parse_number;
+ }
+ }
+ break;
+
+ case '~':
+ if (BYTE (input, 2, NULL) == '=') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 1);
+ status = cr_token_set_includes (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+ break;
+
+ case '|':
+ if (BYTE (input, 2, NULL) == '=') {
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ SKIP_CHARS (a_this, 1);
+ status = cr_token_set_dashmatch (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+ break;
+
+ case '/':
+ if (BYTE (input, 2, NULL) == '*') {
+ status = cr_tknzr_parse_comment (a_this, &str);
+
+ if (status == CR_OK) {
+ status = cr_token_set_comment (token, str);
+ str = NULL;
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ goto done;
+ }
+ }
+ break ;
+
+ case ';':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_semicolon (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case '{':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_cbo (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ goto done;
+
+ case '}':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_cbc (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case '(':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_po (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case ')':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_pc (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case '[':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_bo (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case ']':
+ SKIP_CHARS (a_this, 1);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_bc (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ {
+ guchar *start = NULL,
+ *end = NULL;
+
+ status = cr_tknzr_parse_w (a_this, &start,
+ &end, &location);
+ if (status == CR_OK) {
+ status = cr_token_set_s (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ goto done;
+ }
+ }
+ break;
+
+ case '#':
+ {
+ status = cr_tknzr_parse_hash (a_this, &str);
+ if (status == CR_OK && str) {
+ status = cr_token_set_hash (token, str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ str = NULL;
+ goto done;
+ }
+ }
+ break;
+
+ case '\'':
+ case '"':
+ status = cr_tknzr_parse_string (a_this, &str);
+ if (status == CR_OK && str) {
+ status = cr_token_set_string (token, str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ str = NULL;
+ goto done;
+ }
+ break;
+
+ case '!':
+ status = cr_tknzr_parse_important (a_this, &location);
+ if (status == CR_OK) {
+ status = cr_token_set_important_sym (token);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ goto done;
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ case '+':
+ /* '-' case is handled separately above for --> comments */
+ parse_number:
+ {
+ CRNum *num = NULL;
+
+ status = cr_tknzr_parse_num (a_this, &num);
+ if (status == CR_OK && num) {
+ next_bytes[0] = BYTE (input, 1, NULL);
+ next_bytes[1] = BYTE (input, 2, NULL);
+ next_bytes[2] = BYTE (input, 3, NULL);
+ next_bytes[3] = BYTE (input, 4, NULL);
+
+ if (next_bytes[0] == 'e'
+ && next_bytes[1] == 'm') {
+ num->type = NUM_LENGTH_EM;
+ status = cr_token_set_ems (token,
+ num);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'e'
+ && next_bytes[1] == 'x') {
+ num->type = NUM_LENGTH_EX;
+ status = cr_token_set_exs (token,
+ num);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 'x') {
+ num->type = NUM_LENGTH_PX;
+ status = cr_token_set_length
+ (token, num, LENGTH_PX_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'c'
+ && next_bytes[1] == 'm') {
+ num->type = NUM_LENGTH_CM;
+ status = cr_token_set_length
+ (token, num, LENGTH_CM_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'm'
+ && next_bytes[1] == 'm') {
+ num->type = NUM_LENGTH_MM;
+ status = cr_token_set_length
+ (token, num, LENGTH_MM_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'i'
+ && next_bytes[1] == 'n') {
+ num->type = NUM_LENGTH_IN;
+ status = cr_token_set_length
+ (token, num, LENGTH_IN_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 't') {
+ num->type = NUM_LENGTH_PT;
+ status = cr_token_set_length
+ (token, num, LENGTH_PT_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'p'
+ && next_bytes[1] == 'c') {
+ num->type = NUM_LENGTH_PC;
+ status = cr_token_set_length
+ (token, num, LENGTH_PC_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'd'
+ && next_bytes[1] == 'e'
+ && next_bytes[2] == 'g') {
+ num->type = NUM_ANGLE_DEG;
+ status = cr_token_set_angle
+ (token, num, ANGLE_DEG_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 3);
+ } else if (next_bytes[0] == 'r'
+ && next_bytes[1] == 'a'
+ && next_bytes[2] == 'd') {
+ num->type = NUM_ANGLE_RAD;
+ status = cr_token_set_angle
+ (token, num, ANGLE_RAD_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 3);
+ } else if (next_bytes[0] == 'g'
+ && next_bytes[1] == 'r'
+ && next_bytes[2] == 'a'
+ && next_bytes[3] == 'd') {
+ num->type = NUM_ANGLE_GRAD;
+ status = cr_token_set_angle
+ (token, num, ANGLE_GRAD_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 4);
+ } else if (next_bytes[0] == 'm'
+ && next_bytes[1] == 's') {
+ num->type = NUM_TIME_MS;
+ status = cr_token_set_time
+ (token, num, TIME_MS_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 's') {
+ num->type = NUM_TIME_S;
+ status = cr_token_set_time
+ (token, num, TIME_S_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 1);
+ } else if (next_bytes[0] == 'H'
+ && next_bytes[1] == 'z') {
+ num->type = NUM_FREQ_HZ;
+ status = cr_token_set_freq
+ (token, num, FREQ_HZ_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 2);
+ } else if (next_bytes[0] == 'k'
+ && next_bytes[1] == 'H'
+ && next_bytes[2] == 'z') {
+ num->type = NUM_FREQ_KHZ;
+ status = cr_token_set_freq
+ (token, num, FREQ_KHZ_ET);
+ num = NULL;
+ SKIP_CHARS (a_this, 3);
+ } else if (next_bytes[0] == '%') {
+ num->type = NUM_PERCENTAGE;
+ status = cr_token_set_percentage
+ (token, num);
+ num = NULL;
+ SKIP_CHARS (a_this, 1);
+ } else {
+ status = cr_tknzr_parse_ident (a_this,
+ &str);
+ if (status == CR_OK && str) {
+ num->type = NUM_UNKNOWN_TYPE;
+ status = cr_token_set_dimen
+ (token, num, str);
+ num = NULL;
+ CHECK_PARSING_STATUS (status,
+ TRUE);
+ str = NULL;
+ } else {
+ status = cr_token_set_number
+ (token, num);
+ num = NULL;
+ CHECK_PARSING_STATUS (status, CR_OK);
+ str = NULL;
+ }
+ }
+ if (token && token->u.num) {
+ cr_parsing_location_copy (&token->location,
+ &token->u.num->location) ;
+ } else {
+ status = CR_ERROR ;
+ }
+ goto done ;
+ }
+ }
+ break;
+
+ default:
+ fallback:
+ /*process the fallback cases here */
+
+ if (next_char == '\\'
+ || (cr_utils_is_nonascii (next_bytes[0]) == TRUE)
+ || ((next_char >= 'a') && (next_char <= 'z'))
+ || ((next_char >= 'A') && (next_char <= 'Z'))) {
+ status = cr_tknzr_parse_ident (a_this, &str);
+ if (status == CR_OK && str) {
+ guint32 next_c = 0;
+
+ status = cr_input_peek_char
+ (PRIVATE (a_this)->input, &next_c);
+
+ if (status == CR_OK && next_c == '(') {
+
+ SKIP_CHARS (a_this, 1);
+ status = cr_token_set_function
+ (token, str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ /*ownership is transfered
+ *to token by cr_token_set_function.
+ */
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ str = NULL;
+ } else {
+ status = cr_token_set_ident (token,
+ str);
+ CHECK_PARSING_STATUS (status, TRUE);
+ if (str) {
+ cr_parsing_location_copy (&token->location,
+ &str->location) ;
+ }
+ str = NULL;
+ }
+ goto done;
+ } else {
+ if (str) {
+ cr_string_destroy (str);
+ str = NULL;
+ }
+ }
+ }
+ break;
+ }
+
+ READ_NEXT_CHAR (a_this, &next_char);
+ cr_tknzr_get_parsing_location (a_this,
+ &location) ;
+ status = cr_token_set_delim (token, next_char);
+ CHECK_PARSING_STATUS (status, TRUE);
+ cr_parsing_location_copy (&token->location,
+ &location) ;
+ done:
+
+ if (status == CR_OK && token) {
+ *a_tk = token;
+ /*
+ *store the previous position input stream pos.
+ */
+ memmove (&PRIVATE (a_this)->prev_pos,
+ &init_pos, sizeof (CRInputPos));
+ return CR_OK;
+ }
+
+ error:
+ if (token) {
+ cr_token_destroy (token);
+ token = NULL;
+ }
+
+ if (str) {
+ cr_string_destroy (str);
+ str = NULL;
+ }
+ cr_tknzr_set_cur_pos (a_this, &init_pos);
+ return status;
+
+}
+
+enum CRStatus
+cr_tknzr_parse_token (CRTknzr * a_this, enum CRTokenType a_type,
+ enum CRTokenExtraType a_et, gpointer a_res,
+ gpointer a_extra_res)
+{
+ enum CRStatus status = CR_OK;
+ CRToken *token = NULL;
+
+ g_return_val_if_fail (a_this && PRIVATE (a_this)
+ && PRIVATE (a_this)->input
+ && a_res, CR_BAD_PARAM_ERROR);
+
+ status = cr_tknzr_get_next_token (a_this, &token);
+ if (status != CR_OK)
+ return status;
+ if (token == NULL)
+ return CR_PARSING_ERROR;
+
+ if (token->type == a_type) {
+ switch (a_type) {
+ case NO_TK:
+ case S_TK:
+ case CDO_TK:
+ case CDC_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case IMPORT_SYM_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ case IMPORTANT_SYM_TK:
+ status = CR_OK;
+ break;
+
+ case STRING_TK:
+ case IDENT_TK:
+ case HASH_TK:
+ case ATKEYWORD_TK:
+ case FUNCTION_TK:
+ case COMMENT_TK:
+ case URI_TK:
+ *((CRString **) a_res) = token->u.str;
+ token->u.str = NULL;
+ status = CR_OK;
+ break;
+
+ case EMS_TK:
+ case EXS_TK:
+ case PERCENTAGE_TK:
+ case NUMBER_TK:
+ *((CRNum **) a_res) = token->u.num;
+ token->u.num = NULL;
+ status = CR_OK;
+ break;
+
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case TIME_TK:
+ case FREQ_TK:
+ if (token->extra_type == a_et) {
+ *((CRNum **) a_res) = token->u.num;
+ token->u.num = NULL;
+ status = CR_OK;
+ }
+ break;
+
+ case DIMEN_TK:
+ *((CRNum **) a_res) = token->u.num;
+ if (a_extra_res == NULL) {
+ status = CR_BAD_PARAM_ERROR;
+ goto error;
+ }
+
+ *((CRString **) a_extra_res) = token->dimen;
+ token->u.num = NULL;
+ token->dimen = NULL;
+ status = CR_OK;
+ break;
+
+ case DELIM_TK:
+ *((guint32 *) a_res) = token->u.unichar;
+ status = CR_OK;
+ break;
+
+ case UNICODERANGE_TK:
+ default:
+ status = CR_PARSING_ERROR;
+ break;
+ }
+
+ cr_token_destroy (token);
+ token = NULL;
+ } else {
+ cr_tknzr_unget_token (a_this, token);
+ token = NULL;
+ status = CR_PARSING_ERROR;
+ }
+
+ return status;
+
+ error:
+
+ if (token) {
+ cr_tknzr_unget_token (a_this, token);
+ token = NULL;
+ }
+
+ return status;
+}
+
+void
+cr_tknzr_destroy (CRTknzr * a_this)
+{
+ g_return_if_fail (a_this);
+
+ if (PRIVATE (a_this) && PRIVATE (a_this)->input) {
+ if (cr_input_unref (PRIVATE (a_this)->input)
+ == TRUE) {
+ PRIVATE (a_this)->input = NULL;
+ }
+ }
+
+ if (PRIVATE (a_this)->token_cache) {
+ cr_token_destroy (PRIVATE (a_this)->token_cache);
+ PRIVATE (a_this)->token_cache = NULL;
+ }
+
+ if (PRIVATE (a_this)) {
+ g_free (PRIVATE (a_this));
+ PRIVATE (a_this) = NULL;
+ }
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-tknzr.h b/src/3rdparty/libcroco/cr-tknzr.h
new file mode 100644
index 000000000..13985b30e
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-tknzr.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for coypyright information.
+ */
+
+/**
+ *@file
+ *The declaration of the #CRTknzr (tokenizer)
+ *class.
+ */
+
+#ifndef __CR_TKNZR_H__
+#define __CR_TKNZR_H__
+
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-token.h"
+
+G_BEGIN_DECLS
+
+
+typedef struct _CRTknzr CRTknzr ;
+typedef struct _CRTknzrPriv CRTknzrPriv ;
+
+/**
+ *The tokenizer is the class that knows
+ *about all the css token. Its main job is
+ *to return the next token found in the character
+ *input stream.
+ */
+struct _CRTknzr
+{
+ /*the private data of the tokenizer.*/
+ CRTknzrPriv *priv ;
+} ;
+
+CRTknzr * cr_tknzr_new (CRInput *a_input) ;
+
+CRTknzr * cr_tknzr_new_from_uri (const guchar *a_file_uri,
+ enum CREncoding a_enc) ;
+
+CRTknzr * cr_tknzr_new_from_buf (guchar *a_buf, gulong a_len,
+ enum CREncoding a_enc,
+ gboolean a_free_at_destroy) ;
+
+gboolean cr_tknzr_unref (CRTknzr *a_this) ;
+
+void cr_tknzr_ref (CRTknzr *a_this) ;
+
+enum CRStatus cr_tknzr_read_byte (CRTknzr *a_this, guchar *a_byte) ;
+
+enum CRStatus cr_tknzr_read_char (CRTknzr *a_this, guint32 *a_char);
+
+enum CRStatus cr_tknzr_peek_char (CRTknzr *a_this, guint32 *a_char) ;
+
+enum CRStatus cr_tknzr_peek_byte (CRTknzr *a_this, gulong a_offset,
+ guchar *a_byte) ;
+
+guchar cr_tknzr_peek_byte2 (CRTknzr *a_this, gulong a_offset,
+ gboolean *a_eof) ;
+
+enum CRStatus cr_tknzr_set_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ;
+
+glong cr_tknzr_get_nb_bytes_left (CRTknzr *a_this) ;
+
+enum CRStatus cr_tknzr_get_cur_pos (CRTknzr *a_this, CRInputPos *a_pos) ;
+
+enum CRStatus cr_tknzr_get_parsing_location (CRTknzr *a_this,
+ CRParsingLocation *a_loc) ;
+
+enum CRStatus cr_tknzr_seek_index (CRTknzr *a_this,
+ enum CRSeekPos a_origin,
+ gint a_pos) ;
+
+enum CRStatus cr_tknzr_get_cur_byte_addr (CRTknzr *a_this, guchar **a_addr) ;
+
+
+enum CRStatus cr_tknzr_consume_chars (CRTknzr *a_this, guint32 a_char,
+ glong *a_nb_char) ;
+
+enum CRStatus cr_tknzr_get_next_token (CRTknzr *a_this, CRToken ** a_tk) ;
+
+enum CRStatus cr_tknzr_unget_token (CRTknzr *a_this, CRToken *a_token) ;
+
+
+enum CRStatus cr_tknzr_parse_token (CRTknzr *a_this, enum CRTokenType a_type,
+ enum CRTokenExtraType a_et, gpointer a_res,
+ gpointer a_extra_res) ;
+enum CRStatus cr_tknzr_set_input (CRTknzr *a_this, CRInput *a_input) ;
+
+enum CRStatus cr_tknzr_get_input (CRTknzr *a_this, CRInput **a_input) ;
+
+void cr_tknzr_destroy (CRTknzr *a_this) ;
+
+G_END_DECLS
+
+#endif /*__CR_TKZNR_H__*/
diff --git a/src/3rdparty/libcroco/cr-token.c b/src/3rdparty/libcroco/cr-token.c
new file mode 100644
index 000000000..dfe83e221
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-token.c
@@ -0,0 +1,636 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * see COPYRIGHTS file for copyright information.
+ */
+
+/**
+ *@file
+ *The definition of the #CRToken class.
+ *Abstracts a css2 token.
+ */
+#include <string.h>
+#include "cr-token.h"
+
+/*
+ *TODO: write a CRToken::to_string() method.
+ */
+
+/**
+ *Frees the attributes of the current instance
+ *of #CRtoken.
+ *@param a_this the current instance of #CRToken.
+ */
+static void
+cr_token_clear (CRToken * a_this)
+{
+ g_return_if_fail (a_this);
+
+ switch (a_this->type) {
+ case S_TK:
+ case CDO_TK:
+ case CDC_TK:
+ case INCLUDES_TK:
+ case DASHMATCH_TK:
+ case PAGE_SYM_TK:
+ case MEDIA_SYM_TK:
+ case FONT_FACE_SYM_TK:
+ case CHARSET_SYM_TK:
+ case IMPORT_SYM_TK:
+ case IMPORTANT_SYM_TK:
+ case SEMICOLON_TK:
+ case NO_TK:
+ case DELIM_TK:
+ case CBO_TK:
+ case CBC_TK:
+ case BO_TK:
+ case BC_TK:
+ break;
+
+ case STRING_TK:
+ case IDENT_TK:
+ case HASH_TK:
+ case URI_TK:
+ case FUNCTION_TK:
+ case COMMENT_TK:
+ case ATKEYWORD_TK:
+ if (a_this->u.str) {
+ cr_string_destroy (a_this->u.str);
+ a_this->u.str = NULL;
+ }
+ break;
+
+ case EMS_TK:
+ case EXS_TK:
+ case LENGTH_TK:
+ case ANGLE_TK:
+ case TIME_TK:
+ case FREQ_TK:
+ case PERCENTAGE_TK:
+ case NUMBER_TK:
+ case PO_TK:
+ case PC_TK:
+ if (a_this->u.num) {
+ cr_num_destroy (a_this->u.num);
+ a_this->u.num = NULL;
+ }
+ break;
+
+ case DIMEN_TK:
+ if (a_this->u.num) {
+ cr_num_destroy (a_this->u.num);
+ a_this->u.num = NULL;
+ }
+
+ if (a_this->dimen) {
+ cr_string_destroy (a_this->dimen);
+ a_this->dimen = NULL;
+ }
+
+ break;
+
+ case RGB_TK:
+ if (a_this->u.rgb) {
+ cr_rgb_destroy (a_this->u.rgb) ;
+ a_this->u.rgb = NULL ;
+ }
+ break ;
+
+ case UNICODERANGE_TK:
+ /*not supported yet. */
+ break;
+
+ default:
+ cr_utils_trace_info ("I don't know how to clear this token\n") ;
+ break;
+ }
+
+ a_this->type = NO_TK;
+}
+
+/**
+ *Default constructor of
+ *the #CRToken class.
+ *@return the newly built instance of #CRToken.
+ */
+CRToken *
+cr_token_new (void)
+{
+ CRToken *result = NULL;
+
+ result = (CRToken *) g_try_malloc (sizeof (CRToken));
+
+ if (result == NULL) {
+ cr_utils_trace_info ("Out of memory");
+ return NULL;
+ }
+
+ memset (result, 0, sizeof (CRToken));
+
+ return result;
+}
+
+/**
+ *Sets the type of curren instance of
+ *#CRToken to 'S_TK' (S in the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_s (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = S_TK;
+
+ return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to 'CDO_TK' (CDO as said by the css2 spec)
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdo (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = CDO_TK;
+
+ return CR_OK;
+}
+
+/**
+ *Sets the type of the current token to
+ *CDC_TK (CDC as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_cdc (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = CDC_TK;
+
+ return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to INCLUDES_TK (INCLUDES as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_includes (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = INCLUDES_TK;
+
+ return CR_OK;
+}
+
+/**
+ *Sets the type of the current instance of
+ *#CRToken to DASHMATCH_TK (DASHMATCH as said by the css2 spec).
+ *@param a_this the current instance of #CRToken.
+ *@return CR_OK upon successfull completion, an error
+ *code otherwise.
+ */
+enum CRStatus
+cr_token_set_dashmatch (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = DASHMATCH_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_comment (CRToken * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = COMMENT_TK;
+ a_this->u.str = a_str ;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_string (CRToken * a_this, CRString * a_str)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = STRING_TK;
+
+ a_this->u.str = a_str ;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_ident (CRToken * a_this, CRString * a_ident)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = IDENT_TK;
+ a_this->u.str = a_ident;
+ return CR_OK;
+}
+
+
+enum CRStatus
+cr_token_set_function (CRToken * a_this, CRString * a_fun_name)
+{
+ g_return_val_if_fail (a_this,
+ CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = FUNCTION_TK;
+ a_this->u.str = a_fun_name;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_hash (CRToken * a_this, CRString * a_hash)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = HASH_TK;
+ a_this->u.str = a_hash;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_rgb (CRToken * a_this, CRRgb * a_rgb)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = RGB_TK;
+ a_this->u.rgb = a_rgb;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_import_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = IMPORT_SYM_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_page_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = PAGE_SYM_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_media_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = MEDIA_SYM_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_font_face_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = FONT_FACE_SYM_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_charset_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = CHARSET_SYM_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_atkeyword (CRToken * a_this, CRString * a_atname)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+ a_this->type = ATKEYWORD_TK;
+ a_this->u.str = a_atname;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_important_sym (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ cr_token_clear (a_this);
+ a_this->type = IMPORTANT_SYM_TK;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_ems (CRToken * a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ cr_token_clear (a_this);
+ a_this->type = EMS_TK;
+ a_this->u.num = a_num;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_exs (CRToken * a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ cr_token_clear (a_this);
+ a_this->type = EXS_TK;
+ a_this->u.num = a_num;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_length (CRToken * a_this, CRNum * a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = LENGTH_TK;
+ a_this->extra_type = a_et;
+ a_this->u.num = a_num;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_angle (CRToken * a_this, CRNum * a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = ANGLE_TK;
+ a_this->extra_type = a_et;
+ a_this->u.num = a_num;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_time (CRToken * a_this, CRNum * a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = TIME_TK;
+ a_this->extra_type = a_et;
+ a_this->u.num = a_num;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_freq (CRToken * a_this, CRNum * a_num,
+ enum CRTokenExtraType a_et)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = FREQ_TK;
+ a_this->extra_type = a_et;
+ a_this->u.num = a_num;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_dimen (CRToken * a_this, CRNum * a_num,
+ CRString * a_dim)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+ cr_token_clear (a_this);
+ a_this->type = DIMEN_TK;
+ a_this->u.num = a_num;
+ a_this->dimen = a_dim;
+ return CR_OK;
+
+}
+
+enum CRStatus
+cr_token_set_percentage (CRToken * a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = PERCENTAGE_TK;
+ a_this->u.num = a_num;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_number (CRToken * a_this, CRNum * a_num)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = NUMBER_TK;
+ a_this->u.num = a_num;
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_uri (CRToken * a_this, CRString * a_uri)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = URI_TK;
+ a_this->u.str = a_uri;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_delim (CRToken * a_this, guint32 a_char)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = DELIM_TK;
+ a_this->u.unichar = a_char;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_semicolon (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = SEMICOLON_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_cbo (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = CBO_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_cbc (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = CBC_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_po (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = PO_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_pc (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = PC_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_bo (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = BO_TK;
+
+ return CR_OK;
+}
+
+enum CRStatus
+cr_token_set_bc (CRToken * a_this)
+{
+ g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
+
+ cr_token_clear (a_this);
+
+ a_this->type = BC_TK;
+
+ return CR_OK;
+}
+
+/**
+ *The destructor of the #CRToken class.
+ *@param a_this the current instance of #CRToken.
+ */
+void
+cr_token_destroy (CRToken * a_this)
+{
+ g_return_if_fail (a_this);
+
+ cr_token_clear (a_this);
+
+ g_free (a_this);
+}
diff --git a/src/3rdparty/libcroco/cr-token.h b/src/3rdparty/libcroco/cr-token.h
new file mode 100644
index 000000000..35e914d2d
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-token.h
@@ -0,0 +1,212 @@
+/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#ifndef __CR_TOKEN_H__
+#define __CR_TOKEN_H__
+
+#include "cr-utils.h"
+#include "cr-input.h"
+#include "cr-num.h"
+#include "cr-rgb.h"
+#include "cr-string.h"
+#include "cr-parsing-location.h"
+
+G_BEGIN_DECLS
+
+enum CRTokenType
+{
+ NO_TK, // 0
+ S_TK,
+ CDO_TK,
+ CDC_TK,
+ INCLUDES_TK,
+ DASHMATCH_TK, // 5
+ COMMENT_TK,
+ STRING_TK,
+ IDENT_TK,
+ HASH_TK,
+ IMPORT_SYM_TK, // 10
+ PAGE_SYM_TK,
+ MEDIA_SYM_TK,
+ FONT_FACE_SYM_TK,
+ CHARSET_SYM_TK,
+ ATKEYWORD_TK, // 15
+ IMPORTANT_SYM_TK,
+ EMS_TK,
+ EXS_TK,
+ LENGTH_TK,
+ ANGLE_TK, // 20
+ TIME_TK,
+ FREQ_TK,
+ DIMEN_TK,
+ PERCENTAGE_TK,
+ NUMBER_TK, // 25
+ RGB_TK,
+ URI_TK,
+ FUNCTION_TK,
+ UNICODERANGE_TK,
+ SEMICOLON_TK, // 30
+ CBO_TK, /*opening curly bracket*/
+ CBC_TK, /*closing curly bracket*/
+ PO_TK, /*opening parenthesis*/
+ PC_TK, /*closing parenthesis*/
+ BO_TK, /*opening bracket*/
+ BC_TK, /*closing bracket*/
+ DELIM_TK
+} ;
+
+enum CRTokenExtraType
+{
+ NO_ET = 0,
+ LENGTH_PX_ET,
+ LENGTH_CM_ET,
+ LENGTH_MM_ET,
+ LENGTH_IN_ET,
+ LENGTH_PT_ET,
+ LENGTH_PC_ET,
+ ANGLE_DEG_ET,
+ ANGLE_RAD_ET,
+ ANGLE_GRAD_ET,
+ TIME_MS_ET,
+ TIME_S_ET,
+ FREQ_HZ_ET,
+ FREQ_KHZ_ET
+} ;
+
+typedef struct _CRToken CRToken ;
+
+/**
+ *This class abstracts a css2 token.
+ */
+struct _CRToken
+{
+ enum CRTokenType type ;
+ enum CRTokenExtraType extra_type ;
+ CRInputPos pos ;
+
+ union
+ {
+ CRString *str ;
+ CRRgb *rgb ;
+ CRNum *num ;
+ guint32 unichar ;
+ } u ;
+
+ CRString * dimen ;
+ CRParsingLocation location ;
+} ;
+
+CRToken* cr_token_new (void) ;
+
+enum CRStatus cr_token_set_s (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cdo (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cdc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_includes (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_dashmatch (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_comment (CRToken *a_this, CRString *a_str) ;
+
+enum CRStatus cr_token_set_string (CRToken *a_this, CRString *a_str) ;
+
+enum CRStatus cr_token_set_ident (CRToken *a_this, CRString * a_ident) ;
+
+enum CRStatus cr_token_set_hash (CRToken *a_this, CRString *a_hash) ;
+
+enum CRStatus cr_token_set_rgb (CRToken *a_this, CRRgb *a_rgb) ;
+
+enum CRStatus cr_token_set_import_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_page_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_media_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_font_face_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_charset_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_atkeyword (CRToken *a_this, CRString *a_atname) ;
+
+enum CRStatus cr_token_set_important_sym (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_ems (CRToken *a_this, CRNum *a_num) ;
+
+enum CRStatus cr_token_set_exs (CRToken *a_this, CRNum *a_num) ;
+
+enum CRStatus cr_token_set_length (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+enum CRStatus cr_token_set_angle (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+enum CRStatus cr_token_set_time (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+enum CRStatus cr_token_set_freq (CRToken *a_this, CRNum *a_num,
+ enum CRTokenExtraType a_et) ;
+
+enum CRStatus cr_token_set_dimen (CRToken *a_this, CRNum *a_num,
+ CRString *a_dim) ;
+
+enum CRStatus cr_token_set_percentage (CRToken *a_this, CRNum *a_num) ;
+
+enum CRStatus cr_token_set_number (CRToken *a_this, CRNum *a_num) ;
+
+enum CRStatus cr_token_set_uri (CRToken *a_this, CRString *a_uri) ;
+
+enum CRStatus cr_token_set_function (CRToken *a_this,
+ CRString *a_fun_name) ;
+
+enum CRStatus cr_token_set_bc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_bo (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_po (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_pc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cbc (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_cbo (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_semicolon (CRToken *a_this) ;
+
+enum CRStatus cr_token_set_delim (CRToken *a_this, guint32 a_char) ;
+
+
+/*
+ enum CRStatus
+ cr_token_set_unicoderange (CRToken *a_this,
+ CRUnicodeRange *a_range) ;
+*/
+
+void
+cr_token_destroy (CRToken *a_this) ;
+
+
+G_END_DECLS
+
+#endif /*__CR_TOKEN_H__*/
diff --git a/src/3rdparty/libcroco/cr-utils.c b/src/3rdparty/libcroco/cr-utils.c
new file mode 100644
index 000000000..bfb587017
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-utils.c
@@ -0,0 +1,1330 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * See COPYRIGHTS file for copyright information.
+ */
+
+#include "cr-utils.h"
+#include "cr-string.h"
+
+/**
+ *@file:
+ *Some misc utility functions used
+ *in the libcroco.
+ *Note that troughout this file I will
+ *refer to the CSS SPECIFICATIONS DOCUMENTATION
+ *written by the w3c guys. You can find that document
+ *at http://www.w3.org/TR/REC-CSS2/ .
+ */
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+/*
+ *Here is the correspondance between the ucs-4 charactere codes
+ *and there matching utf-8 encoding pattern as dscribed by RFC 2279:
+ *
+ *UCS-4 range (hex.) UTF-8 octet sequence (binary)
+ *------------------ -----------------------------
+ *0000 0000-0000 007F 0xxxxxxx
+ *0000 0080-0000 07FF 110xxxxx 10xxxxxx
+ *0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
+ *0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
+ */
+
+/**
+ *Given an utf8 string buffer, calculates
+ *the length of this string if it was encoded
+ *in ucs4.
+ *@param a_in_start a pointer to the begining of
+ *the input utf8 string.
+ *@param a_in_end a pointre to the end of the input
+ *utf8 string (points to the last byte of the buffer)
+ *@param a_len out parameter the calculated length.
+ *@return CR_OK upon succesfull completion, an error code
+ *otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (const guchar * a_in_start,
+ const guchar * a_in_end, gulong * a_len)
+{
+ guchar *byte_ptr = NULL;
+ gint len = 0;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR);
+ *a_len = 0;
+
+ for (byte_ptr = (guchar *) a_in_start;
+ byte_ptr <= a_in_end; byte_ptr++) {
+ gint nb_bytes_2_decode = 0;
+
+ if (*byte_ptr <= 0x7F) {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *byte_ptr;
+ nb_bytes_2_decode = 1;
+
+ } else if ((*byte_ptr & 0xE0) == 0xC0) {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x1F;
+ nb_bytes_2_decode = 2;
+
+ } else if ((*byte_ptr & 0xF0) == 0xE0) {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x0F;
+ nb_bytes_2_decode = 3;
+
+ } else if ((*byte_ptr & 0xF8) == 0xF0) {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x7;
+ nb_bytes_2_decode = 4;
+
+ } else if ((*byte_ptr & 0xFC) == 0xF8) {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 3;
+ nb_bytes_2_decode = 5;
+
+ } else if ((*byte_ptr & 0xFE) == 0xFC) {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 1;
+ nb_bytes_2_decode = 6;
+
+ } else {
+ /*
+ *BAD ENCODING
+ */
+ return CR_ENCODING_ERROR;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+ /*decode the next byte */
+ byte_ptr++;
+
+ /*byte pattern must be: 10xx xxxx */
+ if ((*byte_ptr & 0xC0) != 0x80) {
+ return CR_ENCODING_ERROR;
+ }
+
+ c = (c << 6) | (*byte_ptr & 0x3F);
+ }
+
+ len++;
+ }
+
+ *a_len = len;
+
+ return CR_OK;
+}
+
+/**
+ *Given an ucs4 string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (const guint32 * a_in_start,
+ const guint32 * a_in_end, gulong * a_len)
+{
+ gint len = 0;
+ guint32 *char_ptr = NULL;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR);
+
+ for (char_ptr = (guint32 *) a_in_start;
+ char_ptr <= a_in_end; char_ptr++) {
+ if (*char_ptr <= 0x7F) {
+ /*the utf-8 char would take 1 byte */
+ len += 1;
+ } else if (*char_ptr <= 0x7FF) {
+ /*the utf-8 char would take 2 bytes */
+ len += 2;
+ } else if (*char_ptr <= 0xFFFF) {
+ len += 3;
+ } else if (*char_ptr <= 0x1FFFFF) {
+ len += 4;
+ } else if (*char_ptr <= 0x3FFFFFF) {
+ len += 5;
+ } else if (*char_ptr <= 0x7FFFFFFF) {
+ len += 6;
+ }
+ }
+
+ *a_len = len;
+ return CR_OK;
+}
+
+/**
+ *Given an ucsA string, this function
+ *returns the size (in bytes) this string
+ *would have occupied if it was encoded in utf-8.
+ *@param a_in_start a pointer to the beginning of the input
+ *buffer.
+ *@param a_in_end a pointer to the end of the input buffer.
+ *@param a_len out parameter. The computed length.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (const guchar * a_in_start,
+ const guchar * a_in_end, gulong * a_len)
+{
+ gint len = 0;
+ guchar *char_ptr = NULL;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR);
+
+ for (char_ptr = (guchar *) a_in_start;
+ char_ptr <= a_in_end; char_ptr++) {
+ if (*char_ptr <= 0x7F) {
+ /*the utf-8 char would take 1 byte */
+ len += 1;
+ } else {
+ /*the utf-8 char would take 2 bytes */
+ len += 2;
+ }
+ }
+
+ *a_len = len;
+ return CR_OK;
+}
+
+/**
+ *Converts an utf8 buffer into an ucs4 buffer.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of bytes consumed.
+ *@param a_out the output converted ucs4 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of characters decoded.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs4 (const guchar * a_in,
+ gulong * a_in_len, guint32 * a_out, gulong * a_out_len)
+{
+ gulong in_len = 0,
+ out_len = 0,
+ in_index = 0,
+ out_index = 0;
+ enum CRStatus status = CR_OK;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len < 1) {
+ status = CR_OK;
+ goto end;
+ }
+
+ in_len = *a_in_len;
+ out_len = *a_out_len;
+
+ for (in_index = 0, out_index = 0;
+ (in_index < in_len) && (out_index < out_len);
+ in_index++, out_index++) {
+ gint nb_bytes_2_decode = 0;
+
+ if (a_in[in_index] <= 0x7F) {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = a_in[in_index];
+ nb_bytes_2_decode = 1;
+
+ } else if ((a_in[in_index] & 0xE0) == 0xC0) {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x1F;
+ nb_bytes_2_decode = 2;
+
+ } else if ((a_in[in_index] & 0xF0) == 0xE0) {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x0F;
+ nb_bytes_2_decode = 3;
+
+ } else if ((a_in[in_index] & 0xF8) == 0xF0) {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x7;
+ nb_bytes_2_decode = 4;
+
+ } else if ((a_in[in_index] & 0xFC) == 0xF8) {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 3;
+ nb_bytes_2_decode = 5;
+
+ } else if ((a_in[in_index] & 0xFE) == 0xFC) {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 1;
+ nb_bytes_2_decode = 6;
+
+ } else {
+ /*BAD ENCODING */
+ goto end;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+ /*decode the next byte */
+ in_index++;
+
+ /*byte pattern must be: 10xx xxxx */
+ if ((a_in[in_index] & 0xC0) != 0x80) {
+ goto end;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F);
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ /************************
+ *Some security tests
+ ***********************/
+
+ /*be sure c is a char */
+ if (c == 0xFFFF || c == 0xFFFE)
+ goto end;
+
+ /*be sure c is inferior to the max ucs4 char value */
+ if (c > 0x10FFFF)
+ goto end;
+
+ /*
+ *c must be less than UTF16 "lower surrogate begin"
+ *or higher than UTF16 "High surrogate end"
+ */
+ if (c >= 0xD800 && c <= 0xDFFF)
+ goto end;
+
+ /*Avoid characters that equals zero */
+ if (c == 0)
+ goto end;
+
+ a_out[out_index] = c;
+ }
+
+ end:
+ *a_out_len = out_index + 1;
+ *a_in_len = in_index + 1;
+
+ return status;
+}
+
+/**
+ *Reads a character from an utf8 buffer.
+ *Actually decode the next character code (unicode character code)
+ *and returns it.
+ *@param a_in the starting address of the utf8 buffer.
+ *@param a_in_len the length of the utf8 buffer.
+ *@param a_out output parameter. The resulting read char.
+ *@param a_consumed the number of the bytes consumed to
+ *decode the returned character code.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (const guchar * a_in,
+ gulong a_in_len,
+ guint32 * a_out, gulong * a_consumed)
+{
+ gulong in_index = 0,
+ nb_bytes_2_decode = 0;
+ enum CRStatus status = CR_OK;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint32 c = 0;
+
+ g_return_val_if_fail (a_in && a_out && a_out
+ && a_consumed, CR_BAD_PARAM_ERROR);
+
+ if (a_in_len < 1) {
+ status = CR_OK;
+ goto end;
+ }
+
+ if (*a_in <= 0x7F) {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *a_in;
+ nb_bytes_2_decode = 1;
+
+ } else if ((*a_in & 0xE0) == 0xC0) {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *a_in & 0x1F;
+ nb_bytes_2_decode = 2;
+
+ } else if ((*a_in & 0xF0) == 0xE0) {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 0x0F;
+ nb_bytes_2_decode = 3;
+
+ } else if ((*a_in & 0xF8) == 0xF0) {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 0x7;
+ nb_bytes_2_decode = 4;
+
+ } else if ((*a_in & 0xFC) == 0xF8) {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 3;
+ nb_bytes_2_decode = 5;
+
+ } else if ((*a_in & 0xFE) == 0xFC) {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *a_in & 1;
+ nb_bytes_2_decode = 6;
+
+ } else {
+ /*BAD ENCODING */
+ goto end;
+ }
+
+ if (nb_bytes_2_decode > a_in_len) {
+ status = CR_END_OF_INPUT_ERROR;
+ goto end;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for (in_index = 1; in_index < nb_bytes_2_decode; in_index++) {
+ /*byte pattern must be: 10xx xxxx */
+ if ((a_in[in_index] & 0xC0) != 0x80) {
+ goto end;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F);
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ /************************
+ *Some security tests
+ ***********************/
+
+ /*be sure c is a char */
+ if (c == 0xFFFF || c == 0xFFFE)
+ goto end;
+
+ /*be sure c is inferior to the max ucs4 char value */
+ if (c > 0x10FFFF)
+ goto end;
+
+ /*
+ *c must be less than UTF16 "lower surrogate begin"
+ *or higher than UTF16 "High surrogate end"
+ */
+ if (c >= 0xD800 && c <= 0xDFFF)
+ goto end;
+
+ /*Avoid characters that equals zero */
+ if (c == 0)
+ goto end;
+
+ *a_out = c;
+
+ end:
+ *a_consumed = nb_bytes_2_decode;
+
+ return status;
+}
+
+/**
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (const guchar * a_in_start,
+ const guchar * a_in_end, gulong * a_len)
+{
+ /*
+ *Note: this function can be made shorter
+ *but it considers all the cases of the utf8 encoding
+ *to ease further extensions ...
+ */
+
+ guchar *byte_ptr = NULL;
+ gint len = 0;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint c = 0;
+
+ g_return_val_if_fail (a_in_start && a_in_end && a_len,
+ CR_BAD_PARAM_ERROR);
+ *a_len = 0;
+
+ for (byte_ptr = (guchar *) a_in_start;
+ byte_ptr <= a_in_end; byte_ptr++) {
+ gint nb_bytes_2_decode = 0;
+
+ if (*byte_ptr <= 0x7F) {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = *byte_ptr;
+ nb_bytes_2_decode = 1;
+
+ } else if ((*byte_ptr & 0xE0) == 0xC0) {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x1F;
+ nb_bytes_2_decode = 2;
+
+ } else if ((*byte_ptr & 0xF0) == 0xE0) {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x0F;
+ nb_bytes_2_decode = 3;
+
+ } else if ((*byte_ptr & 0xF8) == 0xF0) {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 0x7;
+ nb_bytes_2_decode = 4;
+
+ } else if ((*byte_ptr & 0xFC) == 0xF8) {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 3;
+ nb_bytes_2_decode = 5;
+
+ } else if ((*byte_ptr & 0xFE) == 0xFC) {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = *byte_ptr & 1;
+ nb_bytes_2_decode = 6;
+
+ } else {
+ /*
+ *BAD ENCODING
+ */
+ return CR_ENCODING_ERROR;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+ /*decode the next byte */
+ byte_ptr++;
+
+ /*byte pattern must be: 10xx xxxx */
+ if ((*byte_ptr & 0xC0) != 0x80) {
+ return CR_ENCODING_ERROR;
+ }
+
+ c = (c << 6) | (*byte_ptr & 0x3F);
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ if (c <= 0xFF) { /*Add other conditions to support
+ *other char sets (ucs2, ucs3, ucs4).
+ */
+ len++;
+ } else {
+ /*the char is too long to fit
+ *into the supposed charset len.
+ */
+ return CR_ENCODING_ERROR;
+ }
+ }
+
+ *a_len = len;
+
+ return CR_OK;
+}
+
+/**
+ *Converts an utf8 string into an ucs4 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of bytes
+ *consumed. This can be usefull to debug the input stream in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (const guchar * a_in,
+ gulong * a_in_len,
+ guint32 ** a_out, gulong * a_out_len)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+ status = cr_utils_utf8_str_len_as_ucs4 (a_in,
+ &a_in[*a_in_len - 1],
+ a_out_len);
+
+ g_return_val_if_fail (status == CR_OK, status);
+
+ *a_out = (guint32 *) g_malloc0 (*a_out_len * sizeof (guint32));
+
+ status = cr_utils_utf8_to_ucs4 (a_in, a_in_len, *a_out, a_out_len);
+
+ return status;
+}
+
+/**
+ *Converts an ucs4 buffer into an utf8 buffer.
+ *
+ *@param a_in the input ucs4 buffer to convert.
+ *@param a_in_len in/out parameter. The size of the
+ *input buffer to convert. After return, this parameter contains
+ *the actual number of characters consumed.
+ *@param a_out the output converted utf8 buffer. Must be allocated by
+ *the caller.
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If this size is actually smaller than the real needed size, the function
+ *just converts what it can and returns a success status. After return,
+ *this param points to the actual number of bytes in the buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_to_utf8 (const guint32 * a_in,
+ gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+ gulong in_len = 0,
+ in_index = 0,
+ out_index = 0;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out && a_out_len,
+ CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len < 1) {
+ status = CR_OK;
+ goto end;
+ }
+
+ in_len = *a_in_len;
+
+ for (in_index = 0; in_index < in_len; in_index++) {
+ /*
+ *FIXME: return whenever we encounter forbidden char values.
+ */
+
+ if (a_in[in_index] <= 0x7F) {
+ a_out[out_index] = a_in[in_index];
+ out_index++;
+ } else if (a_in[in_index] <= 0x7FF) {
+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
+ a_out[out_index + 1] =
+ (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 2;
+ } else if (a_in[in_index] <= 0xFFFF) {
+ a_out[out_index] = (0xE0 | (a_in[in_index] >> 12));
+ a_out[out_index + 1] =
+ (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+ a_out[out_index + 2] =
+ (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 3;
+ } else if (a_in[in_index] <= 0x1FFFFF) {
+ a_out[out_index] = (0xF0 | (a_in[in_index] >> 18));
+ a_out[out_index + 1]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+ a_out[out_index + 3]
+ = (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 4;
+ } else if (a_in[in_index] <= 0x3FFFFFF) {
+ a_out[out_index] = (0xF8 | (a_in[in_index] >> 24));
+ a_out[out_index + 1] =
+ (0x80 | (a_in[in_index] >> 18));
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+ a_out[out_index + 3]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+ a_out[out_index + 4]
+ = (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 5;
+ } else if (a_in[in_index] <= 0x7FFFFFFF) {
+ a_out[out_index] = (0xFC | (a_in[in_index] >> 30));
+ a_out[out_index + 1] =
+ (0x80 | (a_in[in_index] >> 24));
+ a_out[out_index + 2]
+ = (0x80 | ((a_in[in_index] >> 18) & 0x3F));
+ a_out[out_index + 3]
+ = (0x80 | ((a_in[in_index] >> 12) & 0x3F));
+ a_out[out_index + 4]
+ = (0x80 | ((a_in[in_index] >> 6) & 0x3F));
+ a_out[out_index + 4]
+ = (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 6;
+ } else {
+ status = CR_ENCODING_ERROR;
+ goto end;
+ }
+ } /*end for */
+
+ end:
+ *a_in_len = in_index + 1;
+ *a_out_len = out_index + 1;
+
+ return status;
+}
+
+/**
+ *Converts an ucs4 string into an utf8 string.
+ *@param a_in the input string to convert.
+ *@param a_in_len in/out parameter. The length of the input
+ *string. After return, points to the actual number of characters
+ *consumed. This can be usefull to debug the input string in case
+ *of encoding error.
+ *@param a_out out parameter. Points to the output string. It is allocated
+ *by this function and must be freed by the caller.
+ *@param a_out_len out parameter. The length (in bytes) of the output string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (const guint32 * a_in,
+ gulong * a_in_len,
+ guchar ** a_out, gulong * a_out_len)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out
+ && a_out_len, CR_BAD_PARAM_ERROR);
+
+ status = cr_utils_ucs4_str_len_as_utf8 (a_in,
+ &a_in[*a_out_len - 1],
+ a_out_len);
+
+ g_return_val_if_fail (status == CR_OK, status);
+
+ status = cr_utils_ucs4_to_utf8 (a_in, a_in_len, *a_out, a_out_len);
+
+ return status;
+}
+
+/**
+ *Converts an ucs1 buffer into an utf8 buffer.
+ *The caller must know the size of the resulting buffer and
+ *allocate it prior to calling this function.
+ *
+ *@param a_in the input ucs1 buffer.
+ *
+ *@param a_in_len in/out parameter. The length of the input buffer.
+ *After return, points to the number of bytes actually consumed even
+ *in case of encoding error.
+ *
+ *@param a_out out parameter. The output utf8 converted buffer.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *If the output buffer size is shorter than the actual needed size,
+ *this function just convert what it can.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_to_utf8 (const guchar * a_in,
+ gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+ gulong out_index = 0,
+ in_index = 0,
+ in_len = 0,
+ out_len = 0;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out_len,
+ CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len == 0) {
+ *a_out_len = 0 ;
+ return status;
+ }
+ g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ;
+
+ in_len = *a_in_len;
+ out_len = *a_out_len;
+
+ for (in_index = 0, out_index = 0;
+ (in_index < in_len) && (out_index < out_len); in_index++) {
+ /*
+ *FIXME: return whenever we encounter forbidden char values.
+ */
+
+ if (a_in[in_index] <= 0x7F) {
+ a_out[out_index] = a_in[in_index];
+ out_index++;
+ } else {
+ a_out[out_index] = (0xC0 | (a_in[in_index] >> 6));
+ a_out[out_index + 1] =
+ (0x80 | (a_in[in_index] & 0x3F));
+ out_index += 2;
+ }
+ } /*end for */
+
+ *a_in_len = in_index;
+ *a_out_len = out_index;
+
+ return status;
+}
+
+/**
+ *Converts an ucs1 string into an utf8 string.
+ *@param a_in_start the beginning of the input string to convert.
+ *@param a_in_end the end of the input string to convert.
+ *@param a_out out parameter. The converted string.
+ *@param a_out out parameter. The length of the converted string.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *
+ */
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (const guchar * a_in,
+ gulong * a_in_len,
+ guchar ** a_out, gulong * a_out_len)
+{
+ gulong out_len = 0;
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len && a_out
+ && a_out_len, CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len < 1) {
+ *a_out_len = 0;
+ *a_out = NULL;
+ return CR_OK;
+ }
+
+ status = cr_utils_ucs1_str_len_as_utf8 (a_in, &a_in[*a_in_len - 1],
+ &out_len);
+
+ g_return_val_if_fail (status == CR_OK, status);
+
+ *a_out = (guchar *) g_malloc0 (out_len);
+
+ status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len);
+
+ *a_out_len = out_len;
+
+ return status;
+}
+
+/**
+ *Converts an utf8 buffer into an ucs1 buffer.
+ *The caller must know the size of the resulting
+ *converted buffer, and allocated it prior to calling this
+ *function.
+ *
+ *@param a_in the input utf8 buffer to convert.
+ *
+ *@param a_in_len in/out parameter. The size of the input utf8 buffer.
+ *After return, points to the number of bytes consumed
+ *by the function even in case of encoding error.
+ *
+ *@param a_out out parameter. Points to the resulting buffer.
+ *Must be allocated by the caller. If the size of a_out is shorter
+ *than its required size, this function converts what it can and return
+ *a successfull status.
+ *
+ *@param a_out_len in/out parameter. The size of the output buffer.
+ *After return, points to the number of bytes consumed even in case of
+ *encoding error.
+ *
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ */
+enum CRStatus
+cr_utils_utf8_to_ucs1 (const guchar * a_in,
+ gulong * a_in_len, guchar * a_out, gulong * a_out_len)
+{
+ gulong in_index = 0,
+ out_index = 0,
+ in_len = 0,
+ out_len = 0;
+ enum CRStatus status = CR_OK;
+
+ /*
+ *to store the final decoded
+ *unicode char
+ */
+ guint32 c = 0;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len < 1) {
+ goto end;
+ }
+
+ in_len = *a_in_len;
+ out_len = *a_out_len;
+
+ for (in_index = 0, out_index = 0;
+ (in_index < in_len) && (out_index < out_len);
+ in_index++, out_index++) {
+ gint nb_bytes_2_decode = 0;
+
+ if (a_in[in_index] <= 0x7F) {
+ /*
+ *7 bits long char
+ *encoded over 1 byte:
+ * 0xxx xxxx
+ */
+ c = a_in[in_index];
+ nb_bytes_2_decode = 1;
+
+ } else if ((a_in[in_index] & 0xE0) == 0xC0) {
+ /*
+ *up to 11 bits long char.
+ *encoded over 2 bytes:
+ *110x xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x1F;
+ nb_bytes_2_decode = 2;
+
+ } else if ((a_in[in_index] & 0xF0) == 0xE0) {
+ /*
+ *up to 16 bit long char
+ *encoded over 3 bytes:
+ *1110 xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x0F;
+ nb_bytes_2_decode = 3;
+
+ } else if ((a_in[in_index] & 0xF8) == 0xF0) {
+ /*
+ *up to 21 bits long char
+ *encoded over 4 bytes:
+ *1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 0x7;
+ nb_bytes_2_decode = 4;
+
+ } else if ((a_in[in_index] & 0xFC) == 0xF8) {
+ /*
+ *up to 26 bits long char
+ *encoded over 5 bytes.
+ *1111 10xx 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 3;
+ nb_bytes_2_decode = 5;
+
+ } else if ((a_in[in_index] & 0xFE) == 0xFC) {
+ /*
+ *up to 31 bits long char
+ *encoded over 6 bytes:
+ *1111 110x 10xx xxxx 10xx xxxx
+ *10xx xxxx 10xx xxxx 10xx xxxx
+ */
+ c = a_in[in_index] & 1;
+ nb_bytes_2_decode = 6;
+
+ } else {
+ /*BAD ENCODING */
+ status = CR_ENCODING_ERROR;
+ goto end;
+ }
+
+ /*
+ *Go and decode the remaining byte(s)
+ *(if any) to get the current character.
+ */
+ if (in_index + nb_bytes_2_decode - 1 >= in_len) {
+ goto end;
+ }
+
+ for (; nb_bytes_2_decode > 1; nb_bytes_2_decode--) {
+ /*decode the next byte */
+ in_index++;
+
+ /*byte pattern must be: 10xx xxxx */
+ if ((a_in[in_index] & 0xC0) != 0x80) {
+ status = CR_ENCODING_ERROR;
+ goto end;
+ }
+
+ c = (c << 6) | (a_in[in_index] & 0x3F);
+ }
+
+ /*
+ *The decoded ucs4 char is now
+ *in c.
+ */
+
+ if (c > 0xFF) {
+ status = CR_ENCODING_ERROR;
+ goto end;
+ }
+
+ a_out[out_index] = c;
+ }
+
+ end:
+ *a_out_len = out_index;
+ *a_in_len = in_index;
+
+ return status;
+}
+
+/**
+ *Converts an utf8 buffer into an
+ *ucs1 buffer.
+ *@param a_in_start the start of the input buffer.
+ *@param a_in_end the end of the input buffer.
+ *@param a_out out parameter. The resulting converted ucs4 buffer.
+ *Must be freed by the caller.
+ *@param a_out_len out parameter. The length of the converted buffer.
+ *@return CR_OK upon successfull completion, an error code otherwise.
+ *Note that out parameters are valid if and only if this function
+ *returns CR_OK.
+ */
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (const guchar * a_in,
+ gulong * a_in_len,
+ guchar ** a_out, gulong * a_out_len)
+{
+ enum CRStatus status = CR_OK;
+
+ g_return_val_if_fail (a_in && a_in_len
+ && a_out && a_out_len, CR_BAD_PARAM_ERROR);
+
+ if (*a_in_len < 1) {
+ *a_out_len = 0;
+ *a_out = NULL;
+ return CR_OK;
+ }
+
+ status = cr_utils_utf8_str_len_as_ucs4 (a_in, &a_in[*a_in_len - 1],
+ a_out_len);
+
+ g_return_val_if_fail (status == CR_OK, status);
+
+ *a_out = (guchar *) g_malloc0 (*a_out_len * sizeof (guint32));
+
+ status = cr_utils_utf8_to_ucs1 (a_in, a_in_len, *a_out, a_out_len);
+ return status;
+}
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+/**
+ *Returns TRUE if a_char is a white space as
+ *defined in the css spec in chap 4.1.1.
+ *
+ *white-space ::= ' '| \t|\r|\n|\f
+ *
+ *@param a_char the character to test.
+ *return TRUE if is a white space, false otherwise.
+ */
+gboolean
+cr_utils_is_white_space (guint32 a_char)
+{
+ switch (a_char) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '\f':
+ return TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ *Returns true if the character is a newline
+ *as defined in the css spec in the chap 4.1.1.
+ *
+ *nl ::= \n|\r\n|\r|\f
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a newline, FALSE otherwise.
+ */
+gboolean
+cr_utils_is_newline (guint32 a_char)
+{
+ switch (a_char) {
+ case '\n':
+ case '\r':
+ case '\f':
+ return TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ *returns TRUE if the char is part of an hexa num char:
+ *i.e hexa_char ::= [0-9A-F]
+ */
+gboolean
+cr_utils_is_hexa_char (guint32 a_char)
+{
+ if ((a_char >= '0' && a_char <= '9')
+ || (a_char >= 'A' && a_char <= 'F')) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ *Returns true if the character is a nonascii
+ *character (as defined in the css spec chap 4.1.1):
+ *
+ *nonascii ::= [^\0-\177]
+ *
+ *@param a_char the character to test.
+ *@return TRUE if the character is a nonascii char,
+ *FALSE otherwise.
+ */
+gboolean
+cr_utils_is_nonascii (guint32 a_char)
+{
+ if (a_char <= 177) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ *Dumps a character a_nb times on a file.
+ *@param a_char the char to dump
+ *@param a_fp the destination file pointer
+ *@param a_nb the number of times a_char is to be dumped.
+ */
+void
+cr_utils_dump_n_chars (guchar a_char, FILE * a_fp, glong a_nb)
+{
+ glong i = 0;
+
+ for (i = 0; i < a_nb; i++) {
+ fprintf (a_fp, "%c", a_char);
+ }
+}
+
+void
+cr_utils_dump_n_chars2 (guchar a_char, GString * a_string, glong a_nb)
+{
+ glong i = 0;
+
+ g_return_if_fail (a_string);
+
+ for (i = 0; i < a_nb; i++) {
+ g_string_append_printf (a_string, "%c", a_char);
+ }
+}
+
+/**
+ *Duplicates a list of GString instances.
+ *@return the duplicated list of GString instances or NULL if
+ *something bad happened.
+ *@param a_list_of_strings the list of strings to be duplicated.
+ */
+GList *
+cr_utils_dup_glist_of_string (GList const * a_list_of_strings)
+{
+ GList const *cur = NULL;
+ GList *result = NULL;
+
+ g_return_val_if_fail (a_list_of_strings, NULL);
+
+ for (cur = a_list_of_strings; cur; cur = cur->next) {
+ GString *str = NULL;
+
+ str = g_string_new_len (((GString *) cur->data)->str,
+ ((GString *) cur->data)->len);
+ if (str)
+ result = g_list_append (result, str);
+ }
+
+ return result;
+}
+
+/**
+ *Duplicate a GList where the GList::data is a CRString.
+ *@param a_list_of_strings the list to duplicate
+ *@return the duplicated list, or NULL if something bad
+ *happened.
+ */
+GList *
+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings)
+{
+ GList const *cur = NULL;
+ GList *result = NULL;
+
+ g_return_val_if_fail (a_list_of_strings, NULL);
+
+ for (cur = a_list_of_strings; cur; cur = cur->next) {
+ CRString *str = NULL;
+
+ str = cr_string_dup ((CRString const *) cur->data) ;
+ if (str)
+ result = g_list_append (result, str);
+ }
+
+ return result;
+}
diff --git a/src/3rdparty/libcroco/cr-utils.h b/src/3rdparty/libcroco/cr-utils.h
new file mode 100644
index 000000000..3959b1037
--- /dev/null
+++ b/src/3rdparty/libcroco/cr-utils.h
@@ -0,0 +1,249 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/*
+ * This file is part of The Croco Library
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ * Author: Dodji Seketeli
+ * Look at file COPYRIGHTS for copyright information
+ */
+
+#ifndef __CR_DEFS_H__
+#define __CR_DEFS_H__
+
+#include <stdio.h>
+#include <glib.h>
+/*
+ * We're disabling this #include for Inkscape: see comment in libcroco.h.
+//#include "libcroco-config.h"
+ */
+
+G_BEGIN_DECLS
+
+/**
+ *@file
+ *The Croco library basic types definitions
+ *And global definitions.
+ */
+
+/**
+ *The status type returned
+ *by the methods of the croco library.
+ */
+enum CRStatus {
+ CR_OK,
+ CR_BAD_PARAM_ERROR,
+ CR_INSTANCIATION_FAILED_ERROR,
+ CR_UNKNOWN_TYPE_ERROR,
+ CR_UNKNOWN_PROP_ERROR,
+ CR_UNKNOWN_PROP_VAL_ERROR,
+ CR_UNEXPECTED_POSITION_SCHEME,
+ CR_START_OF_INPUT_ERROR,
+ CR_END_OF_INPUT_ERROR,
+ CR_OUTPUT_TOO_SHORT_ERROR,
+ CR_INPUT_TOO_SHORT_ERROR,
+ CR_OUT_OF_BOUNDS_ERROR,
+ CR_EMPTY_PARSER_INPUT_ERROR,
+ CR_ENCODING_ERROR,
+ CR_ENCODING_NOT_FOUND_ERROR,
+ CR_PARSING_ERROR,
+ CR_SYNTAX_ERROR,
+ CR_NO_ROOT_NODE_ERROR,
+ CR_NO_TOKEN,
+ CR_OUT_OF_MEMORY_ERROR,
+ CR_PSEUDO_CLASS_SEL_HANDLER_NOT_FOUND_ERROR,
+ CR_BAD_PSEUDO_CLASS_SEL_HANDLER_ERROR,
+ CR_ERROR,
+ CR_FILE_NOT_FOUND_ERROR,
+ CR_VALUE_NOT_FOUND_ERROR
+} ;
+
+/**
+ *Values used by
+ *cr_input_seek_position() ;
+ */
+enum CRSeekPos {
+ CR_SEEK_CUR,
+ CR_SEEK_BEGIN,
+ CR_SEEK_END
+} ;
+
+/**
+ *Encoding values.
+ */
+enum CREncoding
+{
+ CR_UCS_4 = 1/*Must be not NULL*/,
+ CR_UCS_1,
+ CR_ISO_8859_1,
+ CR_ASCII,
+ CR_UTF_8,
+ CR_UTF_16,
+ CR_AUTO/*should be the last one*/
+} ;
+
+
+
+
+#define CROCO_LOG_DOMAIN "LIBCROCO"
+
+#ifdef __GNUC__
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): %s\n", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__, \
+ a_msg)
+#else /*__GNUC__*/
+
+#define cr_utils_trace(a_log_level, a_msg) \
+g_log (CROCO_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ a_msg)
+#endif
+
+/**
+ *Traces an info message.
+ *The file, line and enclosing function
+ *of the message will be automatically
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_info(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_INFO, a_msg)
+
+/**
+ *Trace a debug message.
+ *The file, line and enclosing function
+ *of the message will be automatically
+ *added to the message.
+ *@param a_msg the msg to trace.
+ */
+#define cr_utils_trace_debug(a_msg) \
+cr_utils_trace (G_LOG_LEVEL_DEBUG, a_msg) ;
+
+
+/****************************
+ *Encoding transformations and
+ *encoding helpers
+ ****************************/
+
+enum CRStatus
+cr_utils_read_char_from_utf8_buf (const guchar * a_in, gulong a_in_len,
+ guint32 *a_out, gulong *a_consumed) ;
+
+enum CRStatus
+cr_utils_ucs1_to_utf8 (const guchar *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs1 (const guchar * a_in, gulong * a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_to_utf8 (const guint32 *a_in, gulong *a_in_len,
+ guchar *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs4 (const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs1_str_len_as_utf8 (const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_utf8_str_len_as_ucs1 (const guchar *a_in_start,
+ const guchar *a_in_end,
+ gulong *a_len) ;
+enum CRStatus
+cr_utils_ucs4_str_len_as_utf8 (const guint32 *a_in_start,
+ const guint32 *a_in_end,
+ gulong *a_len) ;
+
+enum CRStatus
+cr_utils_ucs1_str_to_utf8 (const guchar *a_in_start,
+ gulong *a_in_len,
+ guchar **a_out,
+ gulong *a_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs1 (const guchar * a_in_start,
+ gulong * a_in_len,
+ guchar **a_out,
+ gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_to_ucs4 (const guchar * a_in,
+ gulong * a_in_len,
+ guint32 *a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_ucs4_str_to_utf8 (const guint32 *a_in,
+ gulong *a_in_len,
+ guchar **a_out, gulong *a_out_len) ;
+
+enum CRStatus
+cr_utils_utf8_str_to_ucs4 (const guchar * a_in,
+ gulong *a_in_len,
+ guint32 **a_out,
+ gulong *a_out_len) ;
+
+
+/*****************************************
+ *CSS basic types identification utilities
+ *****************************************/
+
+gboolean
+cr_utils_is_newline (guint32 a_char) ;
+
+gboolean
+cr_utils_is_white_space (guint32 a_char) ;
+
+gboolean
+cr_utils_is_nonascii (guint32 a_char) ;
+
+gboolean
+cr_utils_is_hexa_char (guint32 a_char) ;
+
+
+/**********************************
+ *Miscellaneous utility functions
+ ***********************************/
+
+void
+cr_utils_dump_n_chars (guchar a_char,
+ FILE *a_fp,
+ glong a_nb) ;
+
+void
+cr_utils_dump_n_chars2 (guchar a_char,
+ GString *a_string,
+ glong a_nb) ;
+GList *
+cr_utils_dup_glist_of_string (GList const *a_list) ;
+
+GList *
+cr_utils_dup_glist_of_cr_string (GList const * a_list_of_strings) ;
+
+G_END_DECLS
+
+#endif /*__CR_DEFS_H__*/
diff --git a/src/3rdparty/libcroco/libcroco.h b/src/3rdparty/libcroco/libcroco.h
new file mode 100644
index 000000000..579715a6e
--- /dev/null
+++ b/src/3rdparty/libcroco/libcroco.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of The Croco Library
+ *
+ * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __LIBCROCO_H__
+#define __LIBCROCO_H__
+
+/*
+ * We're disabling this for inkscape: none of its macros are actually used anyway,
+ * so we might as well keep the build process simple.
+//#include "libcroco-config.h"
+ */
+
+#include "cr-utils.h"
+#include "cr-pseudo.h"
+#include "cr-term.h"
+#include "cr-attr-sel.h"
+#include "cr-simple-sel.h"
+#include "cr-selector.h"
+#include "cr-enc-handler.h"
+#include "cr-doc-handler.h"
+#include "cr-input.h"
+#include "cr-parser.h"
+#include "cr-statement.h"
+#include "cr-stylesheet.h"
+#include "cr-om-parser.h"
+#include "cr-prop-list.h"
+#include "cr-sel-eng.h"
+#include "cr-style.h"
+#include "cr-string.h"
+
+#endif /*__LIBCROCO_H__*/
diff --git a/src/3rdparty/libdepixelize/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README b/src/3rdparty/libdepixelize/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README
new file mode 100644
index 000000000..df63435d6
--- /dev/null
+++ b/src/3rdparty/libdepixelize/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README
@@ -0,0 +1,9 @@
+All code files in this directory are *direct* copies of the files in
+libdepixelize's BZR repo.
+If you want to change the code, please change it in libdepixelize, then copy the
+files here.
+Otherwise, I will probably miss that you changed something in Inkscape's copy,
+and destroy your changes by copying libdepixelize's files over it during the
+next time I update Inkscape's copy of libdepixelize.
+
+libdepixelize's BZR repo = lp:libdepixelize
diff --git a/src/3rdparty/libdepixelize/CMakeLists.txt b/src/3rdparty/libdepixelize/CMakeLists.txt
new file mode 100644
index 000000000..a69d37bc7
--- /dev/null
+++ b/src/3rdparty/libdepixelize/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+set(libdepixelize_SRC
+ kopftracer2011.cpp
+
+ # -------
+ # Headers
+ kopftracer2011.h
+ splines.h
+
+ priv/branchless.h
+ priv/colorspace.h
+ priv/curvature.h
+ priv/homogeneoussplines.h
+ priv/integral.h
+ priv/iterator.h
+ priv/optimization-kopf2011.h
+ priv/pixelgraph.h
+ priv/point.h
+ priv/simplifiedvoronoi.h
+ priv/splines-kopf2011.h
+)
+
+add_inkscape_lib(depixelize_LIB "${libdepixelize_SRC}")
diff --git a/src/3rdparty/libdepixelize/kopftracer2011.cpp b/src/3rdparty/libdepixelize/kopftracer2011.cpp
new file mode 100644
index 000000000..96784b14f
--- /dev/null
+++ b/src/3rdparty/libdepixelize/kopftracer2011.cpp
@@ -0,0 +1,665 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glibmm.h>
+
+#include <algorithm>
+#include "kopftracer2011.h"
+#include "priv/colorspace.h"
+#include "priv/homogeneoussplines.h"
+#include "priv/branchless.h"
+#include "priv/splines-kopf2011.h"
+#include "priv/iterator.h"
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+#include <glibmm/datetime.h>
+#include <iostream>
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+namespace Tracer {
+namespace Heuristics {
+
+int curves(const PixelGraph &graph, PixelGraph::const_iterator a,
+ PixelGraph::const_iterator b);
+bool islands(PixelGraph::const_iterator a, PixelGraph::const_iterator b);
+
+struct SparsePixels
+{
+ enum Diagonal {
+ /**
+ * From (first) the top left corner to (second) the bottom right.
+ */
+ MAIN_DIAGONAL = 0,
+ /**
+ * From (first) the top right to (second) the bottom left.
+ */
+ SECONDARY_DIAGONAL = 1
+ };
+
+ typedef std::pair<PixelGraph::const_iterator, PixelGraph::const_iterator>
+ Edge;
+ typedef std::pair<Edge, int> EdgeWeight;
+
+ void operator()(const PixelGraph &graph, unsigned radius);
+
+ static bool similar_colors(PixelGraph::const_iterator n,
+ const guint8 (&a)[4], const guint8 (&b)[4]);
+
+ /*
+ * Precondition: Must be filled according to Diagonal enum.
+ */
+ EdgeWeight diagonals[2];
+};
+
+} // namespace Heuristics
+
+Splines Kopf2011::to_voronoi(const std::string &filename,
+ const Options &options)
+{
+ return to_voronoi(Gdk::Pixbuf::create_from_file(filename), options);
+}
+
+Splines Kopf2011::to_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options)
+{
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ SimplifiedVoronoi<Precision, false> voronoi
+ = _voronoi<Precision, false>(buf, options);
+
+ Glib::DateTime profiling_info[2];
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ Splines ret(voronoi);
+
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Splines construction time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+
+ return ret;
+#else // LIBDEPIXELIZE_PROFILE_KOPF2011
+ return Splines(_voronoi<Precision, false>(buf, options));
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+}
+
+Splines Kopf2011::to_grouped_voronoi(const std::string &filename,
+ const Options &options)
+{
+ return to_grouped_voronoi(Gdk::Pixbuf::create_from_file(filename), options);
+}
+
+Splines Kopf2011::to_grouped_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options)
+{
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ SimplifiedVoronoi<Precision, false> voronoi
+ = _voronoi<Precision, false>(buf, options);
+
+ Glib::DateTime profiling_info[2];
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ HomogeneousSplines<Precision> splines(voronoi);
+
+#else // LIBDEPIXELIZE_PROFILE_KOPF2011
+ HomogeneousSplines<Precision> splines(_voronoi<Precision, false>
+ (buf, options));
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::HomogeneousSplines<" << typeid(Precision).name()
+ << ">(Tracer::SimplifiedVoronoi<" << typeid(Precision).name()
+ << ",false>) construction time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ for ( HomogeneousSplines<Precision>::iterator it = splines.begin(),
+ end = splines.end() ; it != end ; ++it ) {
+ for ( HomogeneousSplines<Precision>::Polygon::points_iter
+ it2 = it->vertices.begin(), end2 = it->vertices.end()
+ ; it2 != end2 ; ++it2 ) {
+ it2->smooth = false;
+ }
+ for ( HomogeneousSplines<Precision>::Polygon::holes_iter
+ it2 = it->holes.begin(), end2 = it->holes.end()
+ ; it2 != end2 ; ++it2 ) {
+ for ( HomogeneousSplines<Precision>::Polygon::points_iter
+ it3 = it2->begin(), end3 = it2->end()
+ ; it3 != end3 ; ++it3 ) {
+ it3->smooth = false;
+ }
+ }
+ }
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Kopf2011::to_grouped_voronoi internal work time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ Splines ret(splines, false, options.nthreads);
+
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Splines construction time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+
+ return ret;
+#else // LIBDEPIXELIZE_PROFILE_KOPF2011
+ return Splines(splines, false, options.nthreads);
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+}
+
+Splines Kopf2011::to_splines(const std::string &filename,
+ const Options &options)
+{
+ return to_splines(Gdk::Pixbuf::create_from_file(filename), options);
+}
+
+Splines Kopf2011::to_splines(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options)
+{
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ SimplifiedVoronoi<Precision, true> voronoi
+ = _voronoi<Precision, true>(buf, options);
+
+ Glib::DateTime profiling_info[2];
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ HomogeneousSplines<Precision> splines(voronoi);
+
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::HomogeneousSplines<" << typeid(Precision).name()
+ << "> construction time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ Splines ret(splines, options.optimize, options.nthreads);
+
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Splines construction time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+
+ return ret;
+#else // LIBDEPIXELIZE_PROFILE_KOPF2011
+ HomogeneousSplines<Precision> splines(_voronoi<Precision, true>
+ (buf, options));
+ return Splines(splines, options.optimize, options.nthreads);
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+}
+
+template<class T, bool adjust_splines>
+SimplifiedVoronoi<T, adjust_splines>
+Kopf2011::_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options)
+{
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ Glib::DateTime profiling_info[2];
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ PixelGraph graph(buf);
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::PixelGraph creation time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ // gdk-pixbuf2 already checks if image size is meaningful, but asserts state
+ // preconditions and will be useful if gdk-pixbuf is replaced later
+ assert(graph.width() > 0);
+ assert(graph.height() > 0);
+
+#ifndef NDEBUG
+ graph.checkConsistency();
+#endif
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ // This step could be part of the initialization of PixelGraph
+ // and decrease the necessary number of passes
+ graph.connectAllNeighbors();
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::PixelGraph::connectAllNeighbors() time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+#ifndef NDEBUG
+ graph.checkConsistency();
+#endif
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ // This step can't be part of PixelGraph initilization without adding some
+ // cache misses due to random access patterns that might be injected
+ _disconnect_neighbors_with_dissimilar_colors(graph);
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Kopf2011::"
+ "_disconnect_neighbors_with_dissimilar_colors(Tracer::PixelGraph) time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+#ifndef NDEBUG
+ graph.checkConsistency();
+#endif
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ {
+ // edges_safe and edges_unsafe must be executed in separate.
+ // Otherwise, there will be colateral effects due to misassumption about
+ // the data being read.
+ PixelGraph::EdgePairContainer edges = graph.crossingEdges();
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::PixelGraph::crossingEdges() time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ _remove_crossing_edges_safe(edges);
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Kopf2011::_remove_crossing_edges_safe"
+ "(Tracer::PixelGraph) time: "
+ << profiling_info[1].difference(profiling_info[0])
+ << std::endl;
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+#ifndef NDEBUG
+ graph.checkConsistency();
+#endif
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+ _remove_crossing_edges_unsafe(graph, edges, options);
+ }
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::Kopf2011::_remove_crossing_edges_unsafe"
+ "(Tracer::PixelGraph) time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+
+#ifndef NDEBUG
+ graph.checkConsistency();
+#endif
+
+ assert(graph.crossingEdges().size() == 0);
+
+#ifdef LIBDEPIXELIZE_PROFILE_KOPF2011
+ profiling_info[0] = Glib::DateTime::create_now_utc();
+
+ SimplifiedVoronoi<T, adjust_splines> ret(graph);
+
+ profiling_info[1] = Glib::DateTime::create_now_utc();
+ std::cerr << "Tracer::SimplifiedVoronoi<" << typeid(T).name() << ','
+ << (adjust_splines ? "true" : "false")
+ << ">(Tracer::PixelGraph) construction time: "
+ << profiling_info[1].difference(profiling_info[0]) << std::endl;
+
+ return ret;
+#else // LIBDEPIXELIZE_PROFILE_KOPF2011
+ return SimplifiedVoronoi<T, adjust_splines>(graph);
+#endif // LIBDEPIXELIZE_PROFILE_KOPF2011
+}
+
+// TODO: move this function (plus connectAllNeighbors) to PixelGraph constructor
+inline void
+Kopf2011::_disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph)
+{
+ using colorspace::similar_colors;
+ for ( PixelGraph::iterator it = graph.begin(), end = graph.end() ; it != end
+ ; ++it ) {
+ if ( it->adj.top )
+ it->adj.top = similar_colors(it->rgba, (it - graph.width())->rgba);
+ if ( it->adj.topright ) {
+ it->adj.topright
+ = similar_colors(it->rgba, (it - graph.width() + 1)->rgba);
+ }
+ if ( it->adj.right )
+ it->adj.right = similar_colors(it->rgba, (it + 1)->rgba);
+ if ( it->adj.bottomright ) {
+ it->adj.bottomright
+ = similar_colors(it->rgba, (it + graph.width() + 1)->rgba);
+ }
+ if ( it->adj.bottom ) {
+ it->adj.bottom
+ = similar_colors(it->rgba, (it + graph.width())->rgba);
+ }
+ if ( it->adj.bottomleft ) {
+ it->adj.bottomleft
+ = similar_colors(it->rgba, (it + graph.width() - 1)->rgba);
+ }
+ if ( it->adj.left )
+ it->adj.left = similar_colors(it->rgba, (it - 1)->rgba);
+ if ( it->adj.topleft ) {
+ it->adj.topleft = similar_colors(it->rgba,
+ (it - graph.width() - 1)->rgba);
+ }
+ }
+}
+
+/**
+ * This method removes crossing edges if the 2x2 block is fully connected.
+ *
+ * In this case the two diagonal connections can be safely removed without
+ * affecting the final result.
+ */
+template<class T>
+void Kopf2011::_remove_crossing_edges_safe(T &container)
+{
+ for ( typename T::reverse_iterator it = container.rbegin(),
+ end = container.rend() ; it != end ; ) {
+ /* A | B
+ --+--
+ C | D */
+ PixelGraph::iterator a = it->first.first;
+ PixelGraph::iterator b = it->second.first;
+ PixelGraph::iterator c = it->second.second;
+ PixelGraph::iterator d = it->first.second;
+
+ if ( !a->adj.right || !a->adj.bottom || !b->adj.bottom
+ || !c->adj.right ) {
+ ++it;
+ continue;
+ }
+
+ // main diagonal
+ a->adj.bottomright = 0;
+ d->adj.topleft = 0;
+
+ // secondary diagonal
+ b->adj.bottomleft = 0;
+ c->adj.topright = 0;
+
+ // base iterator is always past one
+ typename T::iterator current = --(it.base());
+ ++it;
+ container.erase(current);
+ }
+}
+
+/**
+ * This method removes crossing edges using the heuristics.
+ */
+template<class T>
+void Kopf2011::_remove_crossing_edges_unsafe(PixelGraph &graph, T &edges,
+ const Options &options)
+{
+ std::vector< std::pair<int, int> > weights(edges.size(),
+ std::make_pair(0, 0));
+
+ // Compute weights
+ for ( typename T::size_type i = 0 ; i != edges.size() ; ++i ) {
+ /* A | B
+ --+--
+ C | D */
+ PixelGraph::iterator a = edges[i].first.first;
+ PixelGraph::iterator b = edges[i].second.first;
+ PixelGraph::iterator c = edges[i].second.second;
+ PixelGraph::iterator d = edges[i].first.second;
+
+ // Curves heuristic
+ weights[i].first += Heuristics::curves(graph, a, d)
+ * options.curvesMultiplier;
+ weights[i].second += Heuristics::curves(graph, b, c)
+ * options.curvesMultiplier;
+
+ // Islands heuristic
+ weights[i].first += Heuristics::islands(a, d) * options.islandsWeight;
+ weights[i].second += Heuristics::islands(b, c) * options.islandsWeight;
+
+ // Sparse pixels heuristic
+ using Heuristics::SparsePixels;
+ SparsePixels sparse_pixels;
+
+ sparse_pixels.diagonals[SparsePixels::MAIN_DIAGONAL].first
+ = edges[i].first;
+ sparse_pixels.diagonals[SparsePixels::SECONDARY_DIAGONAL].first
+ = edges[i].second;
+
+ sparse_pixels(graph, options.sparsePixelsRadius);
+
+ weights[i].first
+ += sparse_pixels.diagonals[SparsePixels::MAIN_DIAGONAL].second
+ * options.sparsePixelsMultiplier;
+ weights[i].second
+ += sparse_pixels.diagonals[SparsePixels::SECONDARY_DIAGONAL].second
+ * options.sparsePixelsMultiplier;
+ }
+
+ // Remove edges with lower weight
+ for ( typename T::size_type i = 0 ; i != edges.size() ; ++i ) {
+ /* A | B
+ --+--
+ C | D */
+ PixelGraph::iterator a = edges[i].first.first;
+ PixelGraph::iterator b = edges[i].second.first;
+ PixelGraph::iterator c = edges[i].second.second;
+ PixelGraph::iterator d = edges[i].first.second;
+
+ if ( weights[i].first > weights[i].second ) {
+ b->adj.bottomleft = 0;
+ c->adj.topright = 0;
+ } else if ( weights[i].first < weights[i].second ) {
+ a->adj.bottomright = 0;
+ d->adj.topleft = 0;
+ } else {
+ a->adj.bottomright = 0;
+ b->adj.bottomleft = 0;
+ c->adj.topright = 0;
+ d->adj.topleft = 0;
+ }
+ }
+
+ edges.clear();
+}
+
+inline int Heuristics::curves(const PixelGraph &graph,
+ PixelGraph::const_iterator a,
+ PixelGraph::const_iterator b)
+{
+ int count = 1;
+ ToPtr<PixelGraph::Node> to_ptr;
+ ToIter<PixelGraph::Node> to_iter(graph.begin());
+
+ // b -> a
+ // and then a -> b
+ for ( int i = 0 ; i != 2 ; ++i ) {
+ PixelGraph::const_iterator it = i ? a : b;
+ PixelGraph::const_iterator prev = i ? b : a;
+ int local_count = 0;
+
+ // Used to avoid inifinite loops in circular-like edges
+ const PixelGraph::const_iterator initial = it;
+
+ while ( it->adjsize() == 2 ) {
+ ++local_count;
+
+ // Iterate to next
+ {
+ // There are only two values that won't be zero'ed
+ // and one of them has the same value of prev
+ guintptr aux = (it->adj.top
+ * guintptr(to_ptr(graph.nodeTop(it))))
+ + (it->adj.topright
+ * guintptr(to_ptr(graph.nodeTopRight(it))))
+ + (it->adj.right
+ * guintptr(to_ptr(graph.nodeRight(it))))
+ + (it->adj.bottomright
+ * guintptr(to_ptr(graph.nodeBottomRight(it))))
+ + (it->adj.bottom
+ * guintptr(to_ptr(graph.nodeBottom(it))))
+ + (it->adj.bottomleft
+ * guintptr(to_ptr(graph.nodeBottomLeft(it))))
+ + (it->adj.left
+ * guintptr(to_ptr(graph.nodeLeft(it))))
+ + (it->adj.topleft
+ * guintptr(to_ptr(graph.nodeTopLeft(it))))
+ - guintptr(to_ptr(prev));
+ prev = it;
+ it = to_iter(reinterpret_cast<PixelGraph::Node const*>(aux));
+ }
+
+ // Break infinite loops
+ if ( it == initial )
+ return local_count;
+ }
+ count += local_count;
+ }
+
+ return count;
+}
+
+inline void Heuristics::SparsePixels::operator ()(const PixelGraph &graph,
+ unsigned radius)
+{
+ if ( !graph.width() || !graph.height() )
+ return;
+
+ // Clear weights
+ for ( int i = 0 ; i != 2 ; ++i )
+ diagonals[i].second = 0;
+
+ if ( !radius )
+ return;
+
+ // Fix radius/bounds
+ {
+ unsigned x = graph.toX(diagonals[MAIN_DIAGONAL].first.first);
+ unsigned y = graph.toY(diagonals[MAIN_DIAGONAL].first.first);
+ unsigned displace = radius - 1;
+
+ {
+ unsigned minor = std::min(x, y);
+
+ if ( displace > minor ) {
+ displace = minor;
+ radius = displace + 1;
+ }
+ }
+
+ displace = radius;
+
+ if ( x + displace >= unsigned(graph.width()) ) {
+ displace = unsigned(graph.width()) - x - 1;
+ radius = displace;
+ }
+
+ if ( y + displace >= unsigned(graph.height()) ) {
+ displace = unsigned(graph.height()) - y - 1;
+ radius = displace;
+ }
+ }
+
+ if ( !radius )
+ return;
+
+ // Iterate over nodes and count them
+ {
+ PixelGraph::const_iterator it = diagonals[MAIN_DIAGONAL].first.first;
+ for ( unsigned i = radius - 1 ; i ; --i )
+ it = graph.nodeTopLeft(it);
+
+ bool invert = false;
+ for ( unsigned i = 0 ; i != 2 * radius ; ++i ) {
+ for ( unsigned j = 0 ; j != 2 * radius ; ++j ) {
+ for ( int k = 0 ; k != 2 ; ++k ) {
+ diagonals[k].second
+ += similar_colors(it, diagonals[k].first.first->rgba,
+ diagonals[k].first.second->rgba);
+ }
+ it = (invert ? graph.nodeLeft(it) : graph.nodeRight(it));
+ }
+ it = (invert ? graph.nodeRight(it) : graph.nodeLeft(it));
+
+
+ invert = !invert;
+ it = graph.nodeBottom(it);
+ }
+ }
+
+ int minor = std::min(diagonals[0].second, diagonals[1].second);
+ for ( int i = 0 ; i != 2 ; ++i )
+ diagonals[i].second -= minor;
+ std::swap(diagonals[0].second, diagonals[1].second);
+}
+
+inline bool
+Heuristics::SparsePixels::similar_colors(PixelGraph::const_iterator n,
+ const guint8 (&a)[4],
+ const guint8 (&b)[4])
+{
+ using colorspace::similar_colors;
+ return similar_colors(n->rgba, a) || similar_colors(n->rgba, b);
+}
+
+inline bool Heuristics::islands(PixelGraph::const_iterator a,
+ PixelGraph::const_iterator b)
+{
+ if ( a->adjsize() == 1 || b->adjsize() == 1 )
+ return true;
+
+ return false;
+}
+
+} // namespace Tracer
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/kopftracer2011.h b/src/3rdparty/libdepixelize/kopftracer2011.h
new file mode 100644
index 000000000..c60d0a61a
--- /dev/null
+++ b/src/3rdparty/libdepixelize/kopftracer2011.h
@@ -0,0 +1,150 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H
+#define LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H
+
+#include <string>
+
+#include <glibmm.h>
+// Contains exception definitions
+#include <glibmm/fileutils.h>
+#include <gdkmm/pixbuf.h>
+#include "splines.h"
+
+namespace Tracer {
+
+class PixelGraph;
+
+class Kopf2011
+{
+public:
+ struct Options
+ {
+ enum Defaults {
+ CURVES_MULTIPLIER = 1,
+ ISLANDS_WEIGHT = 5,
+ SPARSE_PIXELS_MULTIPLIER = 1,
+ SPARSE_PIXELS_RADIUS = 4
+ };
+
+ Options() :
+ curvesMultiplier(CURVES_MULTIPLIER),
+ islandsWeight(ISLANDS_WEIGHT),
+ sparsePixelsMultiplier(SPARSE_PIXELS_MULTIPLIER),
+ sparsePixelsRadius(SPARSE_PIXELS_RADIUS),
+ optimize(true),
+ nthreads(1)
+ {}
+
+ // Heuristics
+ double curvesMultiplier;
+ int islandsWeight;
+ double sparsePixelsMultiplier;
+ unsigned sparsePixelsRadius;
+
+ // Other options
+ bool optimize;
+ int nthreads;
+ };
+
+ /**
+ * # Exceptions
+ *
+ * \p options.optimize and options.nthreads will be ignored
+ *
+ * Glib::FileError
+ * Gdk::PixbufError
+ */
+ static Splines to_voronoi(const std::string &filename,
+ const Options &options = Options());
+
+ /*
+ * \p options.optimize and options.nthreads will be ignored
+ */
+ static Splines to_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options = Options());
+
+ /**
+ * # Exceptions
+ *
+ * \p options.optimize and options.nthreads will be ignored
+ *
+ * Glib::FileError
+ * Gdk::PixbufError
+ */
+ static Splines to_grouped_voronoi(const std::string &filename,
+ const Options &options = Options());
+
+ /*
+ * \p options.optimize and options.nthreads will be ignored
+ */
+ static Splines to_grouped_voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options = Options());
+
+ /**
+ * # Exceptions
+ *
+ * Glib::FileError
+ * Gdk::PixbufError
+ */
+ static Splines to_splines(const std::string &filename,
+ const Options &options = Options());
+
+ static Splines to_splines(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options = Options());
+
+private:
+ typedef Geom::Coord Precision;
+
+ template<class T, bool adjust_splines>
+ static SimplifiedVoronoi<T, adjust_splines>
+ _voronoi(const Glib::RefPtr<Gdk::Pixbuf const> &buf,
+ const Options &options);
+
+ static void _disconnect_neighbors_with_dissimilar_colors(PixelGraph &graph);
+
+ // here, T/template is only used as an easy way to not expose internal
+ // symbols
+ template<class T>
+ static void _remove_crossing_edges_safe(T &container);
+ template<class T>
+ static void _remove_crossing_edges_unsafe(PixelGraph &graph, T &edges,
+ const Options &options);
+};
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_KOPFTRACER2011_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/branchless.h b/src/3rdparty/libdepixelize/priv/branchless.h
new file mode 100644
index 000000000..487a9688d
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/branchless.h
@@ -0,0 +1,58 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_BRANCHLESS_H
+#define LIBDEPIXELIZE_TRACER_BRANCHLESS_H
+
+namespace Tracer {
+
+/**
+ * Branch misprediction proof operations
+ */
+namespace branchless {
+
+/*
+ * All modern processors optimize the branch to a conditional move
+ */
+template<class T>
+T first_if(T first, T second, bool cond)
+{
+ return cond ? first : second;
+}
+
+} // namespace branchless
+} // namespace Tracer {
+
+#endif // LIBDEPIXELIZE_TRACER_BRANCHLESS_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/colorspace.h b/src/3rdparty/libdepixelize/priv/colorspace.h
new file mode 100644
index 000000000..4982630ad
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/colorspace.h
@@ -0,0 +1,111 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_YUV_H
+#define LIBDEPIXELIZE_TRACER_YUV_H
+
+#include <glib.h>
+
+namespace Tracer {
+namespace colorspace {
+
+/**
+ * The same algorithm used in hqx filter
+ */
+inline void rgb2yuv(guint8 r, guint8 g, guint8 b,
+ guint8 &y, guint8 &u, guint8 &v)
+{
+ y = 0.299 * r + 0.587 * g + 0.114 * b;
+ u = guint16(-0.169 * r - 0.331 * g + 0.5 * b) + 128;
+ v = guint16(0.5 * r - 0.419 * g - 0.081 * b) + 128;
+}
+
+inline void rgb2yuv(const guint8 rgb[], guint8 yuv[])
+{
+ rgb2yuv(rgb[0], rgb[1], rgb[2], yuv[0], yuv[1], yuv[2]);
+}
+
+inline bool same_color(const guint8 (&a)[4], const guint8 (&b)[4])
+{
+ return (a[0] == b[0]
+ && a[1] == b[1]
+ && a[2] == b[2]
+ && a[3] == b[3]);
+}
+
+inline bool dissimilar_colors(const guint8 a[], const guint8 b[])
+{
+ // C uses row-major order, so
+ // A[2][3] = { {1, 2, 3}, {4, 5, 6} } = {1, 2, 3, 4, 5, 6}
+ guint8 yuv[2][3];
+ rgb2yuv(a, yuv[0]);
+ rgb2yuv(b, yuv[1]);
+
+ // Magic numbers taken from hqx algorithm
+ // Only used to describe the level of tolerance
+ return abs(yuv[0][0] - yuv[1][0]) > 0x30
+ || abs(yuv[0][1] - yuv[1][1]) > 7
+ || abs(yuv[0][2] - yuv[1][2]) > 6;
+}
+
+inline bool similar_colors(const guint8 a[], const guint8 b[])
+{
+ return !dissimilar_colors(a, b);
+}
+
+inline bool shading_edge(const guint8 a[], const guint8 b[])
+{
+ // C uses row-major order, so
+ // A[2][3] = { {1, 2, 3}, {4, 5, 6} } = {1, 2, 3, 4, 5, 6}
+ guint8 yuv[2][3];
+ rgb2yuv(a, yuv[0]);
+ rgb2yuv(b, yuv[1]);
+
+ // Magic numbers taken from Kopf-Lischinski algorithm
+ // Only used to describe the level of tolerance
+ return abs(yuv[0][0] - yuv[1][0]) <= 100
+ && abs(yuv[0][1] - yuv[1][1]) <= 100
+ && abs(yuv[0][2] - yuv[1][2]) <= 100;
+}
+
+inline bool contour_edge(const guint8 a[], const guint8 b[])
+{
+ return !shading_edge(a, b);
+}
+
+} // namespace colorspace
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_YUV_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/curvature.h b/src/3rdparty/libdepixelize/priv/curvature.h
new file mode 100644
index 000000000..3a1af4197
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/curvature.h
@@ -0,0 +1,115 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_CURVATURE_H
+#define LIBDEPIXELIZE_TRACER_CURVATURE_H
+
+#include "point.h"
+#include <cmath>
+
+namespace Tracer {
+
+/**
+ * Curvature function for a quadratic Bézier curve where the points are know.
+ * Its main use is to numerically integrate the curvature function and then
+ * smooth the B-Splines generated by the Kopf-Lischinski algorithm.
+ */
+template<class T>
+struct Curvature
+{
+ Curvature(Point<T> p0, Point<T> c1, Point<T> p2) :
+ p0(p0), c1(c1), p2(p2)
+ {}
+
+ T operator()(T t) const;
+
+ /**
+ * The derivative of x
+ */
+ T xPrime(T t) const;
+
+ /**
+ * The derivative of y
+ */
+ T yPrime(T t) const;
+
+ /**
+ * The second derivative of x
+ */
+ T xPrimePrime() const;
+
+ /**
+ * The second derivative of y
+ */
+ T yPrimePrime() const;
+
+ Point<T> p0, c1, p2;
+};
+
+template<class T>
+T Curvature<T>::operator()(T t) const
+{
+ T num = xPrime(t) * yPrimePrime() - yPrime(t) * xPrimePrime();
+ T den = std::pow(xPrime(t) * xPrime(t) + yPrime(t) * yPrime(t), T(3) / 2);
+ return num / den;
+}
+
+template<class T>
+T Curvature<T>::xPrime(T t) const
+{
+ return (1-t)*2*(c1.x-p0.x) + t*2*(p2.x-c1.x);
+}
+
+template<class T>
+T Curvature<T>::yPrime(T t) const
+{
+ return (1-t)*2*(c1.y-p0.y) + t*2*(p2.y-c1.y);
+}
+
+template<class T>
+T Curvature<T>::xPrimePrime() const
+{
+ return 2 * (p2.x - 2*c1.x + p0.x);
+}
+
+template<class T>
+T Curvature<T>::yPrimePrime() const
+{
+ return 2 * (p2.y - 2*c1.y + p0.y);
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_CURVATURE_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/homogeneoussplines.h b/src/3rdparty/libdepixelize/priv/homogeneoussplines.h
new file mode 100644
index 000000000..6c4894dd8
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/homogeneoussplines.h
@@ -0,0 +1,472 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H
+#define LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H
+
+#include "simplifiedvoronoi.h"
+#include "point.h"
+#include <algorithm>
+#include <utility>
+
+namespace Tracer {
+
+template<typename T>
+class HomogeneousSplines
+{
+public:
+ struct Polygon
+ {
+ typedef std::vector< Point<T> > Points;
+ typedef typename Points::iterator points_iter;
+ typedef typename Points::const_iterator const_points_iter;
+ typedef typename std::vector<Points>::iterator holes_iter;
+ typedef typename std::vector<Points>::const_iterator const_holes_iter;
+
+ Polygon() {}
+ Polygon(const guint8 (&rgba)[4])
+ {
+ for ( int i = 0 ; i != 4 ; ++i )
+ this->rgba[i] = rgba[i];
+ }
+
+ std::vector< Point<T> > vertices;
+
+ /**
+ * It may be benefited from C++11 move references.
+ */
+ std::vector< std::vector< Point<T> > > holes;
+
+ guint8 rgba[4];
+ };
+
+ typedef typename std::vector<Polygon>::iterator iterator;
+ typedef typename std::vector<Polygon>::const_iterator const_iterator;
+ typedef typename std::vector<Polygon>::size_type size_type;
+
+ template<bool adjust_splines>
+ HomogeneousSplines(const SimplifiedVoronoi<T, adjust_splines> &voronoi);
+
+ // Iterators
+ iterator begin()
+ {
+ return _polygons.begin();
+ }
+
+ const_iterator begin() const
+ {
+ return _polygons.begin();
+ }
+
+ iterator end()
+ {
+ return _polygons.end();
+ }
+
+ const_iterator end() const
+ {
+ return _polygons.end();
+ }
+
+ size_type size() const
+ {
+ return _polygons.size();
+ }
+
+ int width() const
+ {
+ return _width;
+ }
+
+ int height() const
+ {
+ return _height;
+ }
+
+private:
+ typedef std::vector< Point<T> > Points;
+ typedef typename Points::iterator points_iter;
+ typedef typename Points::const_iterator points_citer;
+ typedef typename Points::reverse_iterator points_riter;
+ typedef typename Points::const_reverse_iterator points_criter;
+
+ typedef std::pair<points_iter, points_iter> points_range;
+ typedef std::pair<points_citer, points_citer> points_crange;
+
+ struct CommonEdge
+ {
+ bool ok; //< share an edge
+ Points *dst;
+ const Points *src;
+
+ // the interval is closed on both ends
+ // different from [begin, end) STL style
+ points_iter dst_begin, dst_end;
+ points_citer src_begin, src_end;
+ };
+
+ struct SelfCommonEdge
+ {
+ bool ok; //< share an edge
+
+ // Greater range. The one that should be erased from the vector.
+ points_riter grt_begin, grt_end;
+
+ // Smaller range. The one that should be used to create a new vector.
+ points_riter sml_begin, sml_end;
+ };
+
+ /**
+ * Return ok == true if they share an edge (more than one point).
+ */
+ CommonEdge _common_edge(Points &dst, const Points &src);
+
+ /**
+ * Return ok == true if they share an edge (more than one point).
+ *
+ * - [dst_begin, dst_end) will contain the hole polygon
+ * - [src_begin, src_end) will contain the range to be erased
+ *
+ * It's required to do the search in backward order.
+ */
+ SelfCommonEdge _common_edge(Points &points, points_riter it);
+
+ /*!
+ * Add polygon represented by \p common_edge.src to \p common_edge.dst.
+ */
+ void _polygon_union(CommonEdge common_edge);
+
+ /**
+ * Weird recursive function created to solve the complex problem to fill
+ * polygons holes without the need to store temporaries on the heap nor
+ * changing requirements to some data type that don't invalidate iterators
+ * that point before the current element (maybe I'll write some poetry about
+ * the problem someday).
+ */
+ void _fill_holes(std::vector<Points> &holes, points_iter region_begin,
+ points_iter region_end);
+
+ std::vector<Polygon> _polygons;
+ int _width;
+ int _height;
+};
+
+template<class T>
+template<bool adjust_splines>
+HomogeneousSplines<T>::HomogeneousSplines(const SimplifiedVoronoi<T,
+ adjust_splines> &voronoi) :
+ _width(voronoi.width()),
+ _height(voronoi.height())
+{
+ //if (!voronoi.size())
+ // return;
+ using colorspace::same_color;
+
+ typedef typename SimplifiedVoronoi<T, adjust_splines>::const_iterator
+ voronoi_citer;
+
+ // Identify visible edges (group polygons with the same color)
+ for ( voronoi_citer cell_it = voronoi.begin(), cell_end = voronoi.end()
+ ; cell_it != cell_end ; ++cell_it ) {
+ bool found = false;
+ for ( iterator polygon_it = _polygons.begin(),
+ polygon_end = _polygons.end()
+ ; polygon_it != polygon_end ; ++polygon_it ) {
+ if ( same_color(polygon_it->rgba, cell_it->rgba) ) {
+ CommonEdge common_edge = _common_edge(polygon_it->vertices,
+ cell_it->vertices);
+ if ( common_edge.ok ) {
+ _polygon_union(common_edge);
+ found = true;
+
+ for ( iterator polygon2_it = polygon_it + 1
+ ; polygon2_it != polygon_end ; ++polygon2_it ) {
+ if ( same_color(polygon_it->rgba, polygon2_it->rgba) ) {
+ CommonEdge common_edge2
+ = _common_edge(polygon_it->vertices,
+ polygon2_it->vertices);
+ if ( common_edge2.ok ) {
+ _polygon_union(common_edge2);
+ _polygons.erase(polygon2_it);
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ if ( !found ) {
+ Polygon polygon(cell_it->rgba);
+ polygon.vertices = cell_it->vertices;
+ _polygons.insert(_polygons.end(), polygon);
+ }
+ }
+
+ // Find polygons with holes and fix them
+ // This iteration runs such complex time-consuming algorithm, but each
+ // polygon has an independent result. They wouldn't even need to share/sync
+ // results and the only waste would be a join at the end of the for.
+ for ( typename std::vector<Polygon>::iterator it = _polygons.begin(),
+ end = _polygons.end() ; it != end ; ++it ) {
+ SelfCommonEdge ce = _common_edge(it->vertices, it->vertices.rbegin());
+ while ( ce.ok ) {
+ _fill_holes(it->holes, ce.sml_end.base(), ce.sml_begin.base());
+ it->vertices.erase(ce.grt_end.base() + 1, ce.grt_begin.base());
+ ce = _common_edge(it->vertices, ce.grt_end);
+ }
+ }
+}
+
+// it can infinite loop if points of both entities are equal,
+// but this shouldn't happen if user has only access to Kopf2011 interface
+template<class T>
+typename HomogeneousSplines<T>::CommonEdge
+HomogeneousSplines<T>::_common_edge(Points &dst, const Points &src)
+{
+ // It's an edge, then the points are closer together. After we find the
+ // first point, there is no need for check against all points of the src
+ // a second time
+
+ const points_iter dst_begin = dst.begin();
+ const points_iter dst_end = dst.end();
+
+ const points_citer src_begin = src.begin();
+ const points_citer src_end = src.end();
+
+ for ( points_iter it = dst_begin ; it != dst_end ; ++it ) {
+ points_citer src_it = std::find(src_begin, src_end, *it);
+
+ if ( src_it == src_end )
+ continue;
+
+ points_iter dst_common_edge_begin = it;
+ points_citer src_common_edge_end = src_it;
+
+ // iterate until find the beginning of the common edge range
+ while ( *dst_common_edge_begin == *src_common_edge_end ) {
+ if ( dst_common_edge_begin == dst_begin )
+ dst_common_edge_begin = dst_end - 1;
+ else
+ --dst_common_edge_begin;
+
+ ++src_common_edge_end;
+ if ( src_common_edge_end == src_end )
+ src_common_edge_end = src_begin;
+ }
+
+ // fix {dst_begin, src_end} range
+ ++dst_common_edge_begin;
+ if ( dst_common_edge_begin == dst_end )
+ dst_common_edge_begin = dst_begin;
+
+ if ( src_common_edge_end == src_begin )
+ src_common_edge_end = src_end - 1;
+ else
+ --src_common_edge_end;
+
+ points_iter dst_common_edge_end = it;
+ points_citer src_common_edge_begin = src_it;
+
+ // find the end of the common edge range
+ while ( *dst_common_edge_end == *src_common_edge_begin ) {
+ ++dst_common_edge_end;
+ if ( dst_common_edge_end == dst_end )
+ dst_common_edge_end = dst_begin;
+
+ if ( src_common_edge_begin == src_begin )
+ src_common_edge_begin = src_end - 1;
+ else
+ --src_common_edge_begin;
+ }
+
+ // fix {dst_end, src_begin} range
+ if ( dst_common_edge_end == dst_begin )
+ dst_common_edge_end = dst_end - 1;
+ else
+ --dst_common_edge_end;
+
+ ++src_common_edge_begin;
+ if ( src_common_edge_begin == src_end )
+ src_common_edge_begin = src_begin;
+
+ CommonEdge ret;
+
+ // if only one point in common
+ if ( dst_common_edge_begin == dst_common_edge_end )
+ continue;
+
+ ret.ok = true;
+
+ ret.dst = &dst;
+ ret.dst_begin = dst_common_edge_begin;
+ ret.dst_end = dst_common_edge_end;
+
+ ret.src = &src;
+ ret.src_begin = src_common_edge_begin;
+ ret.src_end = src_common_edge_end;
+
+ return ret;
+ }
+
+ CommonEdge ret;
+ ret.ok = false;
+ return ret;
+}
+
+template<class T>
+typename HomogeneousSplines<T>::SelfCommonEdge
+HomogeneousSplines<T>::_common_edge(Points &points, points_riter it)
+{
+ SelfCommonEdge ret;
+
+ ret.grt_end = points.rend();
+
+ for ( ; it != ret.grt_end ; ++it ) {
+ ret.sml_end = std::find(it + 1, ret.grt_end, *it);
+
+ if ( ret.sml_end == ret.grt_end )
+ continue;
+
+ ret.grt_begin = it;
+ ret.grt_end = ret.sml_end + 1;
+
+ ret.sml_begin = it;
+
+ while ( *ret.sml_begin == *ret.sml_end ) {
+ ++ret.sml_begin;
+ --ret.sml_end;
+ }
+
+ --ret.sml_begin;
+ ++ret.sml_end;
+ ++ret.sml_end;
+
+ ret.ok = true;
+ return ret;
+ }
+
+ ret.ok = false;
+ return ret;
+}
+
+template<class T>
+void HomogeneousSplines<T>::_polygon_union(CommonEdge common_edge)
+{
+ Points &dst = *common_edge.dst;
+ const Points &src = *common_edge.src;
+
+ // the rotated cell must be inserted before (dst.begin() + index)
+ typename Points::difference_type index;
+
+ // first, we remove the common edge in dst
+ if ( common_edge.dst_begin < common_edge.dst_end ) {
+ // common edge is in the middle of dst
+
+ index = dst.erase(common_edge.dst_begin,
+ common_edge.dst_end + 1) - dst.begin();
+ } else {
+ // common edge cross the end of dst
+
+ dst.erase(common_edge.dst_begin, dst.end());
+ dst.erase(dst.begin(), common_edge.dst_end);
+ index = dst.end() - dst.begin();
+ }
+
+ // second, we copy src points to polygon
+ if ( common_edge.src_begin < common_edge.src_end ) {
+ // common edge is in the middle of src
+
+ const typename Points::difference_type nfirstinserted
+ = src.end() - common_edge.src_end;
+ const typename Points::difference_type nsecondinserted
+ = 1 + (common_edge.src_begin - src.begin());
+
+ dst.reserve(dst.size() + nfirstinserted + nsecondinserted);
+
+ dst.insert(dst.begin() + index, common_edge.src_end, src.end());
+
+ dst.insert(dst.begin() + index + nfirstinserted,
+ src.begin(), common_edge.src_begin + 1);
+ } else {
+ // common edge cross the end of src
+
+ dst.reserve(dst.size() + 1
+ + (common_edge.src_begin - common_edge.src_end));
+
+ dst.insert(dst.begin() + index,
+ common_edge.src_end, common_edge.src_begin + 1);
+ }
+}
+
+// The following piece of code is so evil that you could end up invoking an
+// ancient beast if you proceed to read it, but I'll be able to explain it in
+// the form of some video (text is not so representative as an image).
+template<class T>
+void HomogeneousSplines<T>::_fill_holes(std::vector<Points> &holes,
+ points_iter region_begin,
+ points_iter region_end)
+{
+ // the exact location might not always be back and iterators will be
+ // invalidated after some insertions, then the index is required
+ const typename std::vector<Points>::size_type hole_index = holes.size();
+ holes.resize(hole_index + 1);
+
+ for ( points_iter it = region_begin + 1 ; it != region_end ; ++it ) {
+ points_iter res = std::find(it + 1, region_end, *it);
+ if ( res == region_end )
+ continue;
+
+ holes[hole_index].insert(holes[hole_index].end(), region_begin,
+ it);
+ region_begin = res;
+
+ do {
+ ++it;
+ --res;
+ } while ( *it == *res );
+ _fill_holes(holes, it - 1, res + 2);
+
+ it = region_begin;
+ }
+
+ holes[hole_index].insert(holes[hole_index].end(), region_begin,
+ region_end - 1);
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_HOMOGENEOUSSPLINES_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/integral.h b/src/3rdparty/libdepixelize/priv/integral.h
new file mode 100644
index 000000000..fc1a49f27
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/integral.h
@@ -0,0 +1,61 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_INTEGRAL_H
+#define LIBDEPIXELIZE_TRACER_INTEGRAL_H
+
+#include <2geom/coord.h>
+
+namespace Tracer {
+
+/**
+ * Compute the integral numerically using Gaussian Quadrature rule with
+ * \p samples number of samples.
+ */
+template<class T, class F>
+Geom::Coord integral(F f, T begin, T end, unsigned samples)
+{
+ T ret = 0;
+ const T width = (end - begin) / samples;
+
+ for ( unsigned i = 0 ; i != samples ; ++i )
+ ret += width * f(begin + width * (i + .5));
+
+ return ret;
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_INTEGRAL_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/iterator.h b/src/3rdparty/libdepixelize/priv/iterator.h
new file mode 100644
index 000000000..7caa9bfa9
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/iterator.h
@@ -0,0 +1,123 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_ITERATOR_H
+#define LIBDEPIXELIZE_TRACER_ITERATOR_H
+
+#include <vector>
+#include <iterator>
+
+namespace Tracer {
+
+template<typename T>
+const T *to_ptr(typename std::vector<T>::const_iterator it)
+{
+ return &*it;
+}
+
+template<typename T>
+T *to_ptr(typename std::vector<T>::iterator it)
+{
+ return &*it;
+}
+
+template<typename T>
+typename std::vector<T>::const_iterator to_iterator(T const *ptr,
+ typename std::vector<T>
+ ::const_iterator begin)
+{
+ typedef typename std::vector<T>::const_iterator It;
+ typedef typename std::iterator_traits<It>::difference_type difference_type;
+ difference_type idx = ptr - to_ptr<T>(begin);
+ return begin + idx;
+}
+
+template<typename T>
+typename std::vector<T>::iterator to_iterator(T *ptr,
+ typename std::vector<T>::iterator
+ begin)
+{
+ typedef typename std::vector<T>::iterator It;
+ typedef typename std::iterator_traits<It>::difference_type difference_type;
+ difference_type idx = ptr - to_ptr<T>(begin);
+ return begin + idx;
+}
+
+template<typename T>
+class ToIter
+{
+public:
+ typedef typename std::vector<T>::const_iterator const_iterator;
+ typedef typename std::vector<T>::iterator iterator;
+
+ ToIter(const_iterator begin) :
+ begin(begin)
+ {}
+
+ const_iterator operator()(T const *ptr) const
+ {
+ return to_iterator<T>(ptr, begin);
+ }
+
+ iterator operator()(T *ptr) const
+ {
+ return to_iterator<T>(ptr, begin);
+ }
+
+private:
+ typename std::vector<T>::const_iterator begin;
+};
+
+template<typename T>
+class ToPtr
+{
+public:
+ typedef typename std::vector<T>::const_iterator const_iterator;
+ typedef typename std::vector<T>::iterator iterator;
+
+ const T *operator()(const_iterator it) const
+ {
+ return to_ptr<T>(it);
+ }
+
+ T *operator()(iterator it) const
+ {
+ return to_ptr<T>(it);
+ }
+};
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_ITERATOR_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/optimization-kopf2011.h b/src/3rdparty/libdepixelize/priv/optimization-kopf2011.h
new file mode 100644
index 000000000..0c9011ca7
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/optimization-kopf2011.h
@@ -0,0 +1,263 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_OPTIMIZATION_KOPF2011_H
+#define LIBDEPIXELIZE_TRACER_OPTIMIZATION_KOPF2011_H
+
+#include "curvature.h"
+#include "integral.h"
+#include <cmath>
+#include <limits>
+
+namespace Tracer {
+
+/**
+ * m is angular coeficient
+ */
+template<class T>
+bool is_valid_border_m(T a)
+{
+ if ( a < 0 )
+ a *= -1;
+
+ // TODO: alternative behaviour if has no infinity
+ return a == std::numeric_limits<T>::infinity()
+ || a == 3 || a == 1;
+}
+
+/**
+ * Return true if the four points are considered a border.
+ */
+template<class T>
+bool is_border(const Point<T> (&points)[4])
+{
+ T dy[2];
+ T dx[2];
+ T m[2];
+ if ( points[1].y == points[2].y ) {
+ dy[0] = points[1].y - points[0].y;
+ dy[1] = points[3].y - points[2].y;
+
+ dx[0] = points[1].x - points[0].x;
+ dx[1] = points[3].x - points[2].x;
+
+ m[0] = dy[0] / dx[0];
+ m[1] = dy[1] / dx[1];
+ } else if ( points[1].x == points[2].x ) {
+ // It's easier to have a unified logic, then we'll fake dx and dy
+ dy[0] = points[1].x - points[0].x;
+ dy[1] = points[3].x - points[2].x;
+
+ dx[0] = points[1].y - points[0].y;
+ dx[1] = points[3].y - points[2].y;
+
+ m[0] = dy[0] / dx[0];
+ m[1] = dy[1] / dx[1];
+ } else {
+ return false;
+ }
+
+ return m[0] == -m[1] && is_valid_border_m(m[0]);
+}
+
+template<class T>
+typename std::vector< Point<T> >::iterator
+skip1visible(typename std::vector< Point<T> >::iterator it,
+ typename std::vector< Point<T> >::iterator end)
+{
+ for ( ++it ; it != end ; ++it ) {
+ if ( it->visible )
+ return it;
+ }
+ return end;
+}
+
+/**
+ * Return how many elements should be skipped.
+ */
+template<class T>
+typename std::vector< Point<T> >::difference_type
+border_detection(typename std::vector< Point<T> >::iterator it,
+ typename std::vector< Point<T> >::iterator end)
+{
+ typename std::vector< Point<T> >::iterator begin = it;
+
+ if ( end - it < 4 )
+ return 0;
+
+ Point<T> last[4];
+ typename std::vector< Point<T> >::iterator prev = it;
+
+ for ( int i = 0 ; i != 4 ; ++i ) {
+ if ( it == end )
+ return 0;
+ last[i] = *it;
+ prev = it;
+ it = skip1visible<T>(it, end);
+ }
+
+ if ( !is_border(last) )
+ return 0;
+
+ if ( it == end )
+ return prev - begin;
+
+ bool got_another = false;
+ for ( it = skip1visible<T>(it, end) ; it != end
+ ; it = skip1visible<T>(it, end) ) {
+ if ( !got_another ) {
+ last[0] = last[2];
+ last[1] = last[3];
+ last[2] = *it;
+
+ got_another = true;
+ continue;
+ }
+ last[3] = *it;
+
+ if ( !is_border(last) )
+ return prev - begin;
+ prev = it;
+ }
+
+ return prev - begin;
+}
+
+template<class T>
+T smoothness_energy(Point<T> c0, Point<T> c1, Point<T> c2)
+{
+ Point<T> p0 = midpoint(c0, c1);
+ Point<T> p2 = midpoint(c1, c2);
+ Curvature<T> cur(p0, c1, p2);
+
+ return std::abs(integral<T>(cur, 0, 1, 16));
+}
+
+template<class T>
+T positional_energy(Point<T> guess, Point<T> initial)
+{
+ using std::pow;
+
+ return pow(pow(guess.x - initial.x, 2)
+ + pow(guess.y - initial.y, 2), 2);
+}
+
+/**
+ * Kopf-Lischinski simple relaxation procedure: a random new offset position
+ * within a small radius around its current location.
+ *
+ * The small radius is not revealed. I chose the empirically determined value of
+ * 0.125. New tests can give a better value for "small". I believe this value
+ * showed up because the optimization sharply penalize larger deviations.
+ */
+template<class T>
+Point<T> optimization_guess(Point<T> p)
+{
+ // See the value explanation in the function documentation.
+ T radius = 0.125;
+
+ T d[] = {
+ (T(std::rand()) / RAND_MAX) * radius * 2 - radius,
+ (T(std::rand()) / RAND_MAX) * radius * 2 - radius
+ };
+
+ return p + Point<T>(d[0], d[1]);
+}
+
+template<class T>
+std::vector< Point<T> > optimize(const std::vector< Point<T> > &path)
+{
+ typedef std::vector< Point<T> > Path;
+
+ Path ret = path;
+
+ /* The number of vertices not constrained by optimization */
+ unsigned n = 0;
+
+ /* Values chosen by test
+ * TODO: make values configurable via function parameters. */
+ const unsigned iterations = 4;
+ const unsigned nguess_per_iteration = 4;
+
+ for ( unsigned i = 0 ; i != iterations ; ++i ) {
+ n = 0;
+
+ /* This iteration bounds is not something to worry about, because the
+ * smallest path has size 4. */
+ for ( typename Path::size_type j = 0 ; j != ret.size() ; ++j ) {
+ Point<T> prev = ( j == 0 ) ? ret.back() : ret[j-1];
+ Point<T> next = ( j + 1 == ret.size() ) ? ret.front() : ret[j+1] ;
+
+ if ( !ret[j].visible || !ret[j].smooth )
+ continue;
+
+ {
+ typename Path::iterator it = ret.begin() + j;
+ typename Path::difference_type skip
+ = border_detection<T>(it, ret.end());
+ j += skip;
+ if ( j == ret.size() )
+ break;
+ }
+
+ ++n;
+
+ for ( unsigned k = 0 ; k != nguess_per_iteration ; ++k ) {
+ Point<T> guess = optimization_guess(ret[j]);
+
+ T s = smoothness_energy(prev, guess, next);
+ T p = positional_energy(guess, path[j]);
+
+ T e = s + p;
+
+ T prev_e = smoothness_energy(prev, ret[j], next)
+ + positional_energy(ret[j], path[j]);
+
+ if ( prev_e > e ) {
+ // We don't want to screw other metadata, then we manually
+ // assign the new coords
+ ret[j].x = guess.x;
+ ret[j].y = guess.y;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_OPTIMIZATION_KOPF2011_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/pixelgraph.h b/src/3rdparty/libdepixelize/priv/pixelgraph.h
new file mode 100644
index 000000000..112242647
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/pixelgraph.h
@@ -0,0 +1,555 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_PIXELGRAPH_H
+#define LIBDEPIXELIZE_TRACER_PIXELGRAPH_H
+
+#include <gdkmm/pixbuf.h>
+#include <vector>
+#include <cassert>
+#include <utility>
+
+namespace Tracer {
+
+class PixelGraph
+{
+public:
+ class Node
+ {
+ public:
+ /*
+ * Hamming weight of \p adj
+ */
+ unsigned adjsize() const
+ {
+ unsigned all[8] = {
+ adj.top,
+ adj.topright,
+ adj.right,
+ adj.bottomright,
+ adj.bottom,
+ adj.bottomleft,
+ adj.left,
+ adj.topleft
+ };
+ return all[0] + all[1] + all[2] + all[3]
+ + all[4] + all[5] + all[6] + all[7];
+ }
+
+ guint8 rgba[4];
+ // Nodes pointing from this
+ struct Adj
+ {
+ unsigned top: 1;
+ unsigned topright: 1;
+ unsigned right: 1;
+ unsigned bottomright: 1;
+ unsigned bottom: 1;
+ unsigned bottomleft: 1;
+ unsigned left: 1;
+ unsigned topleft: 1;
+ } adj;
+ };
+
+ typedef std::vector<Node>::iterator iterator;
+ typedef std::vector<Node>::const_iterator const_iterator;
+ typedef std::vector<Node>::reverse_iterator reverse_iterator;
+ typedef std::vector<Node>::const_reverse_iterator const_reverse_iterator;
+
+ typedef std::pair<iterator, iterator> Edge;
+ typedef std::pair<Edge, Edge> EdgePair;
+ typedef std::vector<EdgePair> EdgePairContainer;
+
+ class ColumnView
+ {
+ public:
+ ColumnView(std::vector<Node> &nodes, int width, int column) :
+ _nodes(nodes), _width(width), _column(column)
+ {}
+
+ Node &operator[](int line);
+
+ private:
+ std::vector<Node> &_nodes;
+ const int _width;
+ const int _column;
+ };
+
+ PixelGraph(Glib::RefPtr<Gdk::Pixbuf const> pixbuf);
+
+ void checkConsistency();
+
+ /**
+ * It'll let you access the nodes using the syntax:
+ *
+ * graph[x][y]
+ *
+ * Where x is the column and y is the line.
+ */
+ ColumnView operator[](int column);
+
+ // Iterators
+ iterator begin()
+ {
+ return _nodes.begin();
+ }
+
+ const_iterator begin() const
+ {
+ return _nodes.begin();
+ }
+
+ iterator end()
+ {
+ return _nodes.end();
+ }
+
+ const_iterator end() const
+ {
+ return _nodes.end();
+ }
+
+ reverse_iterator rbegin()
+ {
+ return _nodes.rbegin();
+ }
+
+ const_reverse_iterator rbegin() const
+ {
+ return _nodes.rbegin();
+ }
+
+ reverse_iterator rend()
+ {
+ return _nodes.rend();
+ }
+
+ const_reverse_iterator rend() const
+ {
+ return _nodes.rend();
+ }
+
+ size_t size() const
+ {
+ return _nodes.size();
+ }
+
+ int width() const
+ {
+ return _width;
+ }
+
+ int height() const
+ {
+ return _height;
+ }
+
+ // Algorithms
+ void connectAllNeighbors();
+ EdgePairContainer crossingEdges();
+
+ int toX(const_iterator n) const
+ {
+ return (&*n - &_nodes[0]) % _width;
+ }
+
+ int toY(const_iterator n) const
+ {
+ return (&*n - &_nodes[0]) / _width;
+ }
+
+ iterator nodeTop(iterator n)
+ {
+ return n - _width;
+ }
+
+ iterator nodeBottom(iterator n)
+ {
+ return n + _width;
+ }
+
+ iterator nodeLeft(iterator n)
+ {
+ return n - 1;
+ }
+
+ iterator nodeRight(iterator n)
+ {
+ return n + 1;
+ }
+
+ iterator nodeTopLeft(iterator n)
+ {
+ return n - _width - 1;
+ }
+
+ iterator nodeTopRight(iterator n)
+ {
+ return n - _width + 1;
+ }
+
+ iterator nodeBottomLeft(iterator n)
+ {
+ return n + _width - 1;
+ }
+
+ iterator nodeBottomRight(iterator n)
+ {
+ return n + _width + 1;
+ }
+
+ const_iterator nodeTop(const_iterator n) const
+ {
+ return n - _width;
+ }
+
+ const_iterator nodeBottom(const_iterator n) const
+ {
+ return n + _width;
+ }
+
+ const_iterator nodeLeft(const_iterator n) const
+ {
+ return n - 1;
+ }
+
+ const_iterator nodeRight(const_iterator n) const
+ {
+ return n + 1;
+ }
+
+ const_iterator nodeTopLeft(const_iterator n) const
+ {
+ return n - _width - 1;
+ }
+
+ const_iterator nodeTopRight(const_iterator n) const
+ {
+ return n - _width + 1;
+ }
+
+ const_iterator nodeBottomLeft(const_iterator n) const
+ {
+ return n + _width - 1;
+ }
+
+ const_iterator nodeBottomRight(const_iterator n) const
+ {
+ return n + _width + 1;
+ }
+
+private:
+ PixelGraph(const PixelGraph&);
+
+ int _width;
+ int _height;
+
+ // The data representation follows the image data pattern from gdk-pixbuf.
+ //
+ // Quoting:
+ // "Image data in a pixbuf is stored in memory in uncompressed, packed
+ // format. Rows in the image are stored top to bottom, and in each row
+ // pixels are stored from left to right. There may be padding at the end of
+ // a row."
+ //
+ // Differently, _nodes don't put padding among rows.
+ std::vector<Node> _nodes;
+};
+
+inline PixelGraph::PixelGraph(Glib::RefPtr<Gdk::Pixbuf const> pixbuf) :
+ _width(pixbuf->get_width()),
+ _height(pixbuf->get_height()),
+ _nodes(size_t(_width) * _height)
+{
+ if ( !_width || !_height )
+ return;
+
+ // Initialize the graph using the pixels' color data
+ guint8 *pixels = pixbuf->get_pixels();
+ Node *dest = &_nodes[0];
+ const int n_channels = pixbuf->get_n_channels();
+ const int rowpadding = pixbuf->get_rowstride() - _width * n_channels;
+
+ if ( n_channels == 4 ) {
+ for ( int i = 0 ; i != _height ; ++i ) {
+ for ( int j = 0 ; j != _width ; ++j ) {
+ for ( int k = 0 ; k != 4 ; ++k )
+ dest->rgba[k] = pixels[k];
+ {
+ dest->adj.top = 0;
+ dest->adj.topright = 0;
+ dest->adj.right = 0;
+ dest->adj.bottomright = 0;
+ dest->adj.bottom = 0;
+ dest->adj.bottomleft = 0;
+ dest->adj.left = 0;
+ dest->adj.topleft = 0;
+ }
+ pixels += n_channels;
+ ++dest;
+ }
+ pixels += rowpadding;
+ }
+ } else {
+ assert(n_channels == 3);
+ for ( int i = 0 ; i != _height ; ++i ) {
+ for ( int j = 0 ; j != _width ; ++j ) {
+ for ( int k = 0 ; k != 3 ; ++k )
+ dest->rgba[k] = pixels[k];
+ dest->rgba[3] = '\xFF';
+ {
+ dest->adj.top = 0;
+ dest->adj.topright = 0;
+ dest->adj.right = 0;
+ dest->adj.bottomright = 0;
+ dest->adj.bottom = 0;
+ dest->adj.bottomleft = 0;
+ dest->adj.left = 0;
+ dest->adj.topleft = 0;
+ }
+ pixels += n_channels;
+ ++dest;
+ }
+ pixels += rowpadding;
+ }
+ }
+}
+
+inline void PixelGraph::checkConsistency()
+{
+ PixelGraph::Node *it = &_nodes.front();
+ for ( int i = 0 ; i != _height ; ++i ) {
+ for ( int j = 0 ; j != _width ; ++j, ++it ) {
+ if ( it->adj.top )
+ assert((it - _width)->adj.bottom);
+ if ( it->adj.topright )
+ assert((it - _width + 1)->adj.bottomleft);
+ if ( it->adj.right )
+ assert((it + 1)->adj.left);
+ if ( it->adj.bottomright )
+ assert((it + _width + 1)->adj.topleft);
+ if ( it->adj.bottom )
+ assert((it + _width)->adj.top);
+ if ( it->adj.bottomleft )
+ assert((it + _width - 1)->adj.topright);
+ if ( it->adj.left )
+ assert((it - 1)->adj.right);
+ if ( it->adj.topleft )
+ assert((it - _width - 1)->adj.bottomright);
+ }
+ }
+}
+
+inline PixelGraph::ColumnView PixelGraph::operator[](int column)
+{
+ return ColumnView(_nodes, _width, column);
+}
+
+inline void PixelGraph::connectAllNeighbors()
+{
+ // ...the "center" nodes first...
+ if ( _width > 2 && _height > 2 ) {
+ iterator it = nodeBottomRight(begin()); // [1][1]
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ for ( int j = 1 ; j != _width - 1 ; ++j ) {
+ it->adj.top = 1;
+ it->adj.topright = 1;
+ it->adj.right = 1;
+ it->adj.bottomright = 1;
+ it->adj.bottom = 1;
+ it->adj.bottomleft = 1;
+ it->adj.left = 1;
+ it->adj.topleft = 1;
+
+ it = nodeRight(it);
+ }
+ // After the previous loop, 'it' is pointing to the last node from
+ // the row.
+ // Go south, then first node in the row (increment 'it' by 1)
+ // Go to the second node in the line (increment 'it' by 1)
+ it += 2;
+ }
+ }
+
+ // ...then the "top" nodes...
+ if ( _width > 2 ) {
+ Node *it = &_nodes[1];
+ if ( _height > 1 ) {
+ for ( int i = 1 ; i != _width - 1 ; ++i ) {
+ it->adj.right = 1;
+ it->adj.bottomright = 1;
+ it->adj.bottom = 1;
+ it->adj.bottomleft = 1;
+ it->adj.left = 1;
+
+ ++it;
+ }
+ } else {
+ for ( int i = 1 ; i != _width - 1 ; ++i ) {
+ it->adj.right = 1;
+ it->adj.left = 1;
+
+ ++it;
+ }
+ }
+ }
+
+ // ...then the "bottom" nodes...
+ if ( _width > 2 && _height > 1 ) {
+ Node *it = &((*this)[1][_height - 1]);
+ for ( int i = 1 ; i != _width - 1 ; ++i ) {
+ it->adj.left = 1;
+ it->adj.topleft = 1;
+ it->adj.top = 1;
+ it->adj.topright = 1;
+ it->adj.right = 1;
+
+ ++it;
+ }
+ }
+
+ // ...then the "left" nodes...
+ if ( _height > 2 ) {
+ iterator it = nodeBottom(begin()); // [0][1]
+ if ( _width > 1 ) {
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ it->adj.top = 1;
+ it->adj.topright = 1;
+ it->adj.right = 1;
+ it->adj.bottomright = 1;
+ it->adj.bottom = 1;
+
+ it = nodeBottom(it);
+ }
+ } else {
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ it->adj.top = 1;
+ it->adj.bottom = 1;
+
+ it = nodeBottom(it);
+ }
+ }
+ }
+
+ // ...then the "right" nodes...
+ if ( _height > 2 && _width > 1 ) {
+ iterator it = nodeBottom(begin() + _width - 1);// [_width - 1][1]
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ it->adj.bottom = 1;
+ it->adj.bottomleft = 1;
+ it->adj.left = 1;
+ it->adj.topleft = 1;
+ it->adj.top = 1;
+
+ it = nodeBottom(it);
+ }
+ }
+
+ // ...and the 4 corner nodes
+ {
+ Node *const top_left = &(*this)[0][0];
+
+ if ( _width > 1 )
+ top_left->adj.right = 1;
+
+ if ( _width > 1 && _height > 1 )
+ top_left->adj.bottomright = 1;
+
+ if ( _height > 1 )
+ top_left->adj.bottom = 1;
+ }
+ if ( _width > 1 ) {
+ Node *const top_right = &(*this)[_width - 1][0];
+
+ if ( _height > 1 ) {
+ top_right->adj.bottom = 1;
+ top_right->adj.bottomleft = 1;
+ }
+
+ top_right->adj.left = 1;
+ }
+ if ( _height > 1 ) {
+ Node *const down_left = &(*this)[0][_height - 1];
+ down_left->adj.top = 1;
+
+ if ( _width > 1 ) {
+ down_left->adj.topright = 1;
+ down_left->adj.right = 1;
+ }
+ }
+ if ( _width > 1 && _height > 1 ) {
+ Node *const down_right = &(*this)[_width - 1][_height - 1];
+ down_right->adj.left = 1;
+ down_right->adj.topleft = 1;
+ down_right->adj.top = 1;
+ }
+}
+
+PixelGraph::EdgePairContainer PixelGraph::crossingEdges()
+{
+ EdgePairContainer ret;
+
+ if ( width() < 2 || height() < 2 )
+ return ret;
+
+ // Iterate over the graph, 2x2 blocks at time
+ PixelGraph::iterator it = begin();
+ for (int i = 0 ; i != height() - 1 ; ++i, ++it ) {
+ for ( int j = 0 ; j != width() - 1 ; ++j, ++it ) {
+ EdgePair diagonals(
+ Edge(it, nodeBottomRight(it)),
+ Edge(nodeRight(it), nodeBottom(it)));
+
+ // Check if there are crossing edges
+ if ( !diagonals.first.first->adj.bottomright
+ || !diagonals.second.first->adj.bottomleft ) {
+ continue;
+ }
+
+ ret.push_back(diagonals);
+ }
+ }
+
+ return ret;
+}
+
+inline PixelGraph::Node &PixelGraph::ColumnView::operator[](int line)
+{
+ return _nodes[line * _width + _column];
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_PIXELGRAPH_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/point.h b/src/3rdparty/libdepixelize/priv/point.h
new file mode 100644
index 000000000..53babd9dc
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/point.h
@@ -0,0 +1,112 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_POINT_H
+#define LIBDEPIXELIZE_TRACER_POINT_H
+
+namespace Tracer {
+
+template<class T>
+struct Point
+{
+ Point() : smooth(false), visible(true) {}
+ Point(T x, T y) : smooth(false), visible(true), x(x), y(y) {}
+ Point(T x, T y, bool smooth) : smooth(smooth), visible(true), x(x), y(y) {}
+
+ Point operator+(const Point &rhs) const
+ {
+ return Point(x + rhs.x, y + rhs.y);
+ }
+
+ Point operator/(T foo) const
+ {
+ return Point(x / foo, y / foo);
+ }
+
+ Point invisible() const
+ {
+ Point p = *this;
+ p.visible = false;
+ return p;
+ }
+
+ bool smooth;
+
+ /**
+ * By default, all points are visible, but the poor amount of information
+ * that B-Splines (libdepixelize-specific) allows us to represent forces us
+ * to create additional points. But... these additional points don't need to
+ * be visible.
+ */
+ bool visible;
+
+ T x, y;
+};
+
+template<class T>
+Point<T> midpoint(const Point<T> &a, const Point<T> &b)
+{
+ return Point<T>((a.x + b.x) / 2, (a.y + b.y) / 2);
+}
+
+template<class T>
+bool operator==(const Point<T> &lhs, const Point<T> &rhs)
+{
+ return
+ /*
+ * Will make a better job identifying which points can be eliminated by
+ * cells union.
+ */
+#ifndef LIBDEPIXELIZE_IS_VERY_WELL_TESTED
+ lhs.smooth == rhs.smooth &&
+#endif // LIBDEPIXELIZE_IS_VERY_WELL_TESTED
+ lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+template<class T>
+bool weakly_equal(const Point<T> &a, const Point<T> &b)
+{
+ return a.x == b.x && a.y == b.y;
+}
+
+template<class T>
+Geom::Point to_geom_point(Point<T> p)
+{
+ return Geom::Point(p.x, p.y);
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_POINT_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/simplifiedvoronoi.h b/src/3rdparty/libdepixelize/priv/simplifiedvoronoi.h
new file mode 100644
index 000000000..84feab08d
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/simplifiedvoronoi.h
@@ -0,0 +1,1707 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H
+#define LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H
+
+#include "pixelgraph.h"
+#include "colorspace.h"
+#include "point.h"
+#include "branchless.h"
+
+namespace Tracer {
+
+template<typename T, bool adjust_splines>
+class SimplifiedVoronoi
+{
+public:
+ /**
+ * The "smooth" attribute of each vertex is only accurate if edge is
+ * visible. This decision was made because invisible edges will disappear
+ * during polygon-union, the next phase of Kopf-Lischinski.
+ */
+ struct Cell
+ {
+ // There may not exist more than 8 vertices per cell and a
+ // "small vector optimization" could improve the performance
+ // by avoiding memory fragmentation. Serious testing is needed.
+
+ // The vertices are filled in clockwise order
+ std::vector< Point<T> > vertices;
+ guint8 rgba[4];
+ };
+
+ typedef typename std::vector<Cell>::iterator iterator;
+ typedef typename std::vector<Cell>::const_iterator const_iterator;
+ typedef typename std::vector<Cell>::reverse_iterator reverse_iterator;
+
+ typedef typename std::vector<Cell>::const_reverse_iterator
+ const_reverse_iterator;
+
+ /*
+ It will work correctly if no crossing-edges are present.
+ */
+ SimplifiedVoronoi(const PixelGraph &graph);
+
+ // Iterators
+ iterator begin()
+ {
+ return _cells.begin();
+ }
+
+ const_iterator begin() const
+ {
+ return _cells.begin();
+ }
+
+ iterator end()
+ {
+ return _cells.end();
+ }
+
+ const_iterator end() const
+ {
+ return _cells.end();
+ }
+
+ reverse_iterator rbegin()
+ {
+ return _cells.rbegin();
+ }
+
+ const_reverse_iterator rbegin() const
+ {
+ return _cells.rbegin();
+ }
+
+ reverse_iterator rend()
+ {
+ return _cells.rend();
+ }
+
+ const_reverse_iterator rend() const
+ {
+ return _cells.rend();
+ }
+
+ size_t size() const
+ {
+ return _cells.size();
+ }
+
+ int width() const
+ {
+ return _width;
+ }
+
+ int height() const
+ {
+ return _height;
+ }
+
+private:
+#ifdef LIBDEPIXELIZE_VERY_TYPE_SAFE
+ typedef void (*PointTransform)(Point<T> &p, T dx, T dy);
+ typedef bool (*NodeTransform)(PixelGraph::const_iterator);
+#endif // LIBDEPIXELIZE_VERY_TYPE_SAFE
+
+ /**
+ * Output is translated by -.5 in each axis. This function fixes this error.
+ */
+ static Point<T> _adjust(Point<T> p)
+ {
+ return Point<T>(p.x + .5, p.y + .5);
+ }
+
+ /**
+ * Output is translated by -.5 in each axis. This function fixes this error.
+ */
+ static Point<T> _adjust(Point<T> p, bool smooth)
+ {
+ return Point<T>(p.x + .5, p.y + .5, smooth);
+ }
+
+ void _complexTopLeft(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it,
+ Cell *const cells_it, int x, int y);
+ void _complexTopRight(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it,
+ Cell *const cells_it, int x, int y);
+ void _complexBottomRight(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it,
+ Cell *const cells_it, int x, int y);
+ void _complexBottomLeft(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it,
+ Cell *const cells_it, int x, int y);
+
+ static void _complexTopLeftTransform(Point<T> &p, T dx, T dy);
+ static void _complexTopRightTransform(Point<T> &p, T dx, T dy);
+ static void _complexBottomRightTransform(Point<T> &p, T dx, T dy);
+ static void _complexBottomLeftTransform(Point<T> &p, T dx, T dy);
+
+ static bool _complexTopLeftTransformTop(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformTopRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformBottomRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformBottom(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformBottomLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexTopLeftTransformTopLeft(PixelGraph::const_iterator graph_it);
+
+ static bool _complexTopRightTransformTop(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformTopRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformBottomRight(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformBottom(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformBottomLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexTopRightTransformTopLeft(PixelGraph::const_iterator graph_it);
+
+ static bool _complexBottomRightTransformTop(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformTopRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformBottomRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformBottom(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformBottomLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomRightTransformTopLeft(PixelGraph::const_iterator graph_it);
+
+ static bool _complexBottomLeftTransformTop(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformTopRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformBottomRight(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformBottom(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformBottomLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformLeft(PixelGraph::const_iterator graph_it);
+ static bool _complexBottomLeftTransformTopLeft(PixelGraph::const_iterator graph_it);
+
+ /*
+ * The memory layout assumed goes like this (with a_it being the current
+ * iterated element):
+ *
+ * (a_it) | (b_it)
+ * -------+-------
+ * (c_it) | (d_it)
+ *
+ * If you want to use it with another directions (topleft, topright, ...)
+ * **DO NOT** invert x or y axis, because the insertion order will go mad.
+ *
+ * The idea behind this abstraction is to rotate the iterators, then the
+ * insertion order will be preserved.
+ *
+ * The initial value of all nodes that will be inserted is {x, y}. All
+ * changes to this node **MUST** occur through \p transform or _adjust.
+ *
+ * Some maintainers may like this function because they will handle a
+ * code base 4 times smaller and bugs will be MUCH MUCH difficult to hide.
+ *
+ * Some maintainers may go mad because the level extra level of
+ * abstraction.
+ *
+ * "All problems in computer science can be solved by another level of
+ * indirection, except for the problem of too many layers of indirection."
+ * -- David J. Wheeler
+ */
+#ifndef LIBDEPIXELIZE_VERY_TYPE_SAFE
+ template<class PointTransform, class NodeTransform>
+#endif // LIBDEPIXELIZE_VERY_TYPE_SAFE
+ void _genericComplexBottomRight(PixelGraph::const_iterator a_it,
+ PixelGraph::const_iterator b_it,
+ PixelGraph::const_iterator c_it,
+ PixelGraph::const_iterator d_it,
+ Cell *const cells_it, int x, int y,
+ PointTransform transform,
+ NodeTransform top,
+ NodeTransform topright,
+ NodeTransform right,
+ NodeTransform bottomright,
+ NodeTransform bottom,
+ NodeTransform bottomleft,
+ NodeTransform left,
+ NodeTransform topleft);
+
+ int _width;
+ int _height;
+ std::vector<Cell> _cells;
+};
+
+template<class T, bool adjust_splines>
+SimplifiedVoronoi<T, adjust_splines>
+::SimplifiedVoronoi(const PixelGraph &graph) :
+ _width(graph.width()),
+ _height(graph.height()),
+ _cells(graph.size())
+{
+ if (!graph.size())
+ return;
+
+ /*
+ * The insertion order of cells is not a big deal. Here I just follow
+ * the order of PixelGraph arrangement.
+ */
+
+ // ...the "center" cells first...
+ if ( _width > 2 && _height > 2 ) {
+ PixelGraph::const_iterator graph_it = graph.begin() + _width + 1;
+ Cell *cells_it = &_cells.front() + _width + 1;
+
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ for ( int j = 1 ; j != _width - 1 ; ++j, ++graph_it, ++cells_it ) {
+ for ( int k = 0 ; k != 4 ; ++k )
+ cells_it->rgba[k] = graph_it->rgba[k];
+ // Top-left
+ _complexTopLeft(graph, graph_it, cells_it, j, i);
+
+ // Top-right
+ _complexTopRight(graph, graph_it, cells_it, j, i);
+
+ // Bottom-right
+ _complexBottomRight(graph, graph_it, cells_it, j, i);
+
+ // Bottom-left
+ _complexBottomLeft(graph, graph_it, cells_it, j, i);
+ }
+ // After the previous loop, 'it' is pointing to the last cell from
+ // the row.
+ // Go south, then first node in the row (increment 'it' by 1)
+ // Go to the second node in the line (increment 'it' by 1)
+ graph_it += 2;
+ cells_it += 2;
+ }
+ }
+
+ // ...then the "top" cells...
+ if ( _width > 2 ) {
+ PixelGraph::const_iterator graph_it = graph.begin() + 1;
+ Cell *cells_it = &_cells.front() + 1;
+
+ if ( _height > 1 ) {
+ for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(i, 0, false));
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(i + 1, 0, false));
+
+ // Bottom-right
+ _complexBottomRight(graph, graph_it, cells_it, i, 0);
+
+ // Bottom-left
+ _complexBottomLeft(graph, graph_it, cells_it, i, 0);
+ }
+ } else {
+ for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(i, 0, false));
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(i + 1, 0, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(i + 1, 1, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(i, 1, false));
+ }
+ }
+ }
+
+ // ...then the "bottom" cells...
+ if ( _width > 2 && _height > 1 ) {
+ // Node *it = &((*this)[1][_height - 1]);
+ PixelGraph::const_iterator graph_it
+ = graph.begin() + (_height - 1) * _width + 1;
+ Cell *cells_it = &_cells.front() + (_height - 1) * _width + 1;
+
+ for ( int i = 1 ; i != _width - 1 ; ++i, ++graph_it, ++cells_it ) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ _complexTopLeft(graph, graph_it, cells_it, i, _height - 1);
+
+ // Top-right
+ _complexTopRight(graph, graph_it, cells_it, i, _height - 1);
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(i + 1, _height, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(i, _height, false));
+ }
+ }
+
+ // ...then the "left" cells...
+ if ( _height > 2 ) {
+ PixelGraph::const_iterator graph_it = graph.begin() + _width;
+ Cell *cells_it = &_cells.front() + _width;
+
+ if ( _width > 1 ) {
+ for ( int i = 1 ; i != _height - 1 ; ++i) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(0, i, false));
+
+ // Top-right
+ _complexTopRight(graph, graph_it, cells_it, 0, i);
+
+ // Bottom-right
+ _complexBottomRight(graph, graph_it, cells_it, 0, i);
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(0, i + 1, false));
+
+ graph_it += _width;
+ cells_it += _width;
+ }
+ } else {
+ for ( int i = 1 ; i != _height - 1 ; ++i) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(0, i, false));
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(1, i, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(1, i, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(0, i + 1, false));
+
+ graph_it += _width;
+ cells_it += _width;
+ }
+ }
+ }
+
+ // ...then the "right" cells...
+ if ( _height > 2 && _width > 1 ) {
+ PixelGraph::const_iterator graph_it = graph.begin() + 2 * _width - 1;
+ Cell *cells_it = &_cells.front() + 2 * _width - 1;
+
+ for ( int i = 1 ; i != _height - 1 ; ++i ) {
+ for ( int j = 0 ; j != 4 ; ++j )
+ cells_it->rgba[j] = graph_it->rgba[j];
+
+ // Top-left
+ _complexTopLeft(graph, graph_it, cells_it, _width - 1, i);
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(_width, i, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(_width, i + 1, false));
+
+ // Bottom-left
+ _complexBottomLeft(graph, graph_it, cells_it, _width - 1, i);
+
+ graph_it += _width;
+ cells_it += _width;
+ }
+ }
+
+ // ...and the 4 corner nodes
+ // top-left
+ {
+ PixelGraph::const_iterator graph_it = graph.begin();
+ Cell *cells_it = &_cells.front();
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ cells_it->rgba[i] = graph_it->rgba[i];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(0, 0, false));
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(1, 0, false));
+
+ // Bottom-right
+ if ( _width > 1 && _height > 1 )
+ _complexBottomRight(graph, graph_it, cells_it, 0, 0);
+ else
+ cells_it->vertices.push_back(Point<T>(1, 1, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(0, 1, false));
+ }
+
+ // top-right
+ if ( _width > 1 ) {
+ PixelGraph::const_iterator graph_it = graph.begin() + _width - 1;
+ Cell *cells_it = &_cells.front() + _width - 1;
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ cells_it->rgba[i] = graph_it->rgba[i];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(_width - 1, 0, false));
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(_width, 0, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(_width, 1, false));
+
+ // Bottom-left
+ if ( _height > 1 )
+ _complexBottomLeft(graph, graph_it, cells_it, _width - 1, 0);
+ else
+ cells_it->vertices.push_back(Point<T>(_width - 1, 1, false));
+ }
+
+ // bottom-left
+ if ( _height > 1 ) {
+ PixelGraph::const_iterator graph_it
+ = graph.begin() + (_height - 1) * _width;
+ Cell *cells_it = &_cells.front() + (_height - 1) * _width;
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ cells_it->rgba[i] = graph_it->rgba[i];
+
+ // Top-left
+ cells_it->vertices.push_back(Point<T>(0, _height - 1, false));
+
+ // Top-right
+ if ( _width > 1)
+ _complexTopRight(graph, graph_it, cells_it, 0, _height - 1);
+ else
+ cells_it->vertices.push_back(Point<T>(1, _height - 1, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(1, _height, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(0, _height, false));
+ }
+
+ // bottom-right
+ if ( _width > 1 && _height > 1 ) {
+ PixelGraph::const_iterator graph_it = --graph.end();
+ Cell *cells_it = &_cells.back();
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ cells_it->rgba[i] = graph_it->rgba[i];
+
+ // Top-left
+ _complexTopLeft(graph, graph_it, cells_it, _width - 1, _height - 1);
+
+ // Top-right
+ cells_it->vertices.push_back(Point<T>(_width, _height - 1, false));
+
+ // Bottom-right
+ cells_it->vertices.push_back(Point<T>(_width, _height, false));
+
+ // Bottom-left
+ cells_it->vertices.push_back(Point<T>(_width - 1, _height, false));
+ }
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeft(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it, Cell *const cells_it,
+ int x, int y)
+{
+ _genericComplexBottomRight(graph_it,
+ graph.nodeLeft(graph_it),
+ graph.nodeTop(graph_it),
+ graph.nodeTopLeft(graph_it),
+ cells_it, x, y,
+ &SimplifiedVoronoi::_complexTopLeftTransform,
+ &SimplifiedVoronoi::_complexTopLeftTransformTop,
+ &SimplifiedVoronoi::_complexTopLeftTransformTopRight,
+ &SimplifiedVoronoi::_complexTopLeftTransformRight,
+ &SimplifiedVoronoi::_complexTopLeftTransformBottomRight,
+ &SimplifiedVoronoi::_complexTopLeftTransformBottom,
+ &SimplifiedVoronoi::_complexTopLeftTransformBottomLeft,
+ &SimplifiedVoronoi::_complexTopLeftTransformLeft,
+ &SimplifiedVoronoi::_complexTopLeftTransformTopLeft);
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRight(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it, Cell *const cells_it,
+ int x, int y)
+{
+ _genericComplexBottomRight(graph_it,
+ graph.nodeTop(graph_it),
+ graph.nodeRight(graph_it),
+ graph.nodeTopRight(graph_it),
+ cells_it, x, y,
+ &SimplifiedVoronoi::_complexTopRightTransform,
+ &SimplifiedVoronoi::_complexTopRightTransformTop,
+ &SimplifiedVoronoi::_complexTopRightTransformTopRight,
+ &SimplifiedVoronoi::_complexTopRightTransformRight,
+ &SimplifiedVoronoi::_complexTopRightTransformBottomRight,
+ &SimplifiedVoronoi::_complexTopRightTransformBottom,
+ &SimplifiedVoronoi::_complexTopRightTransformBottomLeft,
+ &SimplifiedVoronoi::_complexTopRightTransformLeft,
+ &SimplifiedVoronoi::_complexTopRightTransformTopLeft);
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRight(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it, Cell *const cells_it,
+ int x, int y)
+{
+ _genericComplexBottomRight(graph_it,
+ graph.nodeRight(graph_it),
+ graph.nodeBottom(graph_it),
+ graph.nodeBottomRight(graph_it),
+ cells_it, x, y,
+ &SimplifiedVoronoi::_complexBottomRightTransform,
+ &SimplifiedVoronoi::_complexBottomRightTransformTop,
+ &SimplifiedVoronoi::_complexBottomRightTransformTopRight,
+ &SimplifiedVoronoi::_complexBottomRightTransformRight,
+ &SimplifiedVoronoi::_complexBottomRightTransformBottomRight,
+ &SimplifiedVoronoi::_complexBottomRightTransformBottom,
+ &SimplifiedVoronoi::_complexBottomRightTransformBottomLeft,
+ &SimplifiedVoronoi::_complexBottomRightTransformLeft,
+ &SimplifiedVoronoi::_complexBottomRightTransformTopLeft);
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeft(const PixelGraph &graph,
+ PixelGraph::const_iterator graph_it, Cell *const cells_it,
+ int x, int y)
+{
+ _genericComplexBottomRight(graph_it,
+ graph.nodeBottom(graph_it),
+ graph.nodeLeft(graph_it),
+ graph.nodeBottomLeft(graph_it),
+ cells_it, x, y,
+ &SimplifiedVoronoi::_complexBottomLeftTransform,
+ &SimplifiedVoronoi::_complexBottomLeftTransformTop,
+ &SimplifiedVoronoi::_complexBottomLeftTransformTopRight,
+ &SimplifiedVoronoi::_complexBottomLeftTransformRight,
+ &SimplifiedVoronoi::_complexBottomLeftTransformBottomRight,
+ &SimplifiedVoronoi::_complexBottomLeftTransformBottom,
+ &SimplifiedVoronoi::_complexBottomLeftTransformBottomLeft,
+ &SimplifiedVoronoi::_complexBottomLeftTransformLeft,
+ &SimplifiedVoronoi::_complexBottomLeftTransformTopLeft);
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransform(Point<T> &p, T dx, T dy)
+{
+ p.x -= dx;
+ p.y -= dy;
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransform(Point<T> &p, T dx, T dy)
+{
+ p.x += dy;
+ p.y -= dx;
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransform(Point<T> &p, T dx, T dy)
+{
+ p.x += dx;
+ p.y += dy;
+}
+
+template<class T, bool adjust_splines> void
+SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransform(Point<T> &p, T dx, T dy)
+{
+ p.x -= dy;
+ p.y += dx;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformTop(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottom;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformTopRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.left;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformBottomRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformBottom(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.top;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformBottomLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.right;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopLeftTransformTopLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformTop(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.left;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformTopRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.top;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformBottomRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformBottom(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.right;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformBottomLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottom;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexTopRightTransformTopLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformTop(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.top;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformTopRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.right;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformBottomRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformBottom(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottom;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformBottomLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.left;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomRightTransformTopLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformTop(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.right;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformTopRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomright;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottom;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformBottomRight(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.bottomleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformBottom(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.left;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformBottomLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topleft;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.top;
+}
+
+template<class T, bool adjust_splines>
+bool SimplifiedVoronoi<T, adjust_splines>
+::_complexBottomLeftTransformTopLeft(PixelGraph::const_iterator graph_it)
+{
+ return graph_it->adj.topright;
+}
+
+template<class T, bool adjust_splines>
+#ifndef LIBDEPIXELIZE_VERY_TYPE_SAFE
+template<class PointTransform, class NodeTransform>
+#endif // LIBDEPIXELIZE_VERY_TYPE_SAFE
+void
+SimplifiedVoronoi<T, adjust_splines>
+::_genericComplexBottomRight(PixelGraph::const_iterator a_it,
+ PixelGraph::const_iterator b_it,
+ PixelGraph::const_iterator c_it,
+ PixelGraph::const_iterator d_it,
+ Cell *const cells_it, int x, int y,
+ PointTransform transform,
+ NodeTransform,
+ NodeTransform topright,
+ NodeTransform right,
+ NodeTransform bottomright,
+ NodeTransform bottom,
+ NodeTransform bottomleft,
+ NodeTransform,
+ NodeTransform topleft)
+{
+ using colorspace::contour_edge;
+ using colorspace::same_color;
+
+ const Point<T> initial(x, y);
+
+ /*
+ * The insertion order of points within the cell is very important. You must
+ * follow current practice: Clockwise order.
+ */
+
+ if ( bottomright(a_it) ) {
+ // this and bottom-right are connected
+
+ bool smooth[2] = {
+ ( same_color(a_it->rgba, d_it->rgba)
+ || same_color(a_it->rgba, b_it->rgba)
+ || same_color(b_it->rgba, d_it->rgba) ),
+ ( same_color(a_it->rgba, d_it->rgba)
+ || same_color(a_it->rgba, c_it->rgba)
+ || same_color(c_it->rgba, d_it->rgba) )
+ };
+
+ Point<T> borderMid = initial;
+ {
+ transform(borderMid, 1, 1);
+ borderMid = midpoint(initial, borderMid);
+ }
+
+ Point<T> vertices[2] = {initial, initial};
+ {
+ transform(vertices[0], 1, 0);
+ vertices[0] = _adjust(midpoint(borderMid, vertices[0]), smooth[0]);
+
+ transform(vertices[1], 0, 1);
+ vertices[1] = _adjust(midpoint(borderMid, vertices[1]), smooth[1]);
+ }
+
+ if ( !smooth[0] && adjust_splines ) {
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(vertices[0].invisible());
+#else
+ cells_it->vertices.push_back(vertices[0]);
+#endif
+ {
+ Point<T> another = vertices[0];
+ transform(another,
+ - ( 0.1875
+ - ( topright(a_it) - topleft(b_it) ) * 0.1875 ),
+ // y
+ - ( 0.5625
+ - ( topright(a_it) + topleft(b_it) ) * 0.1875 ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertices[0];
+ transform(another,
+ - ( 0.0625
+ - ( topright(a_it) - topleft(b_it) ) * 0.0625 ),
+ // y
+ - ( 0.1875
+ - ( topright(a_it) + topleft(b_it) ) * 0.0625) );
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertices[0];
+ transform(another,
+ 0.1875
+ - ( bottomright(b_it) + topright(d_it) ) * 0.0625,
+ // y
+ 0.0625
+ + ( bottomright(b_it) - topright(d_it) ) * 0.0625);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ transform(vertices[0],
+ 0.0625
+ + ( topright(a_it) - topright(d_it) - topleft(b_it)
+ - bottomright(b_it) ) * 0.03125,
+ // y
+ - ( 0.0625
+ + ( topright(d_it) - topright(a_it)
+ - topleft(b_it) - bottomright(b_it) )
+ * 0.03125 ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertices[0].visible = false;
+#endif
+ }
+ }
+
+ cells_it->vertices.push_back(vertices[0]);
+
+ if ( !smooth[1] && adjust_splines ) {
+ {
+ Point<T> another = vertices[1];
+ transform(another,
+ - ( 0.0625
+ + ( bottomleft(d_it) - bottomleft(a_it)
+ - topleft(c_it) - bottomright(c_it) )
+ * 0.03125 ),
+ // y
+ 0.0625
+ + ( bottomleft(a_it) - bottomleft(d_it)
+ - topleft(c_it) - bottomright(c_it) ) * 0.03125);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertices[1];
+ transform(another,
+ 0.0625
+ + ( bottomright(c_it) - bottomleft(d_it) ) * 0.0625,
+ // y
+ 0.1875
+ - ( bottomright(c_it) + bottomleft(d_it) ) * 0.0625);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertices[1];
+ transform(another,
+ - ( 0.1875
+ - ( bottomleft(a_it) + topleft(c_it) )
+ * 0.0625 ),
+ // y
+ - ( 0.0625
+ - ( bottomleft(a_it) - topleft(c_it) )
+ * 0.0625 ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertices[1];
+ transform(another,
+ - ( 0.5625
+ - ( bottomleft(a_it) + topleft(c_it) )
+ * 0.1875 ),
+ // y
+ - ( 0.1875
+ - ( bottomleft(a_it) - topleft(c_it) )
+ * 0.1875 ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertices[1].visible = false;
+#endif
+ }
+
+ cells_it->vertices.push_back(vertices[1]);
+ } else if ( bottomleft(b_it) ) {
+ // right and bottom are connected
+
+ Point<T> vertex = initial;
+ transform(vertex, 1, 1);
+ vertex = _adjust(midpoint(midpoint(initial, vertex), initial), true);
+ cells_it->vertices.push_back(vertex);
+ } else {
+ // Connections don't affect the shape of this squared-like
+ // pixel
+
+ Point<T> vertex = initial;
+ transform(vertex, 1, 1);
+ vertex = _adjust(midpoint(initial, vertex));
+
+ // compute smoothness
+ if ( right(a_it) && adjust_splines ) {
+ // this and right are connected
+
+ if ( !right(c_it) && !( bottom(a_it) && bottom(b_it) ) ) {
+ // bottom and bottom-right are disconnected
+
+ bool foreign_is_contour = contour_edge(c_it->rgba, d_it->rgba);
+ bool twin_is_contour = contour_edge(b_it->rgba, d_it->rgba);
+ bool another_is_contour = contour_edge(a_it->rgba, c_it->rgba);
+
+ if ( another_is_contour + twin_is_contour
+ + foreign_is_contour == 2 ) {
+ vertex.smooth = !foreign_is_contour;
+
+ if ( !vertex.smooth ) {
+ if ( another_is_contour ) {
+ {
+ Point<T> another = vertex;
+ T amount = 0.125
+ - ( ( bottomright(c_it) + topleft(c_it) )
+ * 0.03125 );
+ transform(another, - amount, amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * bottomright(c_it);
+ transform(another, amount, 0.25 - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * topleft(c_it);
+ transform(another, - ( 0.25 - amount ),
+ - amount);
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875 * topleft(c_it);
+ transform(another, - ( 0.75 - amount ),
+ - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ } else if ( twin_is_contour ) {
+ T amount = 0.125
+ - ( ( bottomleft(d_it) + topright(d_it) )
+ * 0.03125 );
+ transform(vertex, amount, amount);
+ }
+ } else if ( !same_color(a_it->rgba, b_it->rgba) ) {
+ vertex.smooth = false;
+ // This is the same code of the if ( special )
+ // I REALLY NEED lambdas to improve this code without
+ // creating yet another interface that takes a million
+ // of function parameters and keep code locality
+ {
+ Point<T> another = vertex;
+ T amount = 0.03125;
+ transform(another,
+ amount
+ * ( topleft(c_it) - topright(d_it)
+ + bottomleft(a_it) - bottomright(b_it) ),
+ // y
+ - amount
+ * ( topleft(c_it) + topright(d_it)
+ - bottomleft(a_it) - bottomright(b_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ 0.25 - amount
+ * ( topright(d_it) + bottomright(b_it) ),
+ // y
+ - amount
+ * ( topright(d_it) - bottomright(b_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ - ( 0.25 - amount
+ * ( topleft(c_it) + bottomleft(a_it) ) ),
+ // y
+ - amount
+ * ( topleft(c_it) - bottomleft(a_it) ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875;
+ transform(another,
+ - ( 0.75 - amount
+ * ( topleft(c_it) + bottomleft(a_it) ) ),
+ // y
+ - amount
+ * ( topleft(c_it) - bottomleft(a_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ } else {
+ // {this, right} is the pair with the angle
+ // closest to 180 degrees
+ vertex.smooth = same_color(a_it->rgba, b_it->rgba);
+ }
+ } else {
+ // there might be 2-color, then vertex.smooth = true
+
+ // or it might be 1-color and doesn't matter,
+ // because the current node will disappear
+ vertex.smooth
+ = same_color(a_it->rgba, b_it->rgba)
+ + same_color(a_it->rgba, c_it->rgba)
+ + same_color(d_it->rgba, b_it->rgba)
+ + same_color(d_it->rgba, c_it->rgba) == 2;
+ }
+ } else if ( bottom(a_it) && adjust_splines ) {
+ // this and bottom are connected
+
+ if ( !bottom(b_it) && !( right(a_it) && right(c_it) ) ) {
+ // right and bottom-right are disconnected
+
+ bool foreign_is_contour = contour_edge(b_it->rgba, d_it->rgba);
+ bool twin_is_contour = contour_edge(c_it->rgba, d_it->rgba);
+ bool another_is_contour = contour_edge(a_it->rgba, b_it->rgba);
+
+ if ( another_is_contour + twin_is_contour
+ + foreign_is_contour == 2 ) {
+ vertex.smooth = !foreign_is_contour;
+
+ if ( !vertex.smooth ) {
+ if ( another_is_contour ) {
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(vertex.invisible());
+#else
+ cells_it->vertices.push_back(vertex);
+#endif
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875 * topleft(b_it);
+ transform(another, - amount,
+ - ( 0.75 - amount ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * topleft(b_it);
+ transform(another, - amount,
+ - ( 0.25 - amount ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * bottomright(b_it);
+ transform(another, 0.25 - amount, amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ T amount = 0.125
+ - (bottomright(b_it) + topleft(b_it))
+ * 0.03125;
+ transform(vertex, amount, - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ } else if ( twin_is_contour ) {
+ T amount = 0.125
+ - ( ( topright(d_it) + bottomleft(d_it) )
+ * 0.03125 );
+ transform(vertex, amount, amount);
+ }
+ } else if ( !same_color(a_it->rgba, c_it->rgba) ) {
+ vertex.smooth = false;
+ // This is the same code of the if ( special )
+ // I REALLY NEED lambdas to improve this code without
+ // creating yet another interface that takes a million
+ // of function parameters and keep code locality
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(vertex.invisible());
+#else
+ cells_it->vertices.push_back(vertex);
+#endif
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875;
+ transform(another,
+ - ( topleft(b_it) - topright(a_it) ) * amount,
+ // y
+ - ( 0.75
+ - ( topleft(b_it) + topright(a_it) )
+ * amount ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ - ( topleft(b_it) - topright(a_it) ) * amount,
+ // y
+ - ( 0.25
+ - ( topleft(b_it) + topright(a_it) )
+ * amount ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another, - amount
+ * ( bottomleft(d_it) - bottomright(c_it) ),
+ // y
+ 0.25 - amount
+ * ( bottomleft(d_it) + bottomright(c_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ transform(vertex,
+ - ( topleft(b_it) + bottomleft(d_it)
+ - topright(a_it) - bottomright(c_it) )
+ * 0.03125,
+ // y
+ ( topleft(b_it) - bottomleft(d_it)
+ + topright(a_it) - bottomright(c_it) )
+ * 0.03125);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ }
+ } else {
+ // {this, bottom} is the pair with the angle
+ // closest to 180 degrees
+ vertex.smooth = same_color(a_it->rgba, c_it->rgba);
+ }
+ } else {
+ // there might be 2-color, then vertex.smooth = true
+
+ // or it might be 1-color and doesn't matter,
+ // because the current node will disappear
+ vertex.smooth
+ = same_color(a_it->rgba, c_it->rgba)
+ + same_color(a_it->rgba, b_it->rgba)
+ + same_color(d_it->rgba, b_it->rgba)
+ + same_color(d_it->rgba, c_it->rgba) == 2;
+ }
+ } else if ( bottom(b_it) && adjust_splines ) {
+ // right and bottom-right are connected
+
+ bool special = false;
+
+ bool foreign_is_contour = contour_edge(c_it->rgba, d_it->rgba);
+
+ // the neighbor similar in 90° feature
+ bool similar_neighbor_is_contour
+ = contour_edge(a_it->rgba, c_it->rgba);
+
+ if ( contour_edge(a_it->rgba, b_it->rgba)
+ + similar_neighbor_is_contour
+ + foreign_is_contour == 2 ) {
+ vertex.smooth = !foreign_is_contour;
+
+ if ( !vertex.smooth ) {
+ if ( similar_neighbor_is_contour ) {
+ {
+ Point<T> another = vertex;
+ T amount = 0.125
+ - ( topleft(c_it) + bottomright(c_it) )
+ * 0.03125;
+ transform(another, - amount, amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * bottomright(c_it);
+ transform(another, amount, 0.25 - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * topleft(c_it);
+ transform(another, - ( 0.25 - amount ), - amount);
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875 * topleft(c_it);
+ transform(another, - ( 0.75 - amount ), - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ } else {
+ special = true;
+ }
+ }
+ } else {
+ // {right, bottom-right} is the pair with the
+ // angle closest to 180 degrees
+ vertex.smooth = false;
+
+ special = true;
+ }
+
+ if ( special ) {
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(vertex.invisible());
+#else
+ cells_it->vertices.push_back(vertex);
+#endif
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875;
+ transform(another,
+ - ( topleft(b_it) - topright(a_it) ) * amount,
+ // y
+ - ( 0.75
+ - ( topleft(b_it) + topright(a_it) )
+ * amount ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ - ( topleft(b_it) - topright(a_it) ) * amount,
+ // y
+ - ( 0.25
+ - ( topleft(b_it) + topright(a_it) )
+ * amount ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another, - amount
+ * ( bottomleft(d_it) - bottomright(c_it) ),
+ // y
+ 0.25 - amount
+ * ( bottomleft(d_it) + bottomright(c_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ transform(vertex,
+ - ( topleft(b_it) + bottomleft(d_it)
+ - topright(a_it) - bottomright(c_it) )
+ * 0.03125,
+ // y
+ ( topleft(b_it) - bottomleft(d_it)
+ + topright(a_it) - bottomright(c_it) )
+ * 0.03125);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ }
+ } else if ( right(c_it) && adjust_splines ) {
+ // bottom and bottom-right are connected
+
+ bool special = false;
+
+ bool foreign_is_contour = contour_edge(b_it->rgba, d_it->rgba);
+
+ // the neighbor similar in 90° feature
+ bool similar_neighbor_is_contour
+ = contour_edge(a_it->rgba, b_it->rgba);
+
+ if ( contour_edge(a_it->rgba, c_it->rgba)
+ + similar_neighbor_is_contour
+ + foreign_is_contour == 2 ) {
+ vertex.smooth = !foreign_is_contour;
+
+ if ( !vertex.smooth ) {
+ if ( similar_neighbor_is_contour ) {
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(vertex.invisible());
+#else
+ cells_it->vertices.push_back(vertex);
+#endif
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875 * topleft(b_it);
+ transform(another, - amount, - ( 0.75 - amount ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * topleft(b_it);
+ transform(another, - amount, - ( 0.25 - amount ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625 * bottomright(b_it);
+ transform(another, 0.25 - amount, amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ T amount = 0.125
+ - 0.03125 * (topleft(b_it) + bottomright(b_it));
+ transform(vertex, amount, - amount);
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ } else {
+ special = true;
+ }
+ }
+ } else {
+ // {bottom, bottom-right} is the pair with the
+ // angle closest to 180 degrees
+ vertex.smooth = false;
+
+ special = true;
+ }
+
+ if ( special ) {
+ {
+ Point<T> another = vertex;
+ T amount = 0.03125;
+ transform(another,
+ amount
+ * ( topleft(c_it) - topright(d_it)
+ + bottomleft(a_it) - bottomright(b_it) ),
+ // y
+ - amount
+ * ( topleft(c_it) + topright(d_it)
+ - bottomleft(a_it) - bottomright(b_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_1ST_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ 0.25 - amount
+ * ( topright(d_it) + bottomright(b_it) ),
+ // y
+ - amount
+ * ( topright(d_it) - bottomright(b_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_2ND_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.0625;
+ transform(another,
+ - ( 0.25 - amount
+ * ( topleft(c_it) + bottomleft(a_it) ) ),
+ // y
+ - amount
+ * ( topleft(c_it) - bottomleft(a_it) ));
+ another.smooth = true;
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_3RD_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+ {
+ Point<T> another = vertex;
+ T amount = 0.1875;
+ transform(another,
+ - ( 0.75 - amount
+ * ( topleft(c_it) + bottomleft(a_it) ) ),
+ // y
+ - amount
+ * ( topleft(c_it) - bottomleft(a_it) ));
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_4TH_IS_INVISIBLE
+ cells_it->vertices.push_back(another.invisible());
+#else
+ cells_it->vertices.push_back(another);
+#endif
+ }
+#ifdef LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES_5TH_IS_INVISIBLE
+ vertex.visible = false;
+#endif
+ }
+ } else {
+ // there is a 4-color pattern, where the current node
+ // won't be smooth
+ vertex.smooth = false;
+ }
+
+ cells_it->vertices.push_back(vertex);
+ }
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_SIMPLIFIEDVORONOI_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/priv/splines-kopf2011.h b/src/3rdparty/libdepixelize/priv/splines-kopf2011.h
new file mode 100644
index 000000000..c3da58c05
--- /dev/null
+++ b/src/3rdparty/libdepixelize/priv/splines-kopf2011.h
@@ -0,0 +1,167 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_SPLINES_KOPF2011_H
+#define LIBDEPIXELIZE_TRACER_SPLINES_KOPF2011_H
+
+#include "../splines.h"
+#include "homogeneoussplines.h"
+#include "optimization-kopf2011.h"
+
+namespace Tracer {
+
+/**
+ * Maybe the pass-by-value and then move idiom should be more efficient. But all
+ * this is inlinable and we're not even in C++11 yet.
+ */
+template<class T>
+Geom::Path worker_helper(const std::vector< Point<T> > &source1, bool optimize)
+{
+ typedef Geom::LineSegment Line;
+ typedef Geom::QuadraticBezier Quad;
+ typedef typename std::vector< Point<T> >::const_iterator iterator;
+
+ std::vector< Point<T> > source;
+
+ if ( optimize )
+ source = Tracer::optimize(source1);
+ else
+ source = source1;
+
+ iterator it = source.begin();
+ Point<T> prev = source.back();
+ Geom::Path ret(to_geom_point(midpoint(prev, *it)));
+
+ for ( iterator end = source.end() ; it != end ; ++it ) {
+#if LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES
+ // remove redundant points
+ if ( !it->visible ) {
+ prev = *it;
+ continue;
+ }
+#endif // LIBDEPIXELIZE_ENABLE_EXPERIMENTAL_FEATURES
+
+ if ( !prev.visible ) {
+ Geom::Point middle = to_geom_point(midpoint(prev, *it));
+ if ( ret.finalPoint() != middle ) {
+ // All generated invisible points are straight lines
+ ret.appendNew<Line>(middle);
+ }
+ }
+
+ Point<T> next = (it + 1 == end) ? source.front() : *(it + 1);
+ Point<T> middle = midpoint(*it, next);
+
+ if ( !it->smooth ) {
+ ret.appendNew<Line>(to_geom_point(*it));
+ ret.appendNew<Line>(to_geom_point(middle));
+ } else {
+ ret.appendNew<Quad>(to_geom_point(*it), to_geom_point(middle));
+ }
+
+ prev = *it;
+ }
+
+ return ret;
+}
+
+/**
+ * It should be used by worker threads. Convert only one object.
+ */
+template<class T>
+void worker(const typename HomogeneousSplines<T>::Polygon &source,
+ Splines::Path &dest, bool optimize)
+{
+ //dest.pathVector.reserve(source.holes.size() + 1);
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ dest.rgba[i] = source.rgba[i];
+
+ dest.pathVector.push_back(worker_helper(source.vertices, optimize));
+
+ for ( typename std::vector< std::vector< Point<T> > >::const_iterator
+ it = source.holes.begin(), end = source.holes.end()
+ ; it != end ; ++it ) {
+ dest.pathVector.push_back(worker_helper(*it, optimize));
+ }
+}
+
+template<typename T, bool adjust_splines>
+Splines::Splines(const SimplifiedVoronoi<T, adjust_splines> &diagram) :
+ _width(diagram.width()),
+ _height(diagram.height())
+{
+ _paths.reserve(diagram.size());
+
+ for ( typename SimplifiedVoronoi<T, adjust_splines>::const_iterator
+ it = diagram.begin() , end = diagram.end() ; it != end ; ++it ) {
+ Path path;
+
+ path.pathVector
+ .push_back(Geom::Path(to_geom_point(it->vertices.front())));
+
+ for ( typename std::vector< Point<T> >::const_iterator
+ it2 = ++it->vertices.begin(), end2 = it->vertices.end()
+ ; it2 != end2 ; ++it2 ) {
+ path.pathVector.back()
+ .appendNew<Geom::LineSegment>(Geom::Point(it2->x, it2->y));
+ }
+
+ for ( int i = 0 ; i != 4 ; ++i )
+ path.rgba[i] = it->rgba[i];
+
+ _paths.push_back(path);
+ }
+}
+
+template<class T>
+Splines::Splines(const HomogeneousSplines<T> &homogeneousSplines,
+ bool optimize, int /*nthreads*/) :
+ _paths(homogeneousSplines.size()),
+ _width(homogeneousSplines.width()),
+ _height(homogeneousSplines.height())
+{
+ // TODO: It should be threaded
+ iterator paths_it = begin();
+ for ( typename HomogeneousSplines<T>::const_iterator
+ it = homogeneousSplines.begin(), end = homogeneousSplines.end()
+ ; it != end ; ++it, ++paths_it ) {
+ worker<T>(*it, *paths_it, optimize);
+ }
+}
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_SPLINES_KOPF2011_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libdepixelize/splines.h b/src/3rdparty/libdepixelize/splines.h
new file mode 100644
index 000000000..b06ba8ba9
--- /dev/null
+++ b/src/3rdparty/libdepixelize/splines.h
@@ -0,0 +1,120 @@
+/* This file is part of the libdepixelize project
+ Copyright (C) 2013 Vinícius dos Santos Oliveira <vini.ipsmaker@gmail.com>
+
+ GNU Lesser General Public License Usage
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+ GNU General Public License Usage
+ Alternatively, this library may be used under the terms of the GNU General
+ Public License as published by the Free Software Foundation, either version
+ 2 of the License, or (at your option) any later version.
+ You should have received a copy of the GNU General Public License along with
+ this library. If not, see <http://www.gnu.org/licenses/>.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+*/
+
+#ifndef LIBDEPIXELIZE_TRACER_SPLINES_H
+#define LIBDEPIXELIZE_TRACER_SPLINES_H
+
+#include <2geom/pathvector.h>
+#include <glib.h>
+
+namespace Tracer {
+
+template<typename T, bool adjust_splines = true>
+class SimplifiedVoronoi;
+
+template<typename T>
+class HomogeneousSplines;
+
+class Splines
+{
+public:
+ struct Path
+ {
+ /**
+ * It may be benefited from C++11 move references.
+ */
+ Geom::PathVector pathVector;
+
+ guint8 rgba[4];
+ };
+
+ typedef std::vector<Path>::iterator iterator;
+ typedef std::vector<Path>::const_iterator const_iterator;
+
+ Splines() /* = default */ {}
+
+ template<typename T, bool adjust_splines>
+ Splines(const SimplifiedVoronoi<T, adjust_splines> &simplifiedVoronoi);
+
+ /**
+ * There are two levels of optimization. The first level only removes
+ * redundant points of colinear points. The second level uses the
+ * Kopf-Lischinski optimization. The first level is always enabled.
+ * The second level is enabled using \p optimize.
+ */
+ template<typename T>
+ Splines(const HomogeneousSplines<T> &homogeneousSplines, bool optimize,
+ int nthreads);
+
+ // Iterators
+ iterator begin()
+ {
+ return _paths.begin();
+ }
+
+ const_iterator begin() const
+ {
+ return _paths.begin();
+ }
+
+ iterator end()
+ {
+ return _paths.end();
+ }
+
+ const_iterator end() const
+ {
+ return _paths.end();
+ }
+
+ int width() const
+ {
+ return _width;
+ }
+
+ int height() const
+ {
+ return _height;
+ }
+
+private:
+ std::vector<Path> _paths;
+ int _width;
+ int _height;
+};
+
+} // namespace Tracer
+
+#endif // LIBDEPIXELIZE_TRACER_SPLINES_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/3rdparty/libuemf/CMakeLists.txt b/src/3rdparty/libuemf/CMakeLists.txt
new file mode 100644
index 000000000..9e6b68994
--- /dev/null
+++ b/src/3rdparty/libuemf/CMakeLists.txt
@@ -0,0 +1,30 @@
+
+set(libuemf_SRC
+ symbol_convert.c
+ uemf.c
+ uemf_endian.c
+ uemf_print.c
+ uemf_safe.c
+ uemf_utf.c
+ uwmf.c
+ uwmf_endian.c
+ uwmf_print.c
+ upmf.c
+ upmf_print.c
+
+ # -------
+ # Headers
+ symbol_convert.h
+ uemf.h
+ uemf_endian.h
+ uemf_print.h
+ uemf_safe.h
+ uemf_utf.h
+ uwmf.h
+ uwmf_endian.h
+ uwmf_print.h
+ upmf.h
+ upmf_print.h
+)
+
+add_inkscape_lib(uemf_LIB "${libuemf_SRC}")
diff --git a/src/3rdparty/libuemf/README b/src/3rdparty/libuemf/README
new file mode 100644
index 000000000..f65120c30
--- /dev/null
+++ b/src/3rdparty/libuemf/README
@@ -0,0 +1,577 @@
+Overview:
+
+libUEMF is a portable C99 implementation for reading/writing Enhanced Metafile (EMF),
+Enhanced Metafile Format Plus (PMF), and Windows Metafile (WMF) files. libUEMF
+avoids collisions with Microsoft defined functions and values, so portable programs
+which use it and have a Windows version, do not require any conditional logic to
+separate the native GDI support from the WMF/EMF/PMF support proviced by libUEMF. To
+accomplish this libUEMF does not implement GDI calls. Instead, for each WMR/EMR/PMR
+record type, and each object type incorporated into such a record, it provides
+corresponding *_set, *_print, and *_swap functions. For PMF and WMF there are also
+*_get functions, see below. For example, for the U_EMRBITBLT record there are
+corresponding functions: U_EMRBITBLT_set, U_EMRBITBLT_print, and U_EMRBITBLT_swap. A
+few additional functions are provided for assembling the EMF in memory, debugging, and
+converting the EMF file to/from Little Endian representation. (EMF files' internal
+data representation is always Little Endian.)
+
+This code has been tested on 32 bit Ubuntu (LE), 32 bit Mingw, 64 bit Mageia, and 64
+bit Solaris (BE).
+
+libUEMF is released under the GPL 2 license, read the file 'COPYING' for more information
+
+Version 0.2.5, released Jan 03, 2017.
+
+To report bugs or provide feedback send email to David Mathog, mathog@caltech.edu.
+
+--------------------------------------------------------------------------------------------
+Sources:
+
+EMF file Record structure information has been derived from Mingw, Wine, and libEMF
+header files, and from Microsoft's EMF Information pdf, release date March 28,2012,
+link from here:
+
+ http://msdn2.microsoft.com/en-us/library/cc230514.aspx
+
+If the direct link fails the document may be found
+by searching the web for: "[MS-EMF]: Enhanced Metafile Format".
+
+WMF file Record structure information is from some of the same sources, as well as:
+ http://msdn2.microsoft.com/en-us/library/250370.aspx
+
+If the direct link fails the document may be found
+by searching the web for: "[MS-WMF]: Windows Metafile Format"
+
+EMF+ file Record structure is from many helpful responses from Microsoft documentation support
+and from:
+ http://msdn.microsoft.com/en-us/library/cc230724.aspx
+
+If the direct link fails the document may be found
+by searching the web for: "[MS-EMFPLUS]: Enhanced Metafile Format Plus Extensions"
+
+
+Files:
+
+README This file.
+
+COPYING GPL V2 license file.
+
+DOXYFILE Doxygen configuration file, for generating documentation from the source files.
+
+testbuild.sh Small bash script to build all programs. Modify as needed for target platform.
+
+testit.sh Small bash script that generates all test files and compares
+ them with referencess supplied. This script should be edited
+ to match your test system before it is run!
+
+uemf.c Contains the *_set functions needed to construct an EMF file.
+ Also contains auxilliary functions for debugging and constructing
+ EMF files in memory.
+
+uemf.h Definitions and structures for EMF records and objects.
+ Prototypes for *_set and construction functions.
+
+uemf_print.c Contains the *_print functions needed to print the contents of EMF records and objects.
+
+uemf_print.h Prototypes for *_print functions.
+
+uemf_endian.c Contains the *_swap functions needed to rearrange bytes between Big and Little Endian.
+ U_emf_endian() is the only function here that user could should call.
+
+uemf_endian.h Prototype for U_emf_endian() and definitions for Endian type of the local machine.
+
+uemf_safe.c Contains the *_safe functions for EMF records, which verify that all
+ offsets and counts stay within the declared size of a record. Also checks that
+ core record sizes are sane. U_emf_record_safe() is the only _safe function which
+ user code should call directly, and then ONLY after a previous call to
+ U_emf_record_sizeok(), which is in the endian file.
+
+uemf_safe.h Prototype for U_emf_record_safe().
+ .
+upmf.c Contains the *_set and *_get functions needed to construct or read an EMF+ file.
+ Also contains auxilliary functions for debugging and constructing
+ EMF+ files in memory.
+
+upmf.h Definitions and structures for EMF+ records and objects.
+ Prototypes for *_set, *_get and construction functions.
+
+upmf_print.c Contains the *_print functions needed to print the contents of EMF+ records and objects.
+
+upmf_print.h Prototypes for *_print functions.
+
+
+uwmf.c Contains the *_set and *_get functions needed to construct or read a WMF file.
+ Also contains auxilliary functions for debugging and constructing
+ WMF files in memory.
+
+uwmf.h Definitions and structures for WMF records and objects.
+ Prototypes for *_set, *_get and construction functions.
+
+uwmf_print.c Contains the *_print functions needed to print the contents of WMF records and objects.
+
+uwmf_print.h Prototypes for *_print functions.
+
+uwmf_endian.c Contains the *_swap functions needed to rearrange bytes between Big and Little Endian.
+ U_wmf_endian() is the only function here that user could should call.
+
+uwmf_endian.h Prototype for U_wmf_endian() and definitions for Endian type of the local machine.
+
+
+testbed_emf.c Program used for testing emf functions in libUEMF. Run it like: testbed_emf flags.
+ Run with no argument to see what the bit flag values are.
+ It creates a test file "test_libuemf.emf" which should be identical to
+ test_libuemf_ref.emf. (This file cannot be imported from EMF into PowerPoint
+ because it contains dotted lines. Use "testbed_emf 1" to generate a file without
+ any dotted lines. )
+
+testbed_pmf.c Program used for testing EMF+ functions in libUEMF. Similar to testbed_emf.
+
+testbed_wmf.c Program used for testing wmf functions in libUEMF. Similar to testbed_emf.
+
+test_mapmodes_emf.c
+ Program used for testing emf functions in libUEMF. Generates one test file
+ in each MAPMODE, MM_TEXT through MM_ANISOTROPIC, optionally with offsets to the
+ bounds and with particular Viewport origin. (Bounds offset + Viewport Origin
+ sets the Window origin.)
+
+test_mapmodes_wmf.c
+ Program used for testing wmf functions in libUEMF. Similar to test_mapmodes_emf.
+
+reademf.c Utility that that reads an EMF file and emits its contents in text form.
+ Also processes EMF+ files.
+ Run it like: reademf target_file.emf
+
+readwmf.c Utility that that reads an WMF file and emits its contents in text form.
+ Run it like: reademf target_file.wmf
+
+cutemf.c Utility for removing specific records from an EMF file.
+ Run it like: cutemf '2,10,12...13' src_file.emf dst_file.emf
+
+pmfdual2single.c Utility for reducing dual-mode EMF+ file to single mode. Removes all
+ nonessential EMF records.
+ Run it like: pmfdual2single dual_mode.emf single_mode.emf
+
+
+test_libuemf_ref.emf
+ Example output from: testbed_emf 0
+test_libuemf_p_ref.emf
+ Example output from: testbed_pmf 0
+test_libuemf_ref30.emf
+ Example output from: testbed_emf 4
+test_libuemf_ref.wmf
+ Example output from: testbed_wmf 0
+
+test_libuemf_ref_emf.txt
+ Example output from: reademf test_libuemf_ref.emf
+test_libuemf_ref_wmf.txt
+ Example output from: readwmf test_libuemf_ref.wmf
+
+test_mm_<modes>_ref.emf
+ Example output from: test_mapmodes_emf -vX 2000 -vY 1000
+
+emf-inout.cpp,example
+emf-inout.h.example
+emf-print.cpp.example
+emf-print.h.example
+ Example code from Inkscape, demonstrates how to integrate libUEMF with another program.
+
+--------------------------------------------------------------------------------------------
+How to Build:
+
+In Linux/Unix like environments (omit -g flag for production versions):
+
+ Build and install a shared library (example, details may vary) and then build and link
+ the example programs to the shared library:
+ export CFLAGS="-std=c99 -pedantic -Wall -fPIC -g -c"
+ gcc $CFLAGS uemf.c
+ gcc $CFLAGS uemf_print.c
+ gcc $CFLAGS uemf_endian.c
+ gcc $CFLAGS uemf_safe.c
+ gcc $CFLAGS uemf_utf.c
+ gcc $CFLAGS uwmf.c
+ gcc $CFLAGS uwmf_print.c
+ gcc $CFLAGS uwmf_endian.c
+ gcc $CFLAGS upmf.c
+ gcc $CFLAGS upmf_print.c
+ unset CFLAGS
+ gcc -shared -Wl,-soname,libuemf.so.0 \
+ -o libuemf.so.0.0.3 uemf.o uemf_utf.o uemf_safe.o uemf_print.o uemf_endian.o uwmf.o uwmf_print.o uwmf_endian.o upmf.o upmf_print.o -lc
+ ln -s libuemf.so.0.0.3 libuemf.so.0
+ ln -s libuemf.so.0 libuemf.so
+ /bin/cp -f libuemf.so* /usr/local/lib
+ ldconfig
+ export CFLAGS="-std=c99 -pedantic -Wall -g"
+ export CLIBS="-luemf -lm"
+ gcc $CFLAGS -o cutemf cutemf.c $CLIBS
+ gcc $CFLAGS -o pmfdual2single pmfdual2single.c $CLIBS
+ gcc $CFLAGS -o reademf reademf.c $CLIBS
+ gcc $CFLAGS -o readwmf readwmf.c $CLIBS
+ gcc $CFLAGS -o testbed_emf testbed_emf.c $CLIBS
+ gcc $CFLAGS -o testbed_emf testbed_wmf.c $CLIBS
+ gcc $CFLAGS -o test_mapmodes_emf test_mapmodes_emf.c $CLIBS
+
+ For simple development work just build the example programs statically. Set these
+ two variables up first:
+
+ (linux)
+ export CFLAGS="-std=c99 -pedantic -Wall -g"
+ export CLIBS=-lm
+
+ (Sparc)[ Solaris 8 and 9 are Big Endian, and to work around some minor incompatibilities with more recent systems,
+ assuming gcc is installed in /opt/csw and PATH is set correctly to use it]
+ export CLIBS="-lm -L/opt/csw/lib -liconv"
+ export CFLAGS="-DSOL8 -DWORDS_BIGENDIAN -std=c99 -pedantic -Wall -g"
+
+ (win32) [This uses _wfopen() instead of fopen(), with filename translation from UTF-8 to
+ UTF-16LE. This will allow file opens to utilize unicode names. If WIN32 is omitted on Windows
+ file names must be all ASCII. This works in mingw.]
+ export CLIBS="-lm -liconv"
+ export CFLAGS="-DWIN32 -std=c99 -pedantic -Wall -g"
+
+ Then compile with:
+
+ gcc $CFLAGS -o cutemf cutemf.c uemf.c uemf_endian.c uemf_utf.c $CLIBS
+ gcc $CFLAGS -o pmfdual2single pmfdual2single.c uemf.c uemf_endian.c uemf_utf.c upmf.c $CLIBS
+ gcc $CFLAGS -o reademf reademf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS
+ gcc $CFLAGS -o readwmf readwmf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c uwmf.c uwmf_endian.c uwmf_print.c $CLIBS
+ gcc $CFLAGS -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS
+ gcc $CFLAGS -o testbed_pmf testbed_pmf.c uemf.c uemf_endian.c uemf_safe.c uemf_utf.c upmf.c $CLIBS
+ gcc $CFLAGS -o testbed_wmf testbed_wmf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c uwmf.c uwmf_endian.c $CLIBS
+ gcc $CFLAGS -o test_mapmodes_emf test_mapmodes_emf.c uemf.c uemf_endian.c uemf_safe.c uemf_print.c uemf_utf.c upmf.c upmf_print.c $CLIBS
+
+Extra debugging on linux may be enabled in testbed for use under Valgrind. To build that way do instead:
+
+ gcc -std=c99 -pedantic -Wall -g -DU_VALGRIND -o testbed_emf testbed_emf.c uemf.c uemf_endian.c uemf_print.c uemf_utf.c -lm
+
+
+and then compile as above for linux.
+
+
+Dependencies:
+ libiconv (if not built into your compiler)
+ libpng (in the Inkscape examples)
+
+--------------------------------------------------------------------------------------------
+Testing
+
+All modules must also compile without warning under the more restrictive:
+
+ ls -1 *.c \
+ | extract -fmt 'gcc -Werror=format-security -Wall -Wformat -Wformat-security -W -Wno-pointer-sign -O2 -c -o deleteme.o [1,]' \
+ | execinput
+
+--------------------------------------------------------------------------------------------
+Using libUEMF:
+
+To write an EMF file the code first runs two initialization functions: emf_start() and htable_create().
+Then a U_EMRHEADER record is created. This and all subsequent records are appended to the EMF file in
+memory with emf_append(). Whichever other EMR records are desired are also added. The last EMR record
+added must be the single instance of U_EMREOF. Then the code calls emf_finish(), emf_free(), and
+htable_free(). Conversion of byte order on Big Endian machines to Little Endian is carried out
+automatically in emf_finish(), if it is required.
+
+To input an EMF file it is is opened and the data read into a buffer in memory with emf_readdata(). On a
+Big Endian machine this will also swap machine dependent byte orders as needed. At that point end user code
+generally has to do something with the data in each record. The simplest case is to just print it, as shown
+in reademf.c. More typically it must map the operations into its own graphics model, as shown in the
+emf32*.*.example files from Inkscape. Basically the processing program needs to enter a loop, processing
+one record at a time, pulling the record size and type from the first two uint32_t values present in each
+record. It then enters a switch statement with one case for each EMR record type. Each case: statement
+will generally define a pointer to that type of data object. Accessing the data from that pointer is
+illustrated in the code for the corresponding *_print function.
+
+While libUEMF implements _print and _swap functions for all supported EMR records, end user code would
+never call any of these directly. Instead it should either pass a single EMR record
+to U_emf_onerec_print() (see reademf.c) or the entire completed EMF file in memory buffer to U_emf_endian()
+(see testbed.c).
+
+WMF support is similar, except the functions are wmf_start(), wmf_readdata(), and so forth. It is a good
+idea to separate end user WMF and EMF generating code into different modules, in order to avoid accidentally
+writing EMR records to a WMF file and vice versa. WHile EMF objects are aligned in memory and so may be
+accessed using the supplied structs, the ones for WMF files are not usually aligned and so must be accessed
+using the supplied *_get functions. (The difference may not be evident on an x86 platform, but on RISC directly
+trying to access objects in memory will result in access violations.)
+
+Things to be aware of in EMF files:
+
+The usual idea when employing a graphics file type like EMF is to copy a description of the objects in a
+drawing from one program to another. Many of the record types in an EMF file can be thought of as objects,
+they are lines or shapes or bitmaps or text. However, Microsoft's GDI implements binary and ternary raster
+operations (see the descriptions in uemf.h) and most of these operations are not object like, instead they
+combine things on the drawing surface. (There is in each case a copy operation which is object like.)
+Consequently, EMF files which use these other raster operations are not particularly easy to import as
+graphic objects. For instance, when PowerPoint rotates an image and saves it in an EMF the result is not
+a single rotated image object. Instead there is an image containing the rotated image, which is followed by
+masking operations to make the regions outside of the image transparent. There appears to be no standard
+for when and where these subsequent operations will be applied. That is, there is no equivalent of
+"begin path" and "end path" to delineate the start and end of such a compound operation. So a program
+reading such a file has no easy way of figuring out which previous object is being modified by a subsequent
+raster operation. The testbed program provided in this package generates a region which applies all
+binary raster operations in vertical slices to two images. The expected result appears in Windows "Preview",
+but if that region is imported into PowerPoint and converted to objects within that program the result looks
+nothing like what Preview shows.
+
+Support for U_EMREXTTEXTOUTW is much more common than for U_EMRSMALLTEXT. The latter is easier to use,
+since it does not require a Dx array for each text string, but the objects will not import into PowerPoint,
+for instance.
+
+There are two types of dotted/dashed lines. The first uses a set of predefined flags to set the pattern
+and the latter is end user user defined. Both are restricted to lines of width 1. These built in types are
+problematic as key applications cannot handle them properly. PowerPoint cannot convert either type to its
+internal object format. The first form loses the pattern and comes through as solid lines. The second type
+is toxic - even a single dotted line of the second type will prevent the entire EMF from being converted.
+The safest choice is to avoid these patterned line styles entirely. Convert all dots and dashes to separate
+line draws before writing those into the EMF file. libUEMF has no problem reading these records, so code
+should accept them for input.
+
+As with most graphics file formats there is no single object representation of a complex text string (varying
+font size, super/sub script, bold, italic,.etc.). Such text must be decomposed into multiple text strings,
+each with its own formatting. It is unlikely that a subsequent program reading these records from the EMF
+will be able to reassemble them back into a single complex text string.
+
+If a font used in an EMF file is not present on both the sending and receiving systems text will not look the
+same on both. Font substitution is usually silent in most programs, so it may not be evident why the text looks
+a little odd. However, if text is simple, that is, consists of just one line of text without size, color,
+or other changes, then it will look approximately correct after font substitution.
+
+Things to be aware of in WMF files:
+
+WMF graphics are quite limited when compared to EMF graphics. When reading a WMF file it is essential that
+end user code always create a specified object, even if that object is just a placeholder with no real
+function. If any "create" operation presented by the WMF file is not handled then the object indices used
+further along in the WMF file will be off, with very bad results! WMF "regions" are not supported by libUEMF,
+however, if an operation creates regions, this type of placeholder must still be created.
+
+In theory WMF supports mapmodes other than Anisotropic. However, since many programs do not handle
+these other modes it is strongly suggested that any WMF files generated use Anisotropic. For this
+reason there is no test_mapmodes_wmf program - windows XP preview did not show anything when WMF
+files in the other modes were produced. With no positive control there was no way to verify that they
+were valid.
+
+Things to be aware of in EMF+ files:
+
+EMF+ files are usually stored in files with an ".emf" file extension. In this package EMF+ programs,
+functions, and definitions use PMF or PMR to distinguish them from the EMF and WMF material. ("EMF+"
+is not an allowed variable or function name in C.) Dual mode EMF+ files contain both EMF and
+EMF+ records. HOWEVER, those generated by PowerPoint are defective in that they drop all text
+information from the drawing in the EMF+ representation. There is no simple way to line up the
+EMF and EMF+ records in their representations to determine which ones correspond to which drawing
+object. So it is generally not possible to see which elements are represented in both
+representations, or which are missing in one representation. The example file generated by this library
+has only EMF+ records plus the few EMF records needed to wrap them.
+
+Text in EMF+ is placed not from the baseline, as in EMF, but from the upper left corner of the Em square.
+Use the utility function U_PMR_drawstring() to draw text onto a baseline. Font
+substitutions result in badly placed text because even fonts that look similar on the screen may have
+different font metrics. Specifically, font substitutions look worse in EMF+ files than they do
+in EMF files. There is no way to embed fonts, or their font information in the EMF+ file.
+Consequently the text representation within an EMF+ file is not very portable between systems - it will
+only render correctly if the second system has all of the fonts used in the document. The testbed_pmf.c
+program contains some metrics for common fonts which may be used with U_PMR_drawstring()
+to accurately place text.
+
+
+
+--------------------------------------------------------------------------------------------
+History
+
+ (Note, version numbers in files represent the libUEMF release where it was last modified, so not
+ all files will show the same version numbers in each release.)
+
+0.2.5 2017-01-03
+ Fixed a misplaced paren in uemf.h (thanks to Tavmjong Bah for noticing it)
+ Added more U_SIZE_* definitions in uemf.h for "cores" of record types with final
+ variable length arrays, such as U_SIZE_EMRNAMEDESCAPE
+ Removed redundant U_SIZE_BITMAPINFOHEADER definition from uwmf.h
+
+0.2.4 2016-01-26
+ Record EXTSELECTCLIPRGN is supposed to be valid when the RgnDataSize is 0 if the RegionMode
+ is "COPY". Modified safe and print routines so that they would handle this situation.
+ U_PMR_DrawDriverstring seen for the first time and it crashed reademf. Reason, there was a spurious
+ "Tension" value in the structure, which offset values in the record.
+0.2.3 2015-05-28
+ Fixed an assortment of warnings and a couple of bugs flagged by clang static analysis.
+0.2.2 2015-04-28
+ Added lu_crc32 sums to record information in print statements. Affects only reademf and readwmf.
+ The point of this exercise is to enable the detection of differences in binary fields
+ which are not expanded by the print functions. This (re)uses code from Alexander Peslyak.
+ lu_ in name because crc32 conflicts with other libraries, like png.
+ Minor changes to some wmf function parameter types.
+ Minor changes to upmf.c so that it compiles cleanly with clang.
+ Restrict IS_MEM_UNSAFE 2nd parameter to be int or larger and test for negative values.
+ Updated the examples from Inkscape.
+
+0.2.1 2015-04-23
+ Bug in safety check on EMREXTCREATEFONTINDIRECTW because it had alternative "standard" record sizes.
+ Changed warnings on unimplemented EMF record types encounterd in swap or safe from stdout to stderr.
+ Added memory checking for WMF polyline and polygon records, for the variable part and some others.
+ Note: U_WMRCREATEREGION_get does not check that the variable part stays within the record. Current
+ implementation seems to be broken since it does not show up in XP preview.
+0.2.0 2015-03-20
+ Added UEMF _safe functions to better handle corrupt records, where variable sizes fields might
+ have been specified to read past the end of memory. These are records with offsets, arrays
+ with counts, and bitmaps. Also any record which specifies a size smaller than the minimum
+ for that record type.
+ Added similar code for EMF+.
+ These changed the API so the minor version number was bumped by 1.
+
+0.1.18 2015-01-15
+ Pierre-Francois Carpentier sent some EMF examples which used U_EMR_EXTSELECTCLIPRGN, which had
+ not previously been encountered and showed that the handling of regions was broken.
+ Added tests for U_EMRFILLRGN, U_EMRFRAMERGN, U_EMRFRAMERGN, U_EMREXTSELECTCLIPRGN to testbed_emf.
+
+0.1.18 2014-04-28
+ Fixed typo in testbed_wmf.c. "include,include" in one place should have been
+ "exclude,exclude".
+
+0.1.17 2014-04-25
+ Added text clipping tests to testbed_emf.c, testbed_wmf.c, and testbed_pmf.c.
+ Added option to omit clipping tests in testbed's.
+
+0.1.16 2014-04-14
+ Fixed bug in U_WMRRESTOREDC_set.
+ Added clipping tests to testbed_wmf.c.
+
+0.1.15 2014-04-04
+ Changed record flags for U_EMRSELECTCLIPPATH record, it consumes a path but does not ALTER (which
+ forced a premature draw.)
+ Added U_EMROFFSETCLIPRGN test to testbed_emf.c.
+ Changed location on dist drawing where clipping appears.
+
+0.1.14 2014-03-27
+ Fixed bug, in U_PMF_RECTN_set() in upmf.c. Never tested.
+ Fixed a few potential bugs in upmf.c if a null pointer was passed for
+ certain function arguments. (Previously unhandled cases.)
+ Fixed bug, operations setting variables that are never read along those
+ execution paths: upmf_print.c, uemf.c, uwmf.c, uemf_endian.cm upmf.c.
+ Fixed potential (but very unlikely) memory leaks in upmf.c and uemf_utf.c.
+ Added test of U_PMF_RECTN_set to testbed_pmf.c.
+ Changed U_wmr_names() and U_wmr_escnames() to const char* (from char*).
+ Changed method for suppressing unused parameter warnings.
+
+
+0.1.13 2014-03-21
+ Fixed bug, cutemf was messing up the object count (pens, brushes, etc.).
+ Added cutemf can now take ranges of lines.
+ Added testbed_emf generates clipping records for rect and path (but not region).
+
+0.1.12 2014-02-14
+ Documentation change, U_WMRCREATEPATTERNBRUSH is obsolete.
+ Changed wmf_finish() so that it accurately reflects the largest number of objects used,
+ previously it showed the number of appends, which was much larger.
+
+0.1.11 2014-01-29
+ Fixed bug in uwmf.c (wrong minimum record size on U_WMRTEXTOUT)
+ Fixed bug in uwmf.c (U_WMRCREATEPATTERNBRUSH not right)
+ Fixed bug in uwmf_print.c (U_WMRTEXTOUT_print, x,y were reversed)
+ Added error handling to uemf_utf.c for cases where src is a null pointer.
+ Added a test of createpatternbrush to testlib_wmf
+
+0.1.10 2014-01-14
+ Slight changes in documentation for uemf.h.
+ Fixed typo in uemf_endian.c.
+ Fixed a tiny bug in uemf.c (if memory allocation failed a struct would have
+ been deleted before the struct itself.
+
+0.1.9 2013-12-02
+ Added U_PMF_DASHEDLINEDATA_set3 (dot/dash pattern from bits in a uint32_t).
+ Finally was able to make linear gradient gradientfill records work. Updated
+ testbed_emf.c to include that.
+
+0.1.8 2013-11-28
+ Fixed a bug in U_PMF_REGIONNODEPATH_print(), returned size was 4 too small.
+ Changed formatting of U_PMF_REGIONNODECHILDNODES_print() output to improve readability
+ of nested region structures in reademf.
+
+0.1.7 2013-11-20
+ Added EMF+ support.
+ Converted U_RGA and similar from defines to functions, because the method being used
+ in the define (from C99) was not exactly compatible with C++ compilation.
+ Fixed error in test_mapmodes_emf.c where truncation float to integer was used where round
+ have been, resulting in an off by 1 error on some platforms.
+ Eliminated PU_W* pointers.
+ Cleaned up Doxygen comments.
+
+0.1.6. 2013-04-18
+ Added tests which vary background mode, background color, and text color.
+ Slight modification to testit.sh.
+ Updated example files.
+
+0.1.5. 2013-02-13
+ Added missing parameter for WMF RESTOREDC_set/get.
+ Replaced all sizeof() in uwmf.c that referred to UWMF structures with their
+ U_SIZE_* equivalents.
+ Added DIB related WMF _get functions. (Which were missing). These are U_BITMAPCOREHEADER_get,
+ U_BITMAPINFOHEADER_get, wget_dib_params
+ Added const where appropriate to wmf _get functions.
+ Added comprehensive cap,join,miter tests to testbeds.
+ Fixed bug in gradient4_swap().
+ Fixed bug in emr_arc_points_common(), used vector where unit vectors were
+ needed, sometimes flipped direction for arcs/chords.
+ Fixed bug in U_WMFTEXTOUT_get().
+ Changed all dst->Dst and src->Src as call variables in WMF code.
+ Denigrated htable_*() for emf, these become emf_htable_*(), to match naming convention
+ used for wmf_table_*().
+0.1.4 2013-02-04
+ Added code to handle DIB formats that use clrUsed=0 to mean "maximum number of color entries",
+ this showed up in several places, including uemf.c and uemf_print.c.
+ Added some labels to test drawings, slightly rearranged image section, added
+ PNG and JPG image tests and clrUsed=0 images.
+ Modified uemf_endian.c to suppress some compiler warnings.
+ Changed get_DIB_params to return the Compression enumeration.
+ Fixed a typo in uwmf_print.c.
+0.1.3 2013-01-29 Add modes to EMF test programs that changes worldtransform, so
+ that the resulting test files will exercise rotation transforms.
+ Added flags indication for testbed programs.
+ Added test for ROUNDRECT records. Swapped argument orders for those _get/_set operations.
+0.1.2 2013-01-25 Fixed bug revealed by newer gcc on Solaris, assignment of aligned 32 bit to unaligned
+ 16 bit segfaulted.
+0.1.1 2013-01-24 Fixed a few compiler warnings under g++, mostly having to do
+ with signed unsigned comparisons. Eliminated
+ an unused variable from wmf_finish and two stray lines from U_WMRHEADER_set.
+ Cleaned up doxygen comments.
+0.1.0 2013-01-09 Added WMF functions.
+ Simplified print functions. Changed output format of reademf slightly,
+ from U_EMRXXX to U_EMR_XXX - easier to read the new way.
+0.0.11 2012-12-04 Moved UTF and related functions out of uemf.c uemf.h and into uemf_utf.c uemf_utf.h.
+0.0.10 2012-11-28 Discovered that not enough space was being allocated for some UTF conversions. To be
+ safe need 4 bytes per glyph + 1 for UTF-8.
+0.0.9 2012-09-26 Some "uninitialized variable warnings" for certain versions of
+ gcc. These were, as far as I could tell, all spurious, but to quiet them
+ the variables in question were all initialized to 0.
+ Fixed header related print/swap functions - depending on what type of header there
+ could be an access violation.
+ Fixed U_Utf16leToUtf8, could leak memory if the conversion failed.
+ Fixed sections which were not testing for all types of EMF headers.
+ Added RGBA_to_RGBA() so that extractions of subsets of bitmaps (offset, different size)
+ can be handled.
+ Added cutemf. Utility to remove records from an EMF file.
+ Added test_mapmodes. Program to generate test files in each MAPMODE.
+ Added test_mm_(mode)_ref.emf files. These are reference for:
+ test_mapmodes -vX 2000 -vY 1000
+
+0.0.8 2012-09-10 Fixed bug in htable_insert, failed to celear newly added table
+ slots. Fixed test for EMR_GRADIENTFILL triangle mode (rectangle still produces toxic EMF files.)
+ Fixed bug in gradientfill_swap on Solaris.
+
+0.0.7 2012-08-30 Added/fixed tests for hatched, DIB, and mono strokes.
+ Corrected error in U_EMREXTCREATEPEN_set.
+
+0.0.6 2012-08-21 Added/fixed tests for hatched, DIB, and mono fills.
+
+0.0.5 2012-08-08 Minor changes to uemf.c to suppress compiler warnings. Fixed
+ one bug in SET_CB_FROM_PXBMI macro (which was not triggered in testbed
+ because all images were the same size).
+
+0.0.4 2012-07-25 More tests in testbed.c. Found and fixed bugs in
+ U_POLYPOLYLINE and U_POLYPOLYGON related code.
+
+0.0.3 2012-07-24 Warnings related to printing size_t on 64 bit Linux. Correct
+ fix is to use "zd", but gcc -std=c99 does not support that on Solaris 9,
+ the only available big endian system. So use cast or the size_t to (int)
+ and stick with %d format specifier. This should be OK as the sizes involved
+ should not be all that large.
+
+ Bug in core9 affecting U_EMRARC_swap(), and related, on Big Endian.
+
+0.0.2 2012-07-12 first release
+
diff --git a/src/3rdparty/libuemf/symbol_convert.c b/src/3rdparty/libuemf/symbol_convert.c
new file mode 100644
index 000000000..6a919fc2f
--- /dev/null
+++ b/src/3rdparty/libuemf/symbol_convert.c
@@ -0,0 +1,1008 @@
+/** @file
+ * @brief Windows-only Enhanced Metafile input and output.
+ */
+/* Authors:
+ * David mathog <mathog@caltech.edu>
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ *
+ * References:
+ * see unicode-convert.h
+ *
+ * v1.4 08/21/2012 Changed this so that the incoming routines use uint32_t and the outgoing use uint16_t. This gets rid
+ * of wchar_t, which was different sizes on windows/linux, and required lots of ifdef's elsewhere in the code.
+ * v1.3 04/03/2012 Bullets were a problem. Symbol bullet -> Times New Roman Bullet looks OK, but
+ * it looked bad going the other way. Changed mapping Symbol bullet to 2219 (Bullet operator, math
+ * symbol.) That way Symbol bullet can map in and out, while other font bullet an remain in that
+ * font's bullet glyph.
+ * v1.2 03/26/2012 Introduced bug into SingleUnicodeToNon repaired.
+ * v1.1 03/25/2012 Changed ampersand mapping on Wingdings (to avoid normal Ampersand mapping
+ * to Wingdings ampersand when not intended. Fixed access bugs for when no conversion is
+ * mapped in UnicodeToNon and SingleUnicodeToNon
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include "symbol_convert.h"
+
+
+static bool hold_symb=0; // if any of these change, (re)generate the map table
+static bool hold_wing=0;
+static bool hold_zdng=0;
+static bool hold_pua=0;
+static unsigned char *from_unicode=NULL;
+static unsigned char *to_font=NULL;
+
+/* The following tables were created from the files
+ adobe-dingbats.enc.gz
+ adobe-symbol.enc.gz
+ adobe-standard.enc.gz
+
+ which came as part of the X11-font-encodings rpm on Mandriva 2010.
+ The original source for the data must have been Adobe.
+ Some also from:
+ ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt
+ http://www.csn.ul.ie/~caolan/wingdings/proposal/
+ www.renderx.com/Tests/zapf-dingbats.pdf
+
+ The intent is as follows:
+
+ on conversion from ASCII/extended -> Unicode use the appropriate table for
+ the font and change font + code (symbol, zapf dingbats, wingdings).
+ Going the other way, set up two transfer tables,
+ the first is unicode -> 0-FF values, and the seond is unicode -> cvt_to_font.
+ These tables are filled dingbats, wingdings, then symbols, so with the rightmost one getting
+ precedence if both contain the symbol.
+
+ Whereever possible do NOT map two input characters to the same output character, use a slightly
+ off character if it is somewhat close and disambiguates.
+
+v 1.0.0 14-MAR-2012, David Mathog
+
+*/
+
+static unsigned int wingdings_convert[256]={
+ 0xFFFD, // 0x00 no replacement
+ 0xFFFD, // 0x01 no replacement
+ 0xFFFD, // 0x02 no replacement
+ 0xFFFD, // 0x03 no replacement
+ 0xFFFD, // 0x04 no replacement
+ 0xFFFD, // 0x05 no replacement
+ 0xFFFD, // 0x06 no replacement
+ 0xFFFD, // 0x07 no replacement
+ 0xFFFD, // 0x08 no replacement
+ 0xFFFD, // 0x09 no replacement
+ 0xFFFD, // 0x0A no replacement
+ 0xFFFD, // 0x0B no replacement
+ 0xFFFD, // 0x0C no replacement
+ 0xFFFD, // 0x0D no replacement
+ 0xFFFD, // 0x0E no replacement
+ 0xFFFD, // 0x0F no replacement
+ 0xFFFD, // 0x10 no replacement
+ 0xFFFD, // 0x11 no replacement
+ 0xFFFD, // 0x12 no replacement
+ 0xFFFD, // 0x13 no replacement
+ 0xFFFD, // 0x14 no replacement
+ 0xFFFD, // 0x15 no replacement
+ 0xFFFD, // 0x16 no replacement
+ 0xFFFD, // 0x17 no replacement
+ 0xFFFD, // 0x18 no replacement
+ 0xFFFD, // 0x19 no replacement
+ 0xFFFD, // 0x1A no replacement
+ 0xFFFD, // 0x1B no replacement
+ 0xFFFD, // 0x1C no replacement
+ 0xFFFD, // 0x1D no replacement
+ 0xFFFD, // 0x1E no replacement
+ 0xFFFD, // 0x1F no replacement
+ 0x0020, // 0x20 SPACE
+ 0x270E, // 0x21 LOWER RIGHT PENCIL (close, but not exact)
+ 0x2702, // 0x22 BLACK SCISSORS
+ 0x2701, // 0x23 UPPER BLADE SCISSORS
+ 0xFFFD, // 0x24 no replacement
+ 0xFFFD, // 0x25 no replacement
+ 0xFFFD, // 0x26 no replacement
+ 0xFFFD, // 0x27 no replacement
+ 0x260E, // 0x28 BLACK TELEPHONE
+ 0x2706, // 0x29 TELEPHONE LOCATION SIGN (close, but not exact)
+ 0x2709, // 0x2A ENVELOPE
+ 0x2709, // 0x2B ENVELOPE (close, but not exact)
+ 0xFFFD, // 0x2C no replacement
+ 0xFFFD, // 0x2D no replacement
+ 0xFFFD, // 0x2E no replacement
+ 0xFFFD, // 0x2F no replacement
+ 0xFFFD, // 0x30 no replacement
+ 0xFFFD, // 0x31 no replacement
+ 0xFFFD, // 0x32 no replacement
+ 0xFFFD, // 0x33 no replacement
+ 0xFFFD, // 0x34 no replacement
+ 0xFFFD, // 0x35 no replacement
+ 0x231B, // 0x36 HOURGLASS
+ 0x2328, // 0x37 KEYBOARD
+ 0xFFFD, // 0x38 no replacement
+ 0xFFFD, // 0x39 no replacement
+ 0xFFFD, // 0x3A no replacement
+ 0xFFFD, // 0x3B no replacement
+ 0xFFFD, // 0x3C no replacement
+ 0xFFFD, // 0x3D no replacement
+ 0x2707, // 0x3E TAPE DRIVE
+ 0x270D, // 0x3F WRITING HAND
+ 0x270D, // 0x40 WRITING HAND (close, but not exact)
+ 0x270C, // 0x41 VICTORY HAND
+ 0xFFFD, // 0x42 3 FINGER UP HAND (no replacement)
+ 0xFFFD, // 0x43 THUMBS UP HAND (no replacement)
+ 0xFFFD, // 0x44 THUMBS DOWN HAND (no replacement)
+ 0x261C, // 0x45 WHITE LEFT POINTING INDEX
+ 0x261E, // 0x46 WHITE RIGHT POINTING INDEX
+ 0x261D, // 0x47 WHITE UP POINTING INDEX
+ 0x261F, // 0x48 WHITE DOWN POINTING INDEX
+ 0xFFFD, // 0x49 OPEN HAND (no replacement)
+ 0x263A, // 0x4A WHITE SMILING FACE
+ 0x263A, // 0x4B WHITE SMILING FACE (close, but not exact)
+ 0x2639, // 0x4C WHITE FROWNING FACE
+ 0xFFFD, // 0x4D BOMB (no replacement. 1F4A3)
+ 0x2620, // 0x4E SKULL AND CROSSBONES
+ 0x2690, // 0x4F WHITE FLAG (not exact)
+ 0x2691, // 0x50 WHITE PENANT (use BLACK FLAG)
+ 0x2708, // 0x51 AIRPLANE
+ 0x263C, // 0x52 WHITE SUN WITH RAYS (close, but not exact)
+ 0x2602, // 0x53 RAINDROP (use UMBRELLA)
+ 0x2744, // 0x54 SNOWFLAKE
+ 0x271D, // 0x55 WHITE LATIN CROSS (use BLACK CROSS)
+ 0x271E, // 0x56 SHADOWED WHITE LATIN CROSS
+ 0x271F, // 0x57 CELTIC CROSS (use OUTLINED LATIN CROSS)
+ 0x2720, // 0x58 MALTESE CROSS
+ 0x2721, // 0x59 STAR OF DAVID
+ 0x262A, // 0x5A STAR AND CRESCENT
+ 0x262F, // 0x5B YIN YANG
+ 0x0950, // 0x5C DEVANGARI OM CORRECT|CLOSE: Perhaps PROPOSE SACRED OM ?
+ 0x2638, // 0x5D WHEEL OF DHARMA
+ 0x2648, // 0x5E ARIES
+ 0x2649, // 0x5F TAURUS
+ 0x264A, // 0x60 GEMINI
+ 0x264B, // 0x61 CANCER
+ 0x264C, // 0x62 LEO
+ 0x264D, // 0x63 VIRGO
+ 0x264E, // 0x64 LIBRA
+ 0x264F, // 0x65 SCORPIUS
+ 0x2650, // 0x66 SAGITTARIUS
+ 0x2651, // 0x67 CAPRICORN
+ 0x2652, // 0x68 AQUARIUS
+ 0x2653, // 0x69 PISCES
+ 0xFFFD, // 0x6A LOWER CASE AMPERSAND)?) (no replacement)
+ 0xFF06, // 0x6B AMPERSAND (use FULL WIDTH AMPERSAND, close, but not exact. Do NOT use 0026, or it maps normal Ampersands to Wingdings Ampersand)
+ 0x25CF, // 0x6C BLACK CIRCLE
+ 0x274D, // 0x6D SHADOWED WHITE CIRCLE (close, but not exact)
+ 0x25A0, // 0x6E BLACK SQUARE
+ 0x25A3, // 0x6F WHITE SQUARE IN BLACK RECTANGLE (use BLACK SQUSRE in WHITE SQUARE)
+ 0x25A1, // 0x70 WHITE SQUARE (close, but not exact)
+ 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE
+ 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE
+ 0x25CA, // 0x73 LOZENGE (close, but not exact)
+ 0x25CA, // 0x74 LOZENGE (close, but not exact)
+ 0x25C6, // 0x75 BLACK DIAMOND
+ 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X
+ 0x25C6, // 0x77 BLACK DIAMOND (close, but not exact)
+ 0x2327, // 0x78 X IN A RECTANGLE BOX
+ 0x2353, // 0x79 APL FUNCTIONAL SYMBOL QUAD UP CARET(close, but not exact)
+ 0x2318, // 0x7A PLACE OF INTEREST SIGN
+ 0x2740, // 0x7B WHITE FLORETTE (close, but not exact)
+ 0x273F, // 0x7C BLACK FLORETTE (close, but not exact)
+ 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT
+ 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
+ 0xFFFD, // 0x7F unused
+ 0x24EA, // 0x80 CIRCLED DIGIT ZERO
+ 0x2460, // 0x81 CIRCLED DIGIT ONE
+ 0x2461, // 0x82 CIRCLED DIGIT TWO
+ 0x2462, // 0x83 CIRCLED DIGIT THREE
+ 0x2463, // 0x84 CIRCLED DIGIT FOUR
+ 0x2464, // 0x85 CIRCLED DIGIT FIVE
+ 0x2465, // 0x86 CIRCLED DIGIT SIX
+ 0x2466, // 0x87 CIRCLED DIGIT SEVEN
+ 0x2467, // 0x88 CIRCLED DIGIT EIGHT
+ 0x2468, // 0x89 CIRCLED DIGIT NINE
+ 0x2469, // 0x8A CIRCLED NUMBER TEN
+ 0xFFFD, // 0x8B no replacement
+ 0x2776, // 0x8C DINGBAT NEGATIVE CIRCLED DIGIT ONE
+ 0x2777, // 0x8D DINGBAT NEGATIVE CIRCLED DIGIT TWO
+ 0x2778, // 0x8E DINGBAT NEGATIVE CIRCLED DIGIT THREE
+ 0x2779, // 0x8F DINGBAT NEGATIVE CIRCLED DIGIT FOUR
+ 0x277A, // 0x90 DINGBAT NEGATIVE CIRCLED DIGIT FIVE
+ 0x277B, // 0x91 DINGBAT NEGATIVE CIRCLED DIGIT SIX
+ 0x277C, // 0x92 DINGBAT NEGATIVE CIRCLED DIGIT SEVEN
+ 0x277D, // 0x93 DINGBAT NEGATIVE CIRCLED DIGIT EIGHT
+ 0x277E, // 0x94 DINGBAT NEGATIVE CIRCLED DIGIT NINE
+ 0x277F, // 0x95 DINGBAT NEGATIVE CIRCLED NUMBER TEN
+ 0xFFFD, // 0x96 ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x97 REVERSED ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x98 REVERSED ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x99 ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x9A ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x9B REVERSED ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x9C REVERSED ROTATED FLORAL HEART BULLET (no good replacement)
+ 0xFFFD, // 0x9D ROTATED FLORAL HEART BULLET (no good replacement)
+ 0x2219, // 0x9E BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET)
+ 0x25CF, // 0x9F BLACK CIRCLE (close, but not exact)
+ 0x25AA, // 0xA0 BLACK VERY SMALL SQUARE
+ 0x26AA, // 0xA1 WHITE CIRCLE (use MEDIUM WHITE CIRCLE)
+ 0x25CB, // 0xA2 HEAVY WHITE CIRCLE (use WHITE CIRCLE)
+ 0x25CD, // 0xA3 HEAVIEST CIRCLE (use CIRCLE WITH VERTICAL FILL)
+ 0x25C9, // 0xA4 CIRCLE WITH A CENTRAL DOT (close, dot much bigger)
+ 0x25CE, // 0xA5 BULLSEYE
+ 0x274D, // 0xA6 SHADOWED WHITE CIRCLE (close, but not exact)
+ 0xFFED, // 0xA7 BLACK SMALL SQUARE
+ 0x2610, // 0xA8 WHITE SQUARE (close, but not exact, different fro 25A1)
+ 0xFFFD, // 0xA9 no replacement
+ 0x2726, // 0xAA BLACK FOUR POINTED STAR MAYBE
+ 0x2605, // 0xAB BLACK STAR
+ 0x2736, // 0xAC SIX POINTED BLACK STAR
+ 0x2737, // 0xAD EIGHT POINTED RECTILINEAR BLACK STAR
+ 0x2738, // 0xAE TWELVE POINTED BLACK STAR
+ 0x2735, // 0xAF EIGHT POINTED PINWHEEL STAR
+ 0xFFFD, // 0xB0 no replacement
+ 0xFFFD, // 0xB1 no replacement
+ 0x2727, // 0xB2 WHITE FOUR POINTED STAR
+ 0x2726, // 0xB3 ROTATED WHITE FOUR POINTED STAR (use BLACK FOUR POINTED STAR)
+ 0xFFFD, // 0xB4 REPLACEMENT CHARACTER (close, but not exact)
+ 0x272A, // 0xB5 CIRCLED WHITE STAR
+ 0x2730, // 0xB6 SHADOWED WHITE STAR
+ 0xFFFD, // 0xB7 ANALOG CLOCK 1 (no replacement)
+ 0xFFFD, // 0xB8 ANALOG CLOCK 2 (no replacement)
+ 0xFFFD, // 0xB9 ANALOG CLOCK 3 (no replacement)
+ 0xFFFD, // 0xBA ANALOG CLOCK 4 (no replacement)
+ 0xFFFD, // 0xBB ANALOG CLOCK 5 (no replacement)
+ 0xFFFD, // 0xBC ANALOG CLOCK 6 (no replacement)
+ 0xFFFD, // 0xBD ANALOG CLOCK 7 (no replacement)
+ 0xFFFD, // 0xBE ANALOG CLOCK 8 (no replacement)
+ 0xFFFD, // 0xBF ANALOG CLOCK 9 (no replacement)
+ 0xFFFD, // 0xC0 ANALOG CLOCK 10 (no replacement)
+ 0xFFFD, // 0xC1 ANALOG CLOCK 11 (no replacement)
+ 0xFFFD, // 0xC2 ANALOG CLOCK 12 (no replacement)
+ 0x21B2, // 0xC3 TURN ARROW DOWN AND LEFT (Meaning close, shape differs)
+ 0x21B3, // 0xC4 TURN ARROW DOWN AND RIGHT (Meaning close, shape differs)
+ 0x21B0, // 0xC5 TURN ARROW UP AND LEFT (Meaning close, shape differs)
+ 0x21B1, // 0xC6 TURN ARROW UP AND RIGHT (Meaning close, shape differs)
+ 0x2B11, // 0xC7 TURN ARROW LEFT AND UP (Meaning close, shape differs)
+ 0x2B0F, // 0xC8 TURN ARROW RIGHT AND UP (Meaning close, shape differs)
+ 0x2B10, // 0xC9 TURN ARROW LEFT AND DOWN (Meaning close, shape differs)
+ 0x2B0E, // 0xCA TURN ARROW RIGHT AND DOWN (Meaning close, shape differs)
+ 0xFFFD, // 0xCB no replacement
+ 0xFFFD, // 0xCC no replacement
+ 0xFFFD, // 0xCD no replacement
+ 0xFFFD, // 0xCE no replacement
+ 0xFFFD, // 0xCF no replacement
+ 0xFFFD, // 0xD0 no replacement
+ 0xFFFD, // 0xD1 no replacement
+ 0xFFFD, // 0xD2 no replacement
+ 0xFFFD, // 0xD3 no replacement
+ 0xFFFD, // 0xD4 no replacement
+ 0x232B, // 0xD5 ERASE TO THE LEFT
+ 0x2326, // 0xD6 ERASE TO THE RIGHT
+ 0x25C0, // 0xD7 THREE-D LIGHTED LEFT ARROWHEAD (Use BLACK LEFT TRIANGLE)
+ 0x25B6, // 0xD8 THREE-D LIGHTED RIGHT ARROWHEAD (Use BLACK RIGHT TRIANGLE, 27A2 is exact but has no other directions)
+ 0x25B2, // 0xD9 THREE-D LIGHTED UP ARROWHEAD (Use BLACK UP TRIANGLE)
+ 0x25BC, // 0xDA THREE-D LIGHTED DOWN ARROWHEAD (Use BLACK DOWN TRIANGLE)
+ 0xFFFD, // 0xDB no replacement
+ 0x27B2, // 0xDC CIRCLED HEAVY WHITE RIGHTWARDS ARROW
+ 0xFFFD, // 0xDD no replacement
+ 0xFFFD, // 0xDE no replacement
+ 0x2190, // 0xDF LEFT ARROW
+ 0x2192, // 0xE0 RIGHT ARROW
+ 0x2191, // 0xE1 UP ARROW
+ 0x2193, // 0xE2 DOWN ARROW
+ 0x2196, // 0xE3 UPPER LEFT ARROW
+ 0x2197, // 0xE4 UPPER RIGHT ARROW
+ 0x2199, // 0xE5 LOWER LEFT ARROW
+ 0x2198, // 0xE6 LOWER RIGHT ARROW
+ 0x2B05, // 0xE7 HEAVY LEFT BLACK ARROW (same as regular BLACK ARROW)
+ 0x2B08, // 0xE8 HEAVY RIGHT BLACK ARROW (same as regular BLACK ARROW)
+ 0x2B06, // 0xE9 HEAVY UP BLACK ARROW (no equiv BLACK ARROW)
+ 0x2B07, // 0xEA HEAVY DOWN BLACK ARROW (same as regular BLACK ARROW)
+ 0x2B09, // 0xEB HEAVY UPPER LEFT BLACK ARROW same as regular BLACK ARROW)
+ 0x2B08, // 0xEC HEAVY UPPER RIGHT BLACK ARROW same as regular BLACK ARROW)
+ 0x2B0B, // 0xED HEAVY LOWER LEFT BLACK ARROW (same as regular BLACK ARROW)
+ 0x2B0A, // 0xEE HEAVY LOWER RIGHT BLACK ARROW (same as regular BLACK ARROW)
+ 0x21E6, // 0xEF LEFTWARDS WHITE ARROW
+ 0x21E8, // 0xF0 RIGHTWARDS WHITE ARROW
+ 0x21E7, // 0xF1 UPWARDS WHITE ARROW
+ 0x21E9, // 0xF2 DOWNWARDS WHITE ARROW
+ 0x21D4, // 0xF3 LEFT RIGHT DOUBLE ARROW
+ 0x21D5, // 0xF4 UP DOWN DOUBLE ARROW
+ 0x21D6, // 0xF5 NORTH WEST DOUBLE ARROW (close, but not exact)
+ 0x21D7, // 0xF6 NORTH EAST DOUBLE ARROW (close, but not exact)
+ 0x21D9, // 0xF7 SOUTH WEST DOUBLE ARROW (close, but not exact)
+ 0x21D8, // 0xF8 SOUTH EAST DOUBLE ARROW (close, but not exact)
+ 0xFFFD, // 0xF9 no replacement
+ 0xFFFD, // 0xFA no replacement
+ 0x2717, // 0xFB BALLOT X
+ 0x2713, // 0xFC CHECK MARK
+ 0x2612, // 0xFD BALLOT BOX WITH X
+ 0x2611, // 0xFE BALLOT BOX WITH CHECK
+ 0xFFFD // 0xFF no replacement
+};
+
+/* characters from zapf dingbat font, conversion to a unicode font. Change both the
+ code and the font on conversion. These are untested as the development machine did
+ not have the font installed. */
+static unsigned int dingbats_convert[256]={
+ 0xFFFD, // 0x00 no replacement
+ 0xFFFD, // 0x01 no replacement
+ 0xFFFD, // 0x02 no replacement
+ 0xFFFD, // 0x03 no replacement
+ 0xFFFD, // 0x04 no replacement
+ 0xFFFD, // 0x05 no replacement
+ 0xFFFD, // 0x06 no replacement
+ 0xFFFD, // 0x07 no replacement
+ 0xFFFD, // 0x08 no replacement
+ 0xFFFD, // 0x09 no replacement
+ 0xFFFD, // 0x0A no replacement
+ 0xFFFD, // 0x0B no replacement
+ 0xFFFD, // 0x0C no replacement
+ 0xFFFD, // 0x0D no replacement
+ 0xFFFD, // 0x0E no replacement
+ 0xFFFD, // 0x0F no replacement
+ 0xFFFD, // 0x10 no replacement
+ 0xFFFD, // 0x11 no replacement
+ 0xFFFD, // 0x12 no replacement
+ 0xFFFD, // 0x13 no replacement
+ 0xFFFD, // 0x14 no replacement
+ 0xFFFD, // 0x15 no replacement
+ 0xFFFD, // 0x16 no replacement
+ 0xFFFD, // 0x17 no replacement
+ 0xFFFD, // 0x18 no replacement
+ 0xFFFD, // 0x19 no replacement
+ 0xFFFD, // 0x1A no replacement
+ 0xFFFD, // 0x1B no replacement
+ 0xFFFD, // 0x1C no replacement
+ 0xFFFD, // 0x1D no replacement
+ 0xFFFD, // 0x1E no replacement
+ 0xFFFD, // 0x1F no replacement
+ 0x0020, // 0x20 SPACE
+ 0x2701, // 0x21 UPPER BLADE SCISSORS
+ 0x2702, // 0x22 BLACK SCISSORS
+ 0x2703, // 0x23 LOWER BLADE SCISSORS
+ 0x2704, // 0x24 WHITE SCISSORS
+ 0x260E, // 0x25 BLACK TELEPHONE
+ 0x2706, // 0x26 TELEPHONE LOCATION SIGN
+ 0x2707, // 0x27 TAPE DRIVE
+ 0x2708, // 0x28 AIRPLANE
+ 0x2709, // 0x29 ENVELOPE
+ 0x261B, // 0x2A BLACK RIGHT POINTING INDEX
+ 0x261E, // 0x2B WHITE RIGHT POINTING INDEX
+ 0x270C, // 0x2C VICTORY HAND
+ 0x270D, // 0x2D WRITING HAND
+ 0x270E, // 0x2E LOWER RIGHT PENCIL
+ 0x270F, // 0x2F PENCIL
+ 0x2710, // 0x30 UPPER RIGHT PENCIL
+ 0x2711, // 0x31 WHITE NIB
+ 0x2712, // 0x32 BLACK NIB
+ 0x2713, // 0x33 CHECK MARK
+ 0x2714, // 0x34 HEAVY CHECK MARK
+ 0x2715, // 0x35 MULTIPLICATION X
+ 0x2716, // 0x36 HEAVY MULTIPLICATION X
+ 0x2717, // 0x37 BALLOT X
+ 0x2718, // 0x38 HEAVY BALLOT X
+ 0x2719, // 0x39 OUTLINED GREEK CROSS
+ 0x271A, // 0x3A HEAVY GREEK CROSS
+ 0x271B, // 0x3B OPEN CENTRE CROSS
+ 0x271C, // 0x3C HEAVY OPEN CENTRE CROSS
+ 0x271D, // 0x3D LATIN CROSS
+ 0x271E, // 0x3E SHADOWED WHITE LATIN CROSS
+ 0x271F, // 0x3F OUTLINED LATIN CROSS
+ 0x2720, // 0x40 MALTESE CROSS
+ 0x2721, // 0x41 STAR OF DAVID
+ 0x2722, // 0x42 FOUR TEARDROP-SPOKED ASTERISK
+ 0x2723, // 0x43 FOUR BALLOON-SPOKED ASTERISK
+ 0x2724, // 0x44 HEAVY FOUR BALLOON-SPOKED ASTERISK
+ 0x2725, // 0x45 FOUR CLUB-SPOKED ASTERISK
+ 0x2726, // 0x46 BLACK FOUR POINTED STAR
+ 0x2727, // 0x47 WHITE FOUR POINTED STAR
+ 0x2605, // 0x48 BLACK STAR
+ 0x2729, // 0x49 STRESS OUTLINED WHITE STAR
+ 0x272A, // 0x4A CIRCLED WHITE STAR
+ 0x272B, // 0x4B OPEN CENTRE BLACK STAR
+ 0x272C, // 0x4C BLACK CENTRE WHITE STAR
+ 0x272D, // 0x4D OUTLINED BLACK STAR
+ 0x272E, // 0x4E HEAVY OUTLINED BLACK STAR
+ 0x272F, // 0x4F PINWHEEL STAR
+ 0x2730, // 0x50 SHADOWED WHITE STAR
+ 0x2731, // 0x51 HEAVY ASTERISK
+ 0x2732, // 0x52 OPEN CENTRE ASTERISK
+ 0x2733, // 0x53 EIGHT SPOKED ASTERISK
+ 0x2734, // 0x54 EIGHT POINTED BLACK STAR
+ 0x2735, // 0x55 EIGHT POINTED PINWHEEL STAR
+ 0x2736, // 0x56 SIX POINTED BLACK STAR
+ 0x2737, // 0x57 EIGHT POINTED RECTILINEAR BLACK STAR
+ 0x2738, // 0x58 HEAVY EIGHT POINTED RECTILINEAR BLACK STAR
+ 0x2739, // 0x59 TWELVE POINTED BLACK STAR
+ 0x273A, // 0x5A SIXTEEN POINTED ASTERISK
+ 0x273B, // 0x5B TEARDROP-SPOKED ASTERISK
+ 0x273C, // 0x5C OPEN CENTRE TEARDROP-SPOKED ASTERISK
+ 0x273D, // 0x5D HEAVY TEARDROP-SPOKED ASTERISK
+ 0x273E, // 0x5E SIX PETALLED BLACK AND WHITE FLORETTE
+ 0x273F, // 0x5F BLACK FLORETTE
+ 0x2740, // 0x60 WHITE FLORETTE
+ 0x2741, // 0x61 EIGHT PETALLED OUTLINED BLACK FLORETTE
+ 0x2742, // 0x62 CIRCLED OPEN CENTRE EIGHT POINTED STAR
+ 0x2743, // 0x63 HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK
+ 0x2744, // 0x64 SNOWFLAKE
+ 0x2745, // 0x65 TIGHT TRIFOLIATE SNOWFLAKE
+ 0x2746, // 0x66 HEAVY CHEVRON SNOWFLAKE
+ 0x2747, // 0x67 SPARKLE
+ 0x2748, // 0x68 HEAVY SPARKLE
+ 0x2749, // 0x69 BALLOON-SPOKED ASTERISK
+ 0x274A, // 0x6A EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+ 0x274B, // 0x6B HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+ 0x25CF, // 0x6C BLACK CIRCLE
+ 0x274D, // 0x6D SHADOWED WHITE CIRCLE
+ 0x25A0, // 0x6E BLACK SQUARE
+ 0x274F, // 0x6F LOWER RIGHT DROP-SHADOWED WHITE SQUARE
+ 0x2750, // 0x70 UPPER RIGHT DROP-SHADOWED WHITE SQUARE
+ 0x2751, // 0x71 LOWER RIGHT SHADOWED WHITE SQUARE
+ 0x2752, // 0x72 UPPER RIGHT SHADOWED WHITE SQUARE
+ 0x25B2, // 0x73 BLACK UP-POINTING TRIANGLE
+ 0x25BC, // 0x74 BLACK DOWN-POINTING TRIANGLE
+ 0x25C6, // 0x75 BLACK DIAMOND
+ 0x2756, // 0x76 BLACK DIAMOND MINUS WHITE X
+ 0x25D7, // 0x77 RIGHT HALF BLACK CIRCLE
+ 0x2758, // 0x78 LIGHT VERTICAL BAR
+ 0x2759, // 0x79 MEDIUM VERTICAL BAR
+ 0x275A, // 0x7A HEAVY VERTICAL BAR
+ 0x275B, // 0x7B HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT
+ 0x275C, // 0x7C HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT
+ 0x275D, // 0x7D HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT
+ 0x275E, // 0x7E HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
+ 0xFFFD, // 0x7F no replacement
+ 0xF8D7, // 0x80 MEDIUM LEFT PARENTHESIS ORNAMENT
+ 0xF8D8, // 0x81 MEDIUM RIGHT PARENTHESIS ORNAMENT
+ 0xF8D9, // 0x82 MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+ 0xF8DA, // 0x83 MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+ 0xF8DB, // 0x84 MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+ 0xF8DC, // 0x85 MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ 0xF8DD, // 0x86 HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ 0xF8DE, // 0x87 HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+ 0xF8DF, // 0x88 HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+ 0xF8E0, // 0x89 HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+ 0xF8E1, // 0x8A LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ 0xF8E2, // 0x8B LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ 0xF8E3, // 0x8C MEDIUM LEFT CURLY BRACKET ORNAMENT
+ 0xF8E4, // 0x8D MEDIUM RIGHT CURLY BRACKET ORNAMENT
+ 0xFFFD, // 0x8E no replacement
+ 0xFFFD, // 0x8F no replacement
+ 0xFFFD, // 0x90 no replacement
+ 0xFFFD, // 0x91 no replacement
+ 0xFFFD, // 0x92 no replacement
+ 0xFFFD, // 0x93 no replacement
+ 0xFFFD, // 0x94 no replacement
+ 0xFFFD, // 0x95 no replacement
+ 0xFFFD, // 0x96 no replacement
+ 0xFFFD, // 0x97 no replacement
+ 0xFFFD, // 0x98 no replacement
+ 0xFFFD, // 0x99 no replacement
+ 0xFFFD, // 0x9A no replacement
+ 0xFFFD, // 0x9B no replacement
+ 0xFFFD, // 0x9C no replacement
+ 0xFFFD, // 0x9D no replacement
+ 0xFFFD, // 0x9E no replacement
+ 0xFFFD, // 0x9F no replacement
+ 0xFFFD, // 0xA0 no replacement
+ 0x2761, // 0xA1 CURVED STEM PARAGRAPH SIGN ORNAMENT
+ 0x2762, // 0xA2 HEAVY EXCLAMATION MARK ORNAMENT
+ 0x2763, // 0xA3 HEAVY HEART EXCLAMATION MARK ORNAMENT
+ 0x2764, // 0xA4 HEAVY BLACK HEART
+ 0x2765, // 0xA5 ROTATED HEAVY BLACK HEART BULLET
+ 0x2766, // 0xA6 FLORAL HEART
+ 0x2767, // 0xA7 ROTATED FLORAL HEART BULLET
+ 0x2663, // 0xA8 BLACK CLUB SUIT
+ 0x2666, // 0xA9 BLACK DIAMOND SUIT
+ 0x2665, // 0xAA BLACK HEART SUIT
+ 0x2660, // 0xAB BLACK SPADE SUIT
+ 0x2460, // 0xAC CIRCLED DIGIT ONE
+ 0x2461, // 0xAD CIRCLED DIGIT TWO
+ 0x2462, // 0xAE CIRCLED DIGIT THREE
+ 0x2463, // 0xAF CIRCLED DIGIT FOUR
+ 0x2464, // 0xB0 CIRCLED DIGIT FIVE
+ 0x2465, // 0xB1 CIRCLED DIGIT SIX
+ 0x2466, // 0xB2 CIRCLED DIGIT SEVEN
+ 0x2467, // 0xB3 CIRCLED DIGIT EIGHT
+ 0x2468, // 0xB4 CIRCLED DIGIT NINE
+ 0x2469, // 0xB5 CIRCLED NUMBER TEN
+ 0x2776, // 0xB6 DINGBAT NEGATIVE CIRCLED DIGIT ONE
+ 0x2777, // 0xB7 DINGBAT NEGATIVE CIRCLED DIGIT TWO
+ 0x2778, // 0xB8 DINGBAT NEGATIVE CIRCLED DIGIT THREE
+ 0x2779, // 0xB9 DINGBAT NEGATIVE CIRCLED DIGIT FOUR
+ 0x277A, // 0xBA DINGBAT NEGATIVE CIRCLED DIGIT FIVE
+ 0x277B, // 0xBB DINGBAT NEGATIVE CIRCLED DIGIT SIX
+ 0x277C, // 0xBC DINGBAT NEGATIVE CIRCLED DIGIT SEVEN
+ 0x277D, // 0xBD DINGBAT NEGATIVE CIRCLED DIGIT EIGHT
+ 0x277E, // 0xBE DINGBAT NEGATIVE CIRCLED DIGIT NINE
+ 0x277F, // 0xBF DINGBAT NEGATIVE CIRCLED NUMBER TEN
+ 0x2780, // 0xC0 DINGBAT CIRCLED SANS-SERIF DIGIT ONE
+ 0x2781, // 0xC1 DINGBAT CIRCLED SANS-SERIF DIGIT TWO
+ 0x2782, // 0xC2 DINGBAT CIRCLED SANS-SERIF DIGIT THREE
+ 0x2783, // 0xC3 DINGBAT CIRCLED SANS-SERIF DIGIT FOUR
+ 0x2784, // 0xC4 DINGBAT CIRCLED SANS-SERIF DIGIT FIVE
+ 0x2785, // 0xC5 DINGBAT CIRCLED SANS-SERIF DIGIT SIX
+ 0x2786, // 0xC6 DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN
+ 0x2787, // 0xC7 DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT
+ 0x2788, // 0xC8 DINGBAT CIRCLED SANS-SERIF DIGIT NINE
+ 0x2789, // 0xC9 DINGBAT CIRCLED SANS-SERIF NUMBER TEN
+ 0x278A, // 0xCA DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE
+ 0x278B, // 0xCB DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO
+ 0x278C, // 0xCC DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE
+ 0x278D, // 0xCD DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR
+ 0x278E, // 0xCE DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE
+ 0x278F, // 0xCF DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX
+ 0x2790, // 0xD0 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN
+ 0x2791, // 0xD1 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT
+ 0x2792, // 0xD2 DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE
+ 0x2793, // 0xD3 DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+ 0x2794, // 0xD4 HEAVY WIDE-HEADED RIGHTWARDS ARROW
+ 0x2192, // 0xD5 RIGHTWARDS ARROW
+ 0x2194, // 0xD6 LEFT RIGHT ARROW
+ 0x2195, // 0xD7 UP DOWN ARROW
+ 0x2798, // 0xD8 HEAVY SOUTH EAST ARROW
+ 0x2799, // 0xD9 HEAVY RIGHTWARDS ARROW
+ 0x279A, // 0xDA HEAVY NORTH EAST ARROW
+ 0x279B, // 0xDB DRAFTING POINT RIGHTWARDS ARROW
+ 0x279C, // 0xDC HEAVY ROUND-TIPPED RIGHTWARDS ARROW
+ 0x279D, // 0xDD TRIANGLE-HEADED RIGHTWARDS ARROW
+ 0x279E, // 0xDE HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW
+ 0x279F, // 0xDF DASHED TRIANGLE-HEADED RIGHTWARDS ARROW
+ 0x27A0, // 0xE0 HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW
+ 0x27A1, // 0xE1 BLACK RIGHTWARDS ARROW
+ 0x27A2, // 0xE2 THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD
+ 0x27A3, // 0xE3 THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD
+ 0x27A4, // 0xE4 BLACK RIGHTWARDS ARROWHEAD
+ 0x27A5, // 0xE5 HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW
+ 0x27A6, // 0xE6 HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW
+ 0x27A7, // 0xE7 SQUAT BLACK RIGHTWARDS ARROW
+ 0x27A8, // 0xE8 HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW
+ 0x27A9, // 0xE9 RIGHT-SHADED WHITE RIGHTWARDS ARROW
+ 0x27AA, // 0xEA LEFT-SHADED WHITE RIGHTWARDS ARROW
+ 0x27AB, // 0xEB BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW
+ 0x27AC, // 0xEC FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW
+ 0x27AD, // 0xED HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ 0x27AE, // 0xEE HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ 0x27AF, // 0xEF NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ 0xFFFD, // 0xF0 no replacement
+ 0x27B1, // 0xF1 NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+ 0x27B2, // 0xF2 CIRCLED HEAVY WHITE RIGHTWARDS ARROW
+ 0x27B3, // 0xF3 WHITE-FEATHERED RIGHTWARDS ARROW
+ 0x27B4, // 0xF4 BLACK-FEATHERED SOUTH EAST ARROW
+ 0x27B5, // 0xF5 BLACK-FEATHERED RIGHTWARDS ARROW
+ 0x27B6, // 0xF6 BLACK-FEATHERED NORTH EAST ARROW
+ 0x27B7, // 0xF7 HEAVY BLACK-FEATHERED SOUTH EAST ARROW
+ 0x27B8, // 0xF8 HEAVY BLACK-FEATHERED RIGHTWARDS ARROW
+ 0x27B9, // 0xF9 HEAVY BLACK-FEATHERED NORTH EAST ARROW
+ 0x27BA, // 0xFA TEARDROP-BARBED RIGHTWARDS ARROW
+ 0x27BB, // 0xFB HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW
+ 0x27BC, // 0xFC WEDGE-TAILED RIGHTWARDS ARROW
+ 0x27BD, // 0xFD HEAVY WEDGE-TAILED RIGHTWARDS ARROW
+ 0x27BE, // 0xFE OPEN-OUTLINED RIGHTWARDS ARROW
+ 0xFFFD // 0xFF no replacement
+};
+
+/* characters from symbol font, conversion to a unicode font. Change both the
+ code and the font on conversion. */
+static unsigned int symbol_convert[256]={
+ 0xFFFD, // 0x00 no replacement
+ 0xFFFD, // 0x01 no replacement
+ 0xFFFD, // 0x02 no replacement
+ 0xFFFD, // 0x03 no replacement
+ 0xFFFD, // 0x04 no replacement
+ 0xFFFD, // 0x05 no replacement
+ 0xFFFD, // 0x06 no replacement
+ 0xFFFD, // 0x07 no replacement
+ 0xFFFD, // 0x08 no replacement
+ 0xFFFD, // 0x09 no replacement
+ 0xFFFD, // 0x0A no replacement
+ 0xFFFD, // 0x0B no replacement
+ 0xFFFD, // 0x0C no replacement
+ 0xFFFD, // 0x0D no replacement
+ 0xFFFD, // 0x0E no replacement
+ 0xFFFD, // 0x0F no replacement
+ 0xFFFD, // 0x10 no replacement
+ 0xFFFD, // 0x11 no replacement
+ 0xFFFD, // 0x12 no replacement
+ 0xFFFD, // 0x13 no replacement
+ 0xFFFD, // 0x14 no replacement
+ 0xFFFD, // 0x15 no replacement
+ 0xFFFD, // 0x16 no replacement
+ 0xFFFD, // 0x17 no replacement
+ 0xFFFD, // 0x18 no replacement
+ 0xFFFD, // 0x19 no replacement
+ 0xFFFD, // 0x1A no replacement
+ 0xFFFD, // 0x1B no replacement
+ 0xFFFD, // 0x1C no replacement
+ 0xFFFD, // 0x1D no replacement
+ 0xFFFD, // 0x1E no replacement
+ 0xFFFD, // 0x1F no replacement
+ 0x0020, // 0x20 SPACE
+ 0x0021, // 0x21 EXCLAMATION MARK
+ 0x2200, // 0x22 FOR ALL
+ 0x0023, // 0x23 NUMBER SIGN
+ 0x2203, // 0x24 THERE EXISTS
+ 0x0025, // 0x25 PERCENT SIGN
+ 0x0026, // 0x26 AMPERSAND
+ 0x220B, // 0x27 CONTAINS AS MEMBER
+ 0x0028, // 0x28 OPENING PARENTHESIS
+ 0x0029, // 0x29 CLOSING PARENTHESIS
+ 0x2217, // 0x2A ASTERISK OPERATOR
+ 0x002B, // 0x2B PLUS SIGN
+ 0x002C, // 0x2C COMMA
+ 0x2212, // 0x2D MINUS SIGN
+ 0x002E, // 0x2E PERIOD
+ 0x002F, // 0x2F SLASH
+ 0x0030, // 0x30 DIGIT ZERO
+ 0x0031, // 0x31 DIGIT ONE
+ 0x0032, // 0x32 DIGIT TWO
+ 0x0033, // 0x33 DIGIT THREE
+ 0x0034, // 0x34 DIGIT FOUR
+ 0x0035, // 0x35 DIGIT FIVE
+ 0x0036, // 0x36 DIGIT SIX
+ 0x0037, // 0x37 DIGIT SEVEN
+ 0x0038, // 0x38 DIGIT EIGHT
+ 0x0039, // 0x39 DIGIT NINE
+ 0x003A, // 0x3A COLON
+ 0x003B, // 0x3B SEMICOLON
+ 0x003C, // 0x3C LESS-THAN SIGN
+ 0x003D, // 0x3D EQUALS SIGN
+ 0x003E, // 0x3E GREATER-THAN SIGN
+ 0x003F, // 0x3F QUESTION MARK
+ 0x2245, // 0x40 APPROXIMATELY EQUAL TO
+ 0x0391, // 0x41 GREEK CAPITAL LETTER ALPHA
+ 0x0392, // 0x42 GREEK CAPITAL LETTER BETA
+ 0x03A7, // 0x43 GREEK CAPITAL LETTER CHI
+ 0x0394, // 0x44 GREEK CAPITAL LETTER DELTA
+ 0x0395, // 0x45 GREEK CAPITAL LETTER EPSILON
+ 0x03A6, // 0x46 GREEK CAPITAL LETTER PHI
+ 0x0393, // 0x47 GREEK CAPITAL LETTER GAMMA
+ 0x0397, // 0x48 GREEK CAPITAL LETTER ETA
+ 0x0399, // 0x49 GREEK CAPITAL LETTER IOTA
+ 0x03D1, // 0x4A GREEK SMALL LETTER SCRIPT THETA
+ 0x039A, // 0x4B GREEK CAPITAL LETTER KAPPA
+ 0x039B, // 0x4C GREEK CAPITAL LETTER LAMBDA
+ 0x039C, // 0x4D GREEK CAPITAL LETTER MU
+ 0x039D, // 0x4E GREEK CAPITAL LETTER NU
+ 0x039F, // 0x4F GREEK CAPITAL LETTER OMICRON
+ 0x03A0, // 0x50 GREEK CAPITAL LETTER PI
+ 0x0398, // 0x51 GREEK CAPITAL LETTER THETA
+ 0x03A1, // 0x52 GREEK CAPITAL LETTER RHO
+ 0x03A3, // 0x53 GREEK CAPITAL LETTER SIGMA
+ 0x03A4, // 0x54 GREEK CAPITAL LETTER TAU
+ 0x03A5, // 0x55 GREEK CAPITAL LETTER UPSILON
+ 0x03C2, // 0x56 GREEK SMALL LETTER FINAL SIGMA
+ 0x03A9, // 0x57 GREEK CAPITAL LETTER OMEGA
+ 0x039E, // 0x58 GREEK CAPITAL LETTER XI
+ 0x03A8, // 0x59 GREEK CAPITAL LETTER PSI
+ 0x0396, // 0x5A GREEK CAPITAL LETTER ZETA
+ 0x005B, // 0x5B OPENING SQUARE BRACKET
+ 0x2234, // 0x5C THEREFORE
+ 0x005D, // 0x5D CLOSING SQUARE BRACKET
+ 0x22A5, // 0x5E UP TACK
+ 0x005F, // 0x5F SPACING UNDERSCORE
+ 0x203E, // 0x60 SPACING OVERSCORE
+ 0x03B1, // 0x61 GREEK SMALL LETTER ALPHA
+ 0x03B2, // 0x62 GREEK SMALL LETTER BETA
+ 0x03C7, // 0x63 GREEK SMALL LETTER CHI
+ 0x03B4, // 0x64 GREEK SMALL LETTER DELTA
+ 0x03B5, // 0x65 GREEK SMALL LETTER EPSILON
+ 0x03C6, // 0x66 GREEK SMALL LETTER PHI
+ 0x03B3, // 0x67 GREEK SMALL LETTER GAMMA
+ 0x03B7, // 0x68 GREEK SMALL LETTER ETA
+ 0x03B9, // 0x69 GREEK SMALL LETTER IOTA
+ 0x03D5, // 0x6A GREEK SMALL LETTER SCRIPT PHI
+ 0x03BA, // 0x6B GREEK SMALL LETTER KAPPA
+ 0x03BB, // 0x6C GREEK SMALL LETTER LAMBDA
+ 0x03BC, // 0x6D GREEK SMALL LETTER MU
+ 0x03BD, // 0x6E GREEK SMALL LETTER NU
+ 0x03BF, // 0x6F GREEK SMALL LETTER OMICRON
+ 0x03C0, // 0x70 GREEK SMALL LETTER PI
+ 0x03B8, // 0x71 GREEK SMALL LETTER THETA
+ 0x03C1, // 0x72 GREEK SMALL LETTER RHO
+ 0x03C3, // 0x73 GREEK SMALL LETTER SIGMA
+ 0x03C4, // 0x74 GREEK SMALL LETTER TAU
+ 0x03C5, // 0x75 GREEK SMALL LETTER UPSILON
+ 0x03D6, // 0x76 GREEK SMALL LETTER OMEGA PI
+ 0x03C9, // 0x77 GREEK SMALL LETTER OMEGA
+ 0x03BE, // 0x78 GREEK SMALL LETTER XI
+ 0x03C8, // 0x79 GREEK SMALL LETTER PSI
+ 0x03B6, // 0x7A GREEK SMALL LETTER ZETA
+ 0x007B, // 0x7B OPENING CURLY BRACKET
+ 0x007C, // 0x7C VERTICAL BAR
+ 0x007D, // 0x7D CLOSING CURLY BRACKET
+ 0x223C, // 0x7E TILDE OPERATOR
+ 0xFFFD, // 0x7F no replacement
+ 0xFFFD, // 0x80 no replacement
+ 0xFFFD, // 0x81 no replacement
+ 0xFFFD, // 0x82 no replacement
+ 0xFFFD, // 0x83 no replacement
+ 0xFFFD, // 0x84 no replacement
+ 0xFFFD, // 0x85 no replacement
+ 0xFFFD, // 0x86 no replacement
+ 0xFFFD, // 0x87 no replacement
+ 0xFFFD, // 0x88 no replacement
+ 0xFFFD, // 0x89 no replacement
+ 0xFFFD, // 0x8A no replacement
+ 0xFFFD, // 0x8B no replacement
+ 0xFFFD, // 0x8C no replacement
+ 0xFFFD, // 0x8D no replacement
+ 0xFFFD, // 0x8E no replacement
+ 0xFFFD, // 0x8F no replacement
+ 0xFFFD, // 0x90 no replacement
+ 0xFFFD, // 0x91 no replacement
+ 0xFFFD, // 0x92 no replacement
+ 0xFFFD, // 0x93 no replacement
+ 0xFFFD, // 0x94 no replacement
+ 0xFFFD, // 0x95 no replacement
+ 0xFFFD, // 0x96 no replacement
+ 0xFFFD, // 0x97 no replacement
+ 0xFFFD, // 0x98 no replacement
+ 0xFFFD, // 0x99 no replacement
+ 0xFFFD, // 0x9A no replacement
+ 0xFFFD, // 0x9B no replacement
+ 0xFFFD, // 0x9C no replacement
+ 0xFFFD, // 0x9D no replacement
+ 0xFFFD, // 0x9E no replacement
+ 0xFFFD, // 0x9F no replacement
+ 0x20AC, // 0xA0 EURO SIGN
+ 0x03D2, // 0xA1 GREEK CAPITAL LETTER UPSILON HOOK
+ 0x2032, // 0xA2 PRIME
+ 0x2264, // 0xA3 LESS THAN OR EQUAL TO
+ 0x2044, // 0xA4 FRACTION SLASH
+ 0x221E, // 0xA5 INFINITY
+ 0x0192, // 0xA6 LATIN SMALL LETTER SCRIPT F
+ 0x2663, // 0xA7 BLACK CLUB SUIT
+ 0x2666, // 0xA8 BLACK DIAMOND SUIT
+ 0x2665, // 0xA9 BLACK HEART SUIT
+ 0x2660, // 0xAA BLACK SPADE SUIT
+ 0x2194, // 0xAB LEFT RIGHT ARROW
+ 0x2190, // 0xAC LEFT ARROW
+ 0x2191, // 0xAD UP ARROW
+ 0x2192, // 0xAE RIGHT ARROW
+ 0x2193, // 0xAF DOWN ARROW
+ 0x00B0, // 0xB0 DEGREE SIGN
+ 0x00B1, // 0xB1 PLUS-OR-MINUS SIGN
+ 0x2033, // 0xB2 DOUBLE PRIME
+ 0x2265, // 0xB3 GREATER THAN OR EQUAL TO
+ 0x00D7, // 0xB4 MULTIPLICATION SIGN
+ 0x221D, // 0xB5 PROPORTIONAL TO
+ 0x2202, // 0xB6 PARTIAL DIFFERENTIAL
+ 0x2219, // 0xB7 BULLET (use BULLET operator, so normal font BULLET will not convert to Symbol BULLET)
+ 0x00F7, // 0xB8 DIVISION SIGN
+ 0x2260, // 0xB9 NOT EQUAL TO
+ 0x2261, // 0xBA IDENTICAL TO
+ 0x2248, // 0xBB ALMOST EQUAL TO
+ 0x2026, // 0xBC HORIZONTAL ELLIPSIS
+ 0xF8E6, // 0xBD VERTICAL ARROW EXTENDER
+ 0xF8E7, // 0xBE HORIZONTAL ARROW EXTENDER
+ 0x21B5, // 0xBF DOWN ARROW WITH CORNER LEFT
+ 0x2135, // 0xC0 FIRST TRANSFINITE CARDINAL
+ 0x2111, // 0xC1 BLACK-LETTER I
+ 0x211C, // 0xC2 BLACK-LETTER R
+ 0x2118, // 0xC3 SCRIPT P
+ 0x2297, // 0xC4 CIRCLED TIMES
+ 0x2295, // 0xC5 CIRCLED PLUS
+ 0x2205, // 0xC6 EMPTY SET
+ 0x2229, // 0xC7 INTERSECTION
+ 0x222A, // 0xC8 UNION
+ 0x2283, // 0xC9 SUPERSET OF
+ 0x2287, // 0xCA SUPERSET OF OR EQUAL TO
+ 0x2284, // 0xCB NOT A SUBSET OF
+ 0x2282, // 0xCC SUBSET OF
+ 0x2286, // 0xCD SUBSET OF OR EQUAL TO
+ 0x2208, // 0xCE ELEMENT OF
+ 0x2209, // 0xCF NOT AN ELEMENT OF
+ 0x2220, // 0xD0 ANGLE
+ 0x2207, // 0xD1 NABLA
+ 0x00AE, // 0xD2 REGISTERED TRADE MARK SIGN
+ 0x00A9, // 0xD3 COPYRIGHT SIGN
+ 0x2122, // 0xD4 TRADEMARK
+ 0x220F, // 0xD5 N-ARY PRODUCT
+ 0x221A, // 0xD6 SQUARE ROOT
+ 0x22C5, // 0xD7 DOT OPERATOR
+ 0x00AC, // 0xD8 NOT SIGN
+ 0x2227, // 0xD9 LOGICAL AND
+ 0x2228, // 0xDA LOGICAL OR
+ 0x21D4, // 0xDB LEFT RIGHT DOUBLE ARROW
+ 0x21D0, // 0xDC LEFT DOUBLE ARROW
+ 0x21D1, // 0xDD UP DOUBLE ARROW
+ 0x21D2, // 0xDE RIGHT DOUBLE ARROW
+ 0x21D3, // 0xDF DOWN DOUBLE ARROW
+ 0x25CA, // 0xE0 LOZENGE
+ 0x2329, // 0xE1 BRA
+ 0x00AE, // 0xE2 REGISTERED TRADE MARK SIGN
+ 0x00A9, // 0xE3 COPYRIGHT SIGN
+ 0x2122, // 0xE4 TRADEMARK
+ 0x2211, // 0xE5 N-ARY SUMMATION
+ 0x239B, // 0xE6 LEFT PAREN TOP
+ 0x239C, // 0xE7 LEFT PAREN EXTENDER
+ 0x239D, // 0xE8 LEFT PAREN BOTTOM
+ 0x23A1, // 0xE9 LEFT SQUARE BRACKET TOP
+ 0x23A2, // 0xEA LEFT SQUARE BRACKET EXTENDER
+ 0x23A3, // 0xEB LEFT SQUARE BRACKET BOTTOM
+ 0x23A7, // 0xEC LEFT CURLY BRACKET TOP
+ 0x23A8, // 0xED LEFT CURLY BRACKET MID
+ 0x23A9, // 0xEE LEFT CURLY BRACKET BOTTOM
+ 0x23AA, // 0xEF CURLY BRACKET EXTENDER
+ 0xFFFD, // 0xF0 no replacement
+ 0x232A, // 0xF1 KET
+ 0x222B, // 0xF2 INTEGRAL
+ 0x2320, // 0xF3 TOP HALF INTEGRAL
+ 0x23AE, // 0xF4 INTEGRAL EXTENDER
+ 0x2321, // 0xF5 BOTTOM HALF INTEGRAL
+ 0x239E, // 0xF6 RIGHT PAREN TOP
+ 0x239F, // 0xF7 RIGHT PAREN EXTENDER
+ 0x23A0, // 0xF8 RIGHT PAREN BOTTOM
+ 0x23A4, // 0xF9 RIGHT SQUARE BRACKET TOP
+ 0x23A5, // 0xFA RIGHT SQUARE BRACKET EXTENDER
+ 0x23A6, // 0xFB RIGHT SQUARE BRACKET BOTTOM
+ 0x23AB, // 0xFC RIGHT CURLY BRACKET TOP
+ 0x23AC, // 0xFD RIGHT CURLY BRACKET MID
+ 0x23AD, // 0xFE RIGHT CURLY BRACKET BOTTOM
+ 0xFFFD // 0xFF no replacement
+};
+
+/* Use this for debugging */
+#include <stdio.h>
+void UC_log_message(char *text){
+FILE *fp;
+ fp=fopen("c:/temp/debug.txt","a");
+ fprintf(fp,"%s",text);
+ fclose(fp);
+}
+
+
+//if any character is in the MS private use area (F020 through F0FF) subtract F000, for use with Symbol and Wingdings* from older software
+void msdepua (uint32_t *text)
+{
+ while(*text){
+ if(*text >= 0xF020 && *text <= 0xF0FF){ *text -= 0xF000; }
+ text++;
+ }
+}
+
+//move characters up to MS private use area (F020 through F0FF)
+void msrepua (uint16_t *text)
+{
+ while(*text){
+ if(*text >= 0x20 && *text <= 0xFF){ *text += 0xF000; }
+ text++;
+ }
+}
+
+// Returns the font classification code
+int isNon(char *font){
+int retval;
+ if(!strcmp(font,"Symbol")){
+ retval=CVTSYM;
+ }
+ else if(!strcmp(font,"Wingdings")){
+ retval=CVTWDG;
+ }
+ else if(!strcmp(font,"ZapfDingbats")){
+ retval=CVTZDG;
+ }
+ else {
+ retval=CVTNON;
+ }
+ return retval;
+}
+
+// Returns the font name, given the classification code, or NULL
+// The returned value must NOT be free'd
+char *FontName(int code){
+char *cptr;
+static char name_symbol[]="Symbol";
+static char name_wingdings[]="Wingdings";
+static char name_zapfdingbats[]="ZapfDingbats";
+ switch(code){
+ case CVTSYM: cptr=&name_symbol[0]; break;
+ case CVTWDG: cptr=&name_wingdings[0]; break;
+ case CVTZDG: cptr=&name_zapfdingbats[0]; break;
+ default: cptr=NULL; break;
+ }
+ return(cptr);
+}
+
+
+// Goes through the uint32_t string converting as needed.
+int NonToUnicode(uint32_t *text, char *font){
+int retval;
+unsigned int *convert_from=NULL;
+ retval=isNon(font);
+ switch(retval){
+ case CVTSYM: convert_from=symbol_convert; break;
+ case CVTWDG: convert_from=wingdings_convert; break;
+ case CVTZDG: convert_from=dingbats_convert; break;
+ default: return(retval); //no conversion
+ }
+ while(*text){
+ if(*text > 0xFF){ *text = 0xFFFD; } // out of range
+ else { *text = convert_from[*text]; }
+ text++;
+ }
+ return(retval);
+}
+
+//returns 1 if tables are defines for UnicodeToNon translation
+int CanUTN(void){
+ if(from_unicode)return(1);
+ return(0);
+}
+
+//translates from Unicode to some non unicode font until the target font changes.
+//A target font change is like symbol -> wingdings, or symbol -> no translation
+//returns the number of characters changed in ecount
+//returns the enum value for the destination value in edest
+void UnicodeToNon(uint16_t *text, int *ecount, int *edest){
+int count=0;
+unsigned char target=0;
+ if(to_font){
+ if(text && (target=to_font[*text])){ //There is actually something here to convert
+ while(*text && target==to_font[*text]){
+ *text=from_unicode[*text] + (hold_pua ? 0xF000 : 0 );
+ text++;
+ count++;
+ }
+ }
+ *ecount=count;
+ *edest=target;
+ }
+ else { // no translation tables, so change nothing and return
+ *ecount=0;
+ *edest=CVTNON;
+ }
+}
+
+//Indicates the type of translation for a single character, Unicode to some non unicode
+//returns the enum value for the destination value.
+//If no translation tables are defined returns CVTNON (no conversions)
+int SingleUnicodeToNon(uint16_t text){
+ if(to_font){return(to_font[text]); }
+ else { return(CVTNON); }
+}
+
+void table_filler(unsigned int *src, int code){
+unsigned int i;
+ for(i=0;i<0x100;i++){
+ if(src[i] == 0xFFFD)continue; /* no mapping Unicode -> nonUnicode */
+ if(src[i] == i)continue; /* no remapping of spaces back to spaces, for instance */
+ from_unicode[src[i]] = i;
+ to_font[src[i]] = code;
+ }
+}
+
+//possibly (re)generate the tables
+void TableGen(bool new_symb,bool new_wing, bool new_zdng, bool new_pua){
+int i;
+ if(hold_symb != new_symb || hold_wing != new_wing
+ || hold_zdng != new_zdng || hold_pua != new_pua ){ // must (re)generate tables
+ if(!from_unicode){ // create arrays
+ from_unicode = (unsigned char *) calloc(0x10000,sizeof(unsigned char));
+ to_font = (unsigned char *) calloc(0x10000,sizeof(unsigned char));
+ // should check here for malloc error
+ }
+ hold_symb = new_symb;
+ hold_wing = new_wing;
+ hold_zdng = new_zdng;
+ hold_pua = new_pua;
+ for(i=0;i<0x10000;i++){ from_unicode[i] = to_font[i] = 0; }
+ if(hold_zdng)table_filler(&dingbats_convert[0],CVTZDG);
+ if(hold_wing)table_filler(&wingdings_convert[0],CVTWDG);
+ if(hold_symb)table_filler(&symbol_convert[0],CVTSYM);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/symbol_convert.h b/src/3rdparty/libuemf/symbol_convert.h
new file mode 100644
index 000000000..ac1795092
--- /dev/null
+++ b/src/3rdparty/libuemf/symbol_convert.h
@@ -0,0 +1,51 @@
+/** @file
+ * @brief Enhanced Metafile Input/Output
+ */
+/* Authors:
+ * David Mathog <mathog@caltech.edu>
+ *
+ * Copyright (C) 2012 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SEEN_UNICODE_CONVERT_H
+#define SEEN_UNICODE_CONVERT_H
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+ enum cvt_to_font {CVTNON, CVTSYM, CVTZDG, CVTWDG};
+
+ void msdepua(uint32_t *text); //translate down from Microsoft Private Use Area
+ void msrepua(uint16_t *text); //translate up to Microsoft Private Use Area
+ int isNon(char *font); //returns one of the cvt_to_font enum values
+ char *FontName(int code); //returns the font name (or NULL) given the enum code
+ int NonToUnicode(uint32_t *text, char *font); //nonunicode to Unicode translation
+ int CanUTN(void); // 1 if tables exist for UnicodeToNon translation
+ int SingleUnicodeToNon(uint16_t text); //retuns the enum value for this translation
+ void UnicodeToNon(uint16_t *text, int *ecount, int *edest); //translate Unicode to NonUnicode
+ void TableGen(bool symb, bool wing, bool zdng, bool pua);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SEEN_UNICODE_CONVERT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
+
+
diff --git a/src/3rdparty/libuemf/uemf.c b/src/3rdparty/libuemf/uemf.c
new file mode 100644
index 000000000..fa7689bb6
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf.c
@@ -0,0 +1,5606 @@
+/**
+ @file uemf.c
+
+ @brief Functions for manipulating EMF files and structures.
+
+ [U_EMR]_set all take data and return a pointer to memory holding the constructed record.
+ The size of that record is also returned in recsize.
+ It is also in the second int32 in the record, but may have been byte swapped and so not usable.
+ If something goes wrong a NULL pointer is returned and recsize is set to 0.
+
+ Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for
+ uninitialized data.
+
+ Compile with "SOL8" defined for Solaris 8 or 9 (Sparc).
+*/
+
+/*
+File: uemf.c
+Version: 0.0.31
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <iconv.h>
+#include <wchar.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h> // for INT_MAX, INT_MIN
+#include <math.h> // for U_ROUND()
+#include <stddef.h> /* for offsetof() macro */
+#if 0
+#include <windef.h> //Not actually used, looking for collisions
+#include <winnt.h> //Not actually used, looking for collisions
+#include <wingdi.h> //Not actually used, looking for collisions
+#endif
+#include "uemf.h"
+
+//! \cond
+/* one prototype from uemf_endian. Put it here because end user should never need to see it, so
+not in uemf.h or uemf_endian.h */
+void U_swap2(void *ul, unsigned int count);
+//! \endcond
+
+/**
+ \brief Look up the name of the EMR record by type. Returns U_EMR_INVALID if out of range.
+
+ \return name of the EMR record, "U_EMR_INVALID" if out of range.
+ \param idx EMR record type.
+
+*/
+char *U_emr_names(unsigned int idx){
+ if(idx<U_EMR_MIN || idx > U_EMR_MAX){ idx = 0; }
+ static char *U_EMR_NAMES[U_EMR_MAX+1]={
+ "U_EMR_INVALID",
+ "U_EMR_HEADER",
+ "U_EMR_POLYBEZIER",
+ "U_EMR_POLYGON",
+ "U_EMR_POLYLINE",
+ "U_EMR_POLYBEZIERTO",
+ "U_EMR_POLYLINETO",
+ "U_EMR_POLYPOLYLINE",
+ "U_EMR_POLYPOLYGON",
+ "U_EMR_SETWINDOWEXTEX",
+ "U_EMR_SETWINDOWORGEX",
+ "U_EMR_SETVIEWPORTEXTEX",
+ "U_EMR_SETVIEWPORTORGEX",
+ "U_EMR_SETBRUSHORGEX",
+ "U_EMR_EOF",
+ "U_EMR_SETPIXELV",
+ "U_EMR_SETMAPPERFLAGS",
+ "U_EMR_SETMAPMODE",
+ "U_EMR_SETBKMODE",
+ "U_EMR_SETPOLYFILLMODE",
+ "U_EMR_SETROP2",
+ "U_EMR_SETSTRETCHBLTMODE",
+ "U_EMR_SETTEXTALIGN",
+ "U_EMR_SETCOLORADJUSTMENT",
+ "U_EMR_SETTEXTCOLOR",
+ "U_EMR_SETBKCOLOR",
+ "U_EMR_OFFSETCLIPRGN",
+ "U_EMR_MOVETOEX",
+ "U_EMR_SETMETARGN",
+ "U_EMR_EXCLUDECLIPRECT",
+ "U_EMR_INTERSECTCLIPRECT",
+ "U_EMR_SCALEVIEWPORTEXTEX",
+ "U_EMR_SCALEWINDOWEXTEX",
+ "U_EMR_SAVEDC",
+ "U_EMR_RESTOREDC",
+ "U_EMR_SETWORLDTRANSFORM",
+ "U_EMR_MODIFYWORLDTRANSFORM",
+ "U_EMR_SELECTOBJECT",
+ "U_EMR_CREATEPEN",
+ "U_EMR_CREATEBRUSHINDIRECT",
+ "U_EMR_DELETEOBJECT",
+ "U_EMR_ANGLEARC",
+ "U_EMR_ELLIPSE",
+ "U_EMR_RECTANGLE",
+ "U_EMR_ROUNDRECT",
+ "U_EMR_ARC",
+ "U_EMR_CHORD",
+ "U_EMR_PIE",
+ "U_EMR_SELECTPALETTE",
+ "U_EMR_CREATEPALETTE",
+ "U_EMR_SETPALETTEENTRIES",
+ "U_EMR_RESIZEPALETTE",
+ "U_EMR_REALIZEPALETTE",
+ "U_EMR_EXTFLOODFILL",
+ "U_EMR_LINETO",
+ "U_EMR_ARCTO",
+ "U_EMR_POLYDRAW",
+ "U_EMR_SETARCDIRECTION",
+ "U_EMR_SETMITERLIMIT",
+ "U_EMR_BEGINPATH",
+ "U_EMR_ENDPATH",
+ "U_EMR_CLOSEFIGURE",
+ "U_EMR_FILLPATH",
+ "U_EMR_STROKEANDFILLPATH",
+ "U_EMR_STROKEPATH",
+ "U_EMR_FLATTENPATH",
+ "U_EMR_WIDENPATH",
+ "U_EMR_SELECTCLIPPATH",
+ "U_EMR_ABORTPATH",
+ "U_EMR_UNDEF69",
+ "U_EMR_COMMENT",
+ "U_EMR_FILLRGN",
+ "U_EMR_FRAMERGN",
+ "U_EMR_INVERTRGN",
+ "U_EMR_PAINTRGN",
+ "U_EMR_EXTSELECTCLIPRGN",
+ "U_EMR_BITBLT",
+ "U_EMR_STRETCHBLT",
+ "U_EMR_MASKBLT",
+ "U_EMR_PLGBLT",
+ "U_EMR_SETDIBITSTODEVICE",
+ "U_EMR_STRETCHDIBITS",
+ "U_EMR_EXTCREATEFONTINDIRECTW",
+ "U_EMR_EXTTEXTOUTA",
+ "U_EMR_EXTTEXTOUTW",
+ "U_EMR_POLYBEZIER16",
+ "U_EMR_POLYGON16",
+ "U_EMR_POLYLINE16",
+ "U_EMR_POLYBEZIERTO16",
+ "U_EMR_POLYLINETO16",
+ "U_EMR_POLYPOLYLINE16",
+ "U_EMR_POLYPOLYGON16",
+ "U_EMR_POLYDRAW16",
+ "U_EMR_CREATEMONOBRUSH",
+ "U_EMR_CREATEDIBPATTERNBRUSHPT",
+ "U_EMR_EXTCREATEPEN",
+ "U_EMR_POLYTEXTOUTA",
+ "U_EMR_POLYTEXTOUTW",
+ "U_EMR_SETICMMODE",
+ "U_EMR_CREATECOLORSPACE",
+ "U_EMR_SETCOLORSPACE",
+ "U_EMR_DELETECOLORSPACE",
+ "U_EMR_GLSRECORD",
+ "U_EMR_GLSBOUNDEDRECORD",
+ "U_EMR_PIXELFORMAT",
+ "U_EMR_DRAWESCAPE",
+ "U_EMR_EXTESCAPE",
+ "U_EMR_UNDEF107",
+ "U_EMR_SMALLTEXTOUT",
+ "U_EMR_FORCEUFIMAPPING",
+ "U_EMR_NAMEDESCAPE",
+ "U_EMR_COLORCORRECTPALETTE",
+ "U_EMR_SETICMPROFILEA",
+ "U_EMR_SETICMPROFILEW",
+ "U_EMR_ALPHABLEND",
+ "U_EMR_SETLAYOUT",
+ "U_EMR_TRANSPARENTBLT",
+ "U_EMR_UNDEF117",
+ "U_EMR_GRADIENTFILL",
+ "U_EMR_SETLINKEDUFIS",
+ "U_EMR_SETTEXTJUSTIFICATION",
+ "U_EMR_COLORMATCHTOTARGETW",
+ "U_EMR_CREATECOLORSPACEW"
+ };
+ return(U_EMR_NAMES[idx]);
+}
+
+
+
+/* **********************************************************************************************
+These definitions are for code pieces that are used many times in the following implementation. These
+definitions are not needed in end user code, so they are here rather than in uemf.h.
+*********************************************************************************************** */
+
+//! @cond
+
+// this one may also be used A=Msk,B=MskBmi and F=cbMsk
+#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \
+ if(A){\
+ if(!B)return(NULL); /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \
+ C = F;\
+ D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \
+ E = sizeof(U_BITMAPINFOHEADER) + 4 * get_real_color_count((const char *) &(B->bmiHeader)); /* bmiheader + colortable*/ \
+ }\
+ else { C = 0; D = 0; E=0; }
+
+// variable "off" must be declared in the function
+
+#define APPEND_PXBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR,C=cbBmi, D=Bmi, E=Px, F=cbImage, G=cbImage4 */ \
+ if(C){\
+ memcpy(A + off, D, C);\
+ ((B *) A)->offBmiSrc = off;\
+ ((B *) A)->cbBmiSrc = C;\
+ off += C;\
+ memcpy(A + off, E, F);\
+ ((B *) A)->offBitsSrc = off;\
+ ((B *) A)->cbBitsSrc = F;\
+ if(G - F){ \
+ off += F;\
+ memset(A + off, 0, G - F); \
+ }\
+ }\
+ else {\
+ ((B *) A)->offBmiSrc = 0;\
+ ((B *) A)->cbBmiSrc = 0;\
+ ((B *) A)->offBitsSrc = 0;\
+ ((B *) A)->cbBitsSrc = 0;\
+ }
+
+// variable "off" must be declared in the function
+
+#define APPEND_MSKBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR*,C=cbMskBmi, D=MskBmi, E=Msk, F=cbMskImage, G=cbMskImage4 */ \
+ if(C){\
+ memcpy(A + off, D, C);\
+ ((B *) A)->offBmiMask = off;\
+ ((B *) A)->cbBmiMask = C;\
+ off += C;\
+ memcpy(A + off, Msk, F);\
+ ((B *) A)->offBitsMask = off;\
+ ((B *) A)->cbBitsMask = F;\
+ if(G - F){ memset(A + off, 0, G - F); }\
+ }\
+ else {\
+ ((B *) A)->offBmiMask = 0;\
+ ((B *) A)->cbBmiMask = 0;\
+ ((B *) A)->offBitsMask = 0;\
+ ((B *) A)->cbBitsMask = 0;\
+ }
+
+//! @endcond
+
+/* **********************************************************************************************
+These functions are used for development and debugging and should be be includied in production code.
+*********************************************************************************************** */
+
+/**
+ \brief Debugging utility, used with valgrind to find uninitialized values. Not for use in production code.
+ \param buf memory area to examine !
+ \param size length in bytes of buf!
+*/
+int memprobe(
+ const void *buf,
+ size_t size
+ ){
+ int sum=0;
+ char *ptr=(char *)buf;
+ for(;size;size--,ptr++){ sum += *ptr; } // read all bytes, trigger valgrind warning if any uninitialized
+ return(sum);
+}
+
+/**
+ \brief Dump an EMFHANDLES structure. Not for use in production code.
+ \param string Text to output before dumping eht structure
+ \param handle Handle
+ \param eht EMFHANDLES structure to dump
+*/
+void dumpeht(
+ char *string,
+ unsigned int *handle,
+ EMFHANDLES *eht
+ ){
+ uint32_t i;
+ printf("%s\n",string);
+ printf("sptr: %d peak: %d top: %d\n",eht->sptr,eht->peak,eht->top);
+ if(handle){
+ printf("handle: %d \n",*handle);
+ }
+ for(i=0;i<=5;i++){
+ printf("table[%d]: %d\n",i,eht->table[i]);
+ }
+ for(i=1;i<=5;i++){
+ printf("stack[%d]: %d\n",i,eht->stack[i]);
+ }
+}
+
+/* **********************************************************************************************
+These functions are used for Image conversions and other
+utility operations. Character type conversions are in uemf_utf.c
+*********************************************************************************************** */
+
+/**
+ \brief Make up an approximate dx array to pass to emrtext_set(), based on character height and weight.
+
+ Take abs. value of character height, get width by multiplying by 0.6, and correct weight
+ approximately, with formula (measured on screen for one text line of Arial).
+ Caller is responsible for free() on the returned pointer.
+
+ \return pointer to dx array
+ \param height character height (absolute value will be used)
+ \param weight LF_Weight Enumeration (character weight)
+ \param members Number of entries to put into dx
+
+*/
+uint32_t *dx_set(
+ int32_t height,
+ uint32_t weight,
+ uint32_t members
+ ){
+ uint32_t i, width, *dx;
+ dx = (uint32_t *) malloc(members * sizeof(uint32_t));
+ if(dx){
+ if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL;
+ width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904));
+ for ( i = 0; i < members; i++ ){ dx[i] = width; }
+ }
+ return(dx);
+}
+
+/**
+ \brief Look up the properties (a bit map) of a type of EMR record.
+ Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc..
+
+ \return bitmap of EMR record properties, or U_EMR_INVALID on error or release of all memory
+ \param type EMR record type. If U_EMR_INVALID release memory. (There is no U_EMR_INVALID EMR record type)
+
+*/
+uint32_t emr_properties(uint32_t type){
+ static uint32_t *table=NULL;
+ uint32_t result = U_EMR_INVALID; // initialized to indicate an error (on a lookup) or nothing (on a memory release)
+ if(type == U_EMR_INVALID){
+ if(table)free(table);
+ table=NULL;
+ }
+ else if(type>=1 && type<U_EMR_MAX){
+ if(!table){
+ table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_EMR_MAX));
+ if(!table)return(result);
+ // 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01
+ // Path properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE
+ // PATH FORCE CLOSED NOTEMPTY
+ table[ 0] = 0x00; // Does not map to any EMR record
+ table[ 1] = 0x80; // U_EMRHEADER 1 0 0 0 0 0 0 0
+ table[ 2] = 0x83; // U_EMRPOLYBEZIER 1 0 0 0 0 0 1 1
+ table[ 3] = 0x87; // U_EMRPOLYGON 1 0 0 0 0 1 1 1
+ table[ 4] = 0x83; // U_EMRPOLYLINE 1 0 0 0 0 0 1 1
+ table[ 5] = 0x8B; // U_EMRPOLYBEZIERTO 1 0 0 0 1 0 1 1
+ table[ 6] = 0x8B; // U_EMRPOLYLINETO 1 0 0 0 1 0 1 1
+ table[ 7] = 0x83; // U_EMRPOLYPOLYLINE 1 0 0 0 0 0 1 1
+ table[ 8] = 0x87; // U_EMRPOLYPOLYGON 1 0 0 0 0 1 1 1
+ table[ 9] = 0xA0; // U_EMRSETWINDOWEXTEX 1 0 1 0 0 0 0 0
+ table[ 10] = 0xA0; // U_EMRSETWINDOWORGEX 1 0 1 0 0 0 0 0
+ table[ 11] = 0xA0; // U_EMRSETVIEWPORTEXTEX 1 0 1 0 0 0 0 0
+ table[ 12] = 0xA0; // U_EMRSETVIEWPORTORGEX 1 0 1 0 0 0 0 0
+ table[ 13] = 0xA0; // U_EMRSETBRUSHORGEX 1 0 1 0 0 0 0 0
+ table[ 14] = 0x82; // U_EMREOF 1 0 1 0 0 0 0 0 Force out any pending draw
+ table[ 15] = 0x82; // U_EMRSETPIXELV 1 0 0 0 0 0 1 0
+ table[ 16] = 0xA0; // U_EMRSETMAPPERFLAGS 1 0 1 0 0 0 0 0
+ table[ 17] = 0xA0; // U_EMRSETMAPMODE 1 0 1 0 0 0 0 0
+ table[ 18] = 0x20; // U_EMRSETBKMODE 0 0 1 0 0 0 0 0
+ table[ 19] = 0xA0; // U_EMRSETPOLYFILLMODE 1 0 1 0 0 0 0 0
+ table[ 20] = 0xA0; // U_EMRSETROP2 1 0 1 0 0 0 0 0
+ table[ 21] = 0xA0; // U_EMRSETSTRETCHBLTMODE 1 0 1 0 0 0 0 0
+ table[ 22] = 0x20; // U_EMRSETTEXTALIGN 0 0 1 0 0 0 0 0
+ table[ 23] = 0xA0; // U_EMRSETCOLORADJUSTMENT 1 0 1 0 0 0 0 0
+ table[ 24] = 0x20; // U_EMRSETTEXTCOLOR 0 0 1 0 0 0 0 0
+ table[ 25] = 0x20; // U_EMRSETBKCOLOR 0 0 1 0 0 0 0 0
+ table[ 26] = 0xA0; // U_EMROFFSETCLIPRGN 1 0 1 0 0 0 0 0
+ table[ 27] = 0x89; // U_EMRMOVETOEX 1 0 0 0 1 0 0 1
+ table[ 28] = 0xA0; // U_EMRSETMETARGN 1 0 1 0 0 0 0 0
+ table[ 29] = 0xA0; // U_EMREXCLUDECLIPRECT 1 0 1 0 0 0 0 0
+ table[ 30] = 0xA0; // U_EMRINTERSECTCLIPRECT 1 0 1 0 0 0 0 0
+ table[ 31] = 0xA0; // U_EMRSCALEVIEWPORTEXTEX 1 0 1 0 0 0 0 0
+ table[ 32] = 0xA0; // U_EMRSCALEWINDOWEXTEX 1 0 1 0 0 0 0 0
+ table[ 33] = 0xA0; // U_EMRSAVEDC 1 0 1 0 0 0 0 0
+ table[ 34] = 0xA0; // U_EMRRESTOREDC 1 0 1 0 0 0 0 0
+ table[ 35] = 0xA0; // U_EMRSETWORLDTRANSFORM 1 0 1 0 0 0 0 0
+ table[ 36] = 0xA0; // U_EMRMODIFYWORLDTRANSFORM 1 0 1 0 0 0 0 0
+ table[ 37] = 0x20; // U_EMRSELECTOBJECT 0 0 1 0 0 0 0 0
+ table[ 38] = 0x20; // U_EMRCREATEPEN 0 0 1 0 0 0 0 0
+ table[ 39] = 0x20; // U_EMRCREATEBRUSHINDIRECT 0 0 1 0 0 0 0 0
+ table[ 40] = 0x20; // U_EMRDELETEOBJECT 0 0 1 0 0 0 0 0
+ table[ 41] = 0x83; // U_EMRANGLEARC 1 0 0 0 0 0 1 1
+ table[ 42] = 0x87; // U_EMRELLIPSE 1 0 0 0 0 1 1 1
+ table[ 43] = 0x87; // U_EMRRECTANGLE 1 0 0 0 0 1 1 1
+ table[ 44] = 0x87; // U_EMRROUNDRECT 1 0 0 0 0 1 1 1
+ table[ 45] = 0x83; // U_EMRARC 1 0 0 0 0 0 1 1
+ table[ 46] = 0x87; // U_EMRCHORD 1 0 0 0 0 1 1 1
+ table[ 47] = 0x87; // U_EMRPIE 1 0 0 0 0 1 1 1
+ table[ 48] = 0xA0; // U_EMRSELECTPALETTE 1 0 1 0 0 0 0 0
+ table[ 49] = 0xA0; // U_EMRCREATEPALETTE 1 0 1 0 0 0 0 0
+ table[ 50] = 0xA0; // U_EMRSETPALETTEENTRIES 1 0 1 0 0 0 0 0
+ table[ 51] = 0xA0; // U_EMRRESIZEPALETTE 1 0 1 0 0 0 0 0
+ table[ 52] = 0xA0; // U_EMRREALIZEPALETTE 1 0 1 0 0 0 0 0
+ table[ 53] = 0x82; // U_EMREXTFLOODFILL 1 0 0 0 0 0 1 0
+ table[ 54] = 0x8B; // U_EMRLINETO 1 0 0 0 1 0 1 1
+ table[ 55] = 0x8B; // U_EMRARCTO 1 0 0 0 1 0 1 1
+ table[ 56] = 0x83; // U_EMRPOLYDRAW 1 0 0 0 0 0 1 1
+ table[ 57] = 0xA0; // U_EMRSETARCDIRECTION 1 0 1 0 0 0 0 0
+ table[ 58] = 0xA0; // U_EMRSETMITERLIMIT 1 0 1 0 0 0 0 0
+ table[ 59] = 0xE0; // U_EMRBEGINPATH 1 1 1 0 0 0 0 0
+ table[ 60] = 0x80; // U_EMRENDPATH 1 0 0 0 0 0 0 0
+ table[ 61] = 0x84; // U_EMRCLOSEFIGURE 1 0 0 0 0 1 0 0
+ table[ 62] = 0x94; // U_EMRFILLPATH 1 0 0 1 0 1 0 0
+ table[ 63] = 0x94; // U_EMRSTROKEANDFILLPATH 1 0 0 1 0 1 0 0
+ table[ 64] = 0x90; // U_EMRSTROKEPATH 1 0 0 1 0 0 0 0
+ table[ 65] = 0xA0; // U_EMRFLATTENPATH 1 0 1 0 0 0 0 0
+ table[ 66] = 0xA0; // U_EMRWIDENPATH 1 0 1 0 0 0 0 0
+ table[ 67] = 0x80; // U_EMRSELECTCLIPPATH 1 0 0 0 0 0 0 0 consumes the path, draws nothing
+ table[ 68] = 0xA0; // U_EMRABORTPATH 1 0 1 0 0 0 0 0
+ table[ 69] = 0xA0; // U_EMRUNDEF69 1 0 1 0 0 0 0 0
+ table[ 70] = 0x00; // U_EMRCOMMENT 0 0 0 0 0 0 0 0
+ table[ 71] = 0x82; // U_EMRFILLRGN 1 0 0 0 0 0 1 0
+ table[ 72] = 0x82; // U_EMRFRAMERGN 1 0 0 0 0 0 1 0
+ table[ 73] = 0x82; // U_EMRINVERTRGN 1 0 0 0 0 0 1 0
+ table[ 74] = 0x82; // U_EMRPAINTRGN 1 0 0 0 0 0 1 0
+ table[ 75] = 0xA0; // U_EMREXTSELECTCLIPRGN 1 0 1 0 0 0 0 0
+ table[ 76] = 0x82; // U_EMRBITBLT 1 0 0 0 0 0 1 0
+ table[ 77] = 0x82; // U_EMRSTRETCHBLT 1 0 0 0 0 0 1 0
+ table[ 78] = 0x82; // U_EMRMASKBLT 1 0 0 0 0 0 1 0
+ table[ 79] = 0x82; // U_EMRPLGBLT 1 0 0 0 0 0 1 0
+ table[ 80] = 0xA0; // U_EMRSETDIBITSTODEVICE 1 0 1 0 0 0 0 0
+ table[ 81] = 0xA0; // U_EMRSTRETCHDIBITS 1 0 1 0 0 0 0 0
+ table[ 82] = 0x20; // U_EMREXTCREATEFONTINDIRECTW 0 0 1 0 0 0 0 0
+ table[ 83] = 0x02; // U_EMREXTTEXTOUTA 0 0 0 0 0 0 1 0
+ table[ 84] = 0x02; // U_EMREXTTEXTOUTW 0 0 0 0 0 0 1 0
+ table[ 85] = 0x83; // U_EMRPOLYBEZIER16 1 0 0 0 0 0 1 1
+ table[ 86] = 0x83; // U_EMRPOLYGON16 1 0 0 0 0 0 1 1
+ table[ 87] = 0x83; // U_EMRPOLYLINE16 1 0 0 0 0 0 1 1
+ table[ 88] = 0x8B; // U_EMRPOLYBEZIERTO16 1 0 0 0 1 0 1 1
+ table[ 89] = 0x8B; // U_EMRPOLYLINETO16 1 0 0 0 1 0 1 1
+ table[ 90] = 0x83; // U_EMRPOLYPOLYLINE16 1 0 0 0 0 0 1 1
+ table[ 91] = 0x87; // U_EMRPOLYPOLYGON16 1 0 0 0 0 1 1 1
+ table[ 92] = 0x83; // U_EMRPOLYDRAW16 1 0 0 0 0 0 1 1
+ table[ 93] = 0x80; // U_EMRCREATEMONOBRUSH 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions
+ table[ 94] = 0x80; // U_EMRCREATEDIBPATTERNBRUSHPT 1 0 0 0 0 0 0 0 "
+ table[ 95] = 0x00; // U_EMREXTCREATEPEN 0 0 0 0 0 0 0 0 "
+ table[ 96] = 0x02; // U_EMRPOLYTEXTOUTA 0 0 0 0 0 0 1 0
+ table[ 97] = 0x02; // U_EMRPOLYTEXTOUTW 0 0 0 0 0 0 1 0
+ table[ 98] = 0xA0; // U_EMRSETICMMODE 1 0 1 0 0 0 0 0
+ table[ 99] = 0xA0; // U_EMRCREATECOLORSPACE 1 0 1 0 0 0 0 0
+ table[100] = 0xA0; // U_EMRSETCOLORSPACE 1 0 1 0 0 0 0 0
+ table[101] = 0xA0; // U_EMRDELETECOLORSPACE 1 0 1 0 0 0 0 0
+ table[102] = 0xA0; // U_EMRGLSRECORD 1 0 1 0 0 0 0 0
+ table[103] = 0xA0; // U_EMRGLSBOUNDEDRECORD 1 0 1 0 0 0 0 0
+ table[104] = 0xA0; // U_EMRPIXELFORMAT 1 0 1 0 0 0 0 0
+ table[105] = 0xA0; // U_EMRDRAWESCAPE 1 0 1 0 0 0 0 0
+ table[106] = 0xA0; // U_EMREXTESCAPE 1 0 1 0 0 0 0 0
+ table[107] = 0xA0; // U_EMRUNDEF107 1 0 1 0 0 0 0 0
+ table[108] = 0x02; // U_EMRSMALLTEXTOUT 0 0 0 0 0 0 1 0
+ table[109] = 0xA0; // U_EMRFORCEUFIMAPPING 1 0 1 0 0 0 0 0
+ table[110] = 0xA0; // U_EMRNAMEDESCAPE 1 0 1 0 0 0 0 0
+ table[111] = 0xA0; // U_EMRCOLORCORRECTPALETTE 1 0 1 0 0 0 0 0
+ table[112] = 0xA0; // U_EMRSETICMPROFILEA 1 0 1 0 0 0 0 0
+ table[113] = 0xA0; // U_EMRSETICMPROFILEW 1 0 1 0 0 0 0 0
+ table[114] = 0x82; // U_EMRALPHABLEND 1 0 0 0 0 0 1 0
+ table[115] = 0xA0; // U_EMRSETLAYOUT 1 0 1 0 0 0 0 0
+ table[116] = 0x82; // U_EMRTRANSPARENTBLT 1 0 0 0 0 0 1 0
+ table[117] = 0xA0; // U_EMRUNDEF117 1 0 1 0 0 0 0 0
+ table[118] = 0x82; // U_EMRGRADIENTFILL 1 0 1 0 0 0 1 0
+ table[119] = 0xA0; // U_EMRSETLINKEDUFIS 1 0 1 0 0 0 0 0
+ table[120] = 0x20; // U_EMRSETTEXTJUSTIFICATION 0 0 1 0 0 0 0 0
+ table[121] = 0xA0; // U_EMRCOLORMATCHTOTARGETW 1 0 1 0 0 0 0 0
+ table[122] = 0xA0; // U_EMRCREATECOLORSPACEW 1 0 1 0 0 0 0 0
+ }
+ result = table[type];
+ }
+ return(result);
+}
+
+/**
+ \brief Derive from bounding rect, start and end radials, for arc, chord, or pie, the center, start, and end points, and the bounding rectangle.
+
+ \return 0 on success, other values on errors.
+ \param rclBox bounding rectangle
+ \param ArcStart start of arc
+ \param ArcEnd end of arc
+ \param f1 1 if rotation angle >= 180, else 0
+ \param f2 Rotation direction, 1 if counter clockwise, else 0
+ \param center Center coordinates
+ \param start Start coordinates (point on the ellipse defined by rect)
+ \param end End coordinates (point on the ellipse defined by rect)
+ \param size W,H of the x,y axes of the bounding rectangle.
+*/
+int emr_arc_points_common(
+ PU_RECTL rclBox,
+ PU_POINTL ArcStart,
+ PU_POINTL ArcEnd,
+ int *f1,
+ int f2,
+ PU_PAIRF center,
+ PU_PAIRF start,
+ PU_PAIRF end,
+ PU_PAIRF size
+ ){
+ U_PAIRF estart; // EMF start position, defines a radial
+ U_PAIRF eend; // EMF end position, defines a radial
+ U_PAIRF vec_estart; // define a unit vector from the center to estart
+ U_PAIRF vec_eend; // define a unit vector from the center to eend
+ U_PAIRF radii; // x,y radii of ellipse
+ U_PAIRF ratio; // intermediate value
+ float scale, cross;
+ center->x = ((float)(rclBox->left + rclBox->right ))/2.0;
+ center->y = ((float)(rclBox->top + rclBox->bottom))/2.0;
+ size->x = (float)(rclBox->right - rclBox->left );
+ size->y = (float)(rclBox->bottom - rclBox->top );
+ estart.x = (float)(ArcStart->x);
+ estart.y = (float)(ArcStart->y);
+ eend.x = (float)(ArcEnd->x);
+ eend.y = (float)(ArcEnd->y);
+ radii.x = size->x/2.0;
+ radii.y = size->y/2.0;
+
+ vec_estart.x = (estart.x - center->x); // initial vector, not unit length
+ vec_estart.y = (estart.y - center->y);
+ scale = sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y);
+ if(!scale)return(1); // bogus record, has start at center
+ vec_estart.x /= scale; // now a unit vector
+ vec_estart.y /= scale;
+
+ vec_eend.x = (eend.x - center->x); // initial vector, not unit length
+ vec_eend.y = (eend.y - center->y);
+ scale = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y);
+ if(!scale)return(2); // bogus record, has end at center
+ vec_eend.x /= scale; // now a unit vector
+ vec_eend.y /= scale;
+
+
+ // Find the intersection of the vectors with the ellipse. With no loss of generality
+ // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector)
+ // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1. x is t*(ux), y is t*(uy), where ux,uy are the x,y components
+ // of the unit vector. Substituting gives:
+ // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1
+ // t^2 = 1/( (ux/Rx)^2 + (uy/Ry)^2 )
+ // t = sqrt(1/( (ux/Rx)^2 + (uy/Ry)^2 ))
+
+ ratio.x = vec_estart.x/radii.x;
+ ratio.y = vec_estart.y/radii.y;
+ ratio.x *= ratio.x; // we only use the square
+ ratio.y *= ratio.y;
+ scale = 1.0/sqrt(ratio.x + ratio.y);
+ start->x = center->x + scale * vec_estart.x;
+ start->y = center->y + scale * vec_estart.y;
+
+ ratio.x = vec_eend.x/radii.x;
+ ratio.y = vec_eend.y/radii.y;
+ ratio.x *= ratio.x; // we only use the square
+ ratio.y *= ratio.y;
+ scale = 1.0/sqrt(ratio.x + ratio.y);
+ end->x = center->x + scale * vec_eend.x;
+ end->y = center->y + scale * vec_eend.y;
+
+ //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation
+ //and the two unit vectors.
+
+ cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x;
+ if(!f2){ // counter clockwise rotation
+ if(cross >=0){ *f1 = 1; }
+ else { *f1 = 0; }
+ }
+ else {
+ if(cross >=0){ *f1 = 0; }
+ else { *f1 = 1; }
+ }
+
+
+ return(0);
+}
+
+/**
+ \brief Derive from an EMF arc, chord, or pie the center, start, and end points, and the bounding rectangle.
+
+ \return 0 on success, other values on errors.
+ \param record U_EMRPIE, U_EMRCHORD, or _EMRARC record
+ \param f1 1 if rotation angle >= 180, else 0
+ \param f2 Rotation direction, 1 if counter clockwise, else 0
+ \param center Center coordinates
+ \param start Start coordinates (point on the ellipse defined by rect)
+ \param end End coordinates (point on the ellipse defined by rect)
+ \param size W,H of the x,y axes of the bounding rectangle.
+*/
+int emr_arc_points(
+ PU_ENHMETARECORD record,
+ int *f1,
+ int f2,
+ PU_PAIRF center,
+ PU_PAIRF start,
+ PU_PAIRF end,
+ PU_PAIRF size
+ ){
+ PU_EMRARC pEmr = (PU_EMRARC) (record);
+ return emr_arc_points_common(&(pEmr->rclBox), &(pEmr->ptlStart), &(pEmr->ptlEnd), f1, f2, center, start, end, size );
+}
+
+/**
+ \brief Convert a U_RGBA 32 bit pixmap to one of many different types of DIB pixmaps.
+
+ Conversions to formats using color tables assume that the color table can hold every color
+ in the input image. If that assumption is false then the conversion will fail. Conversion
+ from 8 bit color to N bit colors (N<8) do so by shifting the appropriate number of bits.
+
+ \return 0 on success, other values on errors.
+ \param px DIB pixel array
+ \param cbPx DIB pixel array size in bytes
+ \param ct DIB color table
+ \param numCt DIB color table number of entries
+ \param rgba_px U_RGBA pixel array (32 bits)
+ \param w Width of pixel array
+ \param h Height of pixel array
+ \param stride Row stride of input pixel array in bytes
+ \param colortype DIB BitCount Enumeration
+ \param use_ct If true use color table (only for 1-16 bit DIBs).
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int RGBA_to_DIB(
+ char **px,
+ uint32_t *cbPx,
+ PU_RGBQUAD *ct,
+ int *numCt,
+ const char *rgba_px,
+ int w,
+ int h,
+ int stride,
+ uint32_t colortype,
+ int use_ct,
+ int invert
+ ){
+ int bs;
+ int pad;
+ int i,j,k;
+ int istart, iend, iinc;
+ uint8_t r,g,b,a,tmp8;
+ char *pxptr;
+ const char *rptr;
+ int found;
+ int usedbytes;
+ U_RGBQUAD color;
+ PU_RGBQUAD lct;
+ int32_t index;
+
+ *px=NULL;
+ *ct=NULL;
+ *numCt=0;
+ *cbPx=0;
+ // sanity checking
+ if(!w || !h || !stride || !colortype || !rgba_px)return(1);
+ if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels
+ if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit
+
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = w*bs;
+ }
+ pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
+ *cbPx = h * (usedbytes + pad); // Rows must start on a 4 byte boundary!
+ *px = (char *) malloc(*cbPx);
+ if(!px)return(4);
+ if(use_ct){
+ *numCt = 1<< colortype;
+ if(*numCt >w*h)*numCt=w*h;
+ lct = (PU_RGBQUAD) malloc(*numCt * sizeof(U_RGBQUAD));
+ if(!lct)return(5);
+ *ct = lct;
+ }
+
+ if(invert){
+ istart = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+ else {
+ istart = 0;
+ iend = h;
+ iinc = 1;
+ }
+
+ found = 0;
+ tmp8 = 0;
+ pxptr = *px;
+ for(i=istart; i!=iend; i+=iinc){
+ rptr= rgba_px + i*stride;
+ for(j=0; j<w; j++){
+ r = *rptr++;
+ g = *rptr++;
+ b = *rptr++;
+ a = *rptr++;
+ if(use_ct){
+ color = U_BGRA(r,g,b,a); // color has order in memory: b,g,r,a, same as EMF+ ARGB
+ index = -1;
+ for(lct = *ct, k=0; k<found; k++,lct++){ // Is this color in the table (VERY inefficient if there are a lot of colors!!!)
+ if(*(uint32_t *)lct != *(uint32_t *) &color)continue;
+ index =k;
+ break;
+ }
+ if(index==-1){ // add a color
+ found++;
+ if(found > *numCt){ // More colors found than are supported by the color table
+ free(*ct);
+ free(*px);
+ *numCt=0;
+ *cbPx=0;
+ return(6);
+ }
+ index = found - 1;
+ *lct = color;
+ }
+ switch(colortype){
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ tmp8 = tmp8 >> 1; // This seems wrong, as it fills from the top of each byte. But it works.
+ tmp8 |= index << 7;
+ if(!((j+1) % 8)){
+ *pxptr++ = tmp8;
+ tmp8 = 0;
+ }
+ break;
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ tmp8 = tmp8 << 4;
+ tmp8 |= index;
+ if(!((j+1) % 2)){
+ *pxptr++ = tmp8;
+ tmp8 = 0;
+ }
+ break;
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ tmp8 = index;
+ *pxptr++ = tmp8;
+ break;
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ else {
+ switch(colortype){
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ b /= 8; g /= 8; r /= 8;
+ // Do it in this way so that the bytes are always stored Little Endian
+ tmp8 = b;
+ tmp8 |= g<<5; // least significant 3 bits of green
+ *pxptr++ = tmp8;
+ tmp8 = g>>3; // most significant 2 bits of green (there are only 5 bits of data)
+ tmp8 |= r<<2;
+ *pxptr++ = tmp8;
+ break;
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ *pxptr++ = b;
+ *pxptr++ = g;
+ *pxptr++ = r;
+ break;
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ *pxptr++ = b;
+ *pxptr++ = g;
+ *pxptr++ = r;
+ *pxptr++ = a;
+ break;
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ }
+ if( use_ct && colortype == U_BCBM_MONOCHROME && (j % 8) ){
+ *pxptr++ = tmp8; // Write last few indices
+ tmp8 = 0;
+ }
+ if( use_ct && colortype == U_BCBM_COLOR4 && (j % 2) ){
+ *pxptr++ = tmp8; // Write last few indices
+ tmp8 = 0;
+ }
+ if(pad){
+ memset(pxptr,0,pad); // not strictly necessary, but set all bytes so that we can find important unset ones with valgrind
+ pxptr += pad;
+ }
+ }
+ return(0);
+}
+
+/**
+ \brief Get the actual number of colors in the color table from the BitMapInfoHeader.
+ \return Number of entries in the color table.
+ \param Bmih char * pointer to the U_BITMAPINFOHEADER
+
+ BitmapInfoHeader may list 0 for some types which implies the maximum value.
+ If the image is big enough, that is set by the bit count, as in 256 for an 8
+ bit image.
+ If the image is smaller it is set by width * height.
+ Note, this may be called by WMF code, so it is not safe to assume the data is aligned.
+*/
+int get_real_color_count(
+ const char *Bmih
+ ){
+ int Colors, BitCount, Width, Height;
+ uint32_t utmp4;
+ uint16_t utmp2;
+ int32_t tmp4;
+ char *cBmih = (char *) Bmih;
+ memcpy(&utmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); Colors = utmp4;
+ memcpy(&utmp2, cBmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); BitCount = utmp2;
+ memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); Width = tmp4;
+ memcpy(&tmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); Height = tmp4;
+ return(get_real_color_icount(Colors, BitCount, Width, Height));
+}
+
+/**
+ \brief Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height.
+ \return Number of entries in the color table.
+ \param Colors Number of colors in the table.
+ \param BitCount BitCount Enumeration
+ \param Width bitmap width
+ \param Height bitmap height
+*/
+int get_real_color_icount(
+ int Colors,
+ int BitCount,
+ int Width,
+ int Height
+ ){
+ int area = Width * Height;
+ if(area < 0){ area = -area; } /* Height might be negative */
+ if(Colors == 0){
+ if( BitCount == U_BCBM_MONOCHROME){ Colors = 2; }
+ else if(BitCount == U_BCBM_COLOR4 ){ Colors = 16; }
+ else if(BitCount == U_BCBM_COLOR8 ){ Colors = 256; }
+ if(Colors > area){ Colors = area; }
+ }
+ return(Colors);
+}
+
+
+/**
+ \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA()
+
+ \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid.
+ \param record pointer to EMR record that has a U_BITMAPINFO and bitmap
+ \param offBitsSrc Offset to the bitmap
+ \param offBmiSrc Offset to the U_BITMAPINFO
+ \param px pointer to DIB pixel array in pEmr
+ \param ct pointer to DIB color table in pEmr
+ \param numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image
+ \param width Width of pixel array
+ \param height Height of pixel array (always returned as a positive number)
+ \param colortype DIB BitCount Enumeration
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int get_DIB_params(
+ const char *record,
+ uint32_t offBitsSrc,
+ uint32_t offBmiSrc,
+ const char **px,
+ const U_RGBQUAD **ct,
+ uint32_t *numCt,
+ uint32_t *width,
+ uint32_t *height,
+ uint32_t *colortype,
+ uint32_t *invert
+ ){
+ uint32_t bic;
+ PU_BITMAPINFO Bmi = (PU_BITMAPINFO)(record + offBmiSrc);
+ PU_BITMAPINFOHEADER Bmih = &(Bmi->bmiHeader);
+ /* if biCompression is not U_BI_RGB some or all of the following might not hold real values */
+ bic = Bmih->biCompression;
+ *width = Bmih->biWidth;
+ *colortype = Bmih->biBitCount;
+ if(Bmih->biHeight < 0){
+ *height = -Bmih->biHeight;
+ *invert = 1;
+ }
+ else {
+ *height = Bmih->biHeight;
+ *invert = 0;
+ }
+ if(bic == U_BI_RGB){
+ *numCt = get_real_color_count((const char *) Bmih);
+ if( numCt){ *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); }
+ else { *ct = NULL; }
+ }
+ else if(bic == U_BI_BITFIELDS){ /* to date only encountered once, for 32 bit, from PPT*/
+ *numCt = 0;
+ *ct = NULL;
+ bic = U_BI_RGB; /* there seems to be no difference, at least for the 32 bit images */
+ }
+ else {
+ *numCt = Bmih->biSizeImage;
+ *ct = NULL;
+ }
+ *px = record + offBitsSrc;
+ return(bic);
+}
+
+/**
+ \brief Convert one of many different types of DIB pixmaps to an RGBA 32 bit pixmap.
+
+ \return 0 on success, other values on errors.
+ \param px DIB pixel array
+ \param ct DIB color table
+ \param numCt DIB color table number of entries
+ \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ \param w Width of pixel array in the record
+ \param h Height of pixel array in the record
+ \param colortype DIB BitCount Enumeration
+ \param use_ct Kept for symmetry with RGBA_to_DIB, should be set to numCt
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int DIB_to_RGBA(
+ const char *px,
+ const U_RGBQUAD *ct,
+ int numCt,
+ char **rgba_px,
+ int w,
+ int h,
+ uint32_t colortype,
+ int use_ct,
+ int invert
+ ){
+ uint32_t cbRgba_px;
+ int stride;
+ int bs;
+ int pad;
+ int i,j;
+ int istart, iend, iinc;
+ uint8_t r,g,b,a,tmp8;
+ const char *pxptr;
+ char *rptr;
+ int usedbytes;
+ U_RGBQUAD color;
+ int32_t index;
+
+ // sanity checking
+ if(!w || !h || !colortype || !px)return(1);
+ if(use_ct && colortype >= U_BCBM_COLOR16)return(2); //color tables not used above 16 bit pixels
+ if(!use_ct && colortype < U_BCBM_COLOR16)return(3); //color tables mandatory for < 16 bit
+ if(use_ct && !numCt)return(4); //color table not adequately described
+
+ stride = w * 4;
+ cbRgba_px = stride * h;
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (w*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = w*bs;
+ }
+ pad = UP4(usedbytes) - usedbytes; // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
+ *rgba_px = (char *) malloc(cbRgba_px);
+ if(!rgba_px)return(4);
+
+ if(invert){
+ istart = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+ else {
+ istart = 0;
+ iend = h;
+ iinc = 1;
+ }
+
+ pxptr = px;
+ tmp8 = 0; // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized
+ for(i=istart; i!=iend; i+=iinc){
+ rptr= *rgba_px + i*stride;
+ for(j=0; j<w; j++){
+ if(use_ct){
+ switch(colortype){
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ if(!(j % 8)){ tmp8 = *pxptr++; }
+ index = 0x80 & tmp8; // This seems wrong, as lowest position is top bit, but it works.
+ index = index >> 7;
+ tmp8 = tmp8 << 1;
+ break;
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ if(!(j % 2)){ tmp8 = *pxptr++; }
+ index = 0xF0 & tmp8;
+ index = index >> 4;
+ tmp8 = tmp8 << 4;
+ break;
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ index = (uint8_t) *pxptr++;;
+ break;
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ color = ct[index];
+ b = U_BGRAGetB(color);
+ g = U_BGRAGetG(color);
+ r = U_BGRAGetR(color);
+ a = U_BGRAGetA(color);
+ }
+ else {
+ switch(colortype){
+ case U_BCBM_COLOR16: // 2^16 colors. (Several different color methods))
+ // Do it in this way because the bytes are always stored Little Endian
+ tmp8 = *pxptr++;
+ b = (0x1F & tmp8) <<3; // 5 bits of b into the top 5 of 8
+ g = tmp8 >> 5; // least significant 3 bits of green
+ tmp8 = *pxptr++;
+ r = (0x7C & tmp8) << 1; // 5 bits of r into the top 5 of 8
+ g |= (0x3 & tmp8) << 3; // most significant 2 bits of green (there are only 5 bits of data)
+ g = g << 3; // restore intensity (have lost 3 bits of accuracy)
+ a = 0;
+ break;
+ case U_BCBM_COLOR24: // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+ b = *pxptr++;
+ g = *pxptr++;
+ r = *pxptr++;
+ a = 0;
+ break;
+ case U_BCBM_COLOR32: // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+ b = *pxptr++;
+ g = *pxptr++;
+ r = *pxptr++;
+ a = *pxptr++;
+ break;
+ case U_BCBM_MONOCHROME: // 2 colors. bmiColors array has two entries
+ case U_BCBM_COLOR4: // 2^4 colors. bmiColors array has 16 entries
+ case U_BCBM_COLOR8: // 2^8 colors. bmiColors array has 256 entries
+ case U_BCBM_EXPLICIT: // Derinved from JPG or PNG compressed image or ?
+ default:
+ return(7); // This should not be possible, but might happen with memory corruption
+ }
+ }
+ *rptr++ = r;
+ *rptr++ = g;
+ *rptr++ = b;
+ *rptr++ = a;
+ }
+ for(j=0; j<pad; j++){ pxptr++; } // DIB rows are all 4 byte aligned
+ }
+ return(0);
+}
+
+/**
+ \brief Extract a subset of an RGBA bitmap array.
+ Frees the incoming bitmap array IF a subset is extracted, otherwise it is left alone.
+ If the entire array is extracted it just returns the incoming pointer.
+ If the subset requested is partially outside of the bitmap the region is clipped to the
+ bitmap boundaries and extracted. This seems to be a (very) grey area in EMF files, and
+ even different Microsoft applications do not always do the same thing. For instance,
+ XP Preview gives some different images for EMR_BITBLT records than does the "import image"
+ (but not unpacked) view in PowerPoint. Since all of these states are probably best viewed
+ as undefined or errors we can only try to do something reasonable and not blow up when
+ encountering one.
+
+ \return Pointer to the sub array on success, NULL otherwise.
+ \param rgba_px U_RGBA pixel array (32 bits), created by this routine, caller must free.
+ \param w Width of pixel array in the record
+ \param h Height of pixel array in the record
+ \param sl start left position in the pixel array in the record to start extracting
+ \param st start top position in the pixel array in the record to start extracting
+ \param eew Width of pixel array to extract
+ \param eeh Height of pixel array to extract
+*/
+char *RGBA_to_RGBA(
+ char *rgba_px,
+ int w,
+ int h,
+ int sl,
+ int st,
+ int *eew,
+ int *eeh
+ ){
+ int i;
+ char *sub;
+ char *sptr;
+ int ew = *eew;
+ int eh = *eeh;
+
+ // sanity checking
+ if(w<=0 || h<=0 || ew<=0 || eh<=0 || !rgba_px)return(NULL);
+
+ if(sl>w || st >h)return(NULL); // This is hopeless, the start point is outside of the array.
+ if(sl<0){
+ if(sl+ew<=0)return(NULL); // This is hopeless, the start point is outside of the array.
+ ew += sl;
+ sl = 0;
+ }
+ if(st<0){
+ if(st+eh<=0)return(NULL); // This is hopeless, the start point is outside of the array.
+ eh += st;
+ st = 0;
+ }
+ if(sl+ew > w)ew=w-sl;
+ if(st+eh > h)eh=h-st;
+ if(!sl && !st && (ew == w) && (eh == h)){
+ sub = rgba_px;
+ }
+ else {
+ sptr = sub = malloc(ew*eh*4);
+ if(!sub)return(NULL);
+ for(i=st; i<st+eh; i++){
+ memcpy(sptr,rgba_px + i*w*4 + sl*4,4*ew);
+ sptr += 4*ew;
+ }
+ free(rgba_px);
+ }
+ *eeh = eh;
+ *eew = ew;
+ return(sub);
+ }
+
+
+/* **********************************************************************************************
+These functions are for setting up, appending to, and then tearing down an EMF structure, including
+writing the final data structure out to a file.
+*********************************************************************************************** */
+
+/**
+ \brief Duplicate an EMR record.
+ \param emr record to duplicate
+*/
+char *emr_dup(
+ const char *emr
+ ){
+ char *dup;
+ int irecsize;
+
+ if(!emr)return(NULL);
+ irecsize = ((PU_EMR)emr)->nSize;
+ dup=malloc(irecsize);
+ if(dup){ memcpy(dup,emr,irecsize); }
+ return(dup);
+}
+
+
+/**
+ \brief Start constructing an emf in memory. Supply the file name and initial size.
+ \return 0 for success, >=0 for failure.
+ \param name EMF filename (will be opened)
+ \param initsize Initialize EMF in memory to hold this many bytes
+ \param chunksize When needed increase EMF in memory by this number of bytes
+ \param et EMF in memory
+
+
+*/
+int emf_start(
+ const char *name,
+ const uint32_t initsize,
+ const uint32_t chunksize,
+ EMFTRACK **et
+ ){
+ FILE *fp;
+ EMFTRACK *etl=NULL;
+
+ if(initsize < 1)return(1);
+ if(chunksize < 1)return(2);
+ if(!name)return(3);
+ etl = (EMFTRACK *) malloc(sizeof(EMFTRACK));
+ if(!etl)return(4);
+ etl->buf = malloc(initsize); // no need to zero the memory
+ if(!etl->buf){
+ free(etl);
+ return(5);
+ }
+ fp=emf_fopen(name,U_WRITE);
+ if(!fp){
+ free(etl->buf);
+ free(etl);
+ return(6);
+ }
+ etl->fp = fp;
+ etl->allocated = initsize;
+ etl->used = 0;
+ etl->records = 0;
+ etl->PalEntries = 0;
+ etl->chunk = chunksize;
+ *et=etl;
+ return(0);
+}
+
+/**
+ \brief Finalize the emf in memory and write it to the file.
+ \return 0 on success, >=1 on failure
+ \param et EMF in memory
+ \param eht EMF handle table (peak handle number needed)
+*/
+int emf_finish(
+ EMFTRACK *et,
+ EMFHANDLES *eht
+ ){
+ U_EMRHEADER *record;
+
+ if(!et->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in emf_start
+
+ // Set the header fields which were unknown up until this point
+
+ record = (U_EMRHEADER *)et->buf;
+ record->nBytes = et->used;
+ record->nRecords = et->records;
+ record->nHandles = eht->peak + 1;
+ record->nPalEntries = et->PalEntries;
+
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, EMF data must be Little Endian
+ U_emf_endian(et->buf,et->used,1);
+#endif
+
+ if(1 != fwrite(et->buf,et->used,1,et->fp))return(2);
+ (void) fclose(et->fp);
+ et->fp=NULL;
+ return(0);
+}
+
+/**
+ \brief Release memory for an emf structure in memory. Call this after emf_finish().
+ \return 0 on success, >=1 on failure
+ \param et EMF in memory
+*/
+int emf_free(
+ EMFTRACK **et
+ ){
+ EMFTRACK *etl;
+ if(!et)return(1);
+ etl=*et;
+ if(!etl)return(2);
+ free(etl->buf);
+ free(etl);
+ *et=NULL;
+ return(0);
+}
+
+/**
+ \brief wrapper for fopen, works on any platform
+ \return 0 on success, >=1 on failure
+ \param filename file to open (either ASCII or UTF-8)
+ \param mode U_READ or U_WRITE (these map to "rb" and "wb")
+*/
+FILE *emf_fopen(
+ const char *filename,
+ const int mode
+ ){
+ FILE *fp = NULL;
+#ifdef WIN32
+ uint16_t *fn16;
+ uint16_t *md16;
+ if(mode == U_READ){ md16 = U_Utf8ToUtf16le("rb", 0, NULL); }
+ else { md16 = U_Utf8ToUtf16le("wb", 0, NULL); }
+ fn16 = U_Utf8ToUtf16le(filename, 0, NULL);
+ fp = _wfopen(fn16,md16);
+ free(fn16);
+ free(md16);
+#else
+ if(mode == U_READ){ fp = fopen(filename,"rb"); }
+ else { fp = fopen(filename,"wb"); }
+#endif
+ return(fp);
+}
+
+/**
+ \brief Retrieve contents of an EMF file by name.
+ \return 0 on success, >=1 on failure
+ \param filename Name of file to open, including the path
+ \param contents Contents of the file. Buffer must be free()'d by caller.
+ \param length Number of bytes in Contents
+*/
+int emf_readdata(
+ const char *filename,
+ char **contents,
+ size_t *length
+ ){
+ FILE *fp;
+ int status=0;
+
+ *contents=NULL;
+ fp=emf_fopen(filename,U_READ);
+ if(!fp){ status = 1; }
+ else {
+ // read the entire file into memory
+ fseek(fp, 0, SEEK_END); // move to end
+ *length = ftell(fp);
+ rewind(fp);
+ *contents = (char *) malloc(*length);
+ if(!*contents){
+ status = 2;
+ }
+ else {
+ size_t inbytes = fread(*contents,*length,1,fp);
+ if(inbytes != 1){
+ free(*contents);
+ status = 3;
+ }
+ else {
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, EMF data is Little Endian
+ U_emf_endian(*contents,*length,0); // LE to BE
+#endif
+ }
+ }
+ fclose(fp);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Append an EMF record to an emf in memory. This may reallocate buf memory.
+ \return 0 for success, >=1 for failure.
+ \param rec Record to append to EMF in memory
+ \param et EMF in memory
+ \param freerec If true, free rec after append
+*/
+int emf_append(
+ U_ENHMETARECORD *rec,
+ EMFTRACK *et,
+ int freerec
+ ){
+ size_t deficit;
+
+#ifdef U_VALGRIND
+ printf("\nbefore \n");
+ printf(" probe %d\n",memprobe(rec, U_EMRSIZE(rec)));
+ printf("after \n");
+#endif
+ if(!rec)return(1);
+ if(!et)return(2);
+ if(rec->nSize + et->used > et->allocated){
+ deficit = rec->nSize + et->used - et->allocated;
+ if(deficit < et->chunk)deficit = et->chunk;
+ et->allocated += deficit;
+ et->buf = realloc(et->buf,et->allocated);
+ if(!et->buf)return(3);
+ }
+ memcpy(et->buf + et->used, rec, rec->nSize);
+ et->used += rec->nSize;
+ et->records++;
+ if(rec->iType == U_EMR_EOF){ et->PalEntries = ((U_EMREOF *)rec)->cbPalEntries; }
+ if(freerec){ free(rec); }
+ return(0);
+}
+
+/**
+ \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle.
+ \return 0 for success, >=1 for failure.
+ \param initsize Initialize with space for this number of handles
+ \param chunksize When needed increase space by this number of handles
+ \param eht EMF handle table
+*/
+int emf_htable_create(
+ uint32_t initsize,
+ uint32_t chunksize,
+ EMFHANDLES **eht
+ ){
+ EMFHANDLES *ehtl;
+ unsigned int i;
+
+ if(initsize<1)return(1);
+ if(chunksize<1)return(2);
+ ehtl = (EMFHANDLES *) malloc(sizeof(EMFHANDLES));
+ if(!ehtl)return(3);
+ ehtl->table = malloc(initsize * sizeof(uint32_t));
+ if(!ehtl->table){
+ free(ehtl);
+ return(4);
+ }
+ ehtl->stack = malloc(initsize * sizeof(uint32_t));
+ if(!ehtl->stack){
+ free(ehtl->table);
+ free(ehtl);
+ return(5);
+ }
+ memset(ehtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table
+ for(i=1; i<initsize; i++){ehtl->stack[i]=i;} // preset the stack
+ ehtl->allocated = initsize;
+ ehtl->chunk = chunksize;
+ ehtl->table[0] = 0; // This slot isn't actually ever used
+ ehtl->stack[0] = 0; // This stack position isn't actually ever used
+ ehtl->peak = 1;
+ ehtl->sptr = 1;
+ ehtl->top = 0;
+ *eht = ehtl;
+ return(0);
+}
+
+/**
+ \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param eht EMF handle table
+
+*/
+int emf_htable_delete(
+ uint32_t *ih,
+ EMFHANDLES *eht
+ ){
+ if(!eht)return(1);
+ if(!eht->table)return(2);
+ if(!eht->stack)return(3);
+ if(*ih < 1)return(4); // invalid handle
+ if(!eht->table[*ih])return(5); // requested table position was not in use
+ eht->table[*ih]=0; // remove handle from table
+ while(eht->top>0 && !eht->table[eht->top]){ // adjust top
+ eht->top--;
+ }
+ eht->sptr--; // adjust stack
+ eht->stack[eht->sptr]=*ih; // place handle on stack
+ *ih=0; // invalidate handle variable, so a second delete will of it is not possible
+ return(0);
+}
+
+/**
+ \brief Returns the index of the first free slot.
+ Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param eht EMF handle table
+*/
+int emf_htable_insert(
+ uint32_t *ih,
+ EMFHANDLES *eht
+ ){
+ unsigned int i;
+ size_t newsize;
+
+ if(!eht)return(1);
+ if(!eht->table)return(2);
+ if(!eht->stack)return(3);
+ if(!ih)return(4);
+ if(eht->sptr >= eht->allocated - 1){ // need to reallocate
+ newsize=eht->allocated + eht->chunk;
+ eht->table = realloc(eht->table,newsize * sizeof(uint32_t));
+ if(!eht->table)return(5);
+ memset(&eht->table[eht->allocated] , 0, eht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table
+
+ eht->stack = realloc(eht->stack,newsize * sizeof(uint32_t));
+ if(!eht->stack)return(6);
+ for(i=eht->allocated; i<newsize;i++){ eht->stack[i] = i; } // init all NEW slots in the stack
+ eht->allocated = newsize;
+ }
+ *ih = eht->stack[eht->sptr]; // handle that is inserted
+ if(eht->table[*ih])return(7);
+ eht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table
+ eht->stack[eht->sptr] = 0;
+ if(*ih > eht->top){ eht->top = *ih; }
+ if(eht->sptr > eht->peak){ eht->peak = eht->sptr; }
+ eht->sptr++; // next available handle
+ return(0);
+}
+
+/**
+ \brief Free all memory in an htable. Sets the pointer to NULL.
+ \return 0 for success, >=1 for failure.
+ \param eht EMF handle table
+*/
+int emf_htable_free(
+ EMFHANDLES **eht
+ ){
+ EMFHANDLES *ehtl;
+ if(!eht)return(1);
+ ehtl = *eht;
+ if(!ehtl)return(2);
+ if(!ehtl->table)return(3);
+ if(!ehtl->stack)return(4);
+ free(ehtl->table);
+ free(ehtl->stack);
+ free(ehtl);
+ *eht=NULL;
+ return(0);
+}
+
+/* **********************************************************************************************
+These functions create standard structures used in the EMR records.
+*********************************************************************************************** */
+
+
+/**
+ \brief Set up fields for an EMR_HEADER from the physical device's width and height in mm and dots per millimeter.
+ Typically this is something like 216,279,47.244 (Letter paper, 1200 DPI = 47.244 DPmm)
+ \return 0 for success, >=1 for failure.
+ \param xmm Device width in millimeters
+ \param ymm Device height in millimeters
+ \param dpmm Dots per millimeter
+ \param szlDev Device size structure in pixels
+ \param szlMm Device size structure in mm
+*/
+int device_size(
+ const int xmm,
+ const int ymm,
+ const float dpmm,
+ U_SIZEL *szlDev,
+ U_SIZEL *szlMm
+ ){
+ if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
+ szlDev->cx = U_ROUND((float) xmm * dpmm);
+ szlDev->cy = U_ROUND((float) ymm * dpmm);;
+ szlMm->cx = xmm;
+ szlMm->cy = ymm;
+ return(0);
+}
+
+/**
+ \brief Set up fields for an EMR_HEADER for drawing by physical size in mm and dots per millimeter.
+ Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way
+ of knowing this since it never actually draws anything. Instead this is set to the full drawing size.
+ Coordinates are inclusive inclusive, so 297 -> 0,29699.
+ \return 0 for success, >=1 for failure.
+ \param xmm Drawing width in millimeters
+ \param ymm Drawing height in millimeters
+ \param dpmm Dots per millimeter
+ \param rclBounds Drawing size structure in pixels
+ \param rclFrame Drawing size structure in mm
+*/
+int drawing_size(
+ const int xmm,
+ const int ymm,
+ const float dpmm,
+ U_RECTL *rclBounds,
+ U_RECTL *rclFrame
+ ){
+ if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
+ rclBounds->left = 0;
+ rclBounds->top = 0;
+ rclBounds->right = U_ROUND((float) xmm * dpmm) - 1; // because coordinate system is 0,0 in upper left, N,M in lower right
+ rclBounds->bottom = U_ROUND((float) ymm * dpmm) - 1;
+ rclFrame->left = 0;
+ rclFrame->top = 0;
+ rclFrame->right = U_ROUND((float) xmm * 100.) - 1;
+ rclFrame->bottom = U_ROUND((float) ymm * 100.) - 1;
+ return(0);
+}
+
+/**
+ \brief Set a U_COLORREF value from separate R,G,B values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+
+*/
+U_COLORREF colorref3_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue
+ ){
+ U_COLORREF cr = (U_COLORREF){red , green, blue, 0};
+ return(cr);
+}
+
+/**
+ \brief Set a U_COLORREF value from separate R,G,B, and Reserved values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+ \param Reserved Reserved component
+
+*/
+U_COLORREF colorref4_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t Reserved
+ ){
+ U_COLORREF cr = (U_COLORREF){red , green, blue, Reserved};
+ return(cr);
+}
+
+/**
+ \brief Set a U_RGBQUAD value from separate R,G,B, Reserved values.
+ \param red Red component
+ \param green Green component
+ \param blue Blue component
+ \param reserved Reserved component
+
+*/
+U_RGBQUAD rgbquad_set(
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t reserved
+ ){
+ U_RGBQUAD cr = (U_RGBQUAD){blue , green, red, reserved};
+ return(cr);
+}
+
+/**
+ \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
+ \param ul upper left corner of rectangle
+ \param lr lower right corner of rectangle
+*/
+U_RECTL rectl_set(
+ U_POINTL ul,
+ U_POINTL lr
+ ){
+ U_RECTL rct;
+ rct.left = ul.x;
+ rct.top = ul.y;
+ rct.right = lr.x;
+ rct.bottom = lr.y;
+ return(rct);
+}
+
+/**
+ \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
+ \param array array of rectangles
+ \param index array entry to fill, numbered from 0
+ \param ul upper left corner of rectangle
+ \param lr lower right corner of rectangle
+*/
+void rectli_set(
+ PU_RECTL array,
+ int index,
+ U_POINTL ul,
+ U_POINTL lr
+ ){
+ PU_RECTL rct = &(array[index]);
+ rct->left = ul.x;
+ rct->top = ul.y;
+ rct->right = lr.x;
+ rct->bottom = lr.y;
+}
+
+/**
+ \brief Set sizel objects with X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_SIZEL sizel_set(
+ int32_t x,
+ int32_t y
+ ){
+ U_SIZEL sz;
+ sz.cx = x;
+ sz.cy = y;
+ return(sz);
+}
+
+/**
+ \brief Set pointl objects with X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_POINTL point32_set(
+ int32_t x,
+ int32_t y
+ ){
+ U_POINTL pt;
+ pt.x = x;
+ pt.y = y;
+ return(pt);
+}
+
+/**
+ \brief Set point16 objects with 16 bit X,Y values.
+ \param x X coordinate
+ \param y Y coordinate
+*/
+U_POINT16 point16_set(
+ int16_t x,
+ int16_t y
+ ){
+ U_POINT16 pt;
+ pt.x = x;
+ pt.y = y;
+ return(pt);
+}
+
+/**
+ \brief Find the bounding rectangle from a polyline of a given width.
+ \param count number of points in the polyline
+ \param pts the polyline
+ \param width width of drawn line
+
+*/
+U_RECT findbounds(
+ uint32_t count,
+ PU_POINT pts,
+ uint32_t width
+ ){
+ U_RECT rect={INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN };
+ unsigned int i;
+
+ for(i=0; i<count;i++,pts++){
+ if ( pts->x < rect.left ) rect.left = pts->x;
+ if ( pts->x > rect.right ) rect.right = pts->x;
+ if ( pts->y < rect.top ) rect.top = pts->y;
+ if ( pts->y > rect.bottom ) rect.bottom = pts->y;
+ }
+ if(width > 0){
+ rect.left -= width;
+ rect.right += width;
+ rect.top += width;
+ rect.bottom -= width;
+ }
+ return(rect);
+}
+
+/**
+ \brief Find the bounding rectangle from a polyline of a given width.
+ \param count number of points in the polyline
+ \param pts the polyline
+ \param width width of drawn line
+
+*/
+U_RECT findbounds16(
+ uint32_t count,
+ PU_POINT16 pts,
+ uint32_t width
+ ){
+ U_RECT rect={INT16_MAX, INT16_MAX, INT16_MIN, INT16_MIN };
+ unsigned int i;
+
+ for(i=0; i<count;i++,pts++){
+ if ( pts->x < rect.left ) rect.left = pts->x;
+ if ( pts->x > rect.right ) rect.right = pts->x;
+ if ( pts->y < rect.top ) rect.top = pts->y;
+ if ( pts->y > rect.bottom ) rect.bottom = pts->y;
+ }
+ if(width > 0){
+ rect.left -= width;
+ rect.right += width;
+ rect.top += width;
+ rect.bottom -= width;
+ }
+ return(rect);
+}
+/**
+ \brief Construct a U_LOGBRUSH structure.
+ \return U_LOGBRUSH structure
+ \param lbStyle LB_Style Enumeration
+ \param lbColor Brush color
+ \param lbHatch HatchStyle Enumertaion
+*/
+U_LOGBRUSH logbrush_set(
+ uint32_t lbStyle,
+ U_COLORREF lbColor,
+ int32_t lbHatch
+ ){
+ U_LOGBRUSH lb;
+ lb.lbStyle = lbStyle;
+ lb.lbColor = lbColor;
+ lb.lbHatch = lbHatch;
+ return(lb);
+}
+
+/**
+ \brief Construct a U_XFORM structure.
+ \return U_XFORM structure
+ \param eM11 Rotation Matrix element
+ \param eM12 Rotation Matrix element
+ \param eM21 Rotation Matrix element
+ \param eM22 Rotation Matrix element
+ \param eDx Translation element
+ \param eDy Translation element
+*/
+U_XFORM xform_set(
+ U_FLOAT eM11,
+ U_FLOAT eM12,
+ U_FLOAT eM21,
+ U_FLOAT eM22,
+ U_FLOAT eDx,
+ U_FLOAT eDy
+ ){
+ U_XFORM xform;
+ xform.eM11 = eM11;
+ xform.eM12 = eM12;
+ xform.eM21 = eM21;
+ xform.eM22 = eM22;
+ xform.eDx = eDx;
+ xform.eDy = eDy;
+ return(xform);
+}
+
+/**
+ \brief Construct a U_XFORM structure.
+ \return U_XFORM structure
+ \param scale Scale factor
+ \param ratio Ratio of minor axis/major axis
+ \param rot Rotation angle in degrees, positive is counter clockwise from the x axis.
+ \param axisrot Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis.
+ \param eDx Translation element
+ \param eDy Translation element
+
+ Operation is:
+ 1 Conformal map of points based on scale, axis rotation, and axis ratio,
+ 2. Apply rotation
+ 3. Apply offset
+*/
+U_XFORM xform_alt_set(
+ U_FLOAT scale,
+ U_FLOAT ratio,
+ U_FLOAT rot,
+ U_FLOAT axisrot,
+ U_FLOAT eDx,
+ U_FLOAT eDy
+ ){
+ U_XFORM xform;
+ U_MAT2X2 mat1, mat2;
+ // angles are in degrees, must be in radians
+ rot *= (2.0 * U_PI)/360.0;
+ axisrot *= -(2.0 * U_PI)/360.0;
+ mat1.M11 = cos(rot); // set up the rotation matrix
+ mat1.M12 = -sin(rot);
+ mat1.M21 = sin(rot);
+ mat1.M22 = cos(rot);
+ if(ratio!=1.0){ // set scale/ellipticity matrix
+ mat2.M11 = scale*( cos(axisrot)*cos(axisrot) + ratio*sin(axisrot)*sin(axisrot) );
+ mat2.M12 = mat2.M21 = scale*( sin(axisrot)*cos(axisrot) * (1.0 - ratio) );
+ mat2.M22 = scale*( sin(axisrot)*sin(axisrot) + ratio*cos(axisrot)*cos(axisrot) );
+ }
+ else { // when the ratio is 1.0 then the major axis angle is ignored and only scale matters
+ mat2.M11 = scale;
+ mat2.M12 = 0.0;
+ mat2.M21 = 0.0;
+ mat2.M22 = scale;
+ }
+ xform.eM11 = mat2.M11 * mat1.M11 + mat2.M12 * mat1.M21;
+ xform.eM12 = mat2.M11 * mat1.M12 + mat2.M12 * mat1.M22;;
+ xform.eM21 = mat2.M21 * mat1.M11 + mat2.M22 * mat1.M21;
+ xform.eM22 = mat2.M21 * mat1.M12 + mat2.M22 * mat1.M22;
+ xform.eDx = eDx;
+ xform.eDy = eDy;
+ return(xform);
+}
+
+
+/**
+ \brief Construct a U_LOGCOLORSPACEA structure.
+ \return U_LOGCOLORSPACEA structure
+ \param lcsCSType LCS_CSType Enumeration
+ \param lcsIntent LCS_Intent Enumeration
+ \param lcsEndpoints CIE XYZ color space endpoints
+ \param lcsGammaRGB Gamma For RGB
+ \param lcsFilename Could name an external color profile file, otherwise empty string
+*/
+U_LOGCOLORSPACEA logcolorspacea_set(
+ int32_t lcsCSType,
+ int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints,
+ U_LCS_GAMMARGB lcsGammaRGB,
+ char *lcsFilename
+ ){
+ U_LOGCOLORSPACEA lcsa;
+ lcsa.lcsSignature = U_LCS_SIGNATURE;
+ lcsa.lcsVersion = U_LCS_SIGNATURE;
+ lcsa.lcsSize = sizeof(U_LOGCOLORSPACEA);
+ lcsa.lcsCSType = lcsCSType;
+ lcsa.lcsIntent = lcsIntent;
+ lcsa.lcsEndpoints = lcsEndpoints;
+ lcsa.lcsGammaRGB = lcsGammaRGB;
+ strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
+ return(lcsa);
+}
+
+/**
+
+ \brief Construct a U_LOGCOLORSPACEW structure.
+ \return U_LOGCOLORSPACEW structure
+ \param lcsCSType LCS_CSType Enumeration
+ \param lcsIntent LCS_Intent Enumeration
+ \param lcsEndpoints CIE XYZ color space endpoints
+ \param lcsGammaRGB Gamma For RGB
+ \param lcsFilename Could name an external color profile file, otherwise empty string
+*/
+U_LOGCOLORSPACEW logcolorspacew_set(
+ int32_t lcsCSType,
+ int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints,
+ U_LCS_GAMMARGB lcsGammaRGB,
+ uint16_t *lcsFilename
+ ){
+ U_LOGCOLORSPACEW lcsa;
+ lcsa.lcsSignature = U_LCS_SIGNATURE;
+ lcsa.lcsVersion = U_LCS_SIGNATURE;
+ lcsa.lcsSize = sizeof(U_LOGCOLORSPACEW);
+ lcsa.lcsCSType = lcsCSType;
+ lcsa.lcsIntent = lcsIntent;
+ lcsa.lcsEndpoints = lcsEndpoints;
+ lcsa.lcsGammaRGB = lcsGammaRGB;
+ wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
+ return(lcsa);
+}
+
+/**
+
+ \brief Construct a U_PANOSE structure.
+ \return U_PANOSE structure
+ \param bFamilyType FamilyType Enumeration
+ \param bSerifStyle SerifType Enumeration
+ \param bWeight Weight Enumeration
+ \param bProportion Proportion Enumeration
+ \param bContrast Contrast Enumeration
+ \param bStrokeVariation StrokeVariation Enumeration
+ \param bArmStyle ArmStyle Enumeration
+ \param bLetterform Letterform Enumeration
+ \param bMidline Midline Enumeration
+ \param bXHeight XHeight Enumeration
+*/
+U_PANOSE panose_set(
+ uint8_t bFamilyType,
+ uint8_t bSerifStyle,
+ uint8_t bWeight,
+ uint8_t bProportion,
+ uint8_t bContrast,
+ uint8_t bStrokeVariation,
+ uint8_t bArmStyle,
+ uint8_t bLetterform,
+ uint8_t bMidline,
+ uint8_t bXHeight
+ ){
+ U_PANOSE panose;
+ panose.bFamilyType = bFamilyType;
+ panose.bSerifStyle = bSerifStyle;
+ panose.bWeight = bWeight;
+ panose.bProportion = bProportion;
+ panose.bContrast = bContrast;
+ panose.bStrokeVariation = bStrokeVariation;
+ panose.bArmStyle = bArmStyle;
+ panose.bLetterform = bLetterform;
+ panose.bMidline = bMidline;
+ panose.bXHeight = bXHeight;
+ return(panose);
+}
+
+/**
+ \brief Construct a U_LOGFONT structure.
+ \return U_LOGFONT structure
+ \param lfHeight Height in Logical units
+ \param lfWidth Average Width in Logical units
+ \param lfEscapement Angle in 0.1 degrees betweem escapement vector and X axis
+ \param lfOrientation Angle in 0.1 degrees between baseline and X axis
+ \param lfWeight LF_Weight Enumeration
+ \param lfItalic Italics: 0 or 1
+ \param lfUnderline Underline: 0 or 1
+ \param lfStrikeOut Strikeout: 0 or 1
+ \param lfCharSet LF_CharSet Enumeration
+ \param lfOutPrecision LF_OutPrecision Enumeration
+ \param lfClipPrecision LF_ClipPrecision Enumeration
+ \param lfQuality LF_Quality Enumeration
+ \param lfPitchAndFamily LF_PitchAndFamily Enumeration
+ \param lfFaceName Name of font. truncates at U_LF_FACESIZE, smaller must be null terminated
+
+*/
+U_LOGFONT logfont_set(
+ int32_t lfHeight,
+ int32_t lfWidth,
+ int32_t lfEscapement,
+ int32_t lfOrientation,
+ int32_t lfWeight,
+ uint8_t lfItalic,
+ uint8_t lfUnderline,
+ uint8_t lfStrikeOut,
+ uint8_t lfCharSet,
+ uint8_t lfOutPrecision,
+ uint8_t lfClipPrecision,
+ uint8_t lfQuality,
+ uint8_t lfPitchAndFamily,
+ uint16_t *lfFaceName
+ ){
+ U_LOGFONT lf;
+ lf.lfHeight = lfHeight;
+ lf.lfWidth = lfWidth;
+ lf.lfEscapement = lfEscapement;
+ lf.lfOrientation = lfOrientation;
+ lf.lfWeight = lfWeight;
+ lf.lfItalic = lfItalic;
+ lf.lfUnderline = lfUnderline;
+ lf.lfStrikeOut = lfStrikeOut;
+ lf.lfCharSet = lfCharSet;
+ lf.lfOutPrecision = lfOutPrecision;
+ lf.lfClipPrecision = lfClipPrecision;
+ lf.lfQuality = lfQuality;
+ lf.lfPitchAndFamily = lfPitchAndFamily;
+ wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero
+ lf.lfFaceName[U_LF_FACESIZE-1] = '\0';
+ return(lf);
+}
+
+
+/**
+ \brief Construct a U_LOGFONT_PANOSE structure.
+ \return U_LOGFONT_PANOSE structure
+ \param elfLogFont Basic font attributes
+ \param elfFullName Font full name, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
+ \param elfStyle Font style, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
+ \param elfStyleSize Font hinting starting at this point size, if 0, starts at Height
+ \param elfPanose Panose Object. If all zero, it is ignored.
+*/
+U_LOGFONT_PANOSE logfont_panose_set(
+ U_LOGFONT elfLogFont,
+ uint16_t *elfFullName,
+ uint16_t *elfStyle,
+ uint32_t elfStyleSize,
+ U_PANOSE elfPanose
+ ){
+ U_LOGFONT_PANOSE lfp;
+ memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0.
+ wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE);
+ lfp.elfFullName[U_LF_FULLFACESIZE-1] = '\0';
+ wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE);
+ lfp.elfStyle[U_LF_FACESIZE-1] = '\0';
+ lfp.elfLogFont = elfLogFont;
+ lfp.elfStyleSize = elfStyleSize;
+ lfp.elfPanose = elfPanose;
+ return(lfp);
+}
+
+/**
+ \brief Construct a U_BITMAPINFOHEADER structure.
+ \return U_BITMAPINFOHEADER structure
+ \param biWidth Bitmap width in pixels
+ \param biHeight Bitmap height in pixels
+ \param biPlanes Planes (must be 1)
+ \param biBitCount BitCount Enumeration
+ \param biCompression BI_Compression Enumeration
+ \param biSizeImage Size in bytes of image
+ \param biXPelsPerMeter X Resolution in pixels/meter
+ \param biYPelsPerMeter Y Resolution in pixels/meter
+ \param biClrUsed Number of bmciColors in U_BITMAPCOREINFO
+ \param biClrImportant Number of bmciColors needed (0 means all).
+*/
+U_BITMAPINFOHEADER bitmapinfoheader_set(
+ int32_t biWidth,
+ int32_t biHeight,
+ uint16_t biPlanes,
+ uint16_t biBitCount,
+ uint32_t biCompression,
+ uint32_t biSizeImage,
+ int32_t biXPelsPerMeter,
+ int32_t biYPelsPerMeter,
+ U_NUM_RGBQUAD biClrUsed,
+ uint32_t biClrImportant
+ ){
+ U_BITMAPINFOHEADER Bmi;
+ Bmi.biSize = sizeof(U_BITMAPINFOHEADER);
+ Bmi.biWidth = biWidth;
+ Bmi.biHeight = biHeight;
+ Bmi.biPlanes = biPlanes;
+ Bmi.biBitCount = biBitCount;
+ Bmi.biCompression = biCompression;
+ Bmi.biSizeImage = biSizeImage;
+ Bmi.biXPelsPerMeter = biXPelsPerMeter;
+ Bmi.biYPelsPerMeter = biYPelsPerMeter;
+ Bmi.biClrUsed = biClrUsed;
+ Bmi.biClrImportant = biClrImportant;
+ return(Bmi);
+}
+
+
+/**
+ \brief Allocate and construct a U_BITMAPINFO structure.
+ \return Pointer to a U_BITMAPINFO structure
+ \param BmiHeader Geometry and pixel properties
+ \param BmiColors Color table (must be NULL for some values of BmiHeader->biBitCount)
+*/
+PU_BITMAPINFO bitmapinfo_set(
+ U_BITMAPINFOHEADER BmiHeader,
+ PU_RGBQUAD BmiColors
+ ){
+ char *record;
+ int irecsize;
+ int cbColors, cbColors4, off;
+
+ cbColors = 4*get_real_color_count((char *) &BmiHeader);
+ cbColors4 = UP4(cbColors);
+ irecsize = sizeof(U_BITMAPINFOHEADER) + cbColors4;
+ record = malloc(irecsize);
+ if(record){
+ memcpy(record, &BmiHeader, sizeof(U_BITMAPINFOHEADER));
+ if(cbColors){
+ off = sizeof(U_BITMAPINFOHEADER);
+ memcpy(record + off, BmiColors, cbColors);
+ off += cbColors;
+ if(cbColors4 - cbColors){ memset(record + off, 0, cbColors4 - cbColors); }
+ }
+ }
+ return((PU_BITMAPINFO) record);
+}
+
+/**
+ \brief Allocate and construct a U_EXTLOGPEN structure.
+ \return pointer to U_EXTLOGPEN structure, or NULL on error
+ \param elpPenStyle PenStyle Enumeration
+ \param elpWidth Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel)
+ \param elpBrushStyle LB_Style Enumeration
+ \param elpColor Pen color
+ \param elpHatch HatchStyle Enumeration
+ \param elpNumEntries Count of StyleEntry array
+ \param elpStyleEntry Array of StyleEntry (For user specified dot/dash patterns)
+*/
+PU_EXTLOGPEN extlogpen_set(
+ uint32_t elpPenStyle,
+ uint32_t elpWidth,
+ uint32_t elpBrushStyle,
+ U_COLORREF elpColor,
+ int32_t elpHatch,
+ U_NUM_STYLEENTRY elpNumEntries,
+ U_STYLEENTRY *elpStyleEntry
+ ){
+ int irecsize,szSyleArray;
+ char *record;
+
+ if(elpNumEntries){
+ if(!elpStyleEntry)return(NULL);
+ szSyleArray = elpNumEntries * sizeof(U_STYLEENTRY);
+ irecsize = sizeof(U_EXTLOGPEN) + szSyleArray - sizeof(U_STYLEENTRY); // first one is in the record
+ }
+ else {
+ szSyleArray = 0;
+ irecsize = sizeof(U_EXTLOGPEN);
+ }
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EXTLOGPEN) record)->elpPenStyle = elpPenStyle;
+ ((PU_EXTLOGPEN) record)->elpWidth = elpWidth;
+ ((PU_EXTLOGPEN) record)->elpBrushStyle = elpBrushStyle;
+ ((PU_EXTLOGPEN) record)->elpColor = elpColor;
+ ((PU_EXTLOGPEN) record)->elpHatch = elpHatch;
+ ((PU_EXTLOGPEN) record)->elpNumEntries = elpNumEntries;
+ if(elpNumEntries){ memcpy(((PU_EXTLOGPEN) record)->elpStyleEntry,elpStyleEntry,szSyleArray); }
+ else { memset(((PU_EXTLOGPEN) record)->elpStyleEntry,0,sizeof(U_STYLEENTRY)); } // not used, but this stops valgrind warnings
+ }
+ return((PU_EXTLOGPEN) record);
+}
+
+/**
+ \brief Construct a U_LOGPEN structure.
+ \return U_LOGPEN structure
+ \param lopnStyle PenStyle Enumeration
+ \param lopnWidth Width of pen set by X, Y is ignored
+ \param lopnColor Pen color value
+
+*/
+U_LOGPEN logpen_set(
+ uint32_t lopnStyle,
+ U_POINT lopnWidth,
+ U_COLORREF lopnColor
+ ){
+ U_LOGPEN lp;
+ lp.lopnStyle = lopnStyle;
+ lp.lopnWidth = lopnWidth;
+ lp.lopnColor = lopnColor;
+ return(lp);
+}
+
+/**
+ \brief Construct a U_LOGPLTNTRY structure.
+ \return U_LOGPLTNTRY structure
+ \param peReserved Ignore
+ \param peRed Palette entry Red Intensity
+ \param peGreen Palette entry Green Intensity
+ \param peBlue Palette entry Blue Intensity
+*/
+U_LOGPLTNTRY logpltntry_set(
+ uint8_t peReserved,
+ uint8_t peRed,
+ uint8_t peGreen,
+ uint8_t peBlue
+ ){
+ U_LOGPLTNTRY lpny;
+ lpny.peReserved = peReserved;
+ lpny.peRed = peRed;
+ lpny.peGreen = peGreen;
+ lpny.peBlue = peBlue;
+ return(lpny);
+}
+
+/**
+ \brief Allocate and construct a U_LOGPALETTE structure.
+ \return pointer to U_LOGPALETTE structure, or NULL on error.
+ \param palNumEntries Number of U_LOGPLTNTRY objects
+ \param palPalEntry array, PC_Entry Enumeration
+*/
+PU_LOGPALETTE logpalette_set(
+ U_NUM_LOGPLTNTRY palNumEntries,
+ PU_LOGPLTNTRY *palPalEntry
+ ){
+ PU_LOGPALETTE record;
+ int cbPalArray,irecsize;
+
+ if(palNumEntries == 0 || !palPalEntry)return(NULL);
+ cbPalArray = palNumEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_LOGPALETTE) + cbPalArray - sizeof(U_LOGPLTNTRY);
+ record = (PU_LOGPALETTE) malloc(irecsize);
+ if(irecsize){
+ record->palVersion = U_LP_VERSION;
+ record->palNumEntries = palNumEntries;
+ memcpy(record->palPalEntry,palPalEntry,cbPalArray);
+ }
+ return(record);
+}
+
+/**
+ \brief Construct a U_RGNDATAHEADER structure.
+ \return U_RGNDATAHEADER structure
+ \param nCount Number of rectangles in region
+ \param rclBounds Region bounds
+*/
+U_RGNDATAHEADER rgndataheader_set(
+ U_NUM_RECTL nCount,
+ U_RECTL rclBounds
+ ){
+ U_RGNDATAHEADER rdh;
+ rdh.dwSize = U_RDH_OBJSIZE;
+ rdh.iType = U_RDH_RECTANGLES;
+ rdh.nCount = nCount;
+ rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of rectangle array
+ rdh.rclBounds = rclBounds;
+ return(rdh);
+}
+
+/**
+ \brief Allocate and construct a U_RGNDATA structure.
+ \return pointer to U_RGNDATA structure, or NULL on error.
+ \param rdh Data description
+ \param Buffer Array of U_RECTL elements
+*/
+PU_RGNDATA rgndata_set(
+ U_RGNDATAHEADER rdh,
+ PU_RECTL Buffer
+ ){
+ char *record;
+ int irecsize;
+ int szRgnArray,off;
+
+ if(!Buffer || !rdh.nCount || !rdh.nRgnSize)return(NULL);
+ szRgnArray = rdh.nRgnSize; // size of the U_RECTL array
+ irecsize = sizeof(U_RGNDATA) + szRgnArray - sizeof(U_RECTL); // core + array - overlap
+ record = malloc(irecsize);
+ if(record){
+ memcpy(record, &rdh, sizeof(U_RGNDATAHEADER));
+ off = sizeof(U_RGNDATAHEADER);
+ memcpy(record + off, Buffer, szRgnArray);
+ }
+ return((PU_RGNDATA) record);
+}
+
+/**
+ \brief Construct a U_COLORADJUSTMENT structure.
+ \return U_COLORADJUSTMENT structure
+ \param Size Size of this structure in bytes
+ \param Flags ColorAdjustment Enumeration
+ \param IlluminantIndex Illuminant Enumeration
+ \param RedGamma Red Gamma correction (range:2500:65000, 10000 is no correction)
+ \param GreenGamma Green Gamma correction (range:2500:65000, 10000 is no correction)
+ \param BlueGamma Blue Gamma correction (range:2500:65000, 10000 is no correction)
+ \param ReferenceBlack Values less than this are black (range:0:4000)
+ \param ReferenceWhite Values more than this are white (range:6000:10000)
+ \param Contrast Contrast adjustment (range:-100:100, 0 is no correction)
+ \param Brightness Brightness adjustment (range:-100:100, 0 is no correction)
+ \param Colorfulness Colorfulness adjustment (range:-100:100, 0 is no correction)
+ \param RedGreenTint Tine adjustment (range:-100:100, 0 is no correction)
+*/
+U_COLORADJUSTMENT coloradjustment_set(
+ uint16_t Size,
+ uint16_t Flags,
+ uint16_t IlluminantIndex,
+ uint16_t RedGamma,
+ uint16_t GreenGamma,
+ uint16_t BlueGamma,
+ uint16_t ReferenceBlack,
+ uint16_t ReferenceWhite,
+ int16_t Contrast,
+ int16_t Brightness,
+ int16_t Colorfulness,
+ int16_t RedGreenTint
+ ){
+ U_COLORADJUSTMENT ca;
+ ca.caSize = Size;
+ ca.caFlags = Flags;
+ ca.caIlluminantIndex = IlluminantIndex;
+ ca.caRedGamma = U_MNMX(RedGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ ca.caGreenGamma = U_MNMX(GreenGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ ca.caBlueGamma = U_MNMX(BlueGamma, U_RGB_GAMMA_MIN, U_RGB_GAMMA_MAX);
+ // Next one is different to eliminate compiler warning - U_R_B_MIN is 0 and unsigned
+ ca.caReferenceBlack = U_MAX( ReferenceBlack, U_REFERENCE_BLACK_MAX);
+ ca.caReferenceWhite = U_MNMX(ReferenceWhite, U_REFERENCE_WHITE_MIN, U_REFERENCE_WHITE_MAX);
+ ca.caContrast = U_MNMX(Contrast, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caBrightness = U_MNMX(Brightness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caColorfulness = U_MNMX(Colorfulness, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ ca.caRedGreenTint = U_MNMX(RedGreenTint, U_COLOR_ADJ_MIN, U_COLOR_ADJ_MAX);
+ return(ca);
+}
+
+/**
+ \brief Construct a U_PIXELFORMATDESCRIPTOR structure.
+ \return U_PIXELFORMATDESCRIPTOR structure
+ \param dwFlags PFD_dwFlags Enumeration
+ \param iPixelType PFD_iPixelType Enumeration
+ \param cColorBits RGBA: total bits per pixel
+ \param cRedBits Red bits per pixel
+ \param cRedShift Red shift to data bits
+ \param cGreenBits Green bits per pixel
+ \param cGreenShift Green shift to data bits
+ \param cBlueBits Blue bits per pixel
+ \param cBlueShift Blue shift to data bits
+ \param cAlphaBits Alpha bits per pixel
+ \param cAlphaShift Alpha shift to data bits
+ \param cAccumBits Accumulator buffer, total bitplanes
+ \param cAccumRedBits Red accumulator buffer bitplanes
+ \param cAccumGreenBits Green accumulator buffer bitplanes
+ \param cAccumBlueBits Blue accumulator buffer bitplanes
+ \param cAccumAlphaBits Alpha accumulator buffer bitplanes
+ \param cDepthBits Depth of Z-buffer
+ \param cStencilBits Depth of stencil buffer
+ \param cAuxBuffers Depth of auxilliary buffers (not supported)
+ \param iLayerType PFD_iLayerType Enumeration, may be ignored
+ \param bReserved Bits 0:3/4:7 are number of Overlay/Underlay planes
+ \param dwLayerMask may be ignored
+ \param dwVisibleMask color or index of underlay plane
+ \param dwDamageMask may be ignored
+*/
+U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set(
+ uint32_t dwFlags,
+ uint8_t iPixelType,
+ uint8_t cColorBits,
+ uint8_t cRedBits,
+ uint8_t cRedShift,
+ uint8_t cGreenBits,
+ uint8_t cGreenShift,
+ uint8_t cBlueBits,
+ uint8_t cBlueShift,
+ uint8_t cAlphaBits,
+ uint8_t cAlphaShift,
+ uint8_t cAccumBits,
+ uint8_t cAccumRedBits,
+ uint8_t cAccumGreenBits,
+ uint8_t cAccumBlueBits,
+ uint8_t cAccumAlphaBits,
+ uint8_t cDepthBits,
+ uint8_t cStencilBits,
+ uint8_t cAuxBuffers,
+ uint8_t iLayerType,
+ uint8_t bReserved,
+ uint32_t dwLayerMask,
+ uint32_t dwVisibleMask,
+ uint32_t dwDamageMask
+ ){
+ U_PIXELFORMATDESCRIPTOR pfd;
+ pfd.nSize = sizeof(U_PIXELFORMATDESCRIPTOR);
+ pfd.nVersion = 1;
+ pfd.dwFlags = dwFlags;
+ pfd.iPixelType = iPixelType;
+ pfd.cColorBits = cColorBits;
+ pfd.cRedBits = cRedBits;
+ pfd.cRedShift = cRedShift;
+ pfd.cGreenBits = cGreenBits;
+ pfd.cGreenShift = cGreenShift;
+ pfd.cBlueBits = cBlueBits;
+ pfd.cBlueShift = cBlueShift;
+ pfd.cAlphaBits = cAlphaBits;
+ pfd.cAlphaShift = cAlphaShift;
+ pfd.cAccumBits = cAccumBits;
+ pfd.cAccumRedBits = cAccumRedBits;
+ pfd.cAccumGreenBits = cAccumGreenBits;
+ pfd.cAccumBlueBits = cAccumBlueBits;
+ pfd.cAccumAlphaBits = cAccumAlphaBits;
+ pfd.cDepthBits = cDepthBits;
+ pfd.cStencilBits = cStencilBits;
+ pfd.cAuxBuffers = cAuxBuffers;
+ pfd.iLayerType = iLayerType;
+ pfd.bReserved = bReserved;
+ pfd.dwLayerMask = dwLayerMask;
+ pfd.dwVisibleMask = dwVisibleMask;
+ pfd.dwDamageMask = dwDamageMask;
+ return(pfd);
+}
+
+/**
+ \brief Allocate and create a U_EMRTEXT structure followed by its variable pieces via a char* pointer.
+ Dx cannot be NULL, if the calling program has no appropriate values call dx_set() first.
+ \return char* pointer to U_EMRTEXT structure followed by its variable pieces, or NULL on error
+ \param ptlReference String start coordinates
+ \param NumString Number of characters in string, does NOT include a terminator
+ \param cbChar Number of bytes per character
+ \param String String to write
+ \param fOptions ExtTextOutOptions Enumeration
+ \param rcl (Optional, when fOptions & 7) grayed/clipping/opaque rectangle
+ \param Dx Character spacing array from the start of the RECORD
+*/
+char *emrtext_set(
+ U_POINTL ptlReference,
+ U_NUM_STR NumString,
+ uint32_t cbChar,
+ void *String,
+ uint32_t fOptions,
+ U_RECTL rcl,
+ uint32_t *Dx
+ ){
+ int irecsize,cbDxArray,cbString4,cbString,off;
+ char *record;
+ uint32_t *loffDx;
+
+ if(!String)return(NULL);
+ if(!Dx)return(NULL);
+ cbString = cbChar * NumString; // size of the string in bytes
+ cbString4 = UP4(cbString); // size of the string buffer
+ cbDxArray = sizeof(uint32_t)*NumString; // size of Dx array storage
+ if(fOptions & U_ETO_PDY)cbDxArray += cbDxArray; // of the Dx buffer, here do both X and Y coordinates
+ irecsize = sizeof(U_EMRTEXT) + sizeof(uint32_t) + cbString4 + cbDxArray; // core structure + offDx + string buf + dx buf
+ if(!(fOptions & U_ETO_NO_RECT)){ irecsize += sizeof(U_RECTL); } // plus variable U_RECTL, when it is present
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMRTEXT)record)->ptlReference = ptlReference;
+ ((PU_EMRTEXT)record)->nChars = NumString;
+ // pick up ((PU_EMRTEXT)record)->offString later
+ ((PU_EMRTEXT)record)->fOptions = fOptions;
+ off = sizeof(U_EMRTEXT); // location where variable pieces will start to be written
+ if(!(fOptions & U_ETO_NO_RECT)){ // variable field, may or may not be present
+ memcpy(record + off,&rcl, sizeof(U_RECTL));
+ off += sizeof(U_RECTL);
+ }
+ loffDx = (uint32_t *)(record + off); // offDx will go here, but we do not know with what value yet
+ off += sizeof(uint32_t);
+ memcpy(record + off,String,cbString); // copy the string data to its buffer
+ ((PU_EMRTEXT)record)->offString = off; // now save offset in the structure
+ off += cbString;
+ if(cbString < cbString4){
+ memset(record+off,0,cbString4-cbString); // keeps valgrind happy (initialize padding after string)
+ off += cbString4-cbString;
+ }
+ memcpy(record + off, Dx, cbDxArray); // copy the Dx data to its buffer
+ *loffDx = off; // now save offDx to the structure
+ }
+ return(record);
+}
+
+
+
+/* **********************************************************************************************
+These functions are simpler or more convenient ways to generate the specified types of EMR records.
+Each should be called in preference to the underlying "base" EMR function.
+*********************************************************************************************** */
+
+
+/**
+ \brief Allocate and construct a U_EMRCOMMENT structure with a UTF8 string.
+ A U_EMRCOMMENT contains application specific data, and that may include contain null characters. This function may be used when the
+ comment only incluces UT8 text.
+ \return pointer to U_EMRCOMMENT structure, or NULL on error.
+ \param string UTF8 string to store in the comment
+
+
+*/
+char *textcomment_set(
+ const char *string
+ ){
+ if(!string)return(NULL);
+ return(U_EMRCOMMENT_set(1 + strlen(string),string));
+}
+
+/**
+ \brief Allocate and construct a U_EMRDELETEOBJECT structure and also delete the requested object from the table.
+ Use this function instead of calling U_EMRDELETEOBJECT_set() directly.
+ \return pointer to U_EMRDELETEOBJECT structure, or NULL on error.
+ \param ihObject Pointer to handle to delete. This value is set to 0 if the function succeeds.
+ \param eht EMF handle table
+
+ Note that calling this function should always be conditional on the specifed object being defined. It is easy to
+ write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined.
+ Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will
+ result in a failure when this function reutrns. That problem cannot be handled here because the only values which
+ may be returned are a valid U_EMRDELETEOBJECT record or a NULL, and other errors could result in the NULL.
+ So the object must be checked before the call.
+*/
+char *deleteobject_set(
+ uint32_t *ihObject,
+ EMFHANDLES *eht
+ ){
+ uint32_t saveObject=*ihObject;
+ if(emf_htable_delete(ihObject,eht))return(NULL); // invalid handle or other problem, cannot be deleted
+ return(U_EMRDELETEOBJECT_set(saveObject));
+}
+
+/**
+ \brief Allocate and construct a U_EMRSELECTOBJECT structure, checks that the handle specified is one that can actually be selected.
+ Use this function instead of calling U_EMRSELECTOBJECT_set() directly.
+ \return pointer to U_EMRSELECTOBJECT structure, or NULL on error.
+ \param ihObject handle to select
+ \param eht EMF handle table
+*/
+char *selectobject_set(
+ uint32_t ihObject,
+ EMFHANDLES *eht
+ ){
+ if(!(U_STOCK_OBJECT & ihObject)){ // not a stock object, those go straight through
+ if(ihObject > eht->top)return(NULL); // handle this high is not in the table
+ if(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected
+ }
+ return(U_EMRSELECTOBJECT_set(ihObject));
+}
+
+/**
+ \brief Allocate and construct a U_EMREXTCREATEPEN structure, create a handle and return it.
+ Use this function instead of calling U_EMREXTCREATEPEN_set() directly.
+ \return pointer to U_EMREXTCREATEPEN structure, or NULL on error.
+ \param ihPen handle to be used by new object
+ \param eht EMF handle table
+ \param Bmi bitmapbuffer
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px pixel array (NULL if cbPx == 0)
+ \param elp Pen parameters (Size is Variable!!!!)
+*/
+char *extcreatepen_set(
+ uint32_t *ihPen,
+ EMFHANDLES *eht,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ PU_EXTLOGPEN elp
+ ){
+ if(emf_htable_insert(ihPen, eht))return(NULL);
+ return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp ));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEPEN structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEPEN_set() directly.
+ \return pointer to U_EMRCREATEPEN structure, or NULL on error.
+ \param ihPen handle to be used by new object
+ \param eht EMF handle table
+ \param lopn Pen parameters
+*/
+char *createpen_set(
+ uint32_t *ihPen,
+ EMFHANDLES *eht,
+ U_LOGPEN lopn
+ ){
+ if(emf_htable_insert(ihPen, eht))return(NULL);
+ return(U_EMRCREATEPEN_set(*ihPen, lopn));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEBRUSHINDIRECT structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEBRUSHINDIRECT_set() directly.
+ \return pointer to U_EMRCREATEBRUSHINDIRECT structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param lb Brush parameters
+*/
+char *createbrushindirect_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ U_LOGBRUSH lb
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEDIBPATTERNBRUSHPT_set structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEDIBPATTERNBRUSHPT_set() directly.
+ \return pointer to U_EMRCREATEDIBPATTERNBRUSHPT_set structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bmi Bitmap info
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *createdibpatternbrushpt_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const uint32_t iUsage,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEMONOBRUSH_set structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEMONOBRUSH_set() directly.
+ \return pointer to U_EMRCREATEMONOBRUSH_set structure, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param eht EMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bmi Bitmap info
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *createmonobrush_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const uint32_t iUsage,
+ PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px));
+}
+
+
+/**
+ \brief Allocate and construct a U_EMRCREATECOLORSPACE structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATECOLORSPACE_set() directly.
+ \return pointer to U_EMRCREATECOLORSPACE structure, or NULL on error.
+ \param ihCS ColorSpace handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lcs ColorSpace parameters
+*/
+char *createcolorspace_set(
+ uint32_t *ihCS,
+ EMFHANDLES *eht,
+ U_LOGCOLORSPACEA lcs
+ ){
+ if(emf_htable_insert(ihCS, eht))return(NULL);
+ return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATECOLORSPACEW structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATECOLORSPACEW_set() directly.
+ \return pointer to U_EMRCREATECOLORSPACEW structure, or NULL on error.
+ \param ihCS ColorSpace handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lcs ColorSpace parameters
+ \param dwFlags If low bit set Data is present
+ \param cbData Number of bytes of theData field.
+ \param Data (Optional, dwFlags & 1) color profile data
+*/
+char *createcolorspacew_set(
+ uint32_t *ihCS,
+ EMFHANDLES *eht,
+ U_LOGCOLORSPACEW lcs,
+ uint32_t dwFlags,
+ U_CBDATA cbData,
+ uint8_t *Data
+ ){
+ if(emf_htable_insert(ihCS, eht))return(NULL);
+ return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data));
+}
+
+/**
+ \brief Allocate and construct a U_EMREXTCREATEFONTINDIRECTW structure, create a handle and returns it
+ Use this function instead of calling U_EMREXTCREATEFONTINDIRECTW_set() directly.
+ \return pointer to U_EMREXTCREATEFONTINDIRECTW structure, or NULL on error.
+ \param ihFont Font handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param elf Pointer to Font parameters asPU_LOGFONT
+ \param elfw Pointer to Font parameters as U_LOGFONT_PANOSE
+*/
+char *extcreatefontindirectw_set(
+ uint32_t *ihFont,
+ EMFHANDLES *eht,
+ const char *elf,
+ const char *elfw
+ ){
+ if(emf_htable_insert(ihFont, eht))return(NULL);
+ return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw));
+}
+
+/**
+ \brief Allocate and construct a U_EMRCREATEPALETTE structure, create a handle and returns it
+ Use this function instead of calling U_EMRCREATEPALETTE_set() directly.
+ \return pointer to U_EMRCREATEPALETTE structure, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param lgpl PaletteFont parameters
+*/
+char *createpalette_set(
+ uint32_t *ihPal,
+ EMFHANDLES *eht,
+ U_LOGPALETTE lgpl
+ ){
+ if(emf_htable_insert(ihPal, eht))return(NULL);
+ return(U_EMRCREATEPALETTE_set(*ihPal, lgpl));
+}
+
+/**
+ \brief Allocate and construct a U_EMRSETPALETTEENTRIES structure, create a handle and returns it
+ Use this function instead of calling U_EMRSETPALETTEENTRIES_set() directly.
+ \return pointer to U_EMRSETPALETTEENTRIES structure, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param iStart First Palette entry in selected object to set
+ \param cEntries Number of Palette entries in selected object to set
+ \param aPalEntries Values to set with
+*/
+char *setpaletteentries_set(
+ uint32_t *ihPal,
+ EMFHANDLES *eht,
+ const uint32_t iStart,
+ const U_NUM_LOGPLTNTRY cEntries,
+ const PU_LOGPLTNTRY aPalEntries
+ ){
+ if(emf_htable_insert(ihPal, eht))return(NULL);
+ return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries));
+}
+
+/**
+ \brief Allocate and construct a U_EMRFILLRGN structure, create a handle and returns it
+ Use this function instead of calling U_EMRFILLRGN_set() directly.
+ \return pointer to U_EMRFILLRGN structure, or NULL on error.
+ \param ihBrush Brush handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param rclBounds Bounding rectangle in device units
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *fillrgn_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const U_RECTL rclBounds,
+ const PU_RGNDATA RgnData
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData));
+}
+
+/**
+ \brief Allocate and construct a U_EMRFRAMERGN structure, create a handle and returns it
+ Use this function instead of calling U_EMRFRAMERGN_set() directly.
+ \return pointer to U_EMRFRAMERGN structure, or NULL on error.
+ \param ihBrush Brush handle, will be created and returned
+ \param eht Pointer to structure holding all EMF handles
+ \param rclBounds Bounding rectangle in device units
+ \param szlStroke W & H of Brush stroke
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *framergn_set(
+ uint32_t *ihBrush,
+ EMFHANDLES *eht,
+ const U_RECTL rclBounds,
+ const U_SIZEL szlStroke,
+ const PU_RGNDATA RgnData
+ ){
+ if(emf_htable_insert(ihBrush, eht))return(NULL);
+ return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData));
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_POINT structures.
+ \param points pointer to the source U_POINT structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ May also be used to modify U_RECT by doubling the count and casting the pointer.
+*/
+PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform){
+ PU_POINT newpts;
+ int i;
+ float x,y;
+ newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
+ for(i=0; i<count; i++){
+ x = (float) points[i].x;
+ y = (float) points[i].y;
+ newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
+ newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
+ }
+ return(newpts);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT16 objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_POINT16 structures.
+ \param points pointer to the source U_POINT16 structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ Transformed src points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
+*/
+PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform){
+ PU_POINT16 newpts;
+ int i;
+ float x,y;
+ newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
+ for(i=0; i<count; i++){
+ x = (float) points[i].x;
+ y = (float) points[i].y;
+ newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
+ newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
+ }
+ return(newpts);
+}
+
+/**
+ \brief Allocate and construct an array of U_TRIVERTEX objects which has been subjected to a U_XFORM
+ \returns pointer to an array of U_TRIVERTEX structures.
+ \param tv pointer to the source U_TRIVERTEX structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+ Transformed Trivertex points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
+*/
+PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform){
+ PU_TRIVERTEX newtvs;
+ int i;
+ float x,y;
+ newtvs = (PU_TRIVERTEX) malloc(count * sizeof(U_TRIVERTEX));
+ for(i=0; i<count; i++){
+ x = (float) tv[i].x;
+ y = (float) tv[i].y;
+ newtvs[i] = tv[i];
+ newtvs[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
+ newtvs[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
+ }
+ return(newtvs);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT objects from a set of U_POINT16 objects
+ \returns pointer to an array of U_POINT structures.
+ \param points pointer to the source U_POINT16 structures
+ \param count number of members in points
+
+*/
+PU_POINT point16_to_point(PU_POINT16 points, int count){
+ PU_POINT newpts;
+ int i;
+ newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
+ for(i=0; i<count; i++){
+ newpts[i].x = points[i].x;
+ newpts[i].y = points[i].y;
+ }
+ return(newpts);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT16 objects from a set of U_POINT objects
+ \returns pointer to an array of U_POINT16 structures.
+ \param points pointer to the source U_POINT structures
+ \param count number of members in points
+
+ If a coordinate is out of range it saturates at boundary.
+*/
+PU_POINT16 point_to_point16(PU_POINT points, int count){
+ PU_POINT16 newpts;
+ int i;
+ newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
+ for(i=0; i<count; i++){
+ newpts[i].x = U_MNMX(points[i].x, INT16_MIN, INT16_MAX);
+ newpts[i].y = U_MNMX(points[i].y, INT16_MIN, INT16_MAX);
+ }
+ return(newpts);
+}
+
+// hide these from Doxygen
+//! @cond
+/* **********************************************************************************************
+These functions contain shared code used by various U_EMR*_set functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+
+
+ These are (mostly) ordered by U_EMR_* index number.
+ For all _set functions the caller must eventually call free() on the returned pointer.
+
+ CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
+ CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
+ CORE3(uint32_t iType, uint32_t iMode){ (generic 1 uint)
+ CORE4(uint32_t iType, U_RECTL rclBox){
+ CORE5(uint32_t iType){ (generic noargs)
+ CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE1)
+ CORE7(uint32_t iType, U_PAIR pair){
+ CORE8(uint32_t iType, U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext){
+ CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
+ CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE2)
+ CORE11(uint32_t iType, PU_RGNDATA RgnData){
+ CORE12(uint32_t iType, uint32_t ihBrush, uint32_t iUsage, PU_BITMAPINFO Bmi){
+ CORE13(uint32_t iType, U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest,
+ U_POINTL Src, U_POINTL cSrc, U_XFORM xformSrc, U_COLORREF crBkColorSrc, uint32_t iUsageSrc,
+ uint32_t Data, PU_BITMAPINFO Bmi);
+*********************************************************************************************** */
+
+
+// Functions with the same form starting with U_EMRPOLYBEZIER_set
+char *U_EMR_CORE1_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
+ char *record;
+ int cbPoints;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINTL)*cptl;
+ irecsize = sizeof(U_EMRPOLYBEZIER) + cbPoints - sizeof(U_POINTL); // First instance is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYBEZIER) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYBEZIER) record)->cptl = cptl;
+ memcpy(((PU_EMRPOLYBEZIER) record)->aptl,points,cbPoints);
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_POLYPOLYLINE
+char *U_EMR_CORE2_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
+ char *record;
+ int cbPolys,cbPoints,off;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINTL)*cptl;
+ cbPolys = sizeof(uint32_t)*nPolys;
+ irecsize = sizeof(U_EMRPOLYPOLYLINE) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYPOLYLINE) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYPOLYLINE) record)->nPolys = nPolys;
+ ((PU_EMRPOLYPOLYLINE) record)->cptl = cptl;
+ memcpy(((PU_EMRPOLYPOLYLINE) record)->aPolyCounts,aPolyCounts,cbPolys);
+ off = sizeof(U_EMRPOLYPOLYLINE) - 4 + cbPolys;
+ memcpy(record + off,points,cbPoints);
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_SETMAPMODE_set
+char *U_EMR_CORE3_set(uint32_t iType, uint32_t iMode){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETMAPMODE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETMAPMODE)record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_set, also U_EMRFILLPATH,
+char *U_EMR_CORE4_set(uint32_t iType, U_RECTL rclBox){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRELLIPSE);
+ record = malloc(irecsize);
+ memset(record,0,irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRELLIPSE)record)->rclBox = rclBox; // bounding rectangle in logical units
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMRSETMETARGN_set
+char *U_EMR_CORE5_set(uint32_t iType){
+ char *record;
+ int irecsize = 8;
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER16_set
+char *U_EMR_CORE6_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){
+ char *record;
+ int cbPoints,cbPoints4,off;
+ int irecsize;
+
+ cbPoints = sizeof(U_POINT16)*cpts;
+ cbPoints4 = UP4(cbPoints);
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16); // offset to the start of the variable region
+ irecsize = off + cbPoints4; // First instance is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYBEZIER16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYBEZIER16) record)->cpts = cpts;
+ memcpy(record + off, points, cbPoints);
+ if(cbPoints < cbPoints4){
+ off += cbPoints;
+ memset(record + off, 0, cbPoints4 - cbPoints);
+ }
+ }
+ return(record);
+}
+
+
+// Functions that take a single struct argument which contains two uint32_t, starting with U_EMRSETWINDOWEXTEX_set
+// these all pass two 32 bit ints and are cast by the caller to U_PAIR
+char *U_EMR_CORE7_set(uint32_t iType, U_PAIR pair){
+ char *record;
+ int irecsize = sizeof(U_EMRGENERICPAIR);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRGENERICPAIR)record)->pair = pair;
+ }
+ return(record);
+}
+
+// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW
+char *U_EMR_CORE8_set(
+ uint32_t iType,
+ U_RECTL rclBounds, // Bounding rectangle in device units
+ uint32_t iGraphicsMode, // Graphics mode Enumeration
+ U_FLOAT exScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ U_FLOAT eyScale, // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ PU_EMRTEXT emrtext // Text parameters
+ ){
+ char *record;
+ int irecsize,cbString,cbString4,cbDx,cbEmrtext,cbEmrtextAll;
+ uint32_t *loffDx;
+ int csize;
+
+ if( iType == U_EMR_EXTTEXTOUTA){ csize = 1; } // how many bytes per character
+ else if(iType == U_EMR_EXTTEXTOUTW){ csize = 2; }
+ else { return(NULL); }
+
+ cbString = csize * emrtext->nChars;
+ cbString4 = UP4(cbString); // size of the string buffer
+ cbEmrtext = sizeof(U_EMRTEXT); // size of the constant part of the U_EMRTEXT structure
+ if(!(emrtext->fOptions & U_ETO_NO_RECT)){ cbEmrtext += sizeof(U_RECTL); } // plus the variable U_RECTL, when it is present
+ cbDx = emrtext->nChars * sizeof(int32_t); // size of Dx buffer
+ if(emrtext->fOptions & U_ETO_PDY)cbDx += cbDx; // size of Dx buffer when both x and y offsets are used
+ cbEmrtextAll = cbEmrtext + sizeof(uint32_t) + cbString4 + cbDx; // structure (+- rect) + offDx + string buf + dx buf + offDx
+
+ /* adjust offset fields in emrtext to match the EMRTEXTOUT* field, currently they match EMRTEXT.
+ This works because the variable pieces have all been moved outside of the U_EMRTEXT and U_EMRTEXTOUTA strutures.
+ */
+ ((PU_EMRTEXT)emrtext)->offString += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT); // adjust offString
+ loffDx = (uint32_t *)((char *)emrtext + cbEmrtext);
+ *loffDx += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT);
+
+ // final record size is: U_EMREXTTEXTOUTA (includes constant part of U_EMRTEXT) + U_RECTL (if present) + offDx + dx buffer + string buffer
+ irecsize = sizeof(U_EMREXTTEXTOUTA) + cbEmrtextAll - sizeof(U_EMRTEXT); // do not count core emrtext strcture twice
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTTEXTOUTA) record)->iGraphicsMode = iGraphicsMode;
+ ((PU_EMREXTTEXTOUTA) record)->rclBounds = rclBounds;
+ ((PU_EMREXTTEXTOUTA) record)->exScale = exScale;
+ ((PU_EMREXTTEXTOUTA) record)->eyScale = eyScale;
+ // copy the adjusted U_EMRTEXT into the emrtext part of the full record..
+ memcpy(&(((PU_EMREXTTEXTOUTA) record)->emrtext), emrtext, cbEmrtextAll);
+ }
+ return(record);
+}
+
+// Functions that take a rect and a pair of points, starting with U_EMRARC_set
+char *U_EMR_CORE9_set(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
+ char *record;
+ int irecsize = sizeof(U_EMRARC);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRARC) record)->rclBox = rclBox;
+ ((PU_EMRARC) record)->ptlStart = ptlStart;
+ ((PU_EMRARC) record)->ptlEnd = ptlEnd;
+ }
+ return(record);
+}
+
+// Functions with the same form starting with U_EMR_POLYPOLYLINE16
+char *U_EMR_CORE10_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){
+ char *record;
+ int cbPoints,cbPolys,off;
+ int irecsize;
+
+ cbPolys = sizeof(uint32_t)*nPolys;
+ cbPoints = sizeof(U_POINT16)*cpts;
+ irecsize = sizeof(U_EMRPOLYPOLYLINE16) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYPOLYLINE16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYPOLYLINE16) record)->nPolys = nPolys;
+ ((PU_EMRPOLYPOLYLINE16) record)->cpts = cpts;
+ memcpy(((PU_EMRPOLYPOLYLINE16) record)->aPolyCounts,aPolyCounts,cbPolys);
+ off = sizeof(U_EMRPOLYPOLYLINE16) - 4 + cbPolys;
+ memcpy(record + off,points,cbPoints);
+ }
+ return(record);
+}
+
+// common code for U_EMRINVERTRGN and U_EMRPAINTRGN,
+char *U_EMR_CORE11_set(uint32_t iType, PU_RGNDATA RgnData){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRINVERTRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRINVERTRGN) record)->rclBounds = ((PU_RGNDATAHEADER) RgnData)->rclBounds;
+ ((PU_EMRINVERTRGN) record)->cbRgnData = rds;
+ off = sizeof(U_EMRINVERTRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+
+// common code for U_EMRCREATEMONOBRUSH_set and U_EMRCREATEDIBPATTERNBRUSHPT_set,
+char *U_EMR_CORE12_set(
+ uint32_t iType,
+ uint32_t ihBrush, // Index to place object in EMF object table (this entry must not yet exist)
+ uint32_t iUsage, // DIBcolors Enumeration
+ PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ const char *Px // (Optional) bitmapbuffer (pixel array section )
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRCREATEMONOBRUSH) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEMONOBRUSH) record)->ihBrush = ihBrush;
+ ((PU_EMRCREATEMONOBRUSH) record)->iUsage = iUsage;
+ if(cbBmi){
+ off = sizeof(U_EMRCREATEMONOBRUSH);
+ memcpy(record + off, Bmi, cbBmi);
+ ((PU_EMRCREATEMONOBRUSH) record)->offBmi = off;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = cbBmi;
+ off += cbBmi;
+ memcpy(record + off, Px, cbPx);
+ ((PU_EMRCREATEMONOBRUSH) record)->offBits = off;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBits = cbImage;
+ }
+ else {
+ ((PU_EMRCREATEMONOBRUSH) record)->offBmi = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBmi = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->offBits = 0;
+ ((PU_EMRCREATEMONOBRUSH) record)->cbBits = 0;
+ }
+ }
+ return(record);
+}
+
+// common code for U_EMRBLEND_set and U_EMRTRANSPARENTBLT_set,
+char *U_EMR_CORE13_set(
+ uint32_t iType,
+ U_RECTL rclBounds, // Bounding rectangle in device units
+ U_POINTL Dest, // Destination UL corner in logical units
+ U_POINTL cDest, // Destination width in logical units
+ U_POINTL Src, // Source UL corner in logical units
+ U_POINTL cSrc, // Src W & H in logical units
+ U_XFORM xformSrc, // Transform to apply to source
+ U_COLORREF crBkColorSrc, // Background color
+ uint32_t iUsageSrc, // DIBcolors Enumeration
+ uint32_t Data, // The meaning and type of this field varies, but it is always 4 bytes
+ const PU_BITMAPINFO Bmi, // (Optional) bitmapbuffer (U_BITMAPINFO section)
+ const uint32_t cbPx, // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ char *Px // (Optional) bitmapbuffer (pixel array section )
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRALPHABLEND) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = iType;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRALPHABLEND) record)->rclBounds = rclBounds;
+ ((PU_EMRALPHABLEND) record)->Dest = Dest;
+ ((PU_EMRALPHABLEND) record)->cDest = cDest;
+ ((PU_EMRALPHABLEND) record)->Blend = *((PU_BLEND)&Data);
+ ((PU_EMRALPHABLEND) record)->Src = Src;
+ ((PU_EMRALPHABLEND) record)->xformSrc = xformSrc;
+ ((PU_EMRALPHABLEND) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRALPHABLEND) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRALPHABLEND);
+ APPEND_PXBMISRC(record, U_EMRALPHABLEND, cbBmi, Bmi, Px, cbImage, cbImage4);
+ ((PU_EMRALPHABLEND) record)->cSrc = cSrc;
+ }
+ return(record);
+}
+//! @endcond
+
+/* **********************************************************************************************
+These are the core EMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+// U_EMRHEADER_set 1
+
+/**
+ \brief Allocate and construct a U_EMRHEADER record.
+ \return pointer to U_EMRHEADER record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param rclFrame Bounding rectangle in 0.01 mm units
+ \param pfmtDesc Pointer to a PixelFormatDescriptor
+ \param nDesc number of characters in Description, will include first three '\0'
+ \param Description Description, formatted like: text1\0text2\0\0
+ \param szlDevice Reference device size in pixels
+ \param szlMillimeters Reference device size in 0.01 mm
+ \param bOpenGL nonZero if OpenGL commands are included
+*/
+char *U_EMRHEADER_set(
+ const U_RECTL rclBounds,
+ const U_RECTL rclFrame,
+ U_PIXELFORMATDESCRIPTOR* const pfmtDesc,
+ U_CBSTR nDesc,
+ uint16_t* const Description,
+ const U_SIZEL szlDevice,
+ const U_SIZEL szlMillimeters,
+ const uint32_t bOpenGL
+ ){
+
+ char *record;
+ int cbPFD,cbDesc,cbDesc4;
+ uint32_t off;
+ int irecsize;
+
+ if(pfmtDesc){ cbPFD = sizeof(U_PIXELFORMATDESCRIPTOR); }
+ else { cbPFD = 0; }
+ if(Description){ cbDesc = 2*nDesc; } // also copy the terminator. Size is in bytes
+ else { cbDesc = 0; }
+ cbDesc4 = UP4(cbDesc);
+ irecsize = sizeof(U_EMRHEADER) + cbPFD + cbDesc4;
+ record = malloc(irecsize);
+ if(record){
+ off = sizeof(U_EMRHEADER);
+ ((PU_EMR) record)->iType = U_EMR_HEADER;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRHEADER) record)->rclBounds = rclBounds;
+ ((PU_EMRHEADER) record)->rclFrame = rclFrame;
+ ((PU_EMRHEADER) record)->dSignature = U_ENHMETA_SIGNATURE;
+ ((PU_EMRHEADER) record)->nVersion = U_ENHMETA_VERSION;
+ ((PU_EMRHEADER) record)->nBytes = 0; // Not known yet
+ ((PU_EMRHEADER) record)->nRecords = 0; // Not known yet
+ ((PU_EMRHEADER) record)->nHandles = 0; // Not known yet
+ ((PU_EMRHEADER) record)->sReserved = 0; // Must be 0
+ ((PU_EMRHEADER) record)->nDescription = nDesc;
+ ((PU_EMRHEADER) record)->offDescription = 0; // may change below
+ ((PU_EMRHEADER) record)->nPalEntries = 0; // Not known yet
+ ((PU_EMRHEADER) record)->szlDevice = szlDevice;
+ ((PU_EMRHEADER) record)->szlMillimeters = szlMillimeters;
+ ((PU_EMRHEADER) record)->cbPixelFormat = cbPFD;
+ ((PU_EMRHEADER) record)->offPixelFormat = 0; // may change below
+ ((PU_EMRHEADER) record)->bOpenGL = bOpenGL;
+ ((PU_EMRHEADER) record)->szlMicrometers.cx = szlMillimeters.cx*1000;
+ ((PU_EMRHEADER) record)->szlMicrometers.cy = szlMillimeters.cy*1000;
+ if(cbDesc4){
+ ((PU_EMRHEADER) record)->offDescription = off;
+ memcpy(record + off, Description, cbDesc);
+ off += cbDesc;
+ if(cbDesc < cbDesc4)memset(record + off,0,cbDesc4-cbDesc); // clear any unused bytes
+ off += cbDesc4 - cbDesc;
+ }
+ if(cbPFD){
+ ((PU_EMRHEADER) record)->offPixelFormat = off;
+ memcpy(record+off,pfmtDesc,cbPFD);
+ }
+ }
+ return(record);
+}
+
+// U_EMRPOLYBEZIER_set 2
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIER record.
+ \return pointer to U_EMR_POLYBEZIER record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYBEZIER_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYBEZIER, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYGON_set 3
+/**
+ \brief Allocate and construct a U_EMR_POLYGON record.
+ \return pointer to U_EMR_POLYGON record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYGON_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYGON, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYLINE_set 4
+/**
+ \brief Allocate and construct a U_EMR_POLYLINE record.
+ \return pointer to U_EMR_POLYLINE record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYLINE_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYLINE, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYBEZIERTO_set 5
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
+ \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYBEZIERTO_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYBEZIERTO, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYLINETO_set 6
+/**
+ \brief Allocate and construct a U_EMR_POLYLINETO record.
+ \return pointer to U_EMR_POLYLINETO record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param cptl Number of points to draw
+ \param points array of points
+*/
+char *U_EMRPOLYLINETO_set(
+ const U_RECTL rclBounds,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE1_set(U_EMR_POLYLINETO, rclBounds, cptl, points));
+}
+
+// U_EMRPOLYPOLYLINE_set 7
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYLINE record.
+ \return pointer to U_EMR_POLYPOLYLINE record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cptl Total number of points (over all poly)
+ \param points array of points
+*/
+char *U_EMRPOLYPOLYLINE_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE2_set(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points));
+}
+
+// U_EMRPOLYPOLYGON_set 8
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYGON record.
+ \return pointer to U_EMR_POLYPOLYGON record, or NULL on error.
+ \param rclBounds bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cptl Total number of points (over all poly)
+ \param points array of points
+*/
+char *U_EMRPOLYPOLYGON_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cptl,
+ const U_POINTL *points
+ ){
+ return(U_EMR_CORE2_set(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points));
+}
+
+// U_EMRSETWINDOWEXTEX_set 9
+/**
+ \brief Allocate and construct a U_EMR_SETWINDOWEXTEX record.
+ \return pointer to U_EMR_SETWINDOWEXTEX record, or NULL on error.
+ \param szlExtent H & V extent in logical units
+*/
+char *U_EMRSETWINDOWEXTEX_set(
+ const U_SIZEL szlExtent
+ ){
+ U_PAIR temp;
+ temp.x = szlExtent.cx;
+ temp.y = szlExtent.cy;
+ return(U_EMR_CORE7_set(U_EMR_SETWINDOWEXTEX, temp));
+}
+
+// U_EMRSETWINDOWORGEX_set 10
+/**
+ \brief Allocate and construct a U_EMR_SETWINDOWORGEX record.
+ \return pointer to U_EMR_SETWINDOWORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETWINDOWORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing
+}
+
+// U_EMRSETVIEWPORTEXTEX_set 11
+/**
+ \brief Allocate and construct a U_EMR_SETVIEWPORTEXTEX record.
+ \return pointer to U_EMR_SETVIEWPORTEXTEX record, or NULL on error.
+ \param szlExtent H & V extent in logical units
+*/
+char *U_EMRSETVIEWPORTEXTEX_set(
+ const U_SIZEL szlExtent
+ ){
+ U_PAIR temp;
+ temp.x = szlExtent.cx;
+ temp.y = szlExtent.cy;
+ return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTEXTEX, temp));
+}
+
+// U_EMRSETVIEWPORTORGEX_set 12
+/**
+ \brief Allocate and construct a U_EMR_SETVIEWPORTORGEX record.
+ \return pointer to U_EMR_SETVIEWPORTORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETVIEWPORTORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing
+}
+
+// U_EMRSETBRUSHORGEX_set 13
+/**
+ \brief Allocate and construct a U_EMR_SETBRUSHORGEX record.
+ \return pointer to U_EMR_SETBRUSHORGEX record, or NULL on error.
+ \param ptlOrigin H & V origin in logical units
+*/
+char *U_EMRSETBRUSHORGEX_set(
+ const U_POINTL ptlOrigin
+ ){
+ return(U_EMR_CORE7_set(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin)));
+}
+
+// U_EMREOF_set 14
+/**
+ \brief Allocate and construct a U_EMR_EOF record.
+ \return pointer to U_EMR_EOF record, or NULL on error.
+ \param cbPalEntries Number of palette entries
+ \param PalEntries (optional) array of PalEntries
+ \param et tracking information, needed for nSizeLast calculation
+*/
+char *U_EMREOF_set(
+ const U_CBPLENTRIES cbPalEntries,
+ const PU_LOGPLTNTRY PalEntries,
+ EMFTRACK *et
+ ){
+ char *record;
+ char *ptr;
+ int irecsize;
+ int cbPals; // space allocated for Palette Entries
+ uint32_t off;
+
+ if(cbPalEntries && !PalEntries)return(NULL);
+ if(!et)return(NULL);
+ cbPals = cbPalEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_EMREOF) + cbPals + sizeof(uint32_t); //invariant core, variable palette, palette byte count
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EOF;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREOF) record)->cbPalEntries = cbPalEntries;
+ ((PU_EMREOF) record)->offPalEntries = 0; // May be changed below
+ off = sizeof(U_EMREOF); //start of the variable region
+ if(cbPals){
+ ((PU_EMREOF) record)->offPalEntries = off;
+ memcpy(record+off,PalEntries,cbPals);
+ off += cbPals;
+ }
+ ptr = record + off;
+ *(uint32_t *)ptr = irecsize + et->used; // EMREOF nSizeLast field, not at a fixed position, cannot be accessed by field name
+ }
+ et->PalEntries = cbPalEntries;
+ return(record);
+}
+
+
+// U_EMRSETPIXELV_set 15
+/**
+ \brief Allocate and construct a U_EMR_SETPIXELV record.
+ \return pointer to U_EMR_SETPIXELV record, or NULL on error.
+ \param ptlPixel Pixel coordinates (logical)
+ \param crColor Pixel color
+*/
+char *U_EMRSETPIXELV_set(
+ const U_POINTL ptlPixel,
+ const U_COLORREF crColor
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETPIXELV);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETPIXELV;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETPIXELV)record)->ptlPixel = ptlPixel;
+ ((PU_EMRSETPIXELV)record)->crColor = crColor;
+ }
+ return(record);
+}
+
+
+// U_EMRSETMAPPERFLAGS_set 16
+/**
+ \brief Allocate and construct a U_EMR_SETMAPPERFLAGS record.
+ \return pointer to U_EMR_SETMAPPERFLAGS record, or NULL on error.
+*/
+char *U_EMRSETMAPPERFLAGS_set(void){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETMAPPERFLAGS);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETMAPPERFLAGS;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETMAPPERFLAGS)record)->dwFlags = 1;
+ }
+ return(record);
+}
+
+// U_EMRSETMAPMODE_set 17
+/**
+ \brief Allocate and construct a U_EMR_SETMAPMODE record.
+ \return pointer to U_EMR_SETMAPMODE record, or NULL on error.
+ \param iMode MapMode Enumeration
+*/
+char *U_EMRSETMAPMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETMAPMODE, iMode));
+}
+
+// U_EMRSETBKMODE_set 18
+/**
+ \brief Allocate and construct a U_EMR_SETBKMODE record.
+ \return pointer to U_EMR_SETBKMODE record, or NULL on error.
+ \param iMode BackgroundMode Enumeration
+*/
+char *U_EMRSETBKMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETBKMODE, iMode));
+}
+
+// U_EMRSETPOLYFILLMODE_set 19
+/**
+ \brief Allocate and construct a U_EMR_SETPOLYFILLMODE record.
+ \return pointer to U_EMR_SETPOLYFILLMODE record, or NULL on error.
+ \param iMode PolygonFillMode Enumeration
+*/
+char *U_EMRSETPOLYFILLMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETPOLYFILLMODE, iMode));
+}
+
+// U_EMRSETROP2_set 20
+/**
+ \brief Allocate and construct a U_EMR_SETROP2 record.
+ \return pointer to U_EMR_SETROP2 record, or NULL on error.
+ \param iMode RasterOperation2 Enumeration
+*/
+char *U_EMRSETROP2_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETROP2, iMode));
+}
+
+// U_EMRSETSTRETCHBLTMODE_set 21
+/**
+ \brief Allocate and construct a U_EMR_SETSTRETCHBLTMODE record.
+ \return pointer to U_EMR_SETSTRETCHBLTMODE record, or NULL on error.
+ \param iMode StretchMode Enumeration
+*/
+char *U_EMRSETSTRETCHBLTMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETSTRETCHBLTMODE, iMode));
+}
+
+// U_EMRSETTEXTALIGN_set 22
+/**
+ \brief Allocate and construct a U_EMR_SETTEXTALIGN record.
+ \return pointer to U_EMR_SETTEXTALIGN record, or NULL on error.
+ \param iMode TextAlignment Enumeration
+*/
+char *U_EMRSETTEXTALIGN_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETTEXTALIGN, iMode));
+}
+
+// U_EMRSETCOLORADJUSTMENT_set 23
+/**
+ \brief Allocate and construct a U_EMR_SETCOLORADJUSTMENT record.
+ \return pointer to U_EMR_SETCOLORADJUSTMENT record, or NULL on error.
+ \param ColorAdjustment Color Adjustment
+*/
+char *U_EMRSETCOLORADJUSTMENT_set(
+ const U_COLORADJUSTMENT ColorAdjustment
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETCOLORADJUSTMENT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETCOLORADJUSTMENT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETCOLORADJUSTMENT) record)->ColorAdjustment = ColorAdjustment;
+ }
+ return(record);
+}
+
+// U_EMRSETTEXTCOLOR_set 24
+/**
+ \brief Allocate and construct a U_EMR_SETTEXTCOLOR record.
+ \return pointer to U_EMR_SETTEXTCOLOR record, or NULL on error.
+ \param crColor Text Color
+*/
+char *U_EMRSETTEXTCOLOR_set(
+ const U_COLORREF crColor
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor));
+}
+
+// U_EMRSETBKCOLOR_set 25
+/**
+ \brief Allocate and construct a U_EMR_SETBKCOLOR record.
+ \return pointer to U_EMR_SETBKCOLOR record, or NULL on error.
+ \param crColor Background Color
+*/
+char *U_EMRSETBKCOLOR_set(
+ const U_COLORREF crColor
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor));
+}
+
+// U_EMROFFSETCLIPRGN_set 26
+/**
+ \brief Allocate and construct a U_EMR_OFFSETCLIPRGN record.
+ \return pointer to U_EMR_OFFSETCLIPRGN record, or NULL on error.
+ \param ptl Clipping region
+*/
+char *U_EMROFFSETCLIPRGN_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_OFFSETCLIPRGN, ptl));
+}
+
+// U_EMRMOVETOEX_set 27
+/**
+ \brief Allocate and construct a U_EMR_MOVETOEX record.
+ \return pointer to U_EMR_MOVETOEX record, or NULL on error.
+ \param ptl Point coordinates
+*/
+char *U_EMRMOVETOEX_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_MOVETOEX, ptl));
+}
+
+// U_EMRSETMETARGN_set 28
+/**
+ \brief Allocate and construct a U_EMR_SETMETARGN record.
+ \return pointer to U_EMR_SETMETARGN record, or NULL on error.
+*/
+char *U_EMRSETMETARGN_set(void){
+ return(U_EMR_CORE5_set(U_EMR_SETMETARGN));
+}
+
+// U_EMREXCLUDECLIPRECT_set 29
+/**
+ \brief Allocate and construct a U_EMR_EXCLUDECLIPRECT record.
+ \return pointer to U_EMR_EXCLUDECLIPRECT record, or NULL on error.
+ \param rclClip Clipping Region
+*/
+char *U_EMREXCLUDECLIPRECT_set(
+ const U_RECTL rclClip
+ ){
+ return(U_EMR_CORE4_set(U_EMR_EXCLUDECLIPRECT,rclClip));
+}
+
+// U_EMRINTERSECTCLIPRECT_set 30
+/**
+ \brief Allocate and construct a U_EMR_INTERSECTCLIPRECT record.
+ \return pointer to U_EMR_INTERSECTCLIPRECT record, or NULL on error.
+ \param rclClip Clipping Region
+*/
+char *U_EMRINTERSECTCLIPRECT_set(
+ const U_RECTL rclClip
+ ){
+ return(U_EMR_CORE4_set(U_EMR_INTERSECTCLIPRECT,rclClip));
+}
+
+// U_EMRSCALEVIEWPORTEXTEX_set 31
+/**
+ \brief Allocate and construct a U_EMR_SCALEVIEWPORTEXTEX record.
+ \return pointer to U_EMR_SCALEVIEWPORTEXTEX record, or NULL on error.
+ \param xNum Horizontal multiplier (!=0)
+ \param xDenom Horizontal divisor (!=0)
+ \param yNum Vertical multiplier (!=0)
+ \param yDenom Vertical divisor (!=0)
+*/
+char *U_EMRSCALEVIEWPORTEXTEX_set(
+ const int32_t xNum,
+ const int32_t xDenom,
+ const int32_t yNum,
+ const int32_t yDenom
+ ){
+ return(U_EMR_CORE4_set(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
+}
+
+
+// U_EMRSCALEWINDOWEXTEX_set 32
+/**
+ \brief Allocate and construct a U_EMR_SCALEWINDOWEXTEX record.
+ \return pointer to U_EMR_SCALEWINDOWEXTEX record, or NULL on error.
+ \param xNum Horizontal multiplier (!=0)
+ \param xDenom Horizontal divisor (!=0)
+ \param yNum Vertical multiplier (!=0)
+ \param yDenom Vertical divisor (!=0)
+*/
+char *U_EMRSCALEWINDOWEXTEX_set(
+ const int32_t xNum,
+ const int32_t xDenom,
+ const int32_t yNum,
+ const int32_t yDenom
+ ){
+ return(U_EMR_CORE4_set(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
+}
+
+// U_EMRSAVEDC_set 33
+/**
+ \brief Allocate and construct a U_EMR_SAVEDC record.
+ \return pointer to U_EMR_SAVEDC record, or NULL on error.
+*/
+char *U_EMRSAVEDC_set(void){
+ return(U_EMR_CORE5_set(U_EMR_SAVEDC));
+}
+
+// U_EMRRESTOREDC_set 34
+/**
+ \brief Allocate and construct a U_EMR_RESTOREDC record.
+ \return pointer to U_EMR_RESTOREDC record, or NULL on error.
+ \param iRelative DC to restore. -1 is preceding
+*/
+char *U_EMRRESTOREDC_set(
+ const int32_t iRelative
+ ){
+ return(U_EMR_CORE3_set(U_EMR_RESTOREDC, (uint32_t) iRelative));
+}
+
+// U_EMRSETWORLDTRANSFORM_set 35
+/**
+ \brief Allocate and construct a U_EMR_SETWORLDTRANSFORM record.
+ \return pointer to U_EMR_SETWORLDTRANSFORM record, or NULL on error.
+ \param xform Transform to use
+*/
+char *U_EMRSETWORLDTRANSFORM_set(
+ const U_XFORM xform
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSETWORLDTRANSFORM);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETWORLDTRANSFORM;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETWORLDTRANSFORM) record)->xform = xform;
+ }
+ return(record);
+}
+
+// U_EMRMODIFYWORLDTRANSFORM_set 36
+/**
+ \brief Allocate and construct a U_EMR_MODIFYWORLDTRANSFORM record.
+ \return pointer to U_EMR_MODIFYWORLDTRANSFORM record, or NULL on error.
+ \param xform Transform to use
+ \param iMode ModifyWorldTransformMode Enumeration
+*/
+char *U_EMRMODIFYWORLDTRANSFORM_set(
+ const U_XFORM xform,
+ const uint32_t iMode
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRMODIFYWORLDTRANSFORM);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_MODIFYWORLDTRANSFORM;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRMODIFYWORLDTRANSFORM) record)->xform = xform;
+ ((PU_EMRMODIFYWORLDTRANSFORM) record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// U_EMRSELECTOBJECT_set 37
+/**
+ \brief Allocate and construct a U_EMR_SELECTOBJECT record.
+ Use selectobject_set() instead of calling this function directly.
+ \return pointer to U_EMR_SELECTOBJECT record, or NULL on error.
+ \param ihObject Number of a stock or created object
+*/
+char *U_EMRSELECTOBJECT_set(
+ const uint32_t ihObject
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRSELECTOBJECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SELECTOBJECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSELECTOBJECT) record)->ihObject = ihObject; // Index of object to SELECT
+ }
+ return(record);
+}
+
+// U_EMRCREATEPEN_set 38
+/**
+ \brief Allocate and construct a U_EMR_CREATEPEN record.
+ Use createpen_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEPEN record, or NULL on error.
+ \param ihPen Handle of created pen
+ \param lopn U_LOGPEN structure describing this pen
+*/
+char *U_EMRCREATEPEN_set(
+ const uint32_t ihPen,
+ const U_LOGPEN lopn
+ ){
+ char *record;
+ int irecsize=sizeof(U_EMRCREATEPEN);
+
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEPEN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEPEN) record)->ihPen = ihPen;
+ ((PU_EMRCREATEPEN) record)->lopn = lopn;
+ }
+ return(record);
+}
+
+// U_EMRCREATEBRUSHINDIRECT_set 39
+/**
+ \brief Allocate and construct a U_EMR_CREATEBRUSHINDIRECT record.
+ Use createbrushindirect_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEBRUSHINDIRECT record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param lb Brush properties
+*/
+char *U_EMRCREATEBRUSHINDIRECT_set(
+ const uint32_t ihBrush,
+ const U_LOGBRUSH lb
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATEBRUSHINDIRECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEBRUSHINDIRECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEBRUSHINDIRECT) record)->ihBrush = ihBrush; // Index to place object in EMF object table (this entry must not yet exist)
+ ((PU_EMRCREATEBRUSHINDIRECT) record)->lb = lb;
+ }
+ return(record);
+}
+
+// U_EMRDELETEOBJECT_set 40
+/**
+ \brief Allocate and construct a U_EMR_DELETEOBJECT record.
+ Use deleteobject_set() instead of calling this function directly.
+ \return pointer to U_EMR_DELETEOBJECT record, or NULL on error.
+ \param ihObject Number of a stock or created object
+*/
+char *U_EMRDELETEOBJECT_set(
+ const uint32_t ihObject
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRDELETEOBJECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_DELETEOBJECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRDELETEOBJECT) record)->ihObject = ihObject; // Index of object to DELETE
+ }
+ return(record);
+}
+
+// U_EMRANGLEARC_set 41
+/**
+ \brief Allocate and construct a U_EMR_ANGLEARC record.
+ \return pointer to U_EMR_ANGLEARC record, or NULL on error.
+ \param ptlCenter Center in logical units
+ \param nRadius Radius in logical units
+ \param eStartAngle Starting angle in degrees (counter clockwise from x axis)
+ \param eSweepAngle Sweep angle in degrees
+*/
+char *U_EMRANGLEARC_set(
+ const U_POINTL ptlCenter,
+ const uint32_t nRadius,
+ const U_FLOAT eStartAngle,
+ const U_FLOAT eSweepAngle
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRANGLEARC);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_ANGLEARC;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRANGLEARC) record)->ptlCenter = ptlCenter;
+ ((PU_EMRANGLEARC) record)->nRadius = nRadius;
+ ((PU_EMRANGLEARC) record)->eStartAngle = eStartAngle;
+ ((PU_EMRANGLEARC) record)->eSweepAngle = eSweepAngle;
+ }
+ return(record);
+}
+
+// U_EMRELLIPSE_set 42
+/**
+ \brief Allocate and construct a U_EMR_ELLIPSE record.
+ \return pointer to U_EMR_ELLIPSE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+*/
+char *U_EMRELLIPSE_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_ELLIPSE,rclBox));
+}
+
+// U_EMRRECTANGLE_set 43
+/**
+ \brief Allocate and construct a U_EMR_RECTANGLE record.
+ \return pointer to U_EMR_RECTANGLE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+*/
+char *U_EMRRECTANGLE_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_RECTANGLE,rclBox));
+}
+
+// U_EMRROUNDRECT_set 44
+/**
+ \brief Allocate and construct a U_EMR_ROUNDRECT record.
+ \return pointer to U_EMR_ROUNDRECT record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param szlCorner W & H in logical units of ellipse used to round corner
+*/
+char *U_EMRROUNDRECT_set(
+ const U_RECTL rclBox,
+ const U_SIZEL szlCorner
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRROUNDRECT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_ROUNDRECT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRROUNDRECT) record)->rclBox = rclBox;
+ ((PU_EMRROUNDRECT) record)->szlCorner = szlCorner;
+ }
+ return(record);
+}
+
+// U_EMRARC_set 45
+/**
+ \brief Allocate and construct a U_EMR_ARC record.
+ \return pointer to U_EMR_ARC record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRARC_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_ARC,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRCHORD_set 46
+/**
+ \brief Allocate and construct a U_EMR_CHORD record.
+ \return pointer to U_EMR_CHORD record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRCHORD_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_CHORD,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRPIE_set 47
+/**
+ \brief Allocate and construct a U_EMR_PIE record.
+ \return pointer to U_EMR_PIE record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+*/
+char *U_EMRPIE_set(
+ const U_RECTL rclBox,
+ const U_POINTL ptlStart,
+ const U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_PIE,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRSELECTPALETTE_set 48
+/**
+ \brief Allocate and construct a U_EMR_SELECTPALETTE record.
+ \return pointer to U_EMR_SELECTPALETTE record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+*/
+char *U_EMRSELECTPALETTE_set(
+ const uint32_t ihPal
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SELECTPALETTE, ihPal));
+}
+
+// U_EMRCREATEPALETTE_set 49
+/**
+ \brief Allocate and construct a U_EMR_CREATEPALETTE record.
+ Use createpalette_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEPALETTE record, or NULL on error.
+ \param ihPal Index to place object in EMF object table (this entry must not yet exist)
+ \param lgpl Palette properties
+*/
+char *U_EMRCREATEPALETTE_set(
+ const uint32_t ihPal,
+ const U_LOGPALETTE lgpl
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATEPALETTE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATEPALETTE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATEPALETTE) record)->ihPal = ihPal;
+ ((PU_EMRCREATEPALETTE) record)->lgpl = lgpl;
+ }
+ return(record);
+}
+
+// U_EMRSETPALETTEENTRIES_set 50
+/**
+ \brief Allocate and construct a U_EMR_SETPALETTEENTRIES record.
+ Use setpaletteentries_set() instead of calling this function directly.
+ \return pointer to U_EMR_SETPALETTEENTRIES record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+ \param iStart First Palette entry in selected object to set
+ \param cEntries Number of Palette entries in selected object to set
+ \param aPalEntries Values to set with
+*/
+char *U_EMRSETPALETTEENTRIES_set(
+ const uint32_t ihPal,
+ const uint32_t iStart,
+ const U_NUM_LOGPLTNTRY cEntries,
+ const PU_LOGPLTNTRY aPalEntries
+ ){
+ char *record;
+ int irecsize;
+ int cbPals;
+
+ if(!aPalEntries)return(NULL);
+ cbPals = cEntries * sizeof(U_LOGPLTNTRY);
+ irecsize = sizeof(U_EMRSETPALETTEENTRIES) + cbPals - sizeof(U_LOGPLTNTRY);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETPALETTEENTRIES;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETPALETTEENTRIES) record)->ihPal = ihPal;
+ ((PU_EMRSETPALETTEENTRIES) record)->iStart = iStart;
+ ((PU_EMRSETPALETTEENTRIES) record)->cEntries = cEntries;
+ memcpy(((PU_EMRSETPALETTEENTRIES) record)->aPalEntries, aPalEntries,cbPals);
+ }
+ return(record);
+}
+
+// U_EMRRESIZEPALETTE_set 51
+/**
+ \brief Allocate and construct a U_EMR_RESIZEPALETTE record.
+ \return pointer to U_EMR_RESIZEPALETTE record, or NULL on error.
+ \param ihPal Index of a Palette object in the EMF object table
+ \param cEntries Number to expand or truncate the Palette entry list to
+*/
+char *U_EMRRESIZEPALETTE_set(
+ const uint32_t ihPal,
+ const uint32_t cEntries
+ ){
+ return(U_EMR_CORE7_set(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries}));
+}
+
+// U_EMRREALIZEPALETTE_set 52
+/**
+ \brief Allocate and construct a U_EMR_REALIZEPALETTE record.
+ \return pointer to U_EMR_REALIZEPALETTE record, or NULL on error.
+*/
+char *U_EMRREALIZEPALETTE_set(void){
+ return(U_EMR_CORE5_set(U_EMR_REALIZEPALETTE));
+}
+
+// U_EMREXTFLOODFILL_set 53
+/**
+ \brief Allocate and construct a U_EMR_EXTFLOODFILL record.
+ \return pointer to U_EMR_EXTFLOODFILL record, or NULL on error.
+ \param ptlStart Start point in logical units
+ \param crColor Color to fill with
+ \param iMode FloodFill Enumeration
+*/
+char *U_EMREXTFLOODFILL_set(
+ const U_POINTL ptlStart,
+ const U_COLORREF crColor,
+ const uint32_t iMode
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMREXTFLOODFILL);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTFLOODFILL;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTFLOODFILL) record)->ptlStart = ptlStart;
+ ((PU_EMREXTFLOODFILL) record)->crColor = crColor;
+ ((PU_EMREXTFLOODFILL) record)->iMode = iMode;
+ }
+ return(record);
+}
+
+// U_EMRLINETO_set 54
+/**
+ \brief Allocate and construct a U_EMR_LINETO record.
+ \return pointer to U_EMR_LINETO record, or NULL on error.
+ \param ptl Point coordinates
+*/
+char *U_EMRLINETO_set(
+ const U_POINTL ptl
+ ){
+ return(U_EMR_CORE7_set(U_EMR_LINETO, ptl));
+}
+
+// U_EMRARCTO_set 55
+/**
+ \brief Allocate and construct a U_EMR_ARCTO record.
+ \return pointer to U_EMR_ARCTO record, or NULL on error.
+ \param rclBox bounding rectangle in logical units
+ \param ptlStart Start point in logical units
+ \param ptlEnd End point in logical units
+
+ Note that the draw begins with a line from the current point to ptlStart, which is
+ not indicated in the Microsoft EMF documentation for this record.
+*/
+char *U_EMRARCTO_set(
+ U_RECTL rclBox,
+ U_POINTL ptlStart,
+ U_POINTL ptlEnd
+ ){
+ return(U_EMR_CORE9_set(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd));
+}
+
+// U_EMRPOLYDRAW_set 56
+/**
+ \brief Allocate and construct a U_EMR_POLYDRAW record.
+ \return pointer to U_EMR_POLYDRAW record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cptl Number of U_POINTL objects
+ \param aptl Array of U_POINTL objects
+ \param abTypes Array of Point Enumeration
+*/
+char *U_EMRPOLYDRAW_set(
+ const U_RECTL rclBounds,
+ const U_NUM_POINTL cptl,
+ const U_POINTL *aptl,
+ const uint8_t *abTypes
+ ){
+ char *record;
+ int irecsize;
+ int cbPoints, cbAbTypes, cbAbTypes4, off;
+
+ if(!cptl || !aptl || !abTypes)return(NULL);
+ cbPoints = cptl * sizeof(U_POINTL); // space for aptl
+ cbAbTypes = cptl; // number of abTypes (same array size, 1 byte each)
+ cbAbTypes4 = UP4(cbAbTypes); // space for abTypes
+ irecsize = sizeof(U_EMRPOLYDRAW) + cbPoints + cbAbTypes4 - sizeof(U_POINTL) - 1;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_POLYDRAW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYDRAW) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYDRAW) record)->cptl = cptl;
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part
+ memcpy(record+off,aptl,cbPoints);
+ off += cbPoints;
+ memcpy(record+off,abTypes,cbAbTypes);
+ off += cbAbTypes;
+ if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
+ }
+ return(record);
+}
+
+// U_EMRSETARCDIRECTION_set 57
+/**
+ \brief Allocate and construct a U_EMR_SETARCDIRECTION record.
+ \return pointer to U_EMR_SETARCDIRECTION record, or NULL on error.
+ \param iArcDirection ArcDirection Enumeration
+*/
+char *U_EMRSETARCDIRECTION_set(
+ const uint32_t iArcDirection
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETARCDIRECTION, iArcDirection));
+}
+
+// U_EMRSETMITERLIMIT_set 58
+/**
+ \brief Allocate and construct a U_EMR_SETMITERLIMIT record.
+ \return pointer to U_EMR_SETMITERLIMIT record, or NULL on error.
+ \param eMiterLimit MapMode Enumeration
+*/
+char *U_EMRSETMITERLIMIT_set(
+ const uint32_t eMiterLimit
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETMITERLIMIT, eMiterLimit));
+}
+
+
+// U_EMRBEGINPATH_set 59
+/**
+ \brief Allocate and construct a U_EMR_BEGINPATH record.
+ \return pointer to U_EMR_BEGINPATH record, or NULL on error.
+*/
+char *U_EMRBEGINPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_BEGINPATH));
+}
+
+// U_EMRENDPATH_set 60
+/**
+ \brief Allocate and construct a U_EMR_ENDPATH record.
+ \return pointer to U_EMR_ENDPATH record, or NULL on error.
+*/
+char *U_EMRENDPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_ENDPATH));
+}
+
+// U_EMRCLOSEFIGURE_set 61
+/**
+ \brief Allocate and construct a U_EMR_CLOSEFIGURE record.
+ \return pointer to U_EMR_CLOSEFIGURE record, or NULL on error.
+*/
+char *U_EMRCLOSEFIGURE_set(void){
+ return(U_EMR_CORE5_set(U_EMR_CLOSEFIGURE));
+}
+
+// U_EMRFILLPATH_set 62
+/**
+ \brief Allocate and construct a U_EMR_FILLPATH record.
+ \return pointer to U_EMR_FILLPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_FILLPATH closes the open figure before filling.
+*/
+char *U_EMRFILLPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_FILLPATH,rclBox));
+}
+
+// U_EMRSTROKEANDFILLPATH_set 63
+/**
+ \brief Allocate and construct a U_EMR_STROKEANDFILLPATH record.
+ \return pointer to U_EMR_STROKEANDFILLPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_STROKEANDFILLPATH closes the open figure before filling and stroking.
+ There appears to be no way to fill an open path while stroking it, as any one
+ of U_EMRFILLPATH, U_EMRSTROKEPATH, or U_EMRSTROKEANDFILEPATH will "use up" the path,
+*/
+char *U_EMRSTROKEANDFILLPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_STROKEANDFILLPATH,rclBox));
+}
+
+// U_EMRSTROKEPATH_set 64
+/**
+ \brief Allocate and construct a U_EMR_STROKEPATH record.
+ \return pointer to U_EMR_STROKEPATH record, or NULL on error.
+ \param rclBox Bounding rectangle in device units
+
+ U_EMR_STROKEPATH does NOT close the open figure before stroking it.
+*/
+char *U_EMRSTROKEPATH_set(
+ const U_RECTL rclBox
+ ){
+ return(U_EMR_CORE4_set(U_EMR_STROKEPATH,rclBox));
+}
+
+// U_EMRFLATTENPATH_set 65
+/**
+ \brief Allocate and construct a U_EMR_FLATTENPATH record.
+ \return pointer to U_EMR_FLATTENPATH record, or NULL on error.
+*/
+char *U_EMRFLATTENPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_FLATTENPATH));
+}
+
+// U_EMRWIDENPATH_set 66
+/**
+ \brief Allocate and construct a U_EMR_WIDENPATH record.
+ \return pointer to U_EMR_WIDENPATH record, or NULL on error.
+*/
+char *U_EMRWIDENPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_WIDENPATH));
+}
+
+// U_EMRSELECTCLIPPATH_set 67
+/**
+ \brief Allocate and construct a U_EMR_SELECTCLIPPATH record.
+ \return pointer to U_EMR_SELECTCLIPPATH record, or NULL on error.
+ \param iMode RegionMode Enumeration
+*/
+char *U_EMRSELECTCLIPPATH_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SELECTCLIPPATH, iMode));
+}
+
+// U_EMRABORTPATH_set 68
+/**
+ \brief Allocate and construct a U_EMR_ABORTPATH record.
+ \return pointer to U_EMR_ABORTPATH record, or NULL on error.
+*/
+char *U_EMRABORTPATH_set(void){
+ return(U_EMR_CORE5_set(U_EMR_ABORTPATH));
+}
+
+// U_EMRUNDEF69 69
+
+// U_EMRCOMMENT_set 70 Comment (any binary data, interpretation is program specific)
+/**
+ \brief Allocate and construct a U_EMR_COMMENT record.
+ \return pointer to U_EMR_COMMENT record, or NULL on error.
+ \param cbData Number of bytes in comment
+ \param Data Comment (any binary data, interpretation is program specific)
+*/
+char *U_EMRCOMMENT_set(
+ const U_CBDATA cbData,
+ const char *Data
+ ){
+ char *record;
+ unsigned int cbData4;
+ int irecsize;
+
+ cbData4 = UP4(cbData);
+ irecsize = sizeof(U_EMR) + sizeof(U_CBDATA) + cbData4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_COMMENT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCOMMENT) record)->cbData = cbData;
+ memcpy(record + irecsize - cbData4,Data,cbData);
+ if(cbData4 > cbData)memset(record + irecsize - cbData4 + cbData,0,cbData4-cbData); // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRFILLRGN_set 71
+/**
+ \brief Allocate and construct a U_EMR_FILLRGN record.
+ Use fillrgn_set() instead of calling this function directly.
+ \return pointer to U_EMR_FILLRGN record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param ihBrush Index of a Brush object in the EMF object table
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *U_EMRFILLRGN_set(
+ const U_RECTL rclBounds,
+ const uint32_t ihBrush,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRFILLRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_FILLRGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRFILLRGN) record)->rclBounds = rclBounds;
+ ((PU_EMRFILLRGN) record)->cbRgnData = rds;
+ ((PU_EMRFILLRGN) record)->ihBrush = ihBrush;
+ off = sizeof(U_EMRFILLRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRFRAMERGN_set 72
+/**
+ \brief Allocate and construct a U_EMR_FRAMERGN record.
+ Use framegrn_set() instead of calling this function directly.
+ \return pointer to U_EMR_FRAMERGN record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param ihBrush Index of a Brush object in the EMF object table
+ \param szlStroke W & H of Brush stroke
+ \param RgnData Pointer to a U_RGNDATA structure
+*/
+char *U_EMRFRAMERGN_set(
+ const U_RECTL rclBounds,
+ const uint32_t ihBrush,
+ const U_SIZEL szlStroke,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMRFRAMERGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_FRAMERGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRFRAMERGN) record)->rclBounds = rclBounds;
+ ((PU_EMRFRAMERGN) record)->cbRgnData = rds;
+ ((PU_EMRFRAMERGN) record)->ihBrush = ihBrush;
+ ((PU_EMRFRAMERGN) record)->szlStroke = szlStroke;
+ off = sizeof(U_EMRFRAMERGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRINVERTRGN_set 73
+/**
+ \brief Allocate and construct a U_EMR_INVERTRGN record.
+ \return pointer to U_EMR_INVERTRGN record, or NULL on error.
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMRINVERTRGN_set(
+ const PU_RGNDATA RgnData
+ ){
+ return(U_EMR_CORE11_set(U_EMR_INVERTRGN, RgnData));
+}
+
+// U_EMRPAINTRGN_set 74
+/**
+ \brief Allocate and construct a U_EMR_PAINTRGN record.
+ \return pointer to U_EMR_PAINTRGN record, or NULL on error.
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMRPAINTRGN_set(
+ const PU_RGNDATA RgnData
+ ){
+ return(U_EMR_CORE11_set(U_EMR_PAINTRGN, RgnData));
+}
+
+// U_EMREXTSELECTCLIPRGN_set 75
+/**
+ \brief Allocate and construct a U_EMR_EXTSELECTCLIPRGN record.
+ \return pointer to U_EMR_EXTSELECTCLIPRGN or NULL on error.
+ \param iMode RegionMode Enumeration
+ \param RgnData Variable size U_RGNDATA structure
+*/
+char *U_EMREXTSELECTCLIPRGN_set(
+ const uint32_t iMode,
+ const PU_RGNDATA RgnData
+ ){
+ char *record;
+ int irecsize;
+ int cbRgns,cbRgns4,rds,rds4,off;
+
+ if(!RgnData)return(NULL);
+ cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
+ cbRgns4 = UP4(cbRgns);
+ rds = sizeof(U_RGNDATAHEADER) + cbRgns;
+ rds4 = UP4(rds);
+ irecsize = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTSELECTCLIPRGN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTSELECTCLIPRGN) record)->cbRgnData = rds;
+ ((PU_EMREXTSELECTCLIPRGN) record)->iMode = iMode;
+ off = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RGNDATA);
+ memcpy(record + off, RgnData, rds);
+ off += rds;
+ if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
+ }
+ return(record);
+}
+
+// U_EMRBITBLT_set 76
+/**
+ \brief Allocate and construct a U_EMR_BITBLT record.
+ \return pointer to U_EMR_BITBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source rectangle UL corner in logical units
+ \param xformSrc Source bitmap transform (world to page coordinates)
+ \param crBkColorSrc Source bitmap background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRBITBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ irecsize = sizeof(U_EMRBITBLT) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_BITBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRBITBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRBITBLT) record)->Dest = Dest;
+ ((PU_EMRBITBLT) record)->cDest = cDest;
+ ((PU_EMRBITBLT) record)->dwRop = dwRop;
+ ((PU_EMRBITBLT) record)->Src = Src;
+ ((PU_EMRBITBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRBITBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRBITBLT) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRBITBLT);
+ APPEND_PXBMISRC(record, U_EMRBITBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMRSTRETCHBLT_set 77
+/**
+ \brief Allocate and construct a U_EMR_STRETCHBLT record.
+ \return pointer to U_EMR_STRETCHBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSTRETCHBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSTRETCHBLT) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_STRETCHBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSTRETCHBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRSTRETCHBLT) record)->Dest = Dest;
+ ((PU_EMRSTRETCHBLT) record)->cDest = cDest;
+ ((PU_EMRSTRETCHBLT) record)->dwRop = dwRop;
+ ((PU_EMRSTRETCHBLT) record)->Src = Src;
+ ((PU_EMRSTRETCHBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRSTRETCHBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRSTRETCHBLT) record)->iUsageSrc = iUsageSrc;
+ off = sizeof(U_EMRSTRETCHBLT);
+ APPEND_PXBMISRC(record, U_EMRSTRETCHBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ ((PU_EMRSTRETCHBLT) record)->cSrc = cSrc;
+ }
+ return(record);
+}
+
+// U_EMRMASKBLT_set 78
+/**
+ \brief Allocate and construct a U_EMR_MASKBLT record.
+ \return pointer to U_EMR_MASKBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Mask Mask UL corner in logical units
+ \param iUsageMask DIBcolors Enumeration
+ \param dwRop Ternary Raster Operation enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+ \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
+ \param Msk (Optional) bitmapbuffer (mask section )
+*/
+char *U_EMRMASKBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_POINTL Mask,
+ const uint32_t iUsageMask,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_BITMAPINFO MskBmi,
+ const uint32_t cbMsk,
+ char *Msk
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
+
+ irecsize = sizeof(U_EMRMASKBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_MASKBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRMASKBLT) record)->rclBounds = rclBounds;
+ ((PU_EMRMASKBLT) record)->Dest = Dest;
+ ((PU_EMRMASKBLT) record)->cDest = cDest;
+ ((PU_EMRMASKBLT) record)->dwRop = dwRop;
+ ((PU_EMRMASKBLT) record)->Src = Src;
+ ((PU_EMRMASKBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRMASKBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRMASKBLT) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRMASKBLT) record)->Mask = Mask;
+ ((PU_EMRMASKBLT) record)->iUsageMask = iUsageMask;
+ off = sizeof(U_EMRMASKBLT);
+ APPEND_PXBMISRC(record, U_EMRMASKBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ APPEND_MSKBMISRC(record, U_EMRMASKBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
+ }
+ return(record);
+}
+
+// U_EMRPLGBLT_set 79
+
+/**
+ \brief Allocate and construct a U_EMRPLGBLT record.
+ \return U_EMRPLGBLT record.
+ \param rclBounds Bounding rectangle in device units
+ \param aptlDst Defines parallelogram, UL, UR, LL corners, LR is derived (3 points)
+ \param Src Source UL corner in logical units
+ \param cSrc Source width in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Mask Mask UL corner in logical units
+ \param iUsageMask DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+ \param MskBmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbMsk Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
+ \param Msk (Optional) bitmapbuffer (mask section )
+*/
+char *U_EMRPLGBLT_set(
+ const U_RECTL rclBounds,
+ const PU_POINTL aptlDst,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_POINTL Mask,
+ const uint32_t iUsageMask,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_BITMAPINFO MskBmi,
+ const uint32_t cbMsk,
+ char *Msk
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
+
+ irecsize = sizeof(U_EMRPLGBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_PLGBLT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPLGBLT) record)->rclBounds = rclBounds;
+ memcpy(((PU_EMRPLGBLT) record)->aptlDst,aptlDst,3*sizeof(U_POINTL));
+ ((PU_EMRPLGBLT) record)->Src = Src;
+ ((PU_EMRPLGBLT) record)->cSrc = cSrc;
+ ((PU_EMRPLGBLT) record)->xformSrc = xformSrc;
+ ((PU_EMRPLGBLT) record)->crBkColorSrc = crBkColorSrc;
+ ((PU_EMRPLGBLT) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRPLGBLT) record)->Mask = Mask;
+ ((PU_EMRPLGBLT) record)->iUsageMask = iUsageMask;
+ off = sizeof(U_EMRPLGBLT);
+ APPEND_PXBMISRC(record, U_EMRPLGBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
+ APPEND_MSKBMISRC(record, U_EMRPLGBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
+ }
+ return(record);
+}
+
+// U_EMRSETDIBITSTODEVICE_set 80
+/**
+ \brief Allocate and construct a U_EMR_SETDIBITSTODEVICE record.
+ \return pointer to U_EMR_SETDIBITSTODEVICE record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param iUsageSrc DIBColors Enumeration
+ \param iStartScan First scan line
+ \param cScans Number of scan lines
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSETDIBITSTODEVICE_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t iStartScan,
+ const uint32_t cScans,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSETDIBITSTODEVICE) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SETDIBITSTODEVICE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSETDIBITSTODEVICE) record)->rclBounds = rclBounds;
+ ((PU_EMRSETDIBITSTODEVICE) record)->Dest = Dest;
+ ((PU_EMRSETDIBITSTODEVICE) record)->Src = Src;
+ ((PU_EMRSETDIBITSTODEVICE) record)->cSrc = cSrc;
+ ((PU_EMRSETDIBITSTODEVICE) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRSETDIBITSTODEVICE) record)->iStartScan = iStartScan;
+ ((PU_EMRSETDIBITSTODEVICE) record)->cScans = cScans;
+ off = sizeof(U_EMRSETDIBITSTODEVICE);
+ APPEND_PXBMISRC(record, U_EMRSETDIBITSTODEVICE, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMRSTRETCHDIBITS_set 81
+/**
+ \brief Allocate and construct a U_EMR_EMRSTRETCHDIBITS record.
+ \return pointer to U_EMR_EMRSTRETCHDIBITS record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param iUsageSrc DIBColors Enumeration
+ \param dwRop RasterOPeration Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRSTRETCHDIBITS_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ char *record;
+ int irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = sizeof(U_EMRSTRETCHDIBITS) + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_STRETCHDIBITS;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSTRETCHDIBITS) record)->rclBounds = rclBounds;
+ ((PU_EMRSTRETCHDIBITS) record)->Dest = Dest;
+ ((PU_EMRSTRETCHDIBITS) record)->Src = Src;
+ ((PU_EMRSTRETCHDIBITS) record)->cSrc = cSrc;
+ ((PU_EMRSTRETCHDIBITS) record)->iUsageSrc = iUsageSrc;
+ ((PU_EMRSTRETCHDIBITS) record)->dwRop = dwRop;
+ ((PU_EMRSTRETCHDIBITS) record)->cDest = cDest;
+ off = sizeof(U_EMRSTRETCHDIBITS);
+ APPEND_PXBMISRC(record, U_EMRSTRETCHDIBITS, cbBmi, Bmi, Px, cbImage, cbImage4);
+ }
+ return(record);
+}
+
+// U_EMREXTCREATEFONTINDIRECTW_set 82
+/**
+ \brief Allocate and construct a U_EMR_EXTCREATEFONTINDIRECTW record.
+ Use extcreatefontindirectw_set() instead of calling this function directly.
+ \return pointer to U_EMR_EXTCREATEFONTINDIRECTW record, or NULL on error.
+ \param ihFont Index of the font in the EMF object table
+ \param elf Font parameters as U_LOGFONT
+ \param elfw Font parameters as U_LOGFONT_PANOSE
+*/
+char *U_EMREXTCREATEFONTINDIRECTW_set(
+ const uint32_t ihFont,
+ const char * elf,
+ const char * elfw
+ ){
+ char *record;
+ const char *cptr;
+ int irecsize;
+ int cbLf,off;
+
+ if((elf && elfw) || (!elf && !elfw))return(NULL); // ONE only must be passed
+ if(elf){ cbLf = sizeof(U_LOGFONT); cptr = elf; }
+ else { cbLf = sizeof(U_LOGFONT_PANOSE); cptr = elfw; }
+
+ irecsize = sizeof(U_EMR) + sizeof(uint32_t) + cbLf;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTCREATEFONTINDIRECTW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTCREATEFONTINDIRECTW) record)->ihFont = ihFont;
+ off = sizeof(U_EMR) + sizeof(uint32_t);
+ memcpy(record + off, cptr, cbLf); // No need to add padding for either structure
+ }
+ return(record);
+}
+
+// U_EMREXTTEXTOUTA_set 83
+/**
+ \brief Allocate and construct a U_EMR_EXTTEXTOUTA record.
+ \return pointer to U_EMR_EXTTEXTOUTA record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param iGraphicsMode Graphics mode Enumeration
+ \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param emrtext Text parameters
+*/
+char *U_EMREXTTEXTOUTA_set(
+ const U_RECTL rclBounds,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const PU_EMRTEXT emrtext
+ ){
+ return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
+}
+
+// U_EMREXTTEXTOUTW_set 84
+/**
+ \brief Allocate and construct a U_EMR_EXTTEXTOUTW record.
+ \return pointer to U_EMR_EXTTEXTOUTW record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param iGraphicsMode Graphics mode Enumeration
+ \param exScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param eyScale scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
+ \param emrtext Text parameters
+*/
+char *U_EMREXTTEXTOUTW_set(
+ const U_RECTL rclBounds,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const PU_EMRTEXT emrtext
+ ){
+ return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
+}
+
+// U_EMRPOLYBEZIER16_set 85
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIER16 record.
+ \return pointer to U_EMR_POLYBEZIER16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYBEZIER16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYBEZIER16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYGON16_set 86
+/**
+ \brief Allocate and construct a U_EMR_POLYGON16 record.
+ \return pointer to U_EMR_POLYGON16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYGON16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYGON16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYLINE16_set 87
+/**
+ \brief Allocate and construct a U_EMR_POLYLINE16 record.
+ \return pointer to U_EMR_POLYLINE16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYLINE16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYLINE16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYBEZIERTO16_set 88
+/**
+ \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
+ \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYBEZIERTO16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYLINETO16_set 89
+/**
+ \brief Allocate and construct a U_EMR_POLYLINETO record.
+ \return pointer to U_EMR_POLYLINETO record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYLINETO16_set(
+ const U_RECTL rclBounds,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE6_set(U_EMR_POLYLINETO16, rclBounds, cpts, points));
+}
+
+// U_EMRPOLYPOLYLINE16_set 90
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYLINE16 record.
+ \return pointer to U_EMR_POLYPOLYLINE16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYPOLYLINE16_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE10_set(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points));
+}
+
+// U_EMRPOLYPOLYGON16_set 91
+/**
+ \brief Allocate and construct a U_EMR_POLYPOLYGON16 record.
+ \return pointer to U_EMR_POLYPOLYGON16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param cpts Number of POINT16 in array
+ \param points Array of POINT16
+*/
+char *U_EMRPOLYPOLYGON16_set(
+ const U_RECTL rclBounds,
+ const uint32_t nPolys,
+ const uint32_t *aPolyCounts,
+ const uint32_t cpts,
+ const U_POINT16 *points
+ ){
+ return(U_EMR_CORE10_set(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points));
+}
+
+
+// U_EMRPOLYDRAW16_set 92
+/**
+ \brief Allocate and construct a U_EMR_POLYDRAW16 record.
+ \return pointer to U_EMR_POLYDRAW16 record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param cpts Number of U_POINTL objects
+ \param aptl Array of U_POINTL objects
+ \param abTypes Array of Point Enumeration
+*/
+char *U_EMRPOLYDRAW16_set(
+ const U_RECTL rclBounds,
+ const U_NUM_POINT16 cpts,
+ const U_POINT16 *aptl,
+ const uint8_t *abTypes
+ ){
+ char *record;
+ int irecsize;
+ int cbPoints, cbAbTypes, cbAbTypes4, off;
+
+ if(!cpts || !aptl || !abTypes)return(NULL);
+ cbPoints = cpts * sizeof(U_POINT16); // space for aptl
+ cbAbTypes = cpts; // number of abTypes (same array size, 1 byte each)
+ cbAbTypes4 = UP4(cbAbTypes); // space for abTypes
+ irecsize = sizeof(U_EMRPOLYDRAW16) + cbPoints + cbAbTypes4 - sizeof(U_POINT16) - 1;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_POLYDRAW16;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPOLYDRAW16) record)->rclBounds = rclBounds;
+ ((PU_EMRPOLYDRAW16) record)->cpts = cpts;
+ off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t); // offset to first variable part
+ memcpy(record+off,aptl,cbPoints);
+ off += cbPoints;
+ memcpy(record+off,abTypes,cbAbTypes);
+ off += cbAbTypes;
+ if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
+ }
+ return(record);
+}
+
+// U_EMRCREATEMONOBRUSH_set 93
+/**
+ \brief Allocate and construct a U_EMR_CREATEMONOBRUSH record.
+ \return pointer to U_EMR_CREATEMONOBRUSH record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param iUsage DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRCREATEMONOBRUSH_set(
+ const uint32_t ihBrush,
+ const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+ ){
+ return(U_EMR_CORE12_set(U_EMR_CREATEMONOBRUSH,ihBrush,iUsage,Bmi,cbPx,Px));
+}
+
+// U_EMRCREATEDIBPATTERNBRUSHPT_set 94
+/**
+ \brief Allocate and construct a U_EMR_CREATEDIBPATTERNBRUSHPT record.
+ Use createdibpatternbrushpt_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATEDIBPATTERNBRUSHPT record, or NULL on error.
+ \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
+ \param iUsage DIBcolors Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRCREATEDIBPATTERNBRUSHPT_set(
+ const uint32_t ihBrush,
+ const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ const char *Px
+ ){
+ return(U_EMR_CORE12_set(U_EMR_CREATEDIBPATTERNBRUSHPT,ihBrush,iUsage,Bmi,cbPx,Px));
+}
+
+
+// U_EMREXTCREATEPEN_set 95
+/**
+ \brief Allocate and construct a U_EMR_EXTCREATEPEN record.
+ Use extcreatepen_set() instead of calling this function directly.
+ \return pointer to U_EMR_EXTCREATEPEN record, or NULL on error.
+ \param ihPen ihPen Index to place object in EMF object table (this entry must not yet exist)
+ \param Bmi Bmi bitmapbuffer
+ \param cbPx cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px Px pixel array (NULL if cbPx == 0)
+ \param elp elp Pen parameters (Size is Variable!!!!)
+*/
+char *U_EMREXTCREATEPEN_set(
+ const uint32_t ihPen,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px,
+ const PU_EXTLOGPEN elp
+ ){
+ char *record;
+ int cbImage,cbImage4,cbBmi,off;
+ int irecsize,cbStyleArray,cbElp;
+
+ if(!elp)return(NULL);
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ cbStyleArray = elp->elpNumEntries * sizeof(U_STYLEENTRY); // space actually used by penstyle entries
+ // EXTLOGPEN is already included in EMREXTCREATEPEN, including the possibly unused first penstyle entry
+ if(cbStyleArray){
+ cbElp = sizeof(U_EXTLOGPEN) + cbStyleArray - sizeof(U_STYLEENTRY); // space actually used by elp
+ irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4 + cbStyleArray - sizeof(U_STYLEENTRY);
+ }
+ else {
+ cbElp = sizeof(U_EXTLOGPEN); // first U_STYLEENTRY is present but unused
+ irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4;
+ }
+ record = malloc(irecsize);
+
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_EXTCREATEPEN;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMREXTCREATEPEN) record)->ihPen = ihPen;
+ memcpy(&(((PU_EMREXTCREATEPEN) record)->elp),elp,cbElp);
+ if(cbStyleArray){
+ off = sizeof(U_EMREXTCREATEPEN) + cbStyleArray - sizeof(U_STYLEENTRY);
+ }
+ else {
+ off = sizeof(U_EMREXTCREATEPEN);
+ }
+ // Cannot use APPEND_PXBMISRC here because there is no "Src" in the field names
+ if(cbBmi){
+ memcpy(record + off, Bmi, cbBmi);
+ ((PU_EMREXTCREATEPEN) record)->offBmi = off;
+ ((PU_EMREXTCREATEPEN) record)->cbBmi = cbBmi;
+ off += cbBmi;
+ memcpy(record + off, Px, cbImage);
+ ((PU_EMREXTCREATEPEN) record)->offBits = off;
+ ((PU_EMREXTCREATEPEN) record)->cbBits = cbImage;
+ off += cbImage;
+ if(cbImage4 - cbImage){ memset(record + off, 0, cbImage4 - cbImage); }
+ }
+ else {
+ ((PU_EMREXTCREATEPEN) record)->cbBmi = 0;
+ ((PU_EMREXTCREATEPEN) record)->offBmi = 0;
+ ((PU_EMREXTCREATEPEN) record)->cbBits = 0;
+ ((PU_EMREXTCREATEPEN) record)->offBits = 0;
+ }
+ }
+ return(record);
+}
+
+// U_EMRPOLYTEXTOUTA_set 96 NOT IMPLEMENTED, denigrated after Windows NT
+// U_EMRPOLYTEXTOUTW_set 97 NOT IMPLEMENTED, denigrated after Windows NT
+
+// U_EMRSETICMMODE_set 98
+/**
+ \brief Allocate and construct a U_EMR_SETICMMODE record.
+ \return pointer to U_EMR_SETICMMODE record, or NULL on error.
+ \param iMode ICMMode Enumeration
+*/
+char *U_EMRSETICMMODE_set(
+ const uint32_t iMode
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETICMMODE, iMode));
+}
+
+// U_EMRCREATECOLORSPACE_set 99
+/**
+ \brief Allocate and construct a U_EMR_CREATECOLORSPACE record.
+ Use createcolorspace_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATECOLORSPACE record, or NULL on error.
+ \param ihCS Index to place object in EMF object table (this entry must not yet exist)
+ \param lcs ColorSpace parameters
+*/
+char *U_EMRCREATECOLORSPACE_set(
+ const uint32_t ihCS,
+ const U_LOGCOLORSPACEA lcs
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRCREATECOLORSPACE);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACE;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATECOLORSPACE) record)->ihCS = ihCS;
+ ((PU_EMRCREATECOLORSPACE) record)->lcs = lcs;
+ }
+ return(record);
+}
+
+// U_EMRSETCOLORSPACE_set 100
+/**
+ \brief Allocate and construct a U_EMR_SETCOLORSPACE record.
+ \return pointer to U_EMR_SETCOLORSPACE record, or NULL on error.
+ \param ihCS Index of object in EMF object table
+*/
+char *U_EMRSETCOLORSPACE_set(
+ const uint32_t ihCS
+ ){
+ return(U_EMR_CORE3_set(U_EMR_SETCOLORSPACE, ihCS));
+}
+
+// U_EMRDELETECOLORSPACE_set 101
+/**
+ \brief Allocate and construct a U_EMR_DELETECOLORSPACE record.
+ \return pointer to U_EMR_DELETECOLORSPACE record, or NULL on error.
+ \param ihCS Index of object in EMF object table
+*/
+char *U_EMRDELETECOLORSPACE_set(
+ const uint32_t ihCS
+ ){
+ return(U_EMR_CORE3_set(U_EMR_DELETECOLORSPACE, ihCS));
+}
+
+// U_EMRGLSRECORD_set 102 Not implemented
+// U_EMRGLSBOUNDEDRECORD_set 103 Not implemented
+// U_EMRPIXELFORMAT_set 104
+/**
+ \brief Allocate and construct a U_EMR_PIXELFORMAT record.
+ \return pointer to U_EMR_PIXELFORMAT record, or NULL on error.
+ \param pfd PixelFormatDescriptor
+*/
+char *U_EMRPIXELFORMAT_set(
+ const U_PIXELFORMATDESCRIPTOR pfd
+ ){
+ char *record;
+ int irecsize;
+
+ irecsize = sizeof(U_EMRPIXELFORMAT);
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_PIXELFORMAT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRPIXELFORMAT) record)->pfd = pfd;
+ }
+ return(record);
+}
+// U_EMRDRAWESCAPE_set 105 Not implemented
+// U_EMREXTESCAPE_set 106 Not implemented
+// U_EMRUNDEF107_set 107 Not implemented
+
+// U_EMRSMALLTEXTOUT_set 108
+/**
+ \brief Allocate and construct a U_EMR_SMALLTEXTOUT record.
+ \return pointer to U_EMR_SMALLTEXTOUT record, or NULL on error.
+ \param Dest Where to draw the text
+ \param cChars Characters in TextString (not null terminated)
+ \param fuOptions ExtTextOutOptions Enumeration
+ \param iGraphicsMode GraphicsMode Enumeration
+ \param exScale scale on X axis
+ \param eyScale scale on Y axis
+ \param rclBounds OPTIONAL Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT)
+ \param TextString text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit)
+*/
+char *U_EMRSMALLTEXTOUT_set(
+ const U_POINTL Dest,
+ const U_NUM_STR cChars,
+ const uint32_t fuOptions,
+ const uint32_t iGraphicsMode,
+ const U_FLOAT exScale,
+ const U_FLOAT eyScale,
+ const U_RECTL rclBounds,
+ const char *TextString
+ ){
+ char *record;
+ int irecsize,cbString,cbString4,cbRectl,off;
+ int csize;
+
+ if( fuOptions & U_ETO_SMALL_CHARS ){ csize = 1; } // how many bytes per character
+ else { csize = 2; }
+ cbString = csize * cChars; // filled contents of the string buffer
+ cbString4 = UP4(cbString); // size of the variable string buffer
+ if(fuOptions & U_ETO_NO_RECT){ cbRectl = 0; } // size of the optional U_RECTL field
+ else { cbRectl = sizeof(U_RECTL); }
+
+ irecsize = sizeof(U_EMRSMALLTEXTOUT) + cbString4 + cbRectl;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_SMALLTEXTOUT;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRSMALLTEXTOUT) record)->Dest = Dest;
+ ((PU_EMRSMALLTEXTOUT) record)->cChars = cChars;
+ ((PU_EMRSMALLTEXTOUT) record)->fuOptions = fuOptions;
+ ((PU_EMRSMALLTEXTOUT) record)->iGraphicsMode = iGraphicsMode;
+ ((PU_EMRSMALLTEXTOUT) record)->exScale = exScale;
+ ((PU_EMRSMALLTEXTOUT) record)->eyScale = eyScale;
+ off = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields
+ if(cbRectl){
+ memcpy(record + off, &rclBounds, cbRectl);
+ off += cbRectl;
+ }
+ memcpy(record + off, TextString, cbString);
+ if(cbString < cbString4){
+ off += cbString;
+ memset(record + off, 0, cbString4 - cbString);
+ }
+ }
+ return(record);
+}
+
+// U_EMRFORCEUFIMAPPING_set 109 Not implemented
+// U_EMRNAMEDESCAPE_set 110 Not implemented
+// U_EMRCOLORCORRECTPALETTE_set 111 Not implemented
+// U_EMRSETICMPROFILEA_set 112 Not implemented
+// U_EMRSETICMPROFILEW_set 113 Not implemented
+
+// U_EMRALPHABLEND_set 114
+/**
+ \brief Allocate and construct a U_EMR_ALPHABLEND record.
+ \return pointer to U_EMR_ALPHABLEND record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param Blend Blend function
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRALPHABLEND_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const U_BLEND Blend,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ return(U_EMR_CORE13_set(U_EMR_ALPHABLEND,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,*((uint32_t *) &Blend),Bmi,cbPx,Px));
+}
+
+// U_EMRSETLAYOUT_set 115
+/**
+ \brief Allocate and construct a U_EMR_SETLAYOUT record.
+ \return pointer to U_EMR_SETLAYOUT record, or NULL on error.
+ \param iMode Mirroring Enumeration
+*/
+char *U_EMRSETLAYOUT_set(uint32_t iMode){
+ return(U_EMR_CORE3_set(U_EMR_SETLAYOUT, iMode));
+}
+
+// U_EMRTRANSPARENTBLT_set 116
+/**
+ \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
+ \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param Dest Destination UL corner in logical units
+ \param cDest Destination width in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Src W & H in logical units
+ \param xformSrc Transform to apply to source
+ \param crBkColorSrc Background color
+ \param iUsageSrc DIBcolors Enumeration
+ \param TColor Bitmap color to be treated as transparent
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_EMRTRANSPARENTBLT_set(
+ const U_RECTL rclBounds,
+ const U_POINTL Dest,
+ const U_POINTL cDest,
+ const U_POINTL Src,
+ const U_POINTL cSrc,
+ const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc,
+ const uint32_t TColor,
+ const PU_BITMAPINFO Bmi,
+ const uint32_t cbPx,
+ char *Px
+ ){
+ return(U_EMR_CORE13_set(U_EMR_TRANSPARENTBLT,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,TColor,Bmi,cbPx,Px));
+}
+// U_EMRUNDEF117_set 117 Not implemented
+// U_EMRGRADIENTFILL_set 118
+/**
+ \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
+ \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
+ \param rclBounds Bounding rectangle in device units
+ \param nTriVert Number of TriVertex objects in TriVert
+ \param nGradObj Number of gradient triangle/rectangle objects
+ \param ulMode Gradientfill Enumeration (determines Triangle/Rectangle)
+ \param TriVert Array of TriVertex objects
+ \param GradObj Array of gradient objects (each has 2 [rect] or 3 [triangle] indices into TriVert array)
+
+There is an MS documentation or library problem for this record, as the size of the GradObj must always be set
+as if it was an array of U_GRADIENT3 objects for both rect and triangle. For horizontal and vertical gradients
+this means that there will be unused bytes at the end of the record. This is not what the documentation says,
+but it is how MS's libraries work.
+
+*/
+char *U_EMRGRADIENTFILL_set(
+ const U_RECTL rclBounds,
+ const U_NUM_TRIVERTEX nTriVert,
+ const U_NUM_GRADOBJ nGradObj,
+ const uint32_t ulMode,
+ const PU_TRIVERTEX TriVert,
+ const uint32_t *GradObj
+ ){
+ char *record;
+ unsigned int cbTriVert,cbGradObj,off;
+ unsigned int cbGradObjAlloc; /* larger than cbGradObj, because of problem described above */
+ int irecsize;
+
+ cbTriVert = sizeof(U_TRIVERTEX) * nTriVert; // all of the cb's will be a multiple of 4 bytes
+ if( ulMode == U_GRADIENT_FILL_TRIANGLE){ cbGradObj = sizeof(U_GRADIENT3) * nGradObj; }
+ else if(ulMode == U_GRADIENT_FILL_RECT_H ||
+ ulMode == U_GRADIENT_FILL_RECT_V){ cbGradObj = sizeof(U_GRADIENT4) * nGradObj; }
+ else { return(NULL); }
+ cbGradObjAlloc = sizeof(U_GRADIENT3) * nGradObj;
+
+ irecsize = sizeof(U_EMRGRADIENTFILL) + cbTriVert + cbGradObjAlloc;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_GRADIENTFILL;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRGRADIENTFILL) record)->rclBounds = rclBounds;
+ ((PU_EMRGRADIENTFILL) record)->nTriVert = nTriVert;
+ ((PU_EMRGRADIENTFILL) record)->nGradObj = nGradObj;
+ ((PU_EMRGRADIENTFILL) record)->ulMode = ulMode;
+ off = sizeof(U_EMRGRADIENTFILL); // offset to TriVert field
+ memcpy(record + off, TriVert, cbTriVert);
+ off += cbTriVert;
+ memcpy(record + off, GradObj, cbGradObj);
+ off += cbGradObj;
+ if(cbGradObjAlloc > cbGradObj){
+ memset(record+off,0,cbGradObjAlloc - cbGradObj);
+ }
+ }
+ return(record);
+}
+
+// U_EMRSETLINKEDUFIS_set 119 Not implemented
+// U_EMRSETTEXTJUSTIFICATION_set 120 Not implemented (denigrated)
+// U_EMRCOLORMATCHTOTARGETW_set 121 Not implemented
+
+// U_EMRCREATECOLORSPACEW_set 122
+/**
+ \brief Allocate and construct a U_EMR_CREATECOLORSPACEW record.
+ Use createcolorspacew_set() instead of calling this function directly.
+ \return pointer to U_EMR_CREATECOLORSPACEW record, or NULL on error.
+ \param ihCS Index to place object in EMF object table (this entry must not yet exist)
+ \param lcs ColorSpace parameters
+ \param dwFlags If low bit set Data is present
+ \param cbData Number of bytes of theData field.
+ \param Data (Optional, dwFlags & 1) color profile data
+*/
+char *U_EMRCREATECOLORSPACEW_set(
+ const uint32_t ihCS,
+ const U_LOGCOLORSPACEW lcs,
+ const uint32_t dwFlags,
+ const U_CBDATA cbData,
+ const uint8_t *Data
+ ){
+ char *record;
+ unsigned int cbData4,off;
+ int irecsize;
+
+ cbData4 = UP4(cbData); // buffer to hold Data
+ irecsize = sizeof(U_EMRCREATECOLORSPACEW) + cbData4;
+ record = malloc(irecsize);
+ if(record){
+ ((PU_EMR) record)->iType = U_EMR_CREATECOLORSPACEW;
+ ((PU_EMR) record)->nSize = irecsize;
+ ((PU_EMRCREATECOLORSPACEW) record)->ihCS = ihCS;
+ ((PU_EMRCREATECOLORSPACEW) record)->lcs = lcs;
+ ((PU_EMRCREATECOLORSPACEW) record)->dwFlags = dwFlags;
+ ((PU_EMRCREATECOLORSPACEW) record)->cbData = cbData;
+ off = sizeof(U_EMR) + sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(uint32_t) + sizeof(U_CBDATA); // offset to Data field
+ memcpy(record + off, Data, cbData);
+ if(cbData < cbData4){
+ off += cbData;
+ memset(record + off,0,cbData4-cbData);
+ }
+ }
+ return(record);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uemf.h b/src/3rdparty/libuemf/uemf.h
new file mode 100644
index 000000000..3a51e39e2
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf.h
@@ -0,0 +1,3653 @@
+/**
+ @file uemf.h
+
+ @brief Structures, definitions, and function prototypes for EMF files.
+
+ EMF file Record structure information has been derived from Mingw, Wine, and libEMF header files, and from
+ Microsoft's EMF Information pdf, release date March 28,2012, link from here:
+
+ http://msdn2.microsoft.com/en-us/library/cc230514.aspx
+
+ If the direct link fails the document may be found
+ by searching for: "[MS-EMF]: Enhanced Metafile Format"
+
+*/
+
+/** \mainpage libUEMF overview
+\section ov Overview
+Microsoft's WMF, EMF, and EMF+ metafile types are supported. In each case functions are provided for reading, constructing, writing, and printing
+metafile records. The methods used to do that differ somewhat between metafiles, and the simplest
+way to get started is to have a look at the example programs provided. The WMF, EMF, and EMF+ structs and functions are
+marked with U_WMF, U_EMF, U_PMF and U_WMR, U_EMR, and U_PMR prefixes. (PMF because "+" is a reserved character
+in many contexts, so U_EMF+NAME would be a problem.) Please be aware that normally both EMF and EMF+ files have the ".emf"
+file extension, and that it is very common for such files to contain both an EMF and an EMF+ representation of the
+drawing.
+
+\section example_sec Example Programs
+testbed_emf.c Creates an EMF file test_libuemf.emf.\n
+testbed_wmf.c Creates a WMF file test_libuemf.wmf.\n
+testbed_pmf.c Creates an EMF+ file test_libuemf_p.emf.\n
+reademf.c Reads an EMF or EMF+ file and emits a text summary of its records.\n
+readwmf.c Reads a WMF file and emits a text summary of its records.\n
+emf-inout.cpp.example Example code from Inkscape to convert graphics from EMF to SVG.\n
+emf-print.cpp.example Example code from Inkscape to print a drawing to EMF.\n
+wmf-inout.cpp.example Example code from Inkscape to convert graphics from WMF to SVG.\n
+wmf-print.cpp.example Example code from Inkscape to print a drawing to WMF.
+
+\section doxy_limits Documentation issues
+There are currently some unresolved issues with Doxygen that result in some structs
+not being "defined". This comes up when several different types of structs have the same
+layout. When this occurs the first one listed on the "typedef struct" is defined but all the
+others will only be shown under "typedef struct" referring to the first one. This is why
+clicking on U_RECTL in a function parameter jumps to a typedef struct page, why U_RECTL is shown
+as plain text here, but U_RECT is shown as a link here, and clicking on it jumps directly
+to its structure definition.
+
+An additional issue is that the Enumeration names used in WMF are different from those
+used in EMF, even when the values are either identical or differ only slightly, and no method
+has been found yet to link one to the other in Doxygen. At present the only way to look up
+these WMF enumerations is by referencing the following table:
+
+ EMF WMF WMF Manual
+ EMF Binary Raster Operation Enumeration BinaryRasterOperation Enumeration 2.1.1.2
+ EMF Bitcount Enumeration BitCount Enumeration 2.1.1.3
+ EMF LB_Style Enumeration BrushStyle Enumeration 2.1.1.4
+ EMF LF_CharSet Enumeration CharacterSet Enumeration 2.1.1.5
+ EMF DIBColors Enumeration ColorUsage Enumeration [has 1 extra value] 2.1.1.6
+ EMF BI_Compression Enumeration Compression Enumeration [has 3 extra values] 2.1.1.7
+ - FamilyFont Enumeration 2.1.1.8
+ EMF FloodFill Enumeration FloodFill Enumeration 2.1.1.9
+ EMF LF_Quality Enumeration FontQuality Enumeration 2.1.1.10
+ EMF LCS_Intent Enumeration GamutMappingIntent Enumeration 2.1.1.11
+ EMF HatchStyle Enumeration HatchStyle Enumeration 2.1.1.12
+ EMF Mirroring Enumeration LayoutEnumeration 2.1.1.13
+ - LogicalColorSpace Enumeration 2.1.1.14
+ EMF Profile Enumeration LogicalColorSpaceV5 Enumeration 2.1.1.15
+ EMF MapMode Enumeration MapModeEnumeration 2.1.1.16
+ - MetaFilesEscape Enumeration 2.1.1.17
+ - MetafileType Enumeration 2.1.1.18
+ - MetafileVersion Enumeration 2.1.1.19
+ EMF BackgroundMode Enumeration MixModeEnumeration 2.1.1.20
+ EMF LF_OutPrecision Enumeration OutPrecision Enumeration 2.1.1.21
+ - PaletteEntryFlag Enumeration 2.1.1.22
+ EMF PenStyle Enumeration PenStyle Enumeration [not values >0xFFFF] 2.1.1.23
+ - PitchFont Enumeration 2.1.1.24
+ EMF PolygonFillMode Enumeration PolyFillMode Enumeration [first 2 only] 2.1.1.25
+ - PostScriptCap Enumeration 2.1.1.26
+ - PostScriptClipping Enumeration 2.1.1.27
+ - PostFeatureSetting Enumeration 2.1.1.28
+ - PostScrioptJoin Enumeration 2.1.1.29
+ EMF StretchMode Enumeration StretchMode Enumeration 2.1.1.30
+ EMF Ternary Raster Operation Enumeration TernaryRasterOperation Enumeration 2.1.1.31
+ EMF LF_ClipPrecision Enumeration ClipPrecision Flags 2.1.2.1
+ EMF ExtTextOutOptions Enumeration ExtTextOutOptions Flags [subset] 2.1.2.2
+ EMF TextAlignment Enumeration TextAlignment Enumeration 2.1.2.3
+ EMF TextAlignment Enumeration VertialTextAlignment Enumeration 2.1.2.4
+ EMF LF_PitchAndFamily Enumeration PitchAndFamily Enumerations 2.2.2.14
+
+\section refs Reference documentation
+
+ Manual Date Link
+ EMF 3/28/2012 http://msdn2.microsoft.com/en-us/library/cc230514.aspx
+ EMF+ 7/5/2012 http://msdn.microsoft.com/en-us/library/cc230724.aspx
+ WMF 7/5/2012 http://msdn2.microsoft.com/en-us/library/cc250370.aspx
+*/
+
+/*
+File: uemf.h
+Version: 0.0.34
+Date: 03-JAN-2017
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2017 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UEMF_
+#define _UEMF_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include "uemf_utf.h"
+#include "uemf_endian.h"
+
+
+/** \cond */
+// ***********************************************************************************
+// defines not placed yet
+
+#define U_PAN_CULTURE_LATIN 0
+
+#define U_SYSPAL_ERROR 0
+#define U_SYSPAL_STATIC 1
+#define U_SYSPAL_NOSTATIC 2
+
+#define U_ELF_VENDOR_SIZE 4
+
+#define UNUSED_PARAMETER(x) (void)(x)
+/** \endcond */
+
+// ***************************************************************************
+/** \defgroup U_EMF_Miscellaneous_values EMF Miscellaneous Values
+ @{
+*/
+#define U_NONE 0 //!< Generic for nothing selected for all flag fields
+#define U_PI 3.14159265358979323846 //!< pi
+#define U_READ 1 //!< open file as "rb"
+#define U_WRITE 0 //!< open file as "wb"
+#define U_DV_SGNTR 0x08007664 //!< For U_DESIGNVECTOR Signature field
+#define U_LP_VERSION 0x0300 //!< For U_LOGPALETTE palVersion field
+#define U_RDH_RECTANGLES 1 //!< For U_RGNDATAHEADER iType field
+#define U_RDH_OBJSIZE 0x20 //!< For U_RGNDATAHEADER dwSIze field
+#define U_RGB_GAMMA_MIN (uint16_t)02500 //!< For U_COLORADJUSTMENT ca[Red|Green|Blue]Gamma fields
+#define U_RGB_GAMMA_MAX (uint16_t)65000 //!< For U_COLORADJUSTMENT ca[Red|Green|Blue]Gamma fields
+#define U_REFERENCE_WHITE_MIN (uint16_t)6000 //!< For U_COLORADJUSTMENT caReferenceWhite field
+#define U_REFERENCE_WHITE_MAX (uint16_t)10000 //!< For U_COLORADJUSTMENT caReferenceWhite field
+#define U_REFERENCE_BLACK_MIN (uint16_t)0 //!< For U_COLORADJUSTMENT caReferenceBlack field
+#define U_REFERENCE_BLACK_MAX (uint16_t)4000 //!< For U_COLORADJUSTMENT caReferenceBlack field
+#define U_COLOR_ADJ_MIN ((int16_t)-100) //!< For U_COLORADJUSTMENT ca[Contrast|Brightness|Colorfulness|RedGreenTint] fields
+#define U_COLOR_ADJ_MAX (int16_t) 100 //!< For U_COLORADJUSTMENT ca[Contrast|Brightness|Colorfulness|RedGreenTint] fields
+#define U_MAX_PATH 1024 //!< longest path name for a file
+#define U_LCS_SIGNATURE 0x50534F43 //!< logColorSpace Signature
+#define U_LCS_VERSION 0x400 //!< logColorSpace Version
+#define U_REC_FREE 1 //!< use with emf_append
+#define U_REC_KEEP 0 //!< use with emf_append
+#define U_ROW_ORDER_INVERT 1 //!< For RGBA_to_DIB, invert row order in DIB relative to pixel array
+#define U_ROW_ORDER_SAME 0 //!< For RGBA_to_DIB, same row order in DIB as in pixel array
+#define U_CT_NO 0 //!< For RGBA_to_DIB, do not use color table
+#define U_CT_BGRA 1 //!< For RGBA_to_DIB, use color table (16 bits or less only) BGRA colors, compatible with EMF+ ARGB
+#define U_CT_ARGB 1 //!< For RGBA_to_DIB, use color table (16 bits or less only) BGRA colors, compatible with EMF+ ARGB
+#define U_EMR_COMMENT_SPOOLFONTDEF 0x544F4E46 //!< For U_EMRCOMMENT record that is U_EMR_COMMENT_SPOOL, comment holds font definition informtion.
+/** Solaris 8 has problems with round/roundf, just use this everywhere */
+#define U_ROUND(A) ( (A) > 0 ? floor((A)+0.5) : ( (A) < 0 ? -floor(-(A)+0.5) : (A) ) )
+
+#define MAKE_MIN_PTR(A,B) ( A < B ? A : B)
+/* IS_MEM_UNSAFE takes 3 parameters:
+ A start address of a block of allocated memory
+ B offset into this block starting at A
+ C address of final byte of a block of allocated memory.
+ Returns
+ 1 if B cannot be an int or size_t
+ 1 if C > A
+ 1 if A+B is not in the range A to C, inclusive
+ 0 otherwise.
+ B may be an int, an unsigned int, or a size_t. An int can be negative,
+ which is obviously wrong, but testing for that means that the size
+ of B cannot be more than INT_MAX/2. Accept that limitation since
+ no reasonable EMF record or file should ever be that large.
+ If B is a uint16_t gcc complains about the first test.
+ This Macro must not be used where B needs more than 32 bits!
+*/
+#define IS_MEM_UNSAFE(A,B,C) ( (sizeof(B) < sizeof(int) || (int)(B) < 0) ? 1 : ((int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 ))) //!< Return 1 when a region of memory starting at A of B bytes extends beyond pointer C
+
+/** @} */
+
+
+typedef float U_FLOAT; //!< 32 bit float
+
+typedef uint32_t U_CBBITS; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBBITSMSK; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBBITSSRC; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBBMI; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBBMIMSK; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBBMISRC; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBDATA; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBNAME; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBPLENTRIES; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBPXLFMT; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBRGNDATA; //!< Count of Bytes in object at corresponding U_OFF*
+typedef uint32_t U_CBSTR; //!< Count of Bytes in an 8 or 16 bit string
+
+typedef uint32_t U_OFFBITS; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFBITSMSK; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFBITSSRC; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFBMI; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFBMIMSK; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFBMISRC; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFDATA; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFDESC; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFDX; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFPLENTRIES; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFPXLFMT; //!< Byte offset to TYPE, always measured from the start of the RECORD (not the struct)
+typedef uint32_t U_OFFSTR; //!< Byte offset to string of either 8 or 16 bit characters
+typedef uint8_t U_DATA; //!< any binary sort of data, not otherwise classified.
+
+// "Types" For array components in structures, where not otherwise defined as a structure
+typedef uint32_t U_FNTAXES; //!< Font Axes For U_DESIGNVECTOR
+typedef uint32_t U_STYLEENTRY; //!< StyleEntry For U_EXTLOGPEN
+typedef uint32_t U_POLYCOUNTS; //!< aPolyCounts For U_EMRPOLYPOLYLINE etc.
+
+// "Counts" for array components in structures
+typedef uint32_t U_NUM_FNTAXES; //!< Number of U_FNTAXES
+typedef uint32_t U_NUM_LOGPLTNTRY; //!< Number of U_LOGPLTENTRY
+typedef uint32_t U_NUM_RECTL; //!< Number of U_RECTL
+typedef uint32_t U_NUM_POINTL; //!< Number of U_POINTL
+typedef uint32_t U_NUM_POINT16; //!< Number of U_POINT16
+typedef uint32_t U_NUM_STYLEENTRY; //!< Number of U_STYLEENTRY
+typedef uint32_t U_NUM_POLYCOUNTS; //!< Number of U_POLYCOUNTS
+typedef uint32_t U_NUM_EMRTEXT; //!< Number of U_EMRTEXT
+typedef uint32_t U_NUM_STR; //!< Number of 8 or 16 bit characters in string
+typedef uint32_t U_NUM_TRIVERTEX; //!< Number of U_TRIVERTEX
+typedef uint32_t U_NUM_GRADOBJ; //!< Number of U_GRADIENT4 OR U_GRADIENT3 (determined at run time)
+typedef uint32_t U_NUM_RGBQUAD; //!< Number of U_RGBQUAD (in bmciColors in U_BITMAPCOREINFO)
+
+
+
+/* ************************ WMF pieces used in EMF or EMF+ ****************************** */
+
+/** \defgroup U_EMF_EMRSETROP2_iMode_Qualifiers EMF Binary Raster Operation Enumeration
+
+ For U_EMRSETROP2 iMode field
+ Microsoft name: Binary Raster Operation Enumeration
+ WMF manual 2.1.1.2
+
+ These codes specify:
+ 1. an order of operands (composed of various orders and combinations of: Dest, Pen)
+ (There are 2, hence "Binary Raster Operation")
+ 2. an order of operators to apply to the operands (composed of Not, Xor, Or, And)
+ Only a few of the more common operations are provided here.
+
+ The default is U_R2_COPYPEN. If this value is changed to something else all subsequenty
+ draw operations will use the altered logic. For instance, if it is set to U_R2_BLACK and
+ a red rectangle is drawn it will appear as a black rectangle.
+
+ @{
+*/
+#define U_R2_BLACK 1 //!< BLACK
+#define U_R2_NOTMERGEPEN 2 //!< NOTMERGEPEN
+#define U_R2_MASKNOTPEN 3 //!< MASKNOTPEN
+#define U_R2_NOTCOPYPEN 4 //!< NOTCOPYPEN
+#define U_R2_MASKPENNOT 5 //!< MASKPENNOT
+#define U_R2_NOT 6 //!< NOT
+#define U_R2_XORPEN 7 //!< XORPEN
+#define U_R2_NOTMASKPEN 8 //!< NOTMASKPEN
+#define U_R2_MASKPEN 9 //!< MASKPEN
+#define U_R2_NOTXORPEN 10 //!< NOTXORPEN
+#define U_R2_NOP 11 //!< NOP
+#define U_R2_MERGENOTPEN 12 //!< MERGENOTPEN
+#define U_R2_COPYPEN 13 //!< COPYPEN
+#define U_R2_MERGEPENNOT 14 //!< MERGEPENNOT
+#define U_R2_MERGEPEN 15 //!< MERGEPEN
+#define U_R2_WHITE 16 //!< WHITE
+#define U_R2_LAST 16 //!< LAST
+/** @} */
+
+/** \defgroup U_EMF_BITMAPINFOHEADER_biBitCount_Qualifiers EMF BitCount Enumeration
+ For U_BITMAPINFOHEADER biBitCount field.
+ Microsoft name: Bitcount Enumeration
+ WMF manual 2.1.1.3
+ @{
+*/
+#define U_BCBM_EXPLICIT 0 //!< Derived from JPG or PNG compressed image or ?
+#define U_BCBM_MONOCHROME 1 //!< 2 colors. bmiColors array has two entries
+#define U_BCBM_COLOR4 4 //!< 2^4 colors. bmiColors array has 16 entries
+#define U_BCBM_COLOR8 8 //!< 2^8 colors. bmiColors array has 256 entries
+#define U_BCBM_COLOR16 16 //!< 2^16 colors. bmiColors is not used. Pixels are 5 bits B,G,R with 1 unused bit
+#define U_BCBM_COLOR24 24 //!< 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+#define U_BCBM_COLOR32 32 //!< 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD. Also use for EMF+ ARGB
+/** @} */
+
+/** \defgroup U_EMF_BITMAPINFOHEADER_biCompression_Qualifiers EMF BI_Compression Enumeration
+ For U_BITMAPINFOHEADER biCompression field
+ Microsoft name: Compression Enumeration
+ WMF manual 2.1.1.7
+ @{
+*/
+#define U_BI_UNKNOWN -1 //!< not defined in EMF standard, not to be used in EMF files
+#define U_BI_RGB 0 //!< Supported by libUEMF
+#define U_BI_RLE8 1 //!< NOT supported by libUEMF
+#define U_BI_RLE4 2 //!< NOT supported by libUEMF
+#define U_BI_BITFIELDS 3 //!< Supported by libUEMF
+#define U_BI_JPEG 4 //!< Supported by libUEMF
+#define U_BI_PNG 5 //!< Supported by libUEMF
+/** @} */
+
+/** \defgroup U_EMF_LOGCOLORSPACE_lcsIntent_Qualifiers EMF LCS_Intent Enumeration
+ For U_LOGCOLORSPACEA/U_LOGCOLORSPACEW lcsIntent field
+ Microsoft name: LCS_Intent Enumeration
+ WMF manual 2.1.1.11
+ @{
+*/
+#define U_LCS_GM_BUSINESS 0x00000001L //!< BUSINESS
+#define U_LCS_GM_GRAPHICS 0x00000002L //!< GRAPHICS
+#define U_LCS_GM_IMAGES 0x00000004L //!< IMAGES
+#define U_LCS_GM_ABS_COLORIMETRIC 0x00000008L //!< ABS_COLORIMETRIC
+/** @} */
+
+/** \defgroup U_EMF_LOGCOLORSPACE_lcsCSType_Qualifiers EMF LCS_CSType Enumeration
+ For U_LOGCOLORSPACEA/U_LOGCOLORSPACEW lcsCSType field
+ Microsoft name: LCS_CSType Enumeration
+ WMF manual 2.1.1.14
+ @{
+*/
+#define U_LCS_CALIBRATED_RGB 0x00000000L //!< CALIBRATED_RGB
+#define U_LCS_DEVICE_RGB 0x00000001L //!< DEVICE_RGB
+#define U_LCS_DEVICE_CMYK 0x00000002L //!< DEVICE_CMYK
+/** @} */
+
+/** \defgroup U_EMF_EMR_dwROP_Qualifiers EMF Ternary Raster Operation enumeration
+
+ For U_EMR* dwROP fields.
+ Microsoft name: Ternary Raster Operation enumeration
+ WMF manual 2.1.1.31
+
+ These codes specify:
+ 1. an order of operands (composed of various orders and combinations of: Dest, Src, Pen)
+ (There are 3, hence "Ternary Raster Operation")
+ 2. an order of operators to apply to the operands (composed of Not, Xor, Or, And)
+ Only a few of the more common operations are provided here.
+ When the Operation does not use a Src operand the corresponding source bitmap may be
+ omitted from the record.
+
+ For more details see:
+ http://wiki.winehq.org/TernaryRasterOps
+
+
+ @{
+*/
+#define U_SRCCOPY 0x00cc0020 //!< SRCCOPY
+#define U_SRCPAINT 0x00ee0086 //!< SRCPAINT
+#define U_SRCAND 0x008800c6 //!< SRCAND
+#define U_SRCINVERT 0x00660046 //!< SRCINVERT
+#define U_SRCERASE 0x00440328 //!< SRCERASE
+#define U_NOTSRCCOPY 0x00330008 //!< NOTSRCCOPY
+#define U_NOTSRCERASE 0x001100a6 //!< NOTSRCERASE
+#define U_MERGECOPY 0x00c000ca //!< MERGECOPY
+#define U_MERGEPAINT 0x00bb0226 //!< MERGEPAINT
+#define U_PATCOPY 0x00f00021 //!< PATCOPY
+#define U_PATPAINT 0x00fb0a09 //!< PATPAINT
+#define U_PATINVERT 0x005a0049 //!< PATINVERT
+#define U_DSTINVERT 0x00550009 //!< DSTINVERT
+#define U_BLACKNESS 0x00000042 //!< BLACKNESS
+#define U_WHITENESS 0x00ff0062 //!< WHITENESS
+#define U_NOOP 0x00aa0029 //!< Many GDI programs end with a bitblt with this ROP == "D". Seems to work like flush()
+#define U_NOMIRRORBITMAP 0x80000000 //!< If bit set, disable horizontal reflection of bitmap.
+/** @} */
+
+/** \defgroup U_EMF_EMRSETTEXTALIGN_iMode_Qualifiers EMF TextAlignment Enumeration
+ For U_EMRSETTEXTALIGN iMode field
+ Microsoft name: TextAlignment Enumeration
+ WMF Manual 2.1.2.3
+ WMF Manual 2.1.2.4
+
+ Recall that EMF coordinates have UL closest to {0,0}, LR is below and to the right of UL and so has LARGER
+ {x,y} coordinates. In the following "TOP" is on the horizontal line defined by LR, as it has larger y coordinates,
+ which when viewing the EMF file, would actually be on the BOTTOM of the bounding rectangle. Similarly, left and right
+ are reversed.
+
+ Microsoft documentation (WMF manual, section 2.1.2.3) says that the text starts on certain edges of the bounding rectangle.
+ That is apparently not true, whether the bounding rectangle is {0,0,-1,-1}, which is effectively no bounding rectangle,
+ or if a valid bounding rectangle is specified. In all cases the text (in Windows XP Preview) starts, has center at, or ends
+ at the center point. Vertical offsets seem to be defined analogously, but with respect to the height of the font. The bounding
+ rectangle defined for the U_EMRTEXT record appears to be ignored.
+
+ Microsoft documentation (EMF manual,section 2.2.5) says that the same rectangle is used for "clipping or opaquing" by ExtTextOutA/W.
+ That does not seem to occur either.
+
+ @{
+*/
+// Horizontal text flags
+#define U_TA_DEFAULT 0x00 //!< default alignment
+#define U_TA_NOUPDATECP 0x00 //!< Reference point does not move
+#define U_TA_UPDATECP 0x01 //!< Reference point moves to end of next text drawn.
+#define U_TA_LEFT 0x00 //!< Reference point is on left edge of bounding rectangle
+#define U_TA_RIGHT 0x02 //!< Reference point is on right edge of bounding rectangle
+#define U_TA_CENTER 0x06 //!< Reference point is on center vertical line of bounding rectangle
+#define U_TA_TOP 0x00 //!< Reference point is on top edge of bounding rectangle
+#define U_TA_BOTTOM 0x08 //!< Reference point is on bottom edge of bounding rectangle
+#define U_TA_BASEBIT 0x10 //!< Reference point is on baseline of text if this bit is set, for 0x10 <-> 0x18
+#define U_TA_BASELINE 0x18 //!< Reference point is on baseline of text
+#define U_TA_RTLREADING 0x100 //!< Set for Right to Left languages like Hebrew and Arabic
+#define U_TA_MASK U_TA_BASELINE+U_TA_CENTER+U_TA_UPDATECP+U_TA_RTLREADING //!< Mask for these bits
+// Vertical text flags
+#define U_VTA_BASELINE U_TA_BASELINE //!< same meaning, but for vertical text
+#define U_VTA_LEFT U_TA_BOTTOM //!< same meaning, but for vertical text
+#define U_VTA_RIGHT U_TA_TOP //!< same meaning, but for vertical text
+#define U_VTA_CENTER U_TA_CENTER //!< same meaning, but for vertical text
+#define U_VTA_BOTTOM U_TA_RIGHT //!< same meaning, but for vertical text
+#define U_VTA_TOP U_TA_LEFT //!< same meaning, but for vertical text
+/** @} */
+
+/** WMF manual 2.2.2.3
+ \brief For U_BITMAPINFO bmiHeader field
+
+ Microsoft name: BITMAPINFOHEADER Object
+*/
+typedef struct {
+ uint32_t biSize; //!< Structure size in bytes
+ int32_t biWidth; //!< Bitmap width in pixels
+ int32_t biHeight; //!< Bitmap height in pixels, may be negative.
+ //!< abs(biHeight) is bitmap height
+ //!< bitmap may appear in two orientations:
+ //!< biHeight > 0 origin is LL corner, may be compressed, this is height after decompression.
+ //!< biHeight < 0 origin is UL corner, may not be compressed
+ uint16_t biPlanes; //!< Planes (must be 1)
+ uint16_t biBitCount; //!< BitCount Enumeration (determines number of RBG colors)
+ uint32_t biCompression; //!< BI_Compression Enumeration
+ uint32_t biSizeImage; //!< Image size in bytes or 0 = "default size (calculated from geometry?)"
+ int32_t biXPelsPerMeter; //!< X Resolution in pixels/meter
+ int32_t biYPelsPerMeter; //!< Y Resolution in pixels/meter
+ U_NUM_RGBQUAD biClrUsed; //!< Number of bmciColors in U_BITMAPINFO/U_BITMAPCOREINFO that are used by the bitmap
+ uint32_t biClrImportant; //!< Number of bmciColors needed (0 means all).
+} U_BITMAPINFOHEADER,
+ *PU_BITMAPINFOHEADER; //!< WMF manual 2.2.2.3
+#define U_SIZE_BITMAPINFOHEADER (sizeof(U_BITMAPINFOHEADER))
+
+/** WMF manual 2.2.2.6
+ \brief For U_CIEXYZTRIPLE (all) fields
+
+ Microsoft name: CIEXYZ Object
+*/
+typedef struct {
+ int32_t ciexyzX; //!< CIE color space X component
+ int32_t ciexyzY; //!< CIE color space Y component
+ int32_t ciexyzZ; //!< CIE color space Z component
+} U_CIEXYZ,
+ *PU_CIEXYZ; //!< WMF manual 2.2.2.6
+
+/** WMF manual 2.2.2.7
+ \brief For U_LOGCOLORSPACEA and U_LOGCOLORSPACEW lcsEndpints field
+
+ defines a CIE colorspace.
+ Microsoft name: CIEXYZTRIPLE Object
+
+*/
+typedef struct {
+ U_CIEXYZ ciexyzRed; //!< CIE XYZ coord of red endpoint of colorspace
+ U_CIEXYZ ciexyzGreen; //!< CIE XYZ coord of green endpoint of colorspace
+ U_CIEXYZ ciexyzBlue; //!< CIE XYZ coord of blue endpoint of colorspace
+} U_CIEXYZTRIPLE,
+ *PU_CIEXYZTRIPLE; //!< WMF manual 2.2.2.7
+
+/** WMF manual 2.2.2.8
+ \brief For U_BITMAPINFO crColor field
+
+ NOTE that the color order is RGB reserved, flipped around from the preceding.
+ Microsoft name: COLORREF Object
+*/
+typedef struct {
+ uint8_t Red; //!< Red color (0-255)
+ uint8_t Green; //!< Green color (0-255)
+ uint8_t Blue; //!< Blue color (0-255)
+ uint8_t Reserved; //!< Not used
+} U_COLORREF,
+ *PU_COLORREF; //!< WMF manual 2.2.2.8
+
+/** WMF manual 2.2.2.11
+ \brief For U_LCS_GAMMARGB lcsGamma* fields
+
+ Microsoft name:(unknown)
+*/
+typedef struct {
+ unsigned ignoreHi :8; //!< not used
+ unsigned intPart :8; //!< integer part
+ unsigned fracPart :8; //!< fraction part
+ unsigned ignoreLo :8; //!< not used
+} U_LCS_GAMMA,
+ *PU_LCS_GAMMA; //!< WMF manual 2.2.2.11
+
+/** WMF manual 2.2.2.11
+ \brief For U_LOGCOLORSPACEA and U_LOGCOLORSPACEW lcsGammaRGB field
+
+ Microsoft name:(unknown)
+*/
+typedef struct {
+ U_LCS_GAMMA lcsGammaRed; //!< Red Gamma
+ U_LCS_GAMMA lcsGammaGreen; //!< Green Gamma
+ U_LCS_GAMMA lcsGammaBlue; //!< Blue Gamma
+} U_LCS_GAMMARGB,
+ *PU_LCS_GAMMARGB; //!< WMF manual 2.2.2.11
+
+/** WMF manual 2.2.2.11
+ \brief For U_EMRCREATECOLORSPACE lcs field
+
+ Microsoft name: LOGCOLORSPACEA Object
+*/
+typedef struct {
+ uint32_t lcsSignature; //!< must be U_LCS_SIGNATURE
+ uint32_t lcsVersion; //!< must be U_LCS_VERSION
+ uint32_t lcsSize; //!< Size in bytes of this structure
+ int32_t lcsCSType; //!< LCS_CSType Enumeration
+ int32_t lcsIntent; //!< LCS_Intent Enumeration
+ U_CIEXYZTRIPLE lcsEndpoints; //!< CIE XYZ color space endpoints
+ U_LCS_GAMMARGB lcsGammaRGB; //!< Gamma For RGB
+ char lcsFilename[U_MAX_PATH]; //!< Names an external color profile file, otherwise empty string
+} U_LOGCOLORSPACEA,
+ *PU_LOGCOLORSPACEA; //!< WMF manual 2.2.2.11
+
+/** WMF manual 2.2.2.12
+ \brief For U_EMRCREATECOLORSPACEW lcs field
+
+ Microsoft name: LOGCOLORSPACEW Object
+*/
+typedef struct {
+ uint32_t lcsSignature; //!< must be U_LCS_SIGNATURE
+ uint32_t lcsVersion; //!< must be U_LCS_VERSION
+ uint32_t lcsSize; //!< Size in bytes of this structure
+ int32_t lcsCSType; //!< lcsCSType Enumeration
+ int32_t lcsIntent; //!< lcsIntent Enumeration
+ U_CIEXYZTRIPLE lcsEndpoints; //!< CIE XYZ color space endpoints
+ U_LCS_GAMMARGB lcsGammaRGB; //!< Gamma For RGB
+ uint16_t lcsFilename[U_MAX_PATH]; //!< Could name an external color profile file, otherwise empty string
+} U_LOGCOLORSPACEW,
+ *PU_LOGCOLORSPACEW; //!< WMF manual 2.2.2.12
+
+/** WMF manual 2.2.2.15
+ \brief Used for any generic pair of uint32_t
+
+ Microsoft name: POINTL Object
+*/
+typedef struct {
+ int32_t x; //!< X value
+ int32_t y; //!< Y value
+} U_PAIR,
+ U_POINT, //!< WMF manual 2.2.2.15
+ U_POINTL, //!< WMF manual 2.2.2.15
+ *PU_PAIR, //!< WMF manual 2.2.2.15
+ *PU_POINT, //!< WMF manual 2.2.2.15
+ *PU_POINTL; //!< WMF manual 2.2.2.15
+
+
+/** WMF manual 2.2.2.16
+ \brief Point type for 16 bit EMR drawing functions.
+
+ Microsoft name: POINTS Object.
+ Microsoft name: POINTS16 Object.
+*/
+typedef struct {
+ int16_t x; //!< X size (16 bit)
+ int16_t y; //!< Y size (16 bit)
+} U_POINT16,
+ *PU_POINT16; //!< WMF manual 2.2.2.16
+
+/** WMF manual 2.2.2.19
+ \brief Coordinates of the upper left, lower right corner.
+
+ Note that the coordinate system is 0,0 in the upper left corner
+ of the screen an N,M in the lower right corner.
+ Microsoft name: RECTL Object
+*/
+typedef struct {
+ int32_t left; //!< left coordinate
+ int32_t top; //!< top coordinate
+ int32_t right; //!< right coordinate
+ int32_t bottom; //!< bottom coordinate
+} U_RECT,
+ U_RECTL, //!< WMF manual 2.2.2.19
+ *PU_RECT, //!< WMF manual 2.2.2.19
+ *PU_RECTL; //!< WMF manual 2.2.2.19
+
+/** WMF manual 2.2.2.20
+ \brief For U_BITMAPINFO bmiColors field
+
+ NOTE that the color order is BGR, even though the name is RGB!
+ Microsoft name: RGBQUAD Object
+*/
+typedef struct {
+ uint8_t Blue; //!< Blue color (0-255)
+ uint8_t Green; //!< Green color (0-255)
+ uint8_t Red; //!< Red color (0-255)
+ uint8_t Reserved; //!< Not used
+} U_RGBQUAD,
+ *PU_RGBQUAD; //!< WMF manual 2.2.2.20
+
+#define U_RCL_DEF (U_RECTL){0,0,-1,-1} //!< Use this when no bounds are needed.
+
+/** WMF manual 2.2.2.22
+ \brief Pair of values indicating x and y sizes.
+
+ Microsoft name: SIZE Object
+ Microsoft name: SIZEL Object
+*/
+typedef struct {
+ int32_t cx; //!< X size
+ int32_t cy; //!< Y size
+} U_SIZE,
+ U_SIZEL, //!< WMF manual 2.2.2.22
+ *PU_SIZE, //!< WMF manual 2.2.2.22
+ *PU_SIZEL; //!< WMF manual 2.2.2.22
+
+
+
+/* ************************ EMF or common to EMF and EMF+ ****************************** */
+
+// ***********************************************************************************
+// Value enumerations and other predefined constants, alphabetical order by group
+
+
+/** \defgroup U_EMF_FONT_STRUCT_WIDTHS EMF Font name and style widths in characters
+ For U_LOGFONT and U_LOGFONT_PANOSE,
+ @{
+*/
+#define U_LF_FACESIZE 32 //!< U_LOGFONT lfFaceName and U_LOGFONT_PANOSE elfStyle fields maximum width
+#define U_LF_FULLFACESIZE 64 //!< U_LOGFONT_PANOSE elfFullName field maximum width
+/** @} */
+
+/** \defgroup U_EMF_EMR_Qualifiers EMF RecordType Enumeration
+ (RecordType Enumeration, EMF manual 2.1.1 )
+ For U_EMR iType field
+ EMF manual 2.1.1
+ @{
+*/
+#define U_EMR_HEADER 1 //!< U_EMRHEADER record
+#define U_EMR_POLYBEZIER 2 //!< U_EMRPOLYBEZIER record
+#define U_EMR_POLYGON 3 //!< U_EMRPOLYGON record
+#define U_EMR_POLYLINE 4 //!< U_EMRPOLYLINE record
+#define U_EMR_POLYBEZIERTO 5 //!< U_EMRPOLYBEZIERTO record
+#define U_EMR_POLYLINETO 6 //!< U_EMRPOLYLINETO record
+#define U_EMR_POLYPOLYLINE 7 //!< U_EMRPOLYPOLYLINE record
+#define U_EMR_POLYPOLYGON 8 //!< U_EMRPOLYPOLYGON record
+#define U_EMR_SETWINDOWEXTEX 9 //!< U_EMRSETWINDOWEXTEX record
+#define U_EMR_SETWINDOWORGEX 10 //!< U_EMRSETWINDOWORGEX record
+#define U_EMR_SETVIEWPORTEXTEX 11 //!< U_EMRSETVIEWPORTEXTEX record
+#define U_EMR_SETVIEWPORTORGEX 12 //!< U_EMRSETVIEWPORTORGEX record
+#define U_EMR_SETBRUSHORGEX 13 //!< U_EMRSETBRUSHORGEX record
+#define U_EMR_EOF 14 //!< U_EMREOF record
+#define U_EMR_SETPIXELV 15 //!< U_EMRSETPIXELV record
+#define U_EMR_SETMAPPERFLAGS 16 //!< U_EMRSETMAPPERFLAGS record
+#define U_EMR_SETMAPMODE 17 //!< U_EMRSETMAPMODE record
+#define U_EMR_SETBKMODE 18 //!< U_EMRSETBKMODE record
+#define U_EMR_SETPOLYFILLMODE 19 //!< U_EMRSETPOLYFILLMODE record
+#define U_EMR_SETROP2 20 //!< U_EMRSETROP2 record
+#define U_EMR_SETSTRETCHBLTMODE 21 //!< U_EMRSETSTRETCHBLTMODE record
+#define U_EMR_SETTEXTALIGN 22 //!< U_EMRSETTEXTALIGN record
+#define U_EMR_SETCOLORADJUSTMENT 23 //!< U_EMRSETCOLORADJUSTMENT record
+#define U_EMR_SETTEXTCOLOR 24 //!< U_EMRSETTEXTCOLOR record
+#define U_EMR_SETBKCOLOR 25 //!< U_EMRSETBKCOLOR record
+#define U_EMR_OFFSETCLIPRGN 26 //!< U_EMROFFSETCLIPRGN record
+#define U_EMR_MOVETOEX 27 //!< U_EMRMOVETOEX record
+#define U_EMR_SETMETARGN 28 //!< U_EMRSETMETARGN record
+#define U_EMR_EXCLUDECLIPRECT 29 //!< U_EMREXCLUDECLIPRECT record
+#define U_EMR_INTERSECTCLIPRECT 30 //!< U_EMRINTERSECTCLIPRECT record
+#define U_EMR_SCALEVIEWPORTEXTEX 31 //!< U_EMRSCALEVIEWPORTEXTEX record
+#define U_EMR_SCALEWINDOWEXTEX 32 //!< U_EMRSCALEWINDOWEXTEX record
+#define U_EMR_SAVEDC 33 //!< U_EMRSAVEDC record
+#define U_EMR_RESTOREDC 34 //!< U_EMRRESTOREDC record
+#define U_EMR_SETWORLDTRANSFORM 35 //!< U_EMRSETWORLDTRANSFORM record
+#define U_EMR_MODIFYWORLDTRANSFORM 36 //!< U_EMRMODIFYWORLDTRANSFORM record
+#define U_EMR_SELECTOBJECT 37 //!< U_EMRSELECTOBJECT record
+#define U_EMR_CREATEPEN 38 //!< U_EMRCREATEPEN record
+#define U_EMR_CREATEBRUSHINDIRECT 39 //!< U_EMRCREATEBRUSHINDIRECT record
+#define U_EMR_DELETEOBJECT 40 //!< U_EMRDELETEOBJECT record
+#define U_EMR_ANGLEARC 41 //!< U_EMRANGLEARC record
+#define U_EMR_ELLIPSE 42 //!< U_EMRELLIPSE record
+#define U_EMR_RECTANGLE 43 //!< U_EMRRECTANGLE record
+#define U_EMR_ROUNDRECT 44 //!< U_EMRROUNDRECT record
+#define U_EMR_ARC 45 //!< U_EMRARC record
+#define U_EMR_CHORD 46 //!< U_EMRCHORD record
+#define U_EMR_PIE 47 //!< U_EMRPIE record
+#define U_EMR_SELECTPALETTE 48 //!< U_EMRSELECTPALETTE record
+#define U_EMR_CREATEPALETTE 49 //!< U_EMRCREATEPALETTE record
+#define U_EMR_SETPALETTEENTRIES 50 //!< U_EMRSETPALETTEENTRIES record
+#define U_EMR_RESIZEPALETTE 51 //!< U_EMRRESIZEPALETTE record
+#define U_EMR_REALIZEPALETTE 52 //!< U_EMRREALIZEPALETTE record
+#define U_EMR_EXTFLOODFILL 53 //!< U_EMREXTFLOODFILL record
+#define U_EMR_LINETO 54 //!< U_EMRLINETO record
+#define U_EMR_ARCTO 55 //!< U_EMRARCTO record
+#define U_EMR_POLYDRAW 56 //!< U_EMRPOLYDRAW record
+#define U_EMR_SETARCDIRECTION 57 //!< U_EMRSETARCDIRECTION record
+#define U_EMR_SETMITERLIMIT 58 //!< U_EMRSETMITERLIMIT record
+#define U_EMR_BEGINPATH 59 //!< U_EMRBEGINPATH record
+#define U_EMR_ENDPATH 60 //!< U_EMRENDPATH record
+#define U_EMR_CLOSEFIGURE 61 //!< U_EMRCLOSEFIGURE record
+#define U_EMR_FILLPATH 62 //!< U_EMRFILLPATH record
+#define U_EMR_STROKEANDFILLPATH 63 //!< U_EMRSTROKEANDFILLPATH record
+#define U_EMR_STROKEPATH 64 //!< U_EMRSTROKEPATH record
+#define U_EMR_FLATTENPATH 65 //!< U_EMRFLATTENPATH record
+#define U_EMR_WIDENPATH 66 //!< U_EMRWIDENPATH record
+#define U_EMR_SELECTCLIPPATH 67 //!< U_EMRSELECTCLIPPATH record
+#define U_EMR_ABORTPATH 68 //!< U_EMRABORTPATH record
+#define U_EMR_UNDEF69 69 //!< U_EMRUNDEF69 record
+#define U_EMR_COMMENT 70 //!< U_EMRCOMMENT record
+#define U_EMR_FILLRGN 71 //!< U_EMRFILLRGN record
+#define U_EMR_FRAMERGN 72 //!< U_EMRFRAMERGN record
+#define U_EMR_INVERTRGN 73 //!< U_EMRINVERTRGN record
+#define U_EMR_PAINTRGN 74 //!< U_EMRPAINTRGN record
+#define U_EMR_EXTSELECTCLIPRGN 75 //!< U_EMREXTSELECTCLIPRGN record
+#define U_EMR_BITBLT 76 //!< U_EMRBITBLT record
+#define U_EMR_STRETCHBLT 77 //!< U_EMRSTRETCHBLT record
+#define U_EMR_MASKBLT 78 //!< U_EMRMASKBLT record
+#define U_EMR_PLGBLT 79 //!< U_EMRPLGBLT record
+#define U_EMR_SETDIBITSTODEVICE 80 //!< U_EMRSETDIBITSTODEVICE record
+#define U_EMR_STRETCHDIBITS 81 //!< U_EMRSTRETCHDIBITS record
+#define U_EMR_EXTCREATEFONTINDIRECTW 82 //!< U_EMREXTCREATEFONTINDIRECTW record
+#define U_EMR_EXTTEXTOUTA 83 //!< U_EMREXTTEXTOUTA record
+#define U_EMR_EXTTEXTOUTW 84 //!< U_EMREXTTEXTOUTW record
+#define U_EMR_POLYBEZIER16 85 //!< U_EMRPOLYBEZIER16 record
+#define U_EMR_POLYGON16 86 //!< U_EMRPOLYGON16 record
+#define U_EMR_POLYLINE16 87 //!< U_EMRPOLYLINE16 record
+#define U_EMR_POLYBEZIERTO16 88 //!< U_EMRPOLYBEZIERTO16 record
+#define U_EMR_POLYLINETO16 89 //!< U_EMRPOLYLINETO16 record
+#define U_EMR_POLYPOLYLINE16 90 //!< U_EMRPOLYPOLYLINE16 record
+#define U_EMR_POLYPOLYGON16 91 //!< U_EMRPOLYPOLYGON16 record
+#define U_EMR_POLYDRAW16 92 //!< U_EMRPOLYDRAW16 record
+#define U_EMR_CREATEMONOBRUSH 93 //!< U_EMRCREATEMONOBRUSH record
+#define U_EMR_CREATEDIBPATTERNBRUSHPT 94 //!< U_EMRCREATEDIBPATTERNBRUSHPT record
+#define U_EMR_EXTCREATEPEN 95 //!< U_EMREXTCREATEPEN record
+#define U_EMR_POLYTEXTOUTA 96 //!< U_EMRPOLYTEXTOUTA record
+#define U_EMR_POLYTEXTOUTW 97 //!< U_EMRPOLYTEXTOUTW record
+#define U_EMR_SETICMMODE 98 //!< U_EMRSETICMMODE record
+#define U_EMR_CREATECOLORSPACE 99 //!< U_EMRCREATECOLORSPACE record
+#define U_EMR_SETCOLORSPACE 100 //!< U_EMRSETCOLORSPACE record
+#define U_EMR_DELETECOLORSPACE 101 //!< U_EMRDELETECOLORSPACE record
+#define U_EMR_GLSRECORD 102 //!< U_EMRGLSRECORD record
+#define U_EMR_GLSBOUNDEDRECORD 103 //!< U_EMRGLSBOUNDEDRECORD record
+#define U_EMR_PIXELFORMAT 104 //!< U_EMRPIXELFORMAT record
+#define U_EMR_DRAWESCAPE 105 //!< U_EMRDRAWESCAPE record
+#define U_EMR_EXTESCAPE 106 //!< U_EMREXTESCAPE record
+#define U_EMR_UNDEF107 107 //!< U_EMRUNDEF107 record
+#define U_EMR_SMALLTEXTOUT 108 //!< U_EMRSMALLTEXTOUT record
+#define U_EMR_FORCEUFIMAPPING 109 //!< U_EMRFORCEUFIMAPPING record
+#define U_EMR_NAMEDESCAPE 110 //!< U_EMRNAMEDESCAPE record
+#define U_EMR_COLORCORRECTPALETTE 111 //!< U_EMRCOLORCORRECTPALETTE record
+#define U_EMR_SETICMPROFILEA 112 //!< U_EMRSETICMPROFILEA record
+#define U_EMR_SETICMPROFILEW 113 //!< U_EMRSETICMPROFILEW record
+#define U_EMR_ALPHABLEND 114 //!< U_EMRALPHABLEND record
+#define U_EMR_SETLAYOUT 115 //!< U_EMRSETLAYOUT record
+#define U_EMR_TRANSPARENTBLT 116 //!< U_EMRTRANSPARENTBLT record
+#define U_EMR_UNDEF117 117 //!< U_EMRUNDEF117 record
+#define U_EMR_GRADIENTFILL 118 //!< U_EMRGRADIENTFILL record
+#define U_EMR_SETLINKEDUFIS 119 //!< U_EMRSETLINKEDUFIS record
+#define U_EMR_SETTEXTJUSTIFICATION 120 //!< U_EMRSETTEXTJUSTIFICATION record
+#define U_EMR_COLORMATCHTOTARGETW 121 //!< U_EMRCOLORMATCHTOTARGETW record
+#define U_EMR_CREATECOLORSPACEW 122 //!< U_EMRCREATECOLORSPACEW record
+
+#define U_EMR_MIN 1 //!< Minimum U_EMR_ value.
+#define U_EMR_MAX 122 //!< Maximum U_EMR_ value. Not much beyond 104 is implemented
+
+#define U_EMR_INVALID 0xFFFFFFFF //!< Not any valid U_EMF_ value
+/** @} */
+
+
+/** \defgroup U_EMF_DRAW_PROPERTIES EMF draw properties
+ Used in emr_properties() and wmr_properties. These are the bit definitions.
+ @{
+*/
+#define U_DRAW_NOTEMPTY 0x001 //!< Path has at least a MOVETO in it
+#define U_DRAW_VISIBLE 0x002 //!< Path has at least a LINE in it
+#define U_DRAW_CLOSED 0x004 //!< Path has been closed
+#define U_DRAW_ONLYTO 0x008 //!< Path so far contains only *TO operations
+#define U_DRAW_FORCE 0x010 //!< Path MUST be drawn
+#define U_DRAW_ALTERS 0x020 //!< Alters draw parameters (pen, brush, coordinates...)
+#define U_DRAW_PATH 0x040 //!< An explicit path is being used (with a BEGIN and END)
+#define U_DRAW_TEXT 0x080 //!< Current record forces all pending text to be drawn first.
+#define U_DRAW_OBJECT 0x100 //!< Creates an Object (only used in WMF)
+#define U_DRAW_NOFILL 0x200 //!< Object is not fillable (lines and arc, only used in WMF)
+
+/** @} */
+/** \defgroup U_EMF_EMRSETARCDIRECTION_Qualifiers EMF ArcDirection Enumeration
+ For U_EMRSETARCDIRECTION iArcDirection field
+ Microsoft name: ArcDirection Enumeration
+ EMF manual 2.1.2
+ @{
+*/
+#define U_AD_COUNTERCLOCKWISE 1 //!< Draw arc counterclockwise.
+#define U_AD_CLOCKWISE 2 //!< Draw arc clockwise.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bArmStyle_Qualifiers EMF ArmStyle Enumeration
+ For U_PANOSE bArmStyle field
+ Microsoft name: ArmStyle Enumeration
+ EMF manual 2.1.3
+ @{
+*/
+#define U_PAN_STRAIGHT_ARMS_HORZ 2 //!< straight arms horizontal
+#define U_PAN_STRAIGHT_ARMS_WEDGE 3 //!< straight arms wedge
+#define U_PAN_STRAIGHT_ARMS_VERT 4 //!< straight arms vertical
+#define U_PAN_STRAIGHT_ARMS_SINGLE_SERIF 5 //!< straight arms singleserif
+#define U_PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6 //!< straight arms doubleserif
+#define U_PAN_BENT_ARMS_HORZ 7 //!< bent arms horizontal
+#define U_PAN_BENT_ARMS_WEDGE 8 //!< bent arms wedge
+#define U_PAN_BENT_ARMS_VERT 9 //!< bent arms vertical
+#define U_PAN_BENT_ARMS_SINGLE_SERIF 10 //!< bent arms singleserif
+#define U_PAN_BENT_ARMS_DOUBLE_SERIF 11 //!< bent arms doubleserif
+/** @} */
+
+/** \defgroup U_EMF_EMRSETBKMODE_iMode_Qualifiers EMF BackgroundMode enumeration
+ For U_EMRSETBKMODE iMode field
+ Microsoft name: BackgroundMode enumeration
+ EMF manual 2.1.4
+ @{
+*/
+#define U_TRANSPARENT 1 //!< Transparent background mode
+#define U_OPAQUE 2 //!< Opaque background mode
+/** @} */
+
+/** \defgroup U_EMF_COLORADJUSTMENT_caFlags_Qualifiers EMF ColorAdjustment Enumeration
+ For U_COLORADJUSTMENT caFlags field
+ Microsoft name: ColorAdjustment Enumeration
+ EMF manual 2.1.5
+ @{
+*/
+#define U_CA_NEGATIVE 0x0001 //!< display Negative of image
+#define U_CA_LOG_FILTER 0x0002 //!< display Logarithmi filter of image
+/** @} */
+
+/** \defgroup U_EMF_EMRCOLORMATCHTOTARGETW_dwFlags_Qualifiers EMF ColorMatchToTarget Enumeration
+ For U_EMRCOLORMATCHTOTARGETW dwFlags field
+ Microsoft name: ColorMatchToTarget Enumeration
+ EMF manual 2.1.6
+ @{
+*/
+#define U_COLORMATCHTOTARGET_NOTEMBEDDED 0 //!< Color match profile is not embedded in metafile
+#define U_COLORMATCHTOTARGET_EMBEDDED 1 //!< Color match profile is embedded in metafile
+/** @} */
+
+/** \defgroup U_EMF_EMRCOLORMATCHTOTARGETW_dwAction_Qualifiers EMF ColorSpace Enumeration
+ For U_EMRCOLORMATCHTOTARGETW dwAction field
+ Microsoft name: ColorSpace Enumeration
+ EMF manual 2.1.7
+ @{
+*/
+#define U_CS_ENABLE 1 //!< Enable color proofing.
+#define U_CS_DISABLE 2 //!< Disable color proofing.
+#define U_CS_DELETE_TRANSFORM 3 //!< Disable proofing and delete color transform.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_common_Qualifiers EMF PanoseCommon Enumeration
+ Used by all PAN_* enumerations, but only defined once here.
+ See also U_PAN_ALL1 after the U_PANOSE structure
+ @{
+*/
+#define U_PAN_ANY 0 //!< Any (for any type of Panose enumeration)
+#define U_PAN_NO_FIT 1 //!< No fit (for any type of Panose enumeration)
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bContrast_Qualifiers EMF Contrast Enumeration
+ For U_PANOSE bContrast field
+ Microsoft name: Contrast Enumeration
+ EMF manual 2.1.8
+ @{
+*/
+#define U_PAN_CONTRAST_NONE 2 //!< None
+#define U_PAN_CONTRAST_VERY_LOW 3 //!< Very low
+#define U_PAN_CONTRAST_LOW 4 //!< Low
+#define U_PAN_CONTRAST_MEDIUM_LOW 5 //!< Medium low
+#define U_PAN_CONTRAST_MEDIUM 6 //!< Medium
+#define U_PAN_CONTRAST_MEDIUM_HIGH 7 //!< Medium high
+#define U_PAN_CONTRAST_HIGH 8 //!< High
+#define U_PAN_CONTRAST_VERY_HIGH 9 //!< Very high
+/** @} */
+
+/** \defgroup U_EMF_DIBITS_iUsageSrc_Qualifiers EMF DIBColors Enumeration
+ For U_EMRSETDIBITSTODEIVCE and U_EMRSTRETCHDIBITS iUsageSrc fields.
+ Microsoft name: DIBColors Enumeration
+ EMF manual 2.1.9
+ @{
+*/
+#define U_DIB_RGB_COLORS 0 //!< color table contains colors
+#define U_DIB_PAL_COLORS 1 //!< color table contains 16 bit indices into logical palette
+#define U_DIB_PAL_INDICES 2 //!< no color table, pixel values are indices into logical palette
+/** @} */
+
+/** \defgroup U_EMF_EMR_COMMENT_PUBLIC EMF EMRComment Enumeration
+ For U_EMRCOMMENT_PUBLIC pcIdent fields
+ Microsoft name: EMRComment Enumeration
+ EMF manual 2.1.10
+ @{
+*/
+#define U_EMR_COMMENT_WINDOWS_METAFILE 0x80000001 //!< Comment contains WMF
+#define U_EMR_COMMENT_BEGINGROUP 0x00000002 //!< Comment begins group of EMF records
+#define U_EMR_COMMENT_ENDGROUP 0x00000003 //!< Comment ends group of EMF records
+#define U_EMR_COMMENT_MULTIFORMATS 0x40000004 //!< Comment contains some other representation of drawing
+#define U_EMR_COMMENT_UNICODE_STRING 0x00000040 //!< Reserved
+#define U_EMR_COMMENT_UNICODE_END 0x00000080 //!< Reserved
+/** @} */
+
+/** \defgroup U_EMF_EMRTEXT_foptions_Qualifiers EMF ExtTextOutOptions Enumeration
+ For U_EMRTEXT foptions field
+ Microsoft name: ExtTextOutOptions Enumeration
+ EMF manual 2.1.11
+ @{
+*/
+#define U_ETO_NONE 0x00000000 //!< None
+#define U_ETO_GRAYED 0x00000001 //!< Grayed
+#define U_ETO_OPAQUE 0x00000002 //!< Fill rectangle with background color.
+#define U_ETO_CLIPPED 0x00000004 //!< Clip text to rectangle.
+#define U_ETO_GLYPH_INDEX 0x00000010 //!< Characters are glyph indices for the font.
+#define U_ETO_RTLREADING 0x00000080 //!< Right to left text.
+#define U_ETO_NO_RECT 0x00000100 //!< No bounding rectangle is specified.
+#define U_ETO_SMALL_CHARS 0x00000200 //!< 8 bit characters instead of 16 bit. For EMRSMALLTEXTOUT ONLY, does not affect EMRTEXTOUTA or EMRTEXTOUTW
+#define U_ETO_NUMERICSLOCAL 0x00000400 //!< Show numbers for the current locale.
+#define U_ETO_NUMERICSLATIN 0x00000800 //!< Show numbers using European digits.
+#define U_ETO_IGNORELANGUAGE 0x00001000 //!< Process Right to Left languages exactly as specified in the metafile.
+#define U_ETO_PDY 0x00002000 //!< Both horizontal and vertical displacements are provided.
+#define U_ETO_REVERSE_INDEX_MAP 0x00010000 //!< Reverse_index_map
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bFamilyType_Qualifiers EMF FamilyType Enumeration
+ For U_PANOSE bFamilyType field
+ Microsoft name: FamilyType Enumeration
+ EMF manual 2.1.12
+ @{
+*/
+#define U_PAN_FAMILY_TEXT_DISPLAY 2 //!< Text display
+#define U_PAN_FAMILY_SCRIPT 3 //!< Script
+#define U_PAN_FAMILY_DECORATIVE 4 //!< Decorative
+#define U_PAN_FAMILY_PICTORIAL 5 //!< Pictorial
+/** @} */
+
+/** \defgroup U_EMF_EMREXTFLOODFILL_iMode_Qualifiers EMF FloodFill Enumeration
+ For U_EMREXTFLOODFILL iMode field
+ Microsoft name: FloodFill Enumeration
+ EMF manual 2.1.13
+ @{
+*/
+#define U_FLOODFILLBORDER 0x00000000 //!< Color specified must be the same as the border - brush fill stops at this color
+#define U_FLOODFILLSURFACE 0x00000001 //!< Color specified must be different from the border - brush fills only this color
+/** @} */
+
+/** \defgroup U_EMF_DESIGNVECTOR_Signature_Qualifiers EMF Signature Enumeration
+ For U_DESIGNVECTOR Signature field
+ Microsoft name: Signature Enumeration
+ EMF manual 2.1.14
+ @{
+*/
+#define U_ENHMETA_SIGNATURE 0x464D4520 //!< "EMF" signature also for U_EMRHEADER dSignature field.
+#define U_EPS_SIGNATURE 0x46535045 //!< "FSPE" signature, indicates encapsulated postscript.
+/** @} */
+
+/** \defgroup U_EMF_EMRGRADIENTFILL_ulMode_Qualifiers EMF GradientFill Enumeration
+ For U_EMRGRADIENTFILL ulMode field
+ Microsoft name: GradientFill Enumeration
+ EMF manual 2.1.15
+ @{
+*/
+#define U_GRADIENT_FILL_RECT_H 0x00000000 //!< Gradient is left to right.
+#define U_GRADIENT_FILL_RECT_V 0x00000001 //!< Grident is top to bottom.
+#define U_GRADIENT_FILL_TRIANGLE 0x00000002 //!< Gradient is between 3 vertices of a triangle.
+/** @} */
+
+/** \defgroup U_EMF_EMREXTTEXTOUT_iGraphicsMode_Qualifiers EMF GraphicsMode Enumeration
+ For U_EMREXTTEXTOUTA/U_EMREXTTEXTOUTW and all other iGraphicsMode fields
+ Microsoft name: GraphicsMode Enumeration
+ EMF manual 2.1.16
+ @{
+*/
+#define U_GM_COMPATIBLE 1 //!< TrueType text ignores world to device transform except for Scale. Arcs ignore transform
+#define U_GM_ADVANCED 2 //!< TrueType text and Arcs must conform to all of world to device transform.
+#define U_GM_LAST 2 //!< Number of GraphicsMode Enumeration entries.
+/** @} */
+
+/** \defgroup U_EMF_LOGBRUSH_lbHatch_Qualifiers EMF HatchStyle Enumeration
+ For U_LOGBRUSH lbHatch field
+ Microsoft name: HatchStyle Enumeration
+ EMF manual 2.1.17
+ @{
+*/
+#define U_HS_HORIZONTAL 0 //!< Horizontal.
+#define U_HS_VERTICAL 1 //!< Vertical.
+#define U_HS_FDIAGONAL 2 //!< Forward diagonal.
+#define U_HS_BDIAGONAL 3 //!< Back diagonal.
+#define U_HS_CROSS 4 //!< Cross.
+#define U_HS_DIAGCROSS 5 //!< Diagonal cross.
+#define U_HS_SOLIDCLR 6 //!< Solid color.
+#define U_HS_DITHEREDCLR 7 //!< Dithered color.
+#define U_HS_SOLIDTEXTCLR 8 //!< Solid text color.
+#define U_HS_DITHEREDTEXTCLR 9 //!< Dithered text color.
+#define U_HS_SOLIDBKCLR 10 //!< Solid background color.
+#define U_HS_DITHEREDBKCLR 11 //!< Dithered background color.
+/** @} */
+
+/** \defgroup U_EMF_EMRSETICMMODE_iMode_Qualifiers EMF ICMMode Enumeration
+ For EMF U_EMR_SETICMMODE iMode field
+ Microsoft name: ICMMode Enumeration
+ EMF manual 2.1.18
+ @{
+*/
+#define U_ICM_OFF 1 //!< Off
+#define U_ICM_ON 2 //!< On
+#define U_ICM_QUERY 3 //!< Query
+/** @} */
+
+/** \defgroup U_EMF_COLORADJUSTMENT_caIlluminantIndex_Qualifiers EMF Illuminant Enumeration
+ For U_COLORADJUSTMENT caIlluminantIndex field
+ Microsoft name: Illuminant Enumeration
+ EMF manual 2.1.19
+ @{
+*/
+#define U_ILLUMINANT_DEVICE_DEFAULT 0 //!< Device default
+#define U_ILLUMINANT_A 1 //!< A
+#define U_ILLUMINANT_B 2 //!< B
+#define U_ILLUMINANT_C 3 //!< C
+#define U_ILLUMINANT_D50 4 //!< D50
+#define U_ILLUMINANT_D55 5 //!< D55
+#define U_ILLUMINANT_D65 6 //!< D65
+#define U_ILLUMINANT_D75 7 //!< D75
+#define U_ILLUMINANT_F2 8 //!< F2
+#define U_ILLUMINANT_MAX_INDEX ILLUMINANT_F2 //!< Max index
+#define U_ILLUMINANT_TUNGSTEN ILLUMINANT_A //!< Tungsten
+#define U_ILLUMINANT_DAYLIGHT ILLUMINANT_C //!< Daylight
+#define U_ILLUMINANT_FLUORESCENT ILLUMINANT_F2 //!< Fluorescent
+#define U_ILLUMINANT_NTSC ILLUMINANT_C //!< NTSC
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bLetterForm_Qualifiers EMF Letterform Enumeration
+ For U_PANOSE bLetterForm field
+ Microsoft name: Letterform Enumeration
+ EMF manual 2.1.20
+ @{
+*/
+#define U_PAN_LETT_NORMAL_COMPACT 2 //!< Normal compact
+#define U_PAN_LETT_NORMAL_WEIGHTED 3 //!< Normal weighted
+#define U_PAN_LETT_NORMAL_BOXED 4 //!< Normal boxed
+#define U_PAN_LETT_NORMAL_FLATTENED 5 //!< Normal flattened
+#define U_PAN_LETT_NORMAL_ROUNDED 6 //!< Normal rounded
+#define U_PAN_LETT_NORMAL_OFF_CENTER 7 //!< Normal off center
+#define U_PAN_LETT_NORMAL_SQUARE 8 //!< Normal square
+#define U_PAN_LETT_OBLIQUE_COMPACT 9 //!< Oblique compact
+#define U_PAN_LETT_OBLIQUE_WEIGHTED 10 //!< Oblique weighted
+#define U_PAN_LETT_OBLIQUE_BOXED 11 //!< Oblique boxed
+#define U_PAN_LETT_OBLIQUE_FLATTENED 12 //!< Oblique flattened
+#define U_PAN_LETT_OBLIQUE_ROUNDED 13 //!< Oblique rounded
+#define U_PAN_LETT_OBLIQUE_OFF_CENTER 14 //!< Oblique off center
+#define U_PAN_LETT_OBLIQUE_SQUARE 15 //!< Oblique square
+/** @} */
+
+/** \defgroup U_EMF_EMRSETMAPMODE_iMode_Qualifiers EMF MapMode Enumeration
+ For U_EMRSETMAPMODE iMode field
+ Microsoft name: MapMode Enumeration
+ EMF manual 2.1.21
+ @{
+*/
+#define U_MM_TEXT 1 //!< Text
+#define U_MM_LOMETRIC 2 //!< Low metric
+#define U_MM_HIMETRIC 3 //!< Hig hmetric
+#define U_MM_LOENGLISH 4 //!< Low English
+#define U_MM_HIENGLISH 5 //!< High English
+#define U_MM_TWIPS 6 //!< Twips
+#define U_MM_ISOTROPIC 7 //!< Isotropic
+#define U_MM_ANISOTROPIC 8 //!< Anisotropic
+#define U_MM_MIN U_MM_TEXT //!< smallest enumeration
+#define U_MM_MAX U_MM_ANISOTROPIC //!< largest enumeration
+#define U_MM_MAX_FIXEDSCALE U_MM_TWIPS //!< alternate definition
+/** @} */
+
+/** \defgroup U_EMF_MF_version EMF MetafileVersion Enumeration
+ For U_EMR_COMMENTS_METAFILE version field
+ Microsoft name: MetafileVersion Enumeration
+ EMF manual 2.1.22
+ @{
+*/
+#define U_ENHMETA_VERSION 0x00010000 //!< U_EMRHEADER nVersion field
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bMidline_Qualifiers EMF MidLine Enumeration
+ For U_PANOSE bMidline field
+ Microsoft name: MidLine Enumeration
+ EMF manual 2.1.23
+ @{
+*/
+#define U_PAN_MIDLINE_STANDARD_TRIMMED 2 //!< Midline standard trimmed
+#define U_PAN_MIDLINE_STANDARD_POINTED 3 //!< Midline standard pointed
+#define U_PAN_MIDLINE_STANDARD_SERIFED 4 //!< Midline standard serifed
+#define U_PAN_MIDLINE_HIGH_TRIMMED 5 //!< Midline high trimmed
+#define U_PAN_MIDLINE_HIGH_POINTED 6 //!< Midline high pointed
+#define U_PAN_MIDLINE_HIGH_SERIFED 7 //!< Midline high serifed
+#define U_PAN_MIDLINE_CONSTANT_TRIMMED 8 //!< Midline constant trimmed
+#define U_PAN_MIDLINE_CONSTANT_POINTED 9 //!< Midline constant pointed
+#define U_PAN_MIDLINE_CONSTANT_SERIFED 10 //!< Midline constant serifed
+#define U_PAN_MIDLINE_LOW_TRIMMED 11 //!< Midline low trimmed
+#define U_PAN_MIDLINE_LOW_POINTED 12 //!< Midline low pointed
+#define U_PAN_MIDLINE_LOW_SERIFED 13 //!< Midline low serifed
+/** @} */
+
+/** \defgroup U_EMF_EMRMODIFYWORLDTRANSFORM_iMode_Qualifiers EMF ModifyWorldTransformMode Enumeration
+ For U_EMRMODIFYWORLDTRANSFORM iMode
+ Microsoft name: ModifyWorldTransformMode Enumeration
+ EMF manual 2.1.24
+ @{
+*/
+#define U_MWT_IDENTITY 1 //!< Transform is identity.
+#define U_MWT_LEFTMULTIPLY 2 //!< Left multiply transform.
+#define U_MWT_RIGHTMULTIPLY 3 //!< Right multiply transform.
+#define U_MWT_MIN U_MWT_IDENTITY //!< smallest enumeration.
+#define U_MWT_MAX U_MWT_RIGHTMULTIPLY //!< largest enumeration.
+/** @} */
+
+/** \defgroup U_EMF_LOGPEN_elpPenStyle_Qualifiers EMF PenStyle Enumeration
+ For U_LOGPEN lopnStyle and U_EXTLOGPEN elpPenStyle fields
+ Microsoft name: PenStyle Enumeration
+ EMF manual 2.1.25
+ @{
+*/
+#define U_PS_SOLID 0x00000000 //!< Solid line.
+#define U_PS_DASH 0x00000001 //!< Dashed line. This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to.
+#define U_PS_DOT 0x00000002 //!< Dotted line. This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to.
+#define U_PS_DASHDOT 0x00000003 //!< Dash-Dot line. This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to.
+#define U_PS_DASHDOTDOT 0x00000004 //!< Dash-Dot-Dot line. This only works when NO other U_PS is set. Line width is minimum no matter what pen is set to.
+#define U_PS_NULL 0x00000005 //!< Invisible line.
+#define U_PS_INSIDEFRAME 0x00000006 //!< Draw line around drawing, then shrink drawing to fit within line taking its width into account.
+#define U_PS_USERSTYLE 0x00000007 //!< User defined.
+#define U_PS_ALTERNATE 0x00000008 //!< Every other pixel is drawn.
+#define U_PS_STYLE_MASK 0x0000000f //!< Mask to select just the preceding line type fields.
+
+#define U_PS_ENDCAP_ROUND 0x00000000 //!< Round end cap. Only with U_PS_GEOMETRIC
+#define U_PS_ENDCAP_SQUARE 0x00000100 //!< Square end cap. Only with U_PS_GEOMETRIC
+#define U_PS_ENDCAP_FLAT 0x00000200 //!< Flat end cap. Only with U_PS_GEOMETRIC
+#define U_PS_ENDCAP_MASK 0x00000f00 //!< Mask to select just the preceding ENDCAP fields.
+
+#define U_PS_JOIN_ROUND 0x00000000 //!< Rounded join. Only with U_PS_GEOMETRIC
+#define U_PS_JOIN_BEVEL 0x00001000 //!< Beveled join. Only with U_PS_GEOMETRIC
+#define U_PS_JOIN_MITER 0x00002000 //!< Mitered join. Only with U_PS_GEOMETRIC
+#define U_PS_JOIN_MASK 0x0000f000 //!< Mask to select just the preceding JOIN fields.
+
+#define U_PS_COSMETIC 0x00000000 //!< width may only be 1 pixel. (If set higher it is still drawn as 1).
+#define U_PS_GEOMETRIC 0x00010000 //!< width may be >1 pixel, but style may only be U_PS_SOLID or U_PS_NULL.
+#define U_PS_TYPE_MASK 0x000f0000 //!< Mask to select just the preceding TYPE fields.
+/** @} */
+/** \defgroup U_EMF_EMRPOLY_iMode_Qualifiers EMF Point Enumeration
+ For U_EMRPOLYDRAW and U_EMRPOLAYDRAW16 abTypes fields.
+ Microsoft name: Point Enumeration
+ EMF manual 2.1.26
+ @{
+*/
+#define U_PT_CLOSEFIGURE 0x0001 //!< Close figure
+#define U_PT_LINETO 0x0002 //!< Line to
+#define U_PT_BEZIERTO 0x0004 //!< Bezier to
+#define U_PT_MOVETO 0x0006 //!< Move to
+/** @} */
+
+/** \defgroup U_EMF_EMRSETPOLYFILLMODE_iMode_Qualifiers EMF PolygonFillMode Enumeration
+ For U_EMRSETPOLYFILLMODE iMode field
+ Microsoft name: PolygonFillMode Enumeration
+ EMF manual 2.1.27
+ @{
+*/
+#define U_ALTERNATE 1 //!< Alternate
+#define U_WINDING 2 //!< Winding
+#define U_POLYFILL_LAST 2 //!< Polyfill last
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bProportion_Qualifiers EMF Proportion Enumeration
+ For U_PANOSE bProportion field
+ Microsoft name: Proportion Enumeration
+ EMF manual 2.1.28
+ @{
+*/
+#define U_PAN_PROP_OLD_STYLE 2 //!< Old style
+#define U_PAN_PROP_MODERN 3 //!< Modern
+#define U_PAN_PROP_EVEN_WIDTH 4 //!< Even width
+#define U_PAN_PROP_EXPANDED 5 //!< Expanded
+#define U_PAN_PROP_CONDENSED 6 //!< Condensed
+#define U_PAN_PROP_VERY_EXPANDED 7 //!< Very expanded
+#define U_PAN_PROP_VERY_CONDENSED 8 //!< Very condensed
+#define U_PAN_PROP_MONOSPACED 9 //!< Monospaced
+/** @} */
+
+/** \defgroup U_EMF_EMRSELECTCLIP_iMode_Qualifiers EMF RegionMode Enumeration
+ For U_EMRSELECTCLIPPATH and U_EMREXTSELECTCLIPRGN iMode field
+ Microsoft name: RegionMode Enumeration
+ EMF manual 2.1.29
+ @{
+*/
+#define U_RGN_NONE 0 //!< not part of EMF standard, may be used by others
+#define U_RGN_AND 1 //!< Region becomes intersection of existing region and new region.
+#define U_RGN_OR 2 //!< Region becomes union of existing region and new region.
+#define U_RGN_XOR 3 //!< Region becomes XOR of existing and new regions.
+#define U_RGN_DIFF 4 //!< Region becomes part of existing region not in new region.
+#define U_RGN_COPY 5 //!< Region becomes new region.
+#define U_RGN_MIN U_RGN_AND //!< smallest enumeration.
+#define U_RGN_MAX U_RGN_COPY //!< largest enumeration.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bSerifStyle_Qualifiers EMF SerifType Enumeration
+ For U_PANOSE bSerifStyle field
+ Microsoft name: SerifType Enumeration
+ EMF manual 2.1.30
+ @{
+*/
+#define U_PAN_SERIF_COVE 2 //!< Serif cove
+#define U_PAN_SERIF_OBTUSE_COVE 3 //!< Serif obtuse cove
+#define U_PAN_SERIF_SQUARE_COVE 4 //!< Serif square cove
+#define U_PAN_SERIF_OBTUSE_SQUARE_COVE 5 //!< Serif obtuse square cove
+#define U_PAN_SERIF_SQUARE 6 //!< Serif square
+#define U_PAN_SERIF_THIN 7 //!< Serif thin
+#define U_PAN_SERIF_BONE 8 //!< Serif bone
+#define U_PAN_SERIF_EXAGGERATED 9 //!< Serif exaggerated
+#define U_PAN_SERIF_TRIANGLE 10 //!< Serif triangle
+#define U_PAN_SERIF_NORMAL_SANS 11 //!< Serif normal sans
+#define U_PAN_SERIF_OBTUSE_SANS 12 //!< Serif obtuse sans
+#define U_PAN_SERIF_PERP_SANS 13 //!< Serif perp sans
+#define U_PAN_SERIF_FLARED 14 //!< Serif flared
+#define U_PAN_SERIF_ROUNDED 15 //!< Serif rounded
+/** @} */
+
+/** \defgroup U_EMF_EMRSELECTOBJECT_ihObject_Qualifiers EMF StockObject Enumeration
+ For U_EMRSELECTOBJECT ihObject field.
+ Microsoft name: StockObject Enumeration
+ EMF manual 2.1.31
+ @{
+*/
+#define U_STOCK_OBJECT 0x80000000 //!< Stock object
+#define U_WHITE_BRUSH 0x80000000 //!< White brush
+#define U_LTGRAY_BRUSH 0x80000001 //!< Ltgray brush
+#define U_GRAY_BRUSH 0x80000002 //!< Gray brush
+#define U_DKGRAY_BRUSH 0x80000003 //!< Dkgray brush
+#define U_BLACK_BRUSH 0x80000004 //!< Black brush
+#define U_NULL_BRUSH 0x80000005 //!< Null brush
+#define U_HOLLOW_BRUSH 0x80000005 //!< Hollow brush
+#define U_WHITE_PEN 0x80000006 //!< White pen
+#define U_BLACK_PEN 0x80000007 //!< Black pen
+#define U_NULL_PEN 0x80000008 //!< Null pen
+#define U_OEM_FIXED_FONT 0x8000000A //!< Oem fixed font
+#define U_ANSI_FIXED_FONT 0x8000000B //!< Ansi fixed font
+#define U_ANSI_VAR_FONT 0x8000000C //!< Ansi var font
+#define U_SYSTEM_FONT 0x8000000D //!< System font
+#define U_DEVICE_DEFAULT_FONT 0x8000000E //!< Device default font
+#define U_DEFAULT_PALETTE 0x8000000F //!< Default palette
+#define U_SYSTEM_FIXED_FONT 0x80000010 //!< System fixed font
+#define U_DEFAULT_GUI_FONT 0x80000011 //!< Default GUI font
+#define U_STOCK_LAST 0x80000011 //!< Stock last
+/** @} */
+
+/** \defgroup U_EMF_EMRSETSTRETCHBLTMODE_iMode_Qualifiers EMF StretchMode Enumeration
+ For EMF U_EMRSETSTRETCHBLTMODE iMode field
+ Microsoft name: StretchMode Enumeration
+ EMF manual 2.1.32 and footnote 52 on page 297
+ @{
+*/
+#define U_BLACKONWHITE 1 //!< AND the destination and source pixels.
+#define U_WHITEONBLACK 2 //!< OR the destination and source pixels.
+#define U_COLORONCOLOR 3 //!< Replace the destination pixels with the source pixels.
+#define U_HALFTONE 4 //!< Replace a block of destination pixels with a half-tone representation of the source pixel.
+#define U_MAXSTRETCHBLTMODE 4 //!< largest enumeration.
+#define U_STRETCH_ANDSCANS 1 //!< AND the destination and source pixels.
+#define U_STRETCH_ORSCANS 2 //!< OR the destination and source pixels.
+#define U_STRETCH_DELETESCANS 3 //!< Replace the destination pixels with the source pixels.
+#define U_STRETCH_HALFTONE 4 //!< Replace a block of destination pixels with a half-tone representation of the source pixel.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bStrokeVariation_Qualifiers EMF StrokeVariation Enumeration
+ For U_PANOSE bStrokeVariation field
+ Microsoft name: StrokeVariation Enumeration
+ EMF manual 2.1.33
+ @{
+*/
+#define U_PAN_STROKE_GRADUAL_DIAG 2 //!< Gradual diagonal.
+#define U_PAN_STROKE_GRADUAL_TRAN 3 //!< Gradual transitional.
+#define U_PAN_STROKE_GRADUAL_VERT 4 //!< Gradual vertical.
+#define U_PAN_STROKE_GRADUAL_HORZ 5 //!< Gradual horizontal.
+#define U_PAN_STROKE_RAPID_VERT 6 //!< Rapid vertical.
+#define U_PAN_STROKE_RAPID_HORZ 7 //!< Rapid horizontal.
+#define U_PAN_STROKE_INSTANT_VERT 8 //!< Instant vertical.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bWeight_Qualifiers EMF Weight Enumeration
+ For U_PANOSE bWeight field
+ EMF manual 2.1.34
+ @{
+*/
+#define U_PAN_WEIGHT_VERY_LIGHT 2 //!< Very light
+#define U_PAN_WEIGHT_LIGHT 3 //!< Light
+#define U_PAN_WEIGHT_THIN 4 //!< Thin
+#define U_PAN_WEIGHT_BOOK 5 //!< Book
+#define U_PAN_WEIGHT_MEDIUM 6 //!< Medium
+#define U_PAN_WEIGHT_DEMI 7 //!< Demi
+#define U_PAN_WEIGHT_BOLD 8 //!< Bold
+#define U_PAN_WEIGHT_HEAVY 9 //!< Heavy
+#define U_PAN_WEIGHT_BLACK 10 //!< Black
+#define U_PAN_WEIGHT_NORD 11 //!< Nord
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_bXHeight_Qualifiers EMF XHeight Enumeration
+ For U_PANOSE bXHeight field
+ EMF manual 2.1.35
+ @{
+*/
+#define U_PAN_XHEIGHT_CONSTANT_SMALL 2 //!< Constant small
+#define U_PAN_XHEIGHT_CONSTANT_STANDARD 3 //!< Constant standard
+#define U_PAN_XHEIGHT_CONSTANT_LARGE 4 //!< Constant large
+#define U_PAN_XHEIGHT_DUCKING_SMALL 5 //!< Ducking small
+#define U_PAN_XHEIGHT_DUCKING_STANDARD 6 //!< Ducking standard
+#define U_PAN_XHEIGHT_DUCKING_LARGE 7 //!< Ducking large
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfWeight_Qualifiers EMF LF_Weight Enumeration
+ For U_LOGFONT lfWeight field
+ EMF manual 2.2.13, footnote 61 (on page 297)
+ @{
+*/
+#define U_FW_DONTCARE 0 //!< Don't care
+#define U_FW_THIN 100 //!< Thin
+#define U_FW_EXTRALIGHT 200 //!< Extra light
+#define U_FW_ULTRALIGHT 200 //!< Ultra light
+#define U_FW_LIGHT 300 //!< Light
+#define U_FW_NORMAL 400 //!< Normal
+#define U_FW_REGULAR 400 //!< Regular
+#define U_FW_MEDIUM 500 //!< Medium
+#define U_FW_SEMIBOLD 600 //!< Semibold
+#define U_FW_DEMIBOLD 600 //!< Demibold
+#define U_FW_BOLD 700 //!< Bold
+#define U_FW_EXTRABOLD 800 //!< Extrabold
+#define U_FW_ULTRABOLD 800 //!< Ultrabold
+#define U_FW_HEAVY 900 //!< Heavy
+#define U_FW_BLACK 900 //!< Black
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfItalic_Qualifiers EMF LF_Italic Enumeration
+ For U_LOGFONT lfItalic field
+ Microsoft name: LF_Italic Enumeration
+ EMF manual 2.2.13
+ @{
+*/
+#define U_FW_NOITALIC 0 //!< Do not use italics.
+#define U_FW_ITALIC 1 //!< Use italics.
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfunderline_Qualifiers EMF LF_Underline Enumeration
+ For U_LOGFONT lfunderline field
+ Microsoft name: LF_Underline Enumeration
+ EMF manual 2.2.13
+ @{
+*/
+#define U_FW_NOUNDERLINE 0 //!< Do not use underline.
+#define U_FW_UNDERLINE 1 //!< Use underline.
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfStrikeOut_Qualifiers EMF LF_StrikeOut Enumeration
+ For U_LOGFONT lfStrikeOut field
+ EMF manual 2.2.13
+ @{
+*/
+#define U_FW_NOSTRIKEOUT 0 //!< Do not use strikeout.
+#define U_FW_STRIKEOUT 1 //!< Use strikeout.
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfCharSet_Qualifiers EMF LF_CharSet Enumeration
+ For U_LOGFONT lfCharSet field
+ EMF manual 2.2.13 & WMF manual 2.1.15
+ @{
+*/
+#define U_ANSI_CHARSET (uint8_t)0 //!< CP1252, ansi-0, iso8859-{1,15}
+#define U_DEFAULT_CHARSET (uint8_t)1 //!< Default character set.
+#define U_SYMBOL_CHARSET (uint8_t)2 //!< Symbol character set.
+#define U_SHIFTJIS_CHARSET (uint8_t)128 //!< CP932
+#define U_HANGEUL_CHARSET (uint8_t)129 //!< CP949, ksc5601.1987-0
+#define U_HANGUL_CHARSET U_HANGEUL_CHARSET //!< CP949, ksc5601.1987-0
+#define U_GB2312_CHARSET (uint8_t)134 //!< CP936, gb2312.1980-0
+#define U_CHINESEBIG5_CHARSET (uint8_t)136 //!< CP950, big5.et-0
+#define U_GREEK_CHARSET (uint8_t)161 //!< CP1253
+#define U_TURKISH_CHARSET (uint8_t)162 //!< CP1254, -iso8859-9
+#define U_HEBREW_CHARSET (uint8_t)177 //!< CP1255, -iso8859-8
+#define U_ARABIC_CHARSET (uint8_t)178 //!< CP1256, -iso8859-6
+#define U_BALTIC_CHARSET (uint8_t)186 //!< CP1257, -iso8859-13
+#define U_RUSSIAN_CHARSET (uint8_t)204 //!< CP1251, -iso8859-5
+#define U_EE_CHARSET (uint8_t)238 //!< CP1250, -iso8859-2
+#define U_EASTEUROPE_CHARSET U_EE_CHARSET //!< CP1250, -iso8859-2
+#define U_THAI_CHARSET (uint8_t)222 //!< CP874, iso8859-11, tis620
+#define U_JOHAB_CHARSET (uint8_t)130 //!< korean (johab) CP1361
+#define U_MAC_CHARSET (uint8_t)77 //!< Macintosh character set.
+#define U_OEM_CHARSET (uint8_t)255 //!< OEM character set.
+#define U_VISCII_CHARSET (uint8_t)240 //!< viscii1.1-1
+#define U_TCVN_CHARSET (uint8_t)241 //!< tcvn-0
+#define U_KOI8_CHARSET (uint8_t)242 //!< koi8-{r,u,ru}
+#define U_ISO3_CHARSET (uint8_t)243 //!< iso8859-3
+#define U_ISO4_CHARSET (uint8_t)244 //!< iso8859-4
+#define U_ISO10_CHARSET (uint8_t)245 //!< iso8859-10
+#define U_CELTIC_CHARSET (uint8_t)246 //!< iso8859-14
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfOutPrecision_Qualifiers EMF LF_OutPrecision Enumeration
+ For U_LOGFONT lfOutPrecision field
+ EMF manual 2.2.13 & WMF manual 2.1.1.21
+ @{
+*/
+#define U_OUT_DEFAULT_PRECIS 0 //!< Default precision
+#define U_OUT_STRING_PRECIS 1 //!< String precision
+#define U_OUT_CHARACTER_PRECIS 2 //!< Character precision
+#define U_OUT_STROKE_PRECIS 3 //!< Stroke precision
+#define U_OUT_TT_PRECIS 4 //!< Tt precision
+#define U_OUT_DEVICE_PRECIS 5 //!< Device precision
+#define U_OUT_RASTER_PRECIS 6 //!< Raster precision
+#define U_OUT_TT_ONLY_PRECIS 7 //!< Tt_only precision
+#define U_OUT_OUTLINE_PRECIS 8 //!< Outline precision
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfClipPrecision_Qualifiers EMF LF_ClipPrecision Enumeration
+ For U_LOGFONT lfClipPrecision field
+ EMF manual 2.2.13 & WMF manual 2.1.2.1
+ @{
+*/
+#define U_CLIP_DEFAULT_PRECIS 0x00 //!< Use default clipping precision.
+#define U_CLIP_CHARACTER_PRECIS 0x01 //!< Use character clipping precision
+#define U_CLIP_STROKE_PRECIS 0x02 //!< (Source documentation is vague about what this means.)
+#define U_CLIP_MASK 0x0F //!< MASK for bits in preceding.
+#define U_CLIP_LH_ANGLES 0x10 //!< Set: font rotation by coordinate system, Clear: device fonts (only) rotate counterclockwise.
+#define U_CLIP_TT_ALWAYS 0x20 //!< Reserved.
+#define U_CLIP_EMBEDDED 0x80 //!< Font embedding is required. (Method for doing so is not documented in EMF or WMF.)
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfQuality_Qualifiers EMF LF_Quality Enumeration
+ For For U_LOGFONT lfQuality field
+ EMF manual 2.2.13 & WMF manual 2.1.1.10
+ @{
+*/
+#define U_DEFAULT_QUALITY 0 //!< Default quality
+#define U_DRAFT_QUALITY 1 //!< Draft quality
+#define U_PROOF_QUALITY 2 //!< Proof quality
+#define U_NONANTIALIASED_QUALITY 3 //!< Nonantialiased quality
+#define U_ANTIALIASED_QUALITY 4 //!< Antialiased quality
+/** @} */
+
+/** \defgroup U_EMF_LOGFONT_lfPitchAndFamily_Qualifiers EMF LF_PitchAndFamily Enumeration
+ For U_LOGFONT lfPitchAndFamily field
+ EMF manual 2.2.13 & WMF manual 2.2.2.14
+ @{
+*/
+#define U_DEFAULT_PITCH 0x00 //!< Default pitch
+#define U_FIXED_PITCH 0x01 //!< Fixed pitch
+#define U_VARIABLE_PITCH 0x02 //!< Variable pitch
+#define U_MONO_FONT 0x08 //!< Mono font
+#define U_FF_DONTCARE 0x00 //!< Font family don't care
+#define U_FF_ROMAN 0x10 //!< Font family Roman
+#define U_FF_SWISS 0x20 //!< Font family Swiss
+#define U_FF_MODERN 0x30 //!< Font family Modern
+#define U_FF_SCRIPT 0x40 //!< Font family Script
+#define U_FF_DECORATIVE 0x50 //!< Font family Decorative
+/** @} */
+
+/** \defgroup U_EMF_LOGBRUSH_lbStyle_Qualifiers EMF LB_Style Enumeration
+ For U_LOGBRUSH lbStyle field
+ EMF manual 2.2.20
+ @{
+*/
+#define U_BS_SOLID 0 //!< Solid brush.
+#define U_BS_NULL 1 //!< Null brush.
+#define U_BS_HOLLOW 1 //!< Hollow brush.
+#define U_BS_HATCHED 2 //!< Hatched brush.
+#define U_BS_PATTERN 3 //!< Pattern brush.
+#define U_BS_INDEXED 4 //!< Indexed brush.
+#define U_BS_DIBPATTERN 5 //!< Dibpattern brush.
+#define U_BS_DIBPATTERNPT 6 //!< Dibpatternpt brush.
+#define U_BS_PATTERN8X8 7 //!< Pattern 8x8 brush.
+#define U_BS_DIBPATTERN8X8 8 //!< Dibpattern 8x8 brush.
+#define U_BS_MONOPATTERN 9 //!< Monopattern brush.
+/** @} */
+
+/** \defgroup U_EMF_PANOSE_index EMF PanoseIndex Enumeration
+ Fositions of each field in U_PANOSE structure.
+ Microsoft name: (none)
+ EMF manual 2.2.21
+ @{
+*/
+#define U_PAN_FAMILYTYPE_INDEX 0 //!< Familytype index
+#define U_PAN_SERIFSTYLE_INDEX 1 //!< Serifstyle index
+#define U_PAN_WEIGHT_INDEX 2 //!< Weight index
+#define U_PAN_PROPORTION_INDEX 3 //!< Proportion index
+#define U_PAN_CONTRAST_INDEX 4 //!< Contrast index
+#define U_PAN_STROKEVARIATION_INDEX 5 //!< Strokevariation index
+#define U_PAN_ARMSTYLE_INDEX 6 //!< Armstyle index
+#define U_PAN_LETTERFORM_INDEX 7 //!< Letterform index
+#define U_PAN_MIDLINE_INDEX 8 //!< Midline index
+#define U_PAN_XHEIGHT_INDEX 9 //!< Xheight index
+#define U_PAN_COUNT 10 //!< Count
+/** @} */
+
+
+/** \defgroup U_EMF_PIXELFORMATDESCRIPTOR_iLayerType_Qualifiers EMF PFD_iLayerType Enumeration
+ For U_PIXELFORMATDESCRIPTOR iLayerType field
+ Microsoft name: (none)
+ EMF manual 2.2.22
+ @{
+*/
+#define U_PFD_MAIN_PLANE 0 //!< Main plane
+#define U_PFD_OVERLAY_PLANE 1 //!< Overlay plane
+#define U_PFD_UNDERLAY_PLANE (-1) //!< Underlay plane
+/** @} */
+
+/** \defgroup U_EMF_PIXELFORMATDESCRIPTOR_iPixelType_Qualifiers EMF PFD_iPixelType Enumeration
+ For U_PIXELFORMATDESCRIPTOR iPixelType field
+ Microsoft name: (none)
+ EMF manual 2.2.22
+ @{
+*/
+#define U_PFD_TYPE_RGBA 0 //!< Pixel contains an RGBA value.
+#define U_PFD_TYPE_COLORINDEX 1 //!< Pixel contains an index into the color table.
+/** @} */
+
+/** \defgroup U_EMF_PIXELFORMATDESCRIPTOR_dwFlags_Qualifiers EMF PFD_dwFlags Enumeration
+ For U_PIXELFORMATDESCRIPTOR dwFlags field
+ EMF manual 2.2.22
+ @{
+*/
+#define U_PFD_DOUBLEBUFFER 0x00000001 //!< Doublebuffer
+#define U_PFD_STEREO 0x00000002 //!< Stereo
+#define U_PFD_DRAW_TO_WINDOW 0x00000004 //!< Draw to window
+#define U_PFD_DRAW_TO_BITMAP 0x00000008 //!< Draw to bitmap
+#define U_PFD_SUPPORT_GDI 0x00000010 //!< Support gdi
+#define U_PFD_SUPPORT_OPENGL 0x00000020 //!< Support opengl
+#define U_PFD_GENERIC_FORMAT 0x00000040 //!< Generic format
+#define U_PFD_NEED_PALETTE 0x00000080 //!< Need palette
+#define U_PFD_NEED_SYSTEM_PALETTE 0x00000100 //!< Need system palette
+#define U_PFD_SWAP_EXCHANGE 0x00000200 //!< Swap exchange
+#define U_PFD_SWAP_COPY 0x00000400 //!< Swap copy
+#define U_PFD_SWAP_LAYER_BUFFERS 0x00000800 //!< Swap layer buffers
+#define U_PFD_GENERIC_ACCELERATED 0x00001000 //!< Generic accelerated
+/** @} */
+
+/** \defgroup U_EMF_EMRCOMMENT_TYPES EMF Comment record types
+ For U_EMRCOMMENT_* cIdent fields
+ EMF manual 2.3.3
+ @{
+*/
+#define U_EMR_COMMENT_PUBLIC 0x43494447 //!< Public comment.
+#define U_EMR_COMMENT_SPOOL 0x00000000 //!< Spool comment.
+#define U_EMR_COMMENT_EMFPLUSRECORD 0x2B464D45 //!< EMF+ record comment.
+/** @} */
+
+/** \defgroup U_EMF_EMRSETLAYOUT_iMode_Qualifiers EMF Mirroring Enumeration
+ For U_EMRSETLAYOUT iMode field
+ EMF manual 2.3.11.17
+ @{
+*/
+#define U_LAYOUT_LTR 0x00000000 //!< Left to right lsyout.
+#define U_LAYOUT_RTL 0x00000001 //!< Right to left layout.
+#define U_LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008 //!< Do not flip bitmaps if layout is right to left.
+/** @} */
+
+
+/** \defgroup U_EMF_BLEND_Op_Qualifiers EMF Blend Enumeration
+ For U_BLEND Op field
+ @{
+*/
+#define U_AC_SRC_GLOBAL 0 //!< Global
+#define U_AC_SRC_CONST 0 //!< Const
+#define U_AC_SRC_ALPHA 1 //!< Alpha
+/** @} */
+
+
+// ***************************************************************************
+// Macros
+
+/** \defgroup U_EMF_Common_macros EMF Common Macros
+ @{
+*/
+// Note, many of these were originally defined using C99 (type){val,val,val} format, but that turned out to
+// have incompatibilities with C++, so use functions as the basis to avoid this.
+
+// Set/Get for U_RGBQUAD Colors, which are stored in byte order: {B,G,R,A}.
+// These are used in EMF structures and the byte order must be the same in memory or on disk.
+#define U_BGR(r,g,b) rgbquad_set(r, g, b, 0) //!< Set any BGR color with an {r,g,b} triplet
+#define U_BGRA(r,g,b,a) rgbquad_set(r, g, b, a) //!< Set any BGRA color with an {r,g,b,a} quad
+#define U_WHITE U_BGR(255,255,255) //!< Set BGR white.
+#define U_BLACK U_BGR(0,0,0) //!< Set BGR black.
+#define U_BGRAGetR(rgb) (rgb.Red ) //!< Color BGR Red.
+#define U_BGRAGetG(rgb) (rgb.Green ) //!< Color BGR Green.
+#define U_BGRAGetB(rgb) (rgb.Blue ) //!< Color BGR Blue.
+#define U_BGRAGetA(rgb) (rgb.Reserved) //!< Color BGRA A/reserved
+
+
+// Set/Get for U_COLORREF Color, which are stored in byte order:: {R,G,B,A}.
+// These are used in EMF structures and the byte order must be the same in memory or on disk.
+// These MAY be used in PNG and other libraries if these enforce byte order in memory, otherwise
+// U_swap4 may need to also be employed.
+//
+
+#define colorref_set colorref3_set //!< Most frequent usage is 3 colors, so set the unqualified one to that
+#define U_RGB(r,g,b) colorref3_set(r, g, b) //!< Set any RGB color with an {r,g,b} triplet
+#define U_RGBA(r,g,b,a) colorref4_set(r, g, b, a) //!< Set any RGBA color with an {r,g,b,a} quad
+#define U_RGBAGetR(rgb) (rgb.Red ) //!< Color RGB Red.
+#define U_RGBAGetG(rgb) (rgb.Green ) //!< Color RGB Green
+#define U_RGBAGetB(rgb) (rgb.Blue ) //!< Color RGB Blue
+#define U_RGBAGetA(rgb) (rgb.Reserved) //!< Color RGBA A/reserved
+
+// color type conversions
+#define U_RGB2BGR(rgb) U_BGR(U_RGBAGetR(rgb),U_RGBAGetG(rgb),U_RGBAGetB(rgb)) //!< Set any BGR color from an RGB color
+#define U_BGR2RGB(rgb) U_RGB(U_BGRAGetR(rgb),U_BGRAGetG(rgb),U_BGRAGetB(rgb)) //!< Set any RGB color from an BGR color
+#define U_RGBA2BGRA(rgb) U_BGRA(U_RGBAGetR(rgb),U_RGBAGetG(rgb),U_RGBAGetB(rgb),U_RGBAGetA(rgb)} //!< Set any BGRA color from an RGBA color
+#define U_BGRA2RGBA(rgb) U_RGBA(U_BGRAGetR(rgb),U_BGRAGetG(rgb),U_BGRAGetB(rgb),U_BGRAGetA(rgb)} //!< Set any RGBA color from an BGRA color
+
+// Color CMYK Get/Set Macros
+#define U_CMYK(c,m,y,k)\
+ ((COLOREF)((((uint8_t)(k)|((uint16_t)((uint8_t)(y))<<8))|(((uint32_t)(uint8_t)(m))<<16))|(((uint32_t)(uint8_t)(c))<<24))) \
+ //!< Color CMYK Set Macro.
+#define U_GetKValue(cmyk) ((uint8_t) (cmyk) ) //!< Color CMYK Get K Macro.
+#define U_GetYValue(cmyk) ((uint8_t) ((cymk) >> 8)) //!< Color CMYK Get Y Macro.
+#define U_GetMValue(cmyk) ((uint8_t) ((cymk) >> 16)) //!< Color CMYK Get M Macro.
+#define U_GetCValue(cmyk) ((uint8_t) ((cymk) >> 24)) //!< Color CMYK Get C Macro.
+
+// Other macros
+#define U_Gamma(A) (A < U_RGB_GAMMA_MIN ? U_RGB_GAMMA_MIN : (A > U_RGB_GAMMA_MAX ? U_RGB_GAMMA_MAX: A)) \
+ //!< Gamma set Macro (enforce range).
+#define U_PM(A,B) ((A)<-(B)?-(B):((A)>(B)?(B):(A))) //!< Plus/Minus Range Macro (B must be postitive!).
+#define U_MNMX(A,B,C) ((A)<(B)?(B):((A)>(C)?(C):(A))) //!< Min/Max Range Macro (B <= A <= C).
+#define U_MIN(A,B) ((A)>(B)?(B):(A)) //!< Minimum of A,B
+#define U_MAX(A,B) ((A)>(B)?(A):(B)) //!< Maximum of A,B
+
+// basic EMR macros.
+#define U_EMRTYPE(A) (((PU_EMR)A)->iType) //!< Get iType from U_EMR* record
+#define U_EMRSIZE(A) (((PU_EMR)A)->nSize) //!< Get nSize from U_EMR* record
+
+// Utility macros
+#define UP4(A) (4 * ((A + 3 ) / 4)) //!< Round up to nearest multiple of 4
+
+/** @} */
+
+/** Any generic pair of floats.
+
+ Microsoft name: (none)
+*/
+typedef struct {
+ float x; //!< X value
+ float y; //!< Y value
+} U_PAIRF,
+ *PU_PAIRF; //!< Any generic pair of floats. Microsoft name: (none)
+
+
+/* ************************************************************
+ EMF structures OTHER than those corresponding to complete U_EMR_* records
+ ************************************************************ */
+
+/**
+ \brief For U_POINT28_4 x and y fields.
+
+ EMF manual 2.2.1, Microsoft name: BitFIX28_4 Object.
+*/
+typedef struct {
+ signed IntValue :28; //!< Signed integral bit field
+ unsigned FracValue :4; //!< Unsigned integral bit field
+} U_BITFIX28_4,
+ *PU_BITFIX28_4; //!< EMF manual 2.2.1
+
+/**
+ \brief For U_EMRSETOLORADJUSTMENT ColorAdjustment field
+
+ EMF manual 2.2.2, Microsoft name: ColorAdjustment Object
+
+ Note, range constants are: RGB_GAMMA_[MIN|MAX],REFERENCE_[WHITE|BLACK]_[MIN|MAX],COLOR_ADJ_[MIN|MAX]
+*/
+typedef struct {
+ uint16_t caSize; //!< Size of this structure in bytes
+ uint16_t caFlags; //!< ColorAdjustment Enumeration
+ uint16_t caIlluminantIndex; //!< Illuminant Enumeration
+ uint16_t caRedGamma; //!< Red Gamma correction (range:2500:65000, 10000 is no correction)
+ uint16_t caGreenGamma; //!< Green Gamma correction (range:2500:65000, 10000 is no correction)
+ uint16_t caBlueGamma; //!< Blue Gamma correction (range:2500:65000, 10000 is no correction)
+ uint16_t caReferenceBlack; //!< Values less than this are black (range:0:4000)
+ uint16_t caReferenceWhite; //!< Values more than this are white (range:6000:10000)
+ int16_t caContrast; //!< Contrast adjustment (range:-100:100, 0 is no correction)
+ int16_t caBrightness; //!< Brightness adjustment (range:-100:100, 0 is no correction)
+ int16_t caColorfulness; //!< Colorfulness adjustment (range:-100:100, 0 is no correction)
+ int16_t caRedGreenTint; //!< Tine adjustment (range:-100:100, 0 is no correction)
+} U_COLORADJUSTMENT,
+ *PU_COLORADJUSTMENT; //!< EMF manual 2.2.2
+
+/** EMF manual 2.2.3
+ \brief For ? (not implemented yet)
+
+ Microsoft name: DesignVector Object
+*/
+typedef struct {
+ uint32_t Signature; //!< Must be 0x08007664 (AKA: DV_SGNTR)
+ U_NUM_FNTAXES NumAxes; //!< Number of elements in Values, 0-16
+ U_FNTAXES Values[1]; //!< Optional. Array of font axes for opentype font
+} U_DESIGNVECTOR,
+ *PU_DESIGNVECTOR; //!< EMF manual 2.2.3
+#define U_SIZE_DESIGNVECTOR (sizeof(uint32_t) + sizeof(U_NUM_FNTAXES))
+
+/**
+ \brief For U_EMR_COMMENT_MULTIFORMATS record, where an array of these is used
+
+ EMF manual 2.2.4, Microsoft name: EmrFormat Object
+*/
+typedef struct {
+ uint32_t signature; //!< FormatSignature Enumeration
+ uint32_t nVersion; //!< Must be 1 if signature is EPS, else ignored
+ U_CBDATA cbData; //!< Data size in bytes
+ U_OFFDATA offData; //!< Offset in bytes to the Data from the start of the RECORD
+} U_EMRFORMAT,
+ *PU_EMRFORMAT; //!< EMF manual 2.2.4
+
+/**
+
+ \brief For U_EMR[POLY]EXTTEXTOUT[A|W] emrtext field
+
+ EMF manual 2.2.5, Microsoft name: EmrText Object
+
+ Differs from implementation in Mingw and Wine in that the core struct has a fixed size.
+ Optional and movable components must be handled with offsets.
+ Following invariant core there may/must be:
+
+ U_RECTL rcl; (Optional, absent when fOptions & U_ETO_NO_RECT) grayed/clipping/opaque rectangle
+
+ U_OFFDX offDx; (required) but position isn't static. Offset in bytes to the character spacing array measured
+ from the start of the RECORD, NOT from the start of this structure.
+
+ The order of the next two may be reversed, they are found from their offsets.
+
+ char string (required) String buffer holding nChars (padded to a multiple of 4 bytes in length).
+
+ uint32_t Dx[1] (required) character spacing, array with one entry per glyph.
+*/
+typedef struct {
+ U_POINTL ptlReference; //!< String start coordinates
+ U_NUM_STR nChars; //!< Number of characters in the string
+ U_OFFSTR offString; //!< Offset in bytes to the string from the start of the RECORD
+ uint32_t fOptions; //!< ExtTextOutOptions Enumeration
+} U_EMRTEXT,
+ *PU_EMRTEXT; //!< EMF manual 2.2.5
+
+/**
+ \brief For U_EPS_DATA Points field
+
+ EMF manual 2.2.23, Microsoft name: Point28_4 Object, out of order, needed for 2.2.6
+*/
+typedef struct {
+ U_BITFIX28_4 x; //!< X coordinate
+ U_BITFIX28_4 y; //!< Y coordinate
+} U_POINT28_4,
+ *PU_POINT28_4; //!< EMF manual 2.2.23
+
+/**
+ \brief For embedding EPS in EMF via U_EMRFORMAT offData array in U_EMR_COMMENT_MULTIFORMATS
+
+ EMF manual 2.2.6, Microsoft name: EpsData Object
+*/
+typedef struct {
+ uint32_t sizeData; //!< Size in bytes of this object
+ uint32_t version; //!< Must be 1
+ U_POINT28_4 Points[3]; //!< Defines parallelogram, UL, UR, LL corners, LR is derived.
+ U_RECTL PostScriptData; //!< Record may include optional clipping/opaque rectangle
+} U_EPS_DATA,
+ *PU_EPS_DATA; //!< EMF manual 2.2.6
+
+/**
+ \brief For GRADIENT_[TRIANGLE|U_RECT]
+
+ EMF manual 2.2.26, Microsoft name: TriVertex Object, out of order, needed for 2.2.7
+*/
+typedef struct {
+ int32_t x; //!< X coord
+ int32_t y; //!< Y coord
+ uint16_t Red; //!< Red component
+ uint16_t Green; //!< Green component
+ uint16_t Blue; //!< Bule component
+ uint16_t Alpha; //!< Alpha Transparency
+} U_TRIVERTEX,
+ *PU_TRIVERTEX; //!< EMF manual 2.2.26
+
+/**
+ \brief For U_EMRGRADIENTFILL GradObj field
+
+ EMF manual 2.2.7, Microsoft name: GradientRectangle Object
+*/
+typedef struct {
+ uint32_t UpperLeft; //!< Index of UL corner in an array of U_TRIVERTEX objects
+ uint32_t LowerRight; //!< Index of LR corner in an array of U_TRIVERTEX objects
+} U_GRADIENT4,
+ *PU_GRADIENT4; //!< EMF manual 2.2.7
+
+/**
+ \brief For U_EMRGRADIENTFILL GradObj field
+
+ EMF manual 2.2.8, Microsoft name: GradientTriangle Object
+
+ Gradient object notes. The next two structures are used to define the shape with reference to an existing array
+ of points stored in an array of TriVertex objects in the U_EMRGRADIENTFILL record. The tricky part
+ is that these two structures are different sizes. In some implementations (MingW) the array is cast to uint32_t
+ and basically the cast is then ignored. For libUEMF we leave this out of the structure entirely and get to it with offsets.
+*/
+typedef struct {
+ uint32_t Vertex1; //!< Index of Vertex1 in an array of U_TRIVERTEX objects
+ uint32_t Vertex2; //!< Index of Vertex2 in an array of U_TRIVERTEX objects
+ uint32_t Vertex3; //!< Index of Vertex3 in an array of U_TRIVERTEX objects
+} U_GRADIENT3,
+ *PU_GRADIENT3; //!< EMF manual 2.2.8
+
+//Microsoft name: Header object, EMF manual 2.2.9 defined below with record structs
+//Microsoft name: HeaderExtension1 object, EMF manual 2.2.10 defined below with record structs
+//Microsoft name: HeaderExtension1 object, EMF manual 2.2.11 defined below with record structs
+
+/**
+ \brief For U_EMRCREATEBRUSHINDIRECT lb field
+
+ EMF manual 2.2.12, Microsoft name: LogBrushEx Object
+*/
+typedef struct { //!< In MS documentation this is LogBrushEx Object
+ uint32_t lbStyle; //!< LB_Style Enumeration
+ U_COLORREF lbColor; //!< Brush color
+ uint32_t lbHatch; //!< HatchStyle Enumeration
+} U_LOGBRUSH,
+ U_PATTERN, //!< EMF manual 2.2.12
+ *PU_LOGBRUSH, //!< EMF manual 2.2.12
+ *PU_PATTERN; //!< EMF manual 2.2.12
+
+/**
+ \brief For U_LOGFONT elfLogFont field
+
+ EMF manual 2.2.13, Microsoft name: LogFont Object
+*/
+typedef struct {
+ int32_t lfHeight; //!< Height in Logical units
+ int32_t lfWidth; //!< Average Width in Logical units
+ int32_t lfEscapement; //!< Angle in 0.1 degrees betweem escapement vector and X axis
+ int32_t lfOrientation; //!< Angle in 0.1 degrees between baseline and X axis
+ int32_t lfWeight; //!< LF_Weight Enumeration
+ uint8_t lfItalic; //!< LF_Italic Enumeration
+ uint8_t lfUnderline; //!< LF_Underline Enumeration
+ uint8_t lfStrikeOut; //!< LF_StrikeOut Enumeration
+ uint8_t lfCharSet; //!< LF_CharSet Enumeration
+ uint8_t lfOutPrecision; //!< LF_OutPrecision Enumeration
+ uint8_t lfClipPrecision; //!< LF_ClipPrecision Enumeration
+ uint8_t lfQuality; //!< LF_Quality Enumeration
+ uint8_t lfPitchAndFamily; //!< LF_PitchAndFamily Enumeration
+ uint16_t lfFaceName[U_LF_FACESIZE]; //!< Name of font. If <U_LF_FACESIZE chars must be null terminated
+} U_LOGFONT,
+ *PU_LOGFONT; //!< EMF manual 2.2.13
+
+// Microsoft name: LogFontEx Object (not implemented) EMF manual 2.2.14
+// Microsoft name: LogFontExDv Object (not implemented) EMF manual 2.2.15
+
+/**
+ \brief For U_LOGFONT_PANOSE elfPanose field
+
+ EMF manual 2.2.21, Microsoft name: Panose Object
+*/
+// out of order, needed for 2.2.16
+typedef struct {
+ uint8_t bFamilyType; //!< FamilyType Enumeration
+ uint8_t bSerifStyle; //!< SerifType Enumeration
+ uint8_t bWeight; //!< Weight Enumeration
+ uint8_t bProportion; //!< Proportion Enumeration
+ uint8_t bContrast; //!< Contrast Enumeration
+ uint8_t bStrokeVariation; //!< StrokeVariation Enumeration
+ uint8_t bArmStyle; //!< ArmStyle Enumeration
+ uint8_t bLetterform; //!< Letterform Enumeration
+ uint8_t bMidline; //!< Midline Enumeration
+ uint8_t bXHeight; //!< XHeight Enumeration
+} U_PANOSE,
+ *PU_PANOSE; //!< EMF manual 2.2.21
+
+#define U_PAN_ALL0 (U_PANOSE){0,0,0,0,0,0,0,0,0,0} //!< all U_PAN_ANY, have not seen this in an EMF file
+#define U_PAN_ALL1 (U_PANOSE){1,1,1,1,1,1,1,1,1,1} //!< all U_PAN_NO_FIT, this is what createfont() would have made
+
+/**
+ \brief For U_EMREXTCREATEFONTINDIRECTW elfw field
+
+ EMF manual 2.2.16, Microsoft name: LogFontPanose Object
+*/
+typedef struct {
+ U_LOGFONT elfLogFont; //!< Basic font attributes
+ uint16_t elfFullName[U_LF_FULLFACESIZE]; //!< Font full name
+ uint16_t elfStyle[U_LF_FACESIZE]; //!< Font style (if <U_LF_FACESIZE characters, null terminate string)
+ uint32_t elfVersion; //!< Ignore
+ uint32_t elfStyleSize; //!< Font hinting starting at this point size, if 0, starts at Height
+ uint32_t elfMatch; //!< Ignore
+ uint32_t elfReserved; //!< Must be 0, Ignore
+ uint8_t elfVendorId[U_ELF_VENDOR_SIZE]; //!< Ignore
+ uint32_t elfCulture; //!< Must be 0, Ignore
+ U_PANOSE elfPanose; //!< Panose Object. If all zero, it is ignored.
+ uint16_t elfPadding; //!< Ignore
+} U_LOGFONT_PANOSE,
+ *PU_LOGFONT_PANOSE; //!< EMF manual 2.2.16
+
+/**
+ \brief For U_LOGPALETTE palPalEntry field(s)
+
+ EMF manual 2.2.18, Microsoft name: LogPaletteEntry Object
+*/
+// out of order, needed for 2.2.17
+typedef struct {
+ uint8_t peReserved; //!< Ignore
+ uint8_t peRed; //!< Palette entry Red Intensity
+ uint8_t peGreen; //!< Palette entry Green Intensity
+ uint8_t peBlue; //!< Palette entry Blue Intensity
+} U_LOGPLTNTRY,
+ *PU_LOGPLTNTRY; //!< EMF manual 2.2.18
+
+/**
+ \brief For U_EMRCREATEPALETTE lgpl field
+
+ EMF manual 2.2.17, Microsoft name: LogPalette Object
+
+*/
+typedef struct {
+ uint16_t palVersion; //!< Must be 0x0300 (AKA: U_LP_VERSION)
+ uint16_t palNumEntries; //!< Number of U_LOGPLTNTRY objects
+ U_LOGPLTNTRY palPalEntry[1]; //!< PC_Entry Enumeration
+} U_LOGPALETTE,
+ *PU_LOGPALETTE; //!< EMF manual 2.2.17
+#define U_SIZE_LOGPALETTE (2*sizeof(uint16_t))
+
+// Microsoft name: LogPaletteEntry Object, EMF manual 2.2.18, defined above, before 2.2.17
+
+/**
+ \brief For U_EMRCREATEPEN lopn field
+
+ EMF manual 2.2.19, Microsoft name: LogPen Object
+*/
+typedef struct {
+ uint32_t lopnStyle; //!< PenStyle Enumeration
+ U_POINT lopnWidth; //!< Width of pen set by X, Y is ignored
+ U_COLORREF lopnColor; //!< Pen color value
+} U_LOGPEN,
+ *PU_LOGPEN; //!< EMF manual 2.2.19
+
+// Microsoft name: LogPenEx Object (not implemented) EMF manual 2.2.20
+// Microsoft name: Panose Object, EMF manual 2.2.21, defined above, before 2.2.16
+
+/**
+ \brief For U_EMRPIXELFORMAT pfd field
+
+ EMF manual 2.2.22, Microsoft name: PixelFormatDescriptor Object
+*/
+typedef struct {
+ uint16_t nSize; //!< Structure size in bytes
+ uint16_t nVersion; //!< must be 1
+ uint32_t dwFlags; //!< PFD_dwFlags Enumeration
+ uint8_t iPixelType; //!< PFD_iPixelType Enumeration
+ uint8_t cColorBits; //!< RGBA: total bits per pixel
+ uint8_t cRedBits; //!< Red bits per pixel
+ uint8_t cRedShift; //!< Red shift to data bits
+ uint8_t cGreenBits; //!< Green bits per pixel
+ uint8_t cGreenShift; //!< Green shift to data bits
+ uint8_t cBlueBits; //!< Blue bits per pixel
+ uint8_t cBlueShift; //!< Blue shift to data bits
+ uint8_t cAlphaBits; //!< Alpha bits per pixel
+ uint8_t cAlphaShift; //!< Alpha shift to data bits
+ uint8_t cAccumBits; //!< Accumulator buffer, total bitplanes
+ uint8_t cAccumRedBits; //!< Red accumulator buffer bitplanes
+ uint8_t cAccumGreenBits; //!< Green accumulator buffer bitplanes
+ uint8_t cAccumBlueBits; //!< Blue accumulator buffer bitplanes
+ uint8_t cAccumAlphaBits; //!< Alpha accumulator buffer bitplanes
+ uint8_t cDepthBits; //!< Depth of Z-buffer
+ uint8_t cStencilBits; //!< Depth of stencil buffer
+ uint8_t cAuxBuffers; //!< Depth of auxilliary buffers (not supported)
+ uint8_t iLayerType; //!< PFD_iLayerType Enumeration, may be ignored
+ uint8_t bReserved; //!< Bits 0:3/4:7 are number of Overlay/Underlay planes
+ uint32_t dwLayerMask; //!< may be ignored
+ uint32_t dwVisibleMask; //!< color or index of underlay plane
+ uint32_t dwDamageMask; //!< may be ignored
+} U_PIXELFORMATDESCRIPTOR,
+ *PU_PIXELFORMATDESCRIPTOR; //!< EMF manual 2.2.22
+
+// Microsoft name: Point28_4 Object. EMF manual 2.2.23, defined above, before 2.2.6
+
+/**
+ \brief For U_RGNDATA rdb field
+
+ EMF manual 2.2.25, Microsoft name: RegionDataHeader Object (RGNDATAHEADER)
+*/
+// out of order, needed for 2.2.24
+typedef struct {
+ uint32_t dwSize; //!< Size in bytes, must be 0x20 (AKA: U_RDH_OBJSIZE)
+ uint32_t iType; //!< Must be 1 (AKA: U_RDH_RECTANGLES)
+ U_NUM_RECTL nCount; //!< Number of rectangles in region
+ uint32_t nRgnSize; //!< Size in bytes of rectangle buffer
+ U_RECTL rclBounds; //!< Region bounds
+} U_RGNDATAHEADER,
+ *PU_RGNDATAHEADER; //!< EMF manual 2.2.25
+#define U_SIZE_RGNDATAHEADER (sizeof(U_RGNDATAHEADER))
+
+/**
+ \brief For U_EMRFILLRGN RgnData field(s)
+
+ EMF manual 2.2.24, Microsoft name: RegionData Object
+
+*/
+typedef struct {
+ U_RGNDATAHEADER rdh; //!< Data description
+ U_RECTL Buffer[1]; //!< Array of U_RECTL elements
+} U_RGNDATA,
+ *PU_RGNDATA; //!< EMF manual 2.2.24
+#define U_SIZE_RGNDATA U_SIZE_RGNDATAHEADER
+
+// Microsoft name: RegionDataHeader Object. EMF manual 2.2.25, defined above, before 2.2.24
+// Microsoft name: TriVertex Object. EMF manual 2.2.26, defined above, before 2.2.7
+// Microsoft name: UniversalFontId Object. EMF manual 2.2.27 (not implemented)
+
+/**
+ \brief For U_EMR[FILLRGN|STRETCHBLT|MASKBLT|PLGBLT] xformSrc field
+
+ EMF manual 2.2.28, Microsoft name: Xform Object
+*/
+typedef struct {
+ U_FLOAT eM11; //!< Matrix element M11
+ U_FLOAT eM12; //!< Matrix element M12
+ U_FLOAT eM21; //!< Matrix element M21
+ U_FLOAT eM22; //!< Matrix element M22
+ U_FLOAT eDx; //!< X offset in logical units
+ U_FLOAT eDy; //!< Y offset in logical units
+} U_XFORM ,
+ *PU_XFORM; //!< EMF manual 2.2.28
+
+/**
+ \brief For U_EMREXTCREATEPEN lopn field
+
+ EMF manual 2.2.20, Microsoft name: LogPenEx Object
+*/
+typedef struct {
+ uint32_t elpPenStyle; //!< PenStyle Enumeration
+ uint32_t elpWidth; //!< Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel)
+ uint32_t elpBrushStyle; //!< LB_Style Enumeration
+ U_COLORREF elpColor; //!< Pen color
+ uint32_t elpHatch; //!< HatchStyle Enumeration
+ U_NUM_STYLEENTRY elpNumEntries; //!< Count of StyleEntry array
+ U_STYLEENTRY elpStyleEntry[1]; //!< Array of StyleEntry (For user specified dot/dash patterns)
+} U_EXTLOGPEN,
+ *PU_EXTLOGPEN; //!< EMF manual 2.2.20
+#define U_SIZE_EXTLOGPEN (sizeof(U_EXTLOGPEN) - sizeof(U_STYLEENTRY)) // there may not be any style entries
+
+/**
+ \brief For U_EMR_* OffBmi* fields
+
+ WMF Manual 2.2.2.9, Microsoft name: (none).
+
+ Description of a Bitmap which in some cases is a Device Independent Bitmap (DIB)
+*/
+typedef struct {
+ U_BITMAPINFOHEADER bmiHeader; //!< Geometry and pixel properties
+ U_RGBQUAD bmiColors[1]; //!< Color table. 24 bit images do not use color table values.
+} U_BITMAPINFO,
+ *PU_BITMAPINFO; //!< WMF Manual 2.2.2.9
+#define U_SIZE_BITMAPINFO U_SIZE_BITMAPINFOHEADER
+
+/**
+ \brief U_EMRALPHABLEND Blend field
+
+ EMF Manual 2.3.1.1, Microsoft name: BLENDFUNCTION field of EMR_ALPHABLEND record.
+*/
+typedef struct {
+ uint8_t Operation; //!< Must be 0
+ uint8_t Flags; //!< Must be 0
+ uint8_t Global; //!< Alpha for whole thing if Op is U_AC_SRC_GLOBAL (AKA U_AC_SRC_GLOBAL)
+ uint8_t Op; //!< Blend Enumeration
+} U_BLEND,
+ *PU_BLEND; //!< EMF Manual 2.3.1.1
+#
+
+/**
+ General form of an EMF record.
+ Microsoft name: ENHMETARECORD Object
+ For generic cast of other U_EMR_* records
+*/
+typedef struct {
+ uint32_t iType; //!< Type of EMR record
+ uint32_t nSize; //!< Size of entire record in bytes (multiple of 4).
+ uint32_t dParm[1]; //!< Data in record
+} U_ENHMETARECORD,
+ *PU_ENHMETARECORD; //!< General form of an EMF record.
+#define U_SIZE_ENHMETARECORD (2*sizeof(uint32_t))
+
+/** First two fields of all EMF records,
+ First two fields of all EMF+ records (1 or more within an EMF comment)
+ For accessing iType and nSize files in all U_EMR* records
+ Microsoft name: EMR Object
+*/
+typedef struct {
+ uint32_t iType; //!< Type of EMR record
+ uint32_t nSize; //!< Size of entire record in bytes (multiple of 4).
+} U_EMR,
+ *PU_EMR; //!< First two fields of all EMF records,
+
+/** Generic EMR record with two 32 bit values.
+ Microsoft name: (none)
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_PAIR pair; //!< pair of 32 bit values
+} U_EMRGENERICPAIR,
+ *PU_EMRGENERICPAIR; //!< Generic EMR record with two 32 bit values. Microsoft name: (none)
+
+
+
+
+// ***********************************************************************************
+// The following have U_EMR_# records. They are ordered by their record index, not by EMF manual position.
+
+// records which are documented but not implemented
+#define U_SIZE_EMRNOTIMPLEMENTED 2048
+
+/* Index 1 */
+/**
+ \brief The first U_ENHMETARECORD record in the metafile.
+
+ EMF manual 2.2.9, Microsoft name: Header object, HeaderExtension1 object, HeaderExtension2 object
+
+ Microsoft names instead: Header, HeaderExtension1, and HeaderExtension2 objects. These are
+ used nowhere else, so they are combined here, along with the first two fields which were not listed in the Header.
+
+ Note also that three fields in this file (nBytes, nRecords, nHandles) must be (re)set after the entire EMF
+ is constructed, since typically they are not known until then. bOpenGL may or may not be knowable when this
+ header is written.
+
+ Note also that rclBounds and rclFrame are supposed to be the region bounding the drawn content within the
+ EMF. This is generally smaller than the size from szlDevice. However, since libUEMF does not actually draw
+ anything it has no way of knowing what these values are. Instead when it creates a header it sets these to
+ match the szl* fields.
+
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_RECTL rclFrame; //!< Bounding rectangle in 0.01 mm units
+ uint32_t dSignature; //!< FormatSignature Enumeration (must be U_ENHMETA_SIGNATURE)
+ uint32_t nVersion; //!< Must be U_ENHMETA_VERSION (0x00010000)
+ uint32_t nBytes; //!< Length in bytes of the Metafile
+ uint32_t nRecords; //!< Records in the Metafile
+ uint16_t nHandles; //!< Number of graphics objects used in the Metafile
+ uint16_t sReserved; //!< Must be 0
+ uint32_t nDescription; //!< Characters in the Description field, 0 if no description
+ uint32_t offDescription; //!< Offset in bytes to optional UTF-16BE string Description field
+ uint32_t nPalEntries; //!< Number of Palette entries (in U_EMR_EOF record).
+ U_SIZEL szlDevice; //!< Reference device size in pixels
+ U_SIZEL szlMillimeters; //!< Reference device size in 0.01 mm
+ /** Fields for winver >= win95 */
+ U_CBPXLFMT cbPixelFormat; //!< Size in bytes of PixelFormatDescriptor, 0 if no PFD
+ U_OFFPXLFMT offPixelFormat; //!< Offset in bytes to optional PixelFormatDescriptor from the start of the RECORD, 0 if no PFD
+ uint32_t bOpenGL; //!< nonZero if OpenGL commands are included
+ /** Fields for winver >= win98 */
+ U_SIZEL szlMicrometers; //!< Size of the display device in micrometer
+} U_EMRHEADER,
+ *PU_EMRHEADER; //!< EMF manual 2.2.9
+#define U_SIZE_EMRHEADER sizeof(U_EMRHEADER) // modern EMF files, for _really_ old ones the _MIN size applies
+#define U_SIZE_EMRHEADER_MIN (U_SIZE_EMRHEADER - sizeof(U_CBPXLFMT) - sizeof(U_OFFPXLFMT) - sizeof(uint32_t) - sizeof(U_SIZEL))
+
+/* Index 2,3,4,5,6 */
+/** EMF manual 2.3.5.16
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< bounding rectangle in device units
+ U_NUM_POINTL cptl; //!< Number of points to draw
+ U_POINTL aptl[1]; //!< array of points
+} U_EMRPOLYBEZIER,
+ U_EMRPOLYGON, //!< EMF manual 2.3.5.22
+ U_EMRPOLYLINE, //!< EMF manual 2.3.5.24
+ U_EMRPOLYBEZIERTO, //!< EMF manual 2.3.5.18
+ U_EMRPOLYLINETO, //!< EMF manual 2.3.5.26
+ *PU_EMRPOLYBEZIER, //!< EMF manual 2.3.5.16
+ *PU_EMRPOLYGON, //!< EMF manual 2.3.5.22
+ *PU_EMRPOLYLINE, //!< EMF manual 2.3.5.24
+ *PU_EMRPOLYBEZIERTO, //!< EMF manual 2.3.5.18
+ *PU_EMRPOLYLINETO; //!< EMF manual 2.3.5.26
+
+#define U_SIZE_EMRPOLYBEZIER (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINTL) )
+#define U_SIZE_EMRPOLYGON U_SIZE_EMRPOLYBEZIER
+#define U_SIZE_EMRPOLYLINE U_SIZE_EMRPOLYBEZIER
+#define U_SIZE_EMRPOLYBEZIERTO U_SIZE_EMRPOLYBEZIER
+#define U_SIZE_EMRPOLYLINETO U_SIZE_EMRPOLYBEZIER
+/* Index 7,8 */
+/** EMF manual 2.3.5.30
+
+ After this struct the record also contains an array of points:\n
+ U_POINTL aptl[1];
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< bounding rectangle in device units
+ U_NUM_POLYCOUNTS nPolys; //!< Number of elements in aPolyCounts
+ U_NUM_POINTL cptl; //!< Total number of points (over all poly)
+ U_POLYCOUNTS aPolyCounts[1]; //!< Number of points in each poly (sequential)
+} U_EMRPOLYPOLYLINE,
+ U_EMRPOLYPOLYGON, //!< EMF manual 2.3.5.28
+ *PU_EMRPOLYPOLYLINE, //!< EMF manual 2.3.5.30
+ *PU_EMRPOLYPOLYGON; //!< EMF manual 2.3.5.28
+#define U_SIZE_EMRPOLYPOLYLINE (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_NUM_POINTL))
+#define U_SIZE_EMRPOLYPOLYGON U_SIZE_EMRPOLYPOLYLINE
+
+/* Index 9,11 (numbers interleave with next one) */
+/** EMF manual 2.3.11.30
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_SIZEL szlExtent; //!< H & V extent in logical units
+} U_EMRSETWINDOWEXTEX,
+ U_EMRSETVIEWPORTEXTEX, //!< EMF manual manual 2.3.11.28
+ *PU_EMRSETWINDOWEXTEX, //!< EMF manual manual 2.3.11.30
+ *PU_EMRSETVIEWPORTEXTEX; //!< EMF manual manual 2.3.11.28
+#define U_SIZE_EMRSETWINDOWEXTEX (sizeof(U_EMRSETWINDOWEXTEX ))
+#define U_SIZE_EMRSETVIEWPORTEXTEX (sizeof(U_EMRSETVIEWPORTEXTEX))
+
+/* Index 10,12,13 */
+/** EMF manual 2.3.11.31
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptlOrigin; //!< H & V origin in logical units
+} U_EMRSETWINDOWORGEX,
+ U_EMRSETVIEWPORTORGEX, //!< EMF manual 2.3.11.29
+ U_EMRSETBRUSHORGEX, //!< EMF manual 2.3.11.12
+ *PU_EMRSETWINDOWORGEX, //!< EMF manual 2.3.11.31
+ *PU_EMRSETVIEWPORTORGEX, //!< EMF manual 2.3.11.29
+ *PU_EMRSETBRUSHORGEX; //!< EMF manual 2.3.11.12
+#define U_SIZE_EMRSETWINDOWORGEX (sizeof(U_EMRSETWINDOWORGEX ))
+#define U_SIZE_EMRSETVIEWPORTORGEX (sizeof(U_EMRSETVIEWPORTORGEX))
+#define U_SIZE_EMRSETBRUSHORGEX (sizeof(U_EMRSETBRUSHORGEX ))
+
+/* Index 14 */
+/** EMF manual 3.2.4.1
+
+This is a very odd structure because the nSizeLast follows an optional variable size field. Consequently
+even though nSizeLast has a name it cannot actually be accessed by it! Following the core structure
+appear these fields:\n
+
+ U_LOGPLTNTRY PalEntries[1]; Record may include optional array of PalEntries
+
+ uint32_t nSizeLast; Mandatory, but position isn't fixed. Must have same value as emr.nSize in header record
+
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBPLENTRIES cbPalEntries; //!< Number of palette entries
+ U_OFFPLENTRIES offPalEntries; //!< Offset in bytes to array of palette entries
+} U_EMREOF,
+ *PU_EMREOF; //!< EMF manual 3.2.4.1
+#define U_SIZE_EMREOF (sizeof(U_EMREOF))
+
+/* Index 15 */
+/** EMF manual 2.3.5.36
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptlPixel; //!< Pixel coordinates (logical)
+ U_COLORREF crColor; //!< Pixel color
+} U_EMRSETPIXELV,
+ *PU_EMRSETPIXELV; //!< EMF manual 2.3.5.36
+#define U_SIZE_EMRSETPIXELV (sizeof(U_EMRSETPIXELV))
+
+/* Index 16 */
+/** EMF manual 2.3.11.20
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t dwFlags; //!< must be 1
+} U_EMRSETMAPPERFLAGS,
+ *PU_EMRSETMAPPERFLAGS; //!< EMF manual 2.3.11.20
+#define U_SIZE_EMRSETMAPPERFLAGS (sizeof(U_EMRSETMAPPERFLAGS))
+
+/* Index 17,18,19,20,21,22,67,98,115
+*/
+/** EMF manual 2.3.11.19 MapMode enumeration
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t iMode; //!< enumeration varies with type
+} U_EMRSETMAPMODE,
+ U_EMRSETBKMODE, //!< EMF manual 2.3.11.11 BackgroundMode Enumeration
+ U_EMRSETPOLYFILLMODE, //!< EMF manual 2.3.11.22 PolygonFillMode Enumeration
+ U_EMRSETROP2, //!< EMF manual 2.3.11.23 Binary Raster Operation Enumeration
+ U_EMRSETSTRETCHBLTMODE, //!< EMF manual 2.3.11.24 StretchMode Enumeration
+ U_EMRSETTEXTALIGN, //!< EMF manual 2.3.11.25 TextAlignment enumeration
+ U_EMRSELECTCLIPPATH, //!< EMF manual 2.3.2.5 RegionMode Enumeration
+ U_EMRSETICMMODE, //!< EMF manual 2.3.11.14 ICMMode Enumeration
+ U_EMRSETLAYOUT, //!< EMF manual 2.3.11.17 Mirroring Enumeration
+ *PU_EMRSETMAPMODE, //!< EMF manual 2.3.11.19 MapMode enumeration
+ *PU_EMRSETBKMODE, //!< EMF manual 2.3.11.11 BackgroundMode Enumeration
+ *PU_EMRSETPOLYFILLMODE, //!< EMF manual 2.3.11.22 PolygonFillMode Enumeration
+ *PU_EMRSETROP2, //!< EMF manual 2.3.11.23 Binary Raster Operation Enumeration
+ *PU_EMRSETSTRETCHBLTMODE, //!< EMF manual 2.3.11.24 StretchMode Enumeration
+ *PU_EMRSETTEXTALIGN, //!< EMF manual 2.3.11.25 TextAlignment enumeration
+ *PU_EMRSELECTCLIPPATH, //!< EMF manual 2.3.2.5 RegionMode Enumeration
+ *PU_EMRSETICMMODE, //!< EMF manual 2.3.11.14 ICMMode Enumeration
+ *PU_EMRSETLAYOUT; //!< EMF manual 2.3.11.17 Mirroring Enumeration
+
+#define U_SIZE_EMRSETMAPMODE (sizeof(U_EMRSETMAPMODE ))
+#define U_SIZE_EMRSETBKMODE (sizeof(U_EMRSETBKMODE ))
+#define U_SIZE_EMRSETPOLYFILLMODE (sizeof(U_EMRSETPOLYFILLMODE ))
+#define U_SIZE_EMRSETROP2 (sizeof(U_EMRSETROP2 ))
+#define U_SIZE_EMRSETSTRETCHBLTMODE (sizeof(U_EMRSETSTRETCHBLTMODE))
+#define U_SIZE_EMRSETTEXTALIGN (sizeof(U_EMRSETTEXTALIGN ))
+#define U_SIZE_EMRSELECTCLIPPATH (sizeof(U_EMRSELECTCLIPPATH ))
+#define U_SIZE_EMRSETICMMODE (sizeof(U_EMRSETICMMODE ))
+#define U_SIZE_EMRSETLAYOUT (sizeof(U_EMRSETLAYOUT ))
+
+/* Index 23 */
+/** EMF manual 2.3.11.13
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_COLORADJUSTMENT ColorAdjustment; //!< Color Adjustment
+} U_EMRSETCOLORADJUSTMENT,
+ *PU_EMRSETCOLORADJUSTMENT; //!< EMF manual 2.3.11.13
+#define U_SIZE_EMRSETCOLORADJUSTMENT (sizeof(U_EMRSETCOLORADJUSTMENT))
+
+/* Index 24, 25 */
+/** EMF manual 2.3.11.26
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_COLORREF crColor; //!< Color
+} U_EMRSETTEXTCOLOR,
+ U_EMRSETBKCOLOR, //!< EMF manual 2.3.11.10
+ *PU_EMRSETTEXTCOLOR, //!< EMF manual 2.3.11.26
+ *PU_EMRSETBKCOLOR; //!< EMF manual 2.3.11.10
+#define U_SIZE_EMRSETTEXTCOLOR (sizeof(U_EMRSETTEXTCOLOR))
+#define U_SIZE_EMRSETBKCOLOR (sizeof(U_EMRSETBKCOLOR ))
+
+/* Index 26 */
+/** EMF manual 2.3.2.4
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptlOffset; //!< Clipping region
+} U_EMROFFSETCLIPRGN,
+ *PU_EMROFFSETCLIPRGN; //!< EMF manual 2.3.2.4
+#define U_SIZE_EMROFFSETCLIPRGN (sizeof(U_EMROFFSETCLIPRGN))
+
+/* Index 27, 54 */
+/**
+EMF manual 2.3.11.4
+EMF manual 2.3.5.13
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptl; //!< Point coordinates
+} U_EMRMOVETOEX,
+ U_EMRLINETO, //!< EMF manual 2.3.5.13
+ *PU_EMRMOVETOEX, //!< EMF manual 2.3.11.4
+ *PU_EMRLINETO; //!< EMF manual 2.3.5.13
+#define U_SIZE_EMRMOVETOEX (sizeof(U_EMRMOVETOEX))
+#define U_SIZE_EMRLINETO (sizeof(U_EMRLINETO ))
+
+/* Index 28,33,52,59,60,61,65,66,68 */
+/** EMF manual 2.3.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+}
+ U_EMRSETMETARGN,
+ U_EMRSAVEDC, //!< EMF manual 2.3.11
+ U_EMRREALIZEPALETTE, //!< EMF manual 2.3.10
+ U_EMRBEGINPATH, //!< EMF manual 2.3.10
+ U_EMRENDPATH, //!< EMF manual 2.3.10
+ U_EMRCLOSEFIGURE, //!< EMF manual 2.3.10
+ U_EMRFLATTENPATH, //!< EMF manual 2.3.10
+ U_EMRWIDENPATH, //!< EMF manual 2.3.10
+ U_EMRABORTPATH, //!< EMF manual 2.3.10
+ *PU_EMRSETMETARGN, //!< EMF manual 2.3.2
+ *PU_EMRSAVEDC, //!< EMF manual 2.3.11
+ *PU_EMRREALIZEPALETTE, //!< EMF manual 2.3.10
+ *PU_EMRBEGINPATH, //!< EMF manual 2.3.10
+ *PU_EMRENDPATH, //!< EMF manual 2.3.10
+ *PU_EMRCLOSEFIGURE, //!< EMF manual 2.3.10
+ *PU_EMRFLATTENPATH, //!< EMF manual 2.3.10
+ *PU_EMRWIDENPATH, //!< EMF manual 2.3.10
+ *PU_EMRABORTPATH; //!< EMF manual 2.3.10
+#define U_SIZE_EMRSETMETARGN (sizeof(U_EMRSETMETARGN ))
+#define U_SIZE_EMRSAVEDC (sizeof(U_EMRSAVEDC ))
+#define U_SIZE_EMRREALIZEPALETTE (sizeof(U_EMRREALIZEPALETTE))
+#define U_SIZE_EMRBEGINPATH (sizeof(U_EMRBEGINPATH ))
+#define U_SIZE_EMRENDPATH (sizeof(U_EMRENDPATH ))
+#define U_SIZE_EMRCLOSEFIGURE (sizeof(U_EMRCLOSEFIGURE ))
+#define U_SIZE_EMRFLATTENPATH (sizeof(U_EMRFLATTENPATH ))
+#define U_SIZE_EMRWIDENPATH (sizeof(U_EMRWIDENPATH ))
+#define U_SIZE_EMRABORTPATH (sizeof(U_EMRABORTPATH ))
+
+/* Index 29,30 */
+/** EMF manual 2.3.2.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclClip; //!< Clipping Region
+} U_EMREXCLUDECLIPRECT,
+ U_EMRINTERSECTCLIPRECT, //!< EMF manual 2.3.2.3
+ *PU_EMREXCLUDECLIPRECT, //!< EMF manual 2.3.2.1
+ *PU_EMRINTERSECTCLIPRECT; //!< EMF manual 2.3.2.3
+#define U_SIZE_EMREXCLUDECLIPRECT (sizeof(U_EMREXCLUDECLIPRECT ))
+#define U_SIZE_EMRINTERSECTCLIPRECT (sizeof(U_EMRINTERSECTCLIPRECT ))
+
+/* Index 31,32 */
+/** EMF manual 2.3.11.7
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ int32_t xNum; //!< Horizontal multiplier (!=0)
+ int32_t xDenom; //!< Horizontal divisor (!=0)
+ int32_t yNum; //!< Vertical multiplier (!=0)
+ int32_t yDenom; //!< Vertical divisor (!=0)
+} U_EMRSCALEVIEWPORTEXTEX,
+ U_EMRSCALEWINDOWEXTEX, //!< EMF manual 2.3.11.8
+ *PU_EMRSCALEVIEWPORTEXTEX, //!< EMF manual 2.3.11.7
+ *PU_EMRSCALEWINDOWEXTEX; //!< EMF manual 2.3.11.8
+#define U_SIZE_EMRSCALEVIEWPORTEXTEX (sizeof(U_EMRSCALEVIEWPORTEXTEX))
+#define U_SIZE_EMRSCALEWINDOWEXTEX (sizeof(U_EMRSCALEWINDOWEXTEX ))
+
+/* Index 33 (see 28) */
+
+/* Index 34 */
+/** EMF manual 2.3.11.6
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ int32_t iRelative; //!< DC to restore. -1 is preceding
+} U_EMRRESTOREDC,
+ *PU_EMRRESTOREDC; //!< EMF manual 2.3.11.6
+#define U_SIZE_EMRRESTOREDC (sizeof(U_EMRRESTOREDC))
+
+/* Index 35 */
+/** EMF manual 2.3.12.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_XFORM xform; //!< Transform
+} U_EMRSETWORLDTRANSFORM,
+ *PU_EMRSETWORLDTRANSFORM; //!< EMF manual 2.3.12.2
+#define U_SIZE_EMRSETWORLDTRANSFORM (sizeof(U_EMRSETWORLDTRANSFORM))
+
+/* Index 36 */
+/** EMF manual 2.3.12.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_XFORM xform; //!< Transform
+ uint32_t iMode; //!< ModifyWorldTransformMode Enumeration
+} U_EMRMODIFYWORLDTRANSFORM,
+ *PU_EMRMODIFYWORLDTRANSFORM; //!< EMF manual 2.3.12.1
+#define U_SIZE_EMRMODIFYWORLDTRANSFORM (sizeof(U_EMRMODIFYWORLDTRANSFORM))
+
+/* Index 37,40 */
+/** EMF manual 2.3.8.3
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihObject; //!< Number of a stock or created object
+} U_EMRDELETEOBJECT,
+ U_EMRSELECTOBJECT, //!< EMF manual 2.3.8.5
+ *PU_EMRDELETEOBJECT, //!< EMF manual 2.3.8.3
+ *PU_EMRSELECTOBJECT; //!< EMF manual 2.3.8.5
+#define U_SIZE_EMRDELETEOBJECT (sizeof(U_EMRDELETEOBJECT))
+#define U_SIZE_EMRSELECTOBJECT (sizeof(U_EMRSELECTOBJECT))
+
+/* Index 38 */
+/** EMF manual 2.3.7.7
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPen; //!< Index to place object in EMF object table (this entry must not yet exist)
+ U_LOGPEN lopn; //!< Pen properties
+} U_EMRCREATEPEN,
+ *PU_EMRCREATEPEN; //!< EMF manual 2.3.7.7
+#define U_SIZE_EMRCREATEPEN (sizeof(U_EMRCREATEPEN))
+
+/* Index 39 */
+/** EMF manual 2.3.7.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist)
+ U_LOGBRUSH lb; //!< Brush properties
+} U_EMRCREATEBRUSHINDIRECT,
+ *PU_EMRCREATEBRUSHINDIRECT; //!< EMF manual 2.3.7.1
+#define U_SIZE_EMRCREATEBRUSHINDIRECT (sizeof(U_EMRCREATEBRUSHINDIRECT))
+
+/* Index 40 see 37 */
+
+/* Index 41 */
+/** EMF manual 2.3.5.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptlCenter; //!< Center in logical units
+ uint32_t nRadius; //!< Radius in logical units
+ U_FLOAT eStartAngle; //!< Starting angle in degrees (counter clockwise from x axis)
+ U_FLOAT eSweepAngle; //!< Sweep angle in degrees
+} U_EMRANGLEARC,
+ *PU_EMRANGLEARC; //!< EMF manual 2.3.5.1
+#define U_SIZE_EMRANGLEARC (sizeof(U_EMRANGLEARC))
+
+/* Index 42,43 */
+/** EMF manual 2.3.5.5
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBox; //!< bounding rectangle in logical units
+} U_EMRELLIPSE,
+ U_EMRRECTANGLE, //!< EMF manual 2.3.5.5
+ *PU_EMRELLIPSE, //!< EMF manual 2.3.5.5
+ *PU_EMRRECTANGLE; //!< EMF manual 2.3.5.34
+#define U_SIZE_EMRELLIPSE (sizeof(U_EMRELLIPSE ))
+#define U_SIZE_EMRRECTANGLE (sizeof(U_EMRRECTANGLE))
+
+/* Index 44 */
+/** EMF manual 2.3.5.35
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBox; //!< bounding rectangle in logical units
+ U_SIZEL szlCorner; //!< W & H in logical units of ellipse used to round corner
+} U_EMRROUNDRECT,
+ *PU_EMRROUNDRECT; //!< EMF manual 2.3.5.35
+#define U_SIZE_EMRROUNDRECT (sizeof(U_EMRROUNDRECT))
+
+/* Index 45, 46 ,47, 55 */
+/** EMF manual 2.3.5.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBox; //!< bounding rectangle in logical units
+ U_POINTL ptlStart; //!< Start point in logical units
+ U_POINTL ptlEnd; //!< End point in logical units
+} U_EMRARC,
+ U_EMRCHORD, //!< EMF manual 2.3.5.4
+ U_EMRPIE, //!< EMF manual 2.3.5.15
+ U_EMRARCTO, //!< EMF manual 2.3.5.3
+ *PU_EMRARC, //!< EMF manual 2.3.5.2
+ *PU_EMRCHORD, //!< EMF manual 2.3.5.4
+ *PU_EMRPIE, //!< EMF manual 2.3.5.15
+ *PU_EMRARCTO; //!< EMF manual 2.3.5.3
+#define U_SIZE_EMRARC (sizeof(U_EMRARC ))
+#define U_SIZE_EMRCHORD (sizeof(U_EMRCHORD))
+#define U_SIZE_EMRPIE (sizeof(U_EMRPIE ))
+#define U_SIZE_EMRARCTO (sizeof(U_EMRARCTO))
+
+/* Index 48 */
+/** EMF manual 2.3.8.6
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPal; //!< Index of a Palette object in the EMF object table
+} U_EMRSELECTPALETTE,
+ *PU_EMRSELECTPALETTE; //!< EMF manual 2.3.8.6
+#define U_SIZE_EMRSELECTPALETTE (sizeof(U_EMRSELECTPALETTE))
+
+/* Index 49 */
+/** EMF manual 2.3.7.6
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPal; //!< Index to place object in EMF object table (this entry must not yet exist)
+ U_LOGPALETTE lgpl; //!< Palette properties (variable size)
+} U_EMRCREATEPALETTE,
+ *PU_EMRCREATEPALETTE; //!< EMF manual 2.3.7.6
+#define U_SIZE_EMRCREATEPALETTE (sizeof(U_EMR) + sizeof(uint32_t) + U_SIZE_LOGPALETTE)
+
+/* Index 50 */
+/** EMF manual 2.3.8.8
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPal; //!< Index of a Palette object in the EMF object table
+ uint32_t iStart; //!< First Palette entry in selected object to set
+ U_NUM_LOGPLTNTRY cEntries; //!< Number of Palette entries in selected object to set
+ U_LOGPLTNTRY aPalEntries[1]; //!< Values to set with
+} U_EMRSETPALETTEENTRIES,
+ *PU_EMRSETPALETTEENTRIES; //!< EMF manual 2.3.8.8
+#define U_SIZE_EMRSETPALETTEENTRIES (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_NUM_LOGPLTNTRY))
+
+/* Index 51 */
+/** EMF manual 2.3.8.4
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPal; //!< Index of a Palette object in the EMF object table
+ uint32_t cEntries; //!< Number to expand or truncate the Palette entry list to.
+} U_EMRRESIZEPALETTE,
+ *PU_EMRRESIZEPALETTE; //!< EMF manual 2.3.8.4
+#define U_SIZE_EMRRESIZEPALETTE (sizeof(U_EMRRESIZEPALETTE))
+
+/* Index 52 (see 28) */
+
+/* Index 53 */
+/** EMF manual 2.3.5.6
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL ptlStart; //!< Start point in logical units
+ U_COLORREF crColor; //!< Color to fill with
+ uint32_t iMode; //!< FloodFill Enumeration
+} U_EMREXTFLOODFILL,
+ *PU_EMREXTFLOODFILL; //!< EMF manual 2.3.5.6
+#define U_SIZE_EMREXTFLOODFILL (sizeof(U_EMREXTFLOODFILL))
+
+/* Index 54 (see 27) */
+
+/* Index 55 (see 45) */
+
+/* Index 56 */
+/** EMF manual 2.3.5.20
+
+ followed by
+ uint8_t abTypes[1]; //!< Array of Point Enumeration
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_NUM_POINTL cptl; //!< Number of U_POINTL objects
+ U_POINTL aptl[1]; //!< Array of U_POINTL objects
+} U_EMRPOLYDRAW,
+ *PU_EMRPOLYDRAW; //!< EMF manual 2.3.5.20
+#define U_SIZE_EMRPOLYDRAW (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINTL))
+
+/* Index 57 */
+/** EMF manual 2.3.11.9
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t iArcDirection; //!< ArcDirection Enumeration
+} U_EMRSETARCDIRECTION,
+ *PU_EMRSETARCDIRECTION; //!< EMF manual 2.3.11.9
+#define U_SIZE_EMRSETARCDIRECTION (sizeof(U_EMRSETARCDIRECTION))
+
+/* Index 58 */
+/** EMF manual 2.3.11.21
+
+IMPORTANT!!!! The Microsoft structure uses a float for the miterlimit but the EMF file record
+uses an unsigned int. The latter form is used in this structure.
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t eMiterLimit; //!< Miter limit (max value of mitered length / line width)
+} U_EMRSETMITERLIMIT,
+ *PU_EMRSETMITERLIMIT; //!< EMF manual 2.3.11.21
+#define U_SIZE_EMRSETMITERLIMIT (sizeof(U_EMRSETMITERLIMIT))
+
+/* Index 59,60,61 (see 28) */
+
+/* Index 62,63,64 */
+/** EMF manual 2.3.5.9
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+} U_EMRFILLPATH,
+ U_EMRSTROKEANDFILLPATH, //!< EMF manual 2.3.5.38
+ U_EMRSTROKEPATH, //!< EMF manual 2.3.5.39
+ *PU_EMRFILLPATH, //!< EMF manual 2.3.5.9
+ *PU_EMRSTROKEANDFILLPATH, //!< EMF manual 2.3.5.38
+ *PU_EMRSTROKEPATH; //!< EMF manual 2.3.5.39
+#define U_SIZE_EMRFILLPATH (sizeof(U_EMRFILLPATH ))
+#define U_SIZE_EMRSTROKEANDFILLPATH (sizeof(U_EMRSTROKEANDFILLPATH))
+#define U_SIZE_EMRSTROKEPATH (sizeof(U_EMRSTROKEPATH ))
+
+/* Index 65,66 (see 28) */
+/* Index 67 (see 17) */
+/* Index 68 (see 28) */
+/* Index 69 (not a defined U_EMR record type ) */
+
+
+/* Index 70 */
+/** EMF manual 2.3.3.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbData; //!< Number of bytes in comment
+ uint8_t Data[1]; //!< Comment (any binary data, interpretation is program specific)
+} U_EMRCOMMENT,
+ *PU_EMRCOMMENT; //!< EMF manual 2.3.3.1, AKA GDICOMMENT
+#define U_SIZE_EMRCOMMENT (sizeof(U_EMR) + sizeof(U_CBDATA))
+
+/* variant comment types */
+/** EMF manual 2.3.3.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbData; //!< Number of bytes in comment
+ uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_EMFPLUSRECORD
+ uint8_t Data[1]; //!< EMF Plus record
+} U_EMRCOMMENT_EMFPLUS,
+ *PU_EMRCOMMENT_EMFPLUS; //!< EMF manual 2.3.3.2, EMF Plus comment
+#define U_SIZE_EMRCOMMENT_EMFPLUS (sizeof(U_EMR) + sizeof(U_CBDATA) + sizeof(uint32_t))
+
+/** EMF manual 2.3.3.3
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbData; //!< Number of bytes in comment
+ uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_SPOOL
+ uint32_t esrIdent; //!< EMFSpoolRecordIdentifier, may be U_EMR_COMMENT_SPOOLFONTDEF
+ uint8_t Data[1]; //!< EMF Spool records
+} U_EMRCOMMENT_SPOOL,
+ *PU_EMRCOMMENT_SPOOL; //!< EMF manual 2.3.3.3, EMF Spool comment
+#define U_SIZE_EMRCOMMENT_SPOOL (sizeof(U_EMR) + sizeof(U_CBDATA) + 2*sizeof(uint32_t))
+
+/** EMF manual 2.3.3.4
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbData; //!< Number of bytes in comment
+ uint32_t cIdent; //!< Comment identifier, must be U_EMR_COMMENT_PUBLIC
+ uint32_t pcIdent; //!< Public Comment Identifier, from EMRComment Enumeration
+ uint8_t Data[1]; //!< Public comment data
+} U_EMRCOMMENT_PUBLIC,
+ *PU_EMRCOMMENT_PUBLIC; //!< EMF manual 2.3.3.4, EMF Public comment
+#define U_SIZE_EMRCOMMENT_PUBLIC (sizeof(U_EMR) + sizeof(U_CBDATA) + 2*sizeof(uint32_t))
+
+/* Index 71 */
+/** EMF manual 2.3.5.10
+ followed by a variable number of U_RECTLs
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data
+ uint32_t ihBrush; //!< Index of a Brush object in the EMF object table
+ U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure
+} U_EMRFILLRGN,
+ *PU_EMRFILLRGN; //!< EMF manual 2.3.5.10
+#define U_SIZE_EMRFILLRGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA) + sizeof(uint32_t))
+
+/* Index 72 */
+/** EMF manual 2.3.5.11
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data
+ uint32_t ihBrush; //!< Index of a Brush object in the EMF object table
+ U_SIZEL szlStroke; //!< W & H of Brush stroke
+ U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure
+} U_EMRFRAMERGN,
+ *PU_EMRFRAMERGN; //!< EMF manual 2.3.5.11
+#define U_SIZE_EMRFRAMERGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA) + sizeof(uint32_t) + sizeof(U_SIZEL))
+
+/* Index 73,74 */
+/** EMF manual 2.3.11.3
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data
+ U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure
+} U_EMRINVERTRGN,
+ U_EMRPAINTRGN, //!< EMF manual 2.3.5.14
+ *PU_EMRINVERTRGN, //!< EMF manual 2.3.11.3
+ *PU_EMRPAINTRGN; //!< EMF manual 2.3.5.14
+#define U_SIZE_EMRINVERTRGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA))
+#define U_SIZE_EMRPAINTRGN U_SIZE_EMRINVERTRGN
+
+/* Index 75 */
+/** EMF manual 2.3.2.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBRGNDATA cbRgnData; //!< Size in bytes of Region data
+ uint32_t iMode; //!< RegionMode Enumeration
+ U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure
+} U_EMREXTSELECTCLIPRGN,
+ *PU_EMREXTSELECTCLIPRGN; //!< EMF manual 2.3.2.2
+#define U_SIZE_EMREXTSELECTCLIPRGN (sizeof(U_EMR) + sizeof(U_CBRGNDATA) + sizeof(uint32_t))
+
+/* Index 76 */
+/** EMF manual 2.3.1.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL cDest; //!< Destination width in logical units
+ uint32_t dwRop; //!< Ternary Raster Operation enumeration
+ U_POINTL Src; //!< Source retangle UL corner in logical units
+ U_XFORM xformSrc; //!< Source bitmap transform (world to page coordinates)
+ U_COLORREF crBkColorSrc; //!< Source bitmap background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ //!< Record may include optional bitmapbuffer
+} U_EMRBITBLT,
+ *PU_EMRBITBLT; //!< EMF manual 2.3.1.2
+#define U_SIZE_EMRBITBLT (sizeof(U_EMRBITBLT))
+
+/* Index 77 */
+/** EMF manual 2.3.1.6
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL cDest; //!< Destination width in logical units
+ uint32_t dwRop; //!< Ternary Raster Operation enumeration
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_XFORM xformSrc; //!< Transform to apply to source
+ U_COLORREF crBkColorSrc; //!< Background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ U_POINTL cSrc; //!< Src W & H in logical units
+ //!< Record may include optional bitmapbuffer
+} U_EMRSTRETCHBLT,
+ *PU_EMRSTRETCHBLT; //!< EMF manual 2.3.1.6
+#define U_SIZE_EMRSTRETCHBLT (sizeof(U_EMRSTRETCHBLT))
+
+/* Index 78 */
+/** EMF manual 2.3.1.3
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL cDest; //!< Destination width in logical units
+ uint32_t dwRop; //!< Ternary Raster Operation enumeration
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_XFORM xformSrc; //!< Transform to apply to source
+ U_COLORREF crBkColorSrc; //!< Background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within srcbitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the src bitmap (within srcbitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of src bitmap
+ U_POINTL Mask; //!< Mask UL corner in logical units
+ uint32_t iUsageMask; //!< DIBcolors Enumeration
+ U_OFFBMIMSK offBmiMask; //!< Offset in bytes to U_BITMAPINFO (within maskbitmapbuffer)
+ U_CBBMIMSK cbBmiMask; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSMSK offBitsMask; //!< Offset in bytes to the mask bitmap (within maskbitmapbuffer)
+ U_CBBITSMSK cbBitsMask; //!< Size in bytes of bitmap
+ //!< Record may include optional Source and mask bitmapbuffers
+} U_EMRMASKBLT,
+ *PU_EMRMASKBLT; //!< EMF manual 2.3.1.3
+#define U_SIZE_EMRMASKBLT (sizeof(U_EMRMASKBLT))
+
+/* Index 79 */
+/** EMF manual 2.3.1.4
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL aptlDst[3]; //!< Defines parallelogram, UL, UR, LL corners, LR is derived.
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_POINTL cSrc; //!< Src W & H in logical units
+ U_XFORM xformSrc; //!< Transform to apply to source
+ U_COLORREF crBkColorSrc; //!< Background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within srcbitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the src bitmap (within srcbitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of src bitmap
+ U_POINTL Mask; //!< Mask UL corner in logical units
+ uint32_t iUsageMask; //!< DIBcolors Enumeration
+ U_OFFBMIMSK offBmiMask; //!< Offset in bytes to U_BITMAPINFO (within maskbitmapbuffer)
+ U_CBBMIMSK cbBmiMask; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSMSK offBitsMask; //!< Offset in bytes to the mask bitmap (within maskbitmapbuffer)
+ U_CBBITSMSK cbBitsMask; //!< Size in bytes of bitmap
+ //!< Record may include optional Source and mask bitmapbuffers
+} U_EMRPLGBLT,
+ *PU_EMRPLGBLT; //!< EMF manual 2.3.1.4
+#define U_SIZE_EMRPLGBLT (sizeof(U_EMRPLGBLT))
+
+/* Index 80 */
+/** EMF manual 2.3.1.5
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL Src; //!< Source LL corner in logical units
+ U_POINTL cSrc; //!< Src W & H in logical units
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to bitmap
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ uint32_t iUsageSrc; //!< DIBColors Enumeration
+ uint32_t iStartScan; //!< First scan line
+ uint32_t cScans; //!< Number of scan lines
+ //!< Record may includes optional bitmapbuffer
+} U_EMRSETDIBITSTODEVICE,
+ *PU_EMRSETDIBITSTODEVICE; //!< EMF manual 2.3.1.5
+#define U_SIZE_EMRSETDIBITSTODEVICE (sizeof(U_EMRSETDIBITSTODEVICE))
+
+/* Index 81 */
+/** EMF manual 2.3.1.7
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_POINTL cSrc; //!< Source W & H in logical units
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to bitmap
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ uint32_t iUsageSrc; //!< DIBColors Enumeration
+ uint32_t dwRop; //!< Ternary Raster Operation enumeration
+ U_POINTL cDest; //!< Destination W & H in logical units
+ //!< Record may includes optional bitmapbuffer
+} U_EMRSTRETCHDIBITS,
+ *PU_EMRSTRETCHDIBITS; //!< EMF manual 2.3.1.7
+#define U_SIZE_EMRSTRETCHDIBITS (sizeof(U_EMRSTRETCHDIBITS))
+
+/* Index 82 */
+/** EMF manual 2.3.7.8
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihFont; //!< Index of the font in the EMF object table
+ U_LOGFONT_PANOSE elfw; //!< Font parameters, either U_LOGFONT or U_LOGFONT_PANOSE, the latter is bigger so use that type here
+} U_EMREXTCREATEFONTINDIRECTW,
+ *PU_EMREXTCREATEFONTINDIRECTW; //!< EMF manual 2.3.7.8
+#define U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE (sizeof(U_EMR) + 4 + sizeof(U_LOGFONT_PANOSE))
+#define U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT (sizeof(U_EMR) + 4 + sizeof(U_LOGFONT))
+
+/* Index 83,84 */
+/** EMF manual 2.3.5.7
+
+Variable and optional fields may follow core structure in record:\n
+
+ U_RECTL rcl; absent when fOptions & U_ETO_NO_RECT) grayed/clipping/opaque rectangle
+
+ U_OFFDX offDx; (required) Offset in bytes to the character spacing array from the start of the RECORD
+
+ uint32_t Dx (optional) character spacing array (Required, but position is not static.)
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ uint32_t iGraphicsMode; //!< GraphicsMode Enumeration
+ U_FLOAT exScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE)
+ U_FLOAT eyScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE)
+ U_EMRTEXT emrtext; //!< Text parameters
+} U_EMREXTTEXTOUTA,
+ U_EMREXTTEXTOUTW, //!< EMF manual 2.3.5.8
+ *PU_EMREXTTEXTOUTA, //!< EMF manual 2.3.5.7
+ *PU_EMREXTTEXTOUTW; //!< EMF manual 2.3.5.8
+#define U_SIZE_EMREXTTEXTOUTA (sizeof(U_EMREXTTEXTOUTA))
+#define U_SIZE_EMREXTTEXTOUTW (sizeof(U_EMREXTTEXTOUTW))
+
+/* Index 85,86,87,88,89 */
+/** EMF manual 2.3.5.17
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_NUM_POINT16 cpts; //!< Number of POINT16 in array
+ U_POINT16 apts[1]; //!< Array of POINT16
+} U_EMRPOLYBEZIER16,
+ U_EMRPOLYGON16, //!< EMF manual 2.3.5.23
+ U_EMRPOLYLINE16, //!< EMF manual 2.3.5.25
+ U_EMRPOLYBEZIERTO16, //!< EMF manual 2.3.5.19
+ U_EMRPOLYLINETO16, //!< EMF manual 2.3.5.27
+ *PU_EMRPOLYBEZIER16, //!< EMF manual 2.3.5.17
+ *PU_EMRPOLYGON16, //!< EMF manual 2.3.5.23
+ *PU_EMRPOLYLINE16, //!< EMF manual 2.3.5.25
+ *PU_EMRPOLYBEZIERTO16, //!< EMF manual 2.3.5.19
+ *PU_EMRPOLYLINETO16; //!< EMF manual 2.3.5.27
+#define U_SIZE_EMRPOLYBEZIER16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16))
+#define U_SIZE_EMRPOLYGON16 U_SIZE_EMRPOLYBEZIER16
+#define U_SIZE_EMRPOLYLINE16 U_SIZE_EMRPOLYBEZIER16
+#define U_SIZE_EMRPOLYBEZIERTO16 U_SIZE_EMRPOLYBEZIER16
+#define U_SIZE_EMRPOLYLINETO16 U_SIZE_EMRPOLYBEZIER16
+/* Index 90,91 */
+/** EMF manual 2.3.5.31
+
+ followed by
+ U_POINT16 apts[1]; //!< array of point16
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_NUM_POLYCOUNTS nPolys; //!< Number of elements in aPolyCounts
+ U_NUM_POINT16 cpts; //!< Total number of points (over all poly)
+ U_POLYCOUNTS aPolyCounts[1]; //!< Number of points in each poly (sequential)
+} U_EMRPOLYPOLYLINE16,
+ U_EMRPOLYPOLYGON16, //!< EMF manual 2.3.5.29
+ *PU_EMRPOLYPOLYLINE16, //!< EMF manual 2.3.5.31
+ *PU_EMRPOLYPOLYGON16; //!< EMF manual 2.3.5.29
+#define U_SIZE_EMRPOLYPOLYLINE16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_NUM_POINT16))
+#define U_SIZE_EMRPOLYPOLYGON16 U_SIZE_EMRPOLYPOLYLINE16
+
+/* Index 92 */
+/** EMF manual 2.3.5.21
+
+ followed by
+ uint8_t abTypes[1]; //!< Array of Point Enumeration
+
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_NUM_POINT16 cpts; //!< Total number of points (over all poly)
+ U_POINT16 apts[1]; //!< array of points
+} U_EMRPOLYDRAW16,
+ *PU_EMRPOLYDRAW16; //!< EMF manual 2.3.5.21
+#define U_SIZE_EMRPOLYDRAW16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16))
+
+/* Index 93 */
+/** EMF manual 2.3.7.5
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist)
+ uint32_t iUsage; //!< DIBcolors Enumeration
+ U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIBbitmapbuffer)
+ U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIBbitmapbuffer
+ U_CBBITS cbBits; //!< Size in bytes of DIB bitmap
+ //!< Record may include optional DIB bitmapbuffer
+} U_EMRCREATEMONOBRUSH,
+ *PU_EMRCREATEMONOBRUSH; //!< EMF manual 2.3.7.5
+#define U_SIZE_EMRCREATEMONOBRUSH (sizeof(U_EMRCREATEMONOBRUSH))
+
+/* Index 94 */
+/** EMF manual 2.3.7.4
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihBrush; //!< Index to place object in EMF object table (this entry must not yet exist)
+ uint32_t iUsage; //!< DIBcolors Enumeration
+ U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIB bitmapbuffer)
+ U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIB bitmapbuffer
+ U_CBBITS cbBits; //!< Size in bytes of DIB bitmap
+ //!< Record may include optional DIB bitmapbuffer
+} U_EMRCREATEDIBPATTERNBRUSHPT,
+ *PU_EMRCREATEDIBPATTERNBRUSHPT; //!< EMF manual 2.3.7.4
+#define U_SIZE_EMRCREATEDIBPATTERNBRUSHPT (sizeof(U_EMRCREATEDIBPATTERNBRUSHPT))
+
+/* Index 95 */
+/** EMF manual 2.3.7.9
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihPen; //!< Index to place object in EMF object table (this entry must not yet exist)
+ U_OFFBMI offBmi; //!< Offset in bytes to U_BITMAPINFO (within DIB bitmapbuffer)
+ U_CBBMI cbBmi; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITS offBits; //!< Offset in bytes to the DIB bitmap data (within DIB bitmapbuffer
+ U_CBBITS cbBits; //!< Size in bytes of DIB bitmap
+ U_EXTLOGPEN elp; //!< Pen parameters (Size is Variable!!!!)
+ //!< Record may include optional DIB bitmap
+} U_EMREXTCREATEPEN,
+ *PU_EMREXTCREATEPEN; //!< EMF manual 2.3.7.9
+#define U_SIZE_EMREXTCREATEPEN (sizeof(U_EMREXTCREATEPEN) - sizeof(U_EXTLOGPEN) + U_SIZE_EXTLOGPEN)
+
+/* Index 96.97 */
+/** EMF manual 2.3.5.32
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ uint32_t iGraphicsMode; //!< GraphicsMode Enumeration
+ U_FLOAT exScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE)
+ U_FLOAT eyScale; //!< scale to 0.01 mm units ( only if iGraphicsMode & U_GM_COMPATIBLE)
+ U_NUM_EMRTEXT cStrings; //!< Number of U_EMRTEXT in array
+ U_EMRTEXT emrtext[1]; //!< Text parameters
+} U_EMRPOLYTEXTOUTA,
+ U_EMRPOLYTEXTOUTW, //!< EMF manual 2.3.5.33
+ *PU_EMRPOLYTEXTOUTA, //!< EMF manual 2.3.5.32
+ *PU_EMRPOLYTEXTOUTW; //!< EMF manual 2.3.5.33
+#define U_SIZE_EMRPOLYTEXTOUTA (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t) + 2*sizeof(U_FLOAT) + sizeof(U_NUM_EMRTEXT))
+#define U_SIZE_EMRPOLYTEXTOUTW U_SIZE_EMRPOLYTEXTOUTA
+
+/* Index 98 (see 17) */
+
+/* Index 99 */
+/** EMF manual 2.3.7.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihCS; //!< Index to place object in EMF object table (this entry must not yet exist)
+ U_LOGCOLORSPACEA lcs; //!< ColorSpace parameters
+} U_EMRCREATECOLORSPACE,
+ *PU_EMRCREATECOLORSPACE; //!< EMF manual 2.3.7.2
+#define U_SIZE_EMRCREATECOLORSPACE (sizeof(U_EMRCREATECOLORSPACE))
+
+/* Index 100,101 */
+/** EMF manual 2.3.8.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihCS; //!< Index of object in EMF object table
+} U_EMRDELETECOLORSPACE,
+ U_EMRSETCOLORSPACE, //!< EMF manual 2.3.8.7
+ *PU_EMRDELETECOLORSPACE, //!< EMF manual 2.3.8.2
+ *PU_EMRSETCOLORSPACE; //!< EMF manual 2.3.8.7
+#define U_SIZE_EMRDELETECOLORSPACE (sizeof(U_EMRDELETECOLORSPACE))
+#define U_SIZE_EMRSETCOLORSPACE (sizeof(U_EMRSETCOLORSPACE ))
+
+/* Index 102 */
+/** EMF manual 2.3.9.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbData; //!< Size of OpenGL data in bytes
+ U_DATA Data[1]; //!< OpenGL data
+} U_EMRGLSRECORD,
+ *PU_EMRGLSRECORD; //!< EMF manual 2.3.9.2
+#define U_SIZE_EMRGLSRECORD (sizeof(U_EMR) + sizeof(U_CBDATA))
+
+/* Index 103 */
+/** EMF manual 2.3.9.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_CBDATA cbData; //!< Size of OpenGL data in bytes
+ U_DATA Data[1]; //!< OpenGL data
+} U_EMRGLSBOUNDEDRECORD,
+ *PU_EMRGLSBOUNDEDRECORD; //!< EMF manual 2.3.9.1
+#define U_SIZE_EMRGLSBOUNDEDRECORD (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBDATA))
+
+/* Index 104 */
+/** EMF manual 2.3.11.5
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_PIXELFORMATDESCRIPTOR pfd; //!< PixelFormatDescriptor
+} U_EMRPIXELFORMAT,
+ *PU_EMRPIXELFORMAT; //!< EMF manual 2.3.11.5
+#define U_SIZE_EMRPIXELFORMAT (sizeof(U_EMRPIXELFORMAT))
+
+/* Index 105 */
+/** EMF manual 2.3.6.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cjIn; //!< Number of bytes to send to printer driver
+ U_DATA Data[1]; //!< Data to send
+} U_EMRDRAWESCAPE,
+ *PU_EMRDRAWESCAPE; //!< EMF manual 2.3.6.1
+#define U_SIZE_EMRDRAWESCAPE (sizeof(U_EMR) + sizeof(U_CBDATA))
+
+/* Index 106 */
+/** EMF manual 2.3.6.2
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cjIn; //!< Number of bytes to send to printer driver
+ U_DATA Data[1]; //!< Data to send
+} U_EMREXTESCAPE,
+ *PU_EMREXTESCAPE; //!< EMF manual 2.3.6.2
+#define U_SIZE_EMREXTESCAPE (sizeof(U_EMR) + sizeof(U_CBDATA))
+
+/* Index 107 (not implemented ) */
+
+/* Index 108 */
+/** EMF manual 2.3.5.37
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_POINTL Dest; //!< Where to draw the text
+ U_NUM_STR cChars; //!< Characters in TextString (not null terminated)
+ uint32_t fuOptions; //!< ExtTextOutOptions Enumeration
+ uint32_t iGraphicsMode; //!< GraphicsMode Enumeration
+ U_FLOAT exScale; //!< scale on X axis
+ U_FLOAT eyScale; //!< scale on Y axis
+//!< the tail end of this record is variable.
+//!< U_RECTL rclBounds; Record may include optional Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT)
+//!< uint32_t TextString; text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit)
+} U_EMRSMALLTEXTOUT,
+ *PU_EMRSMALLTEXTOUT; //!< EMF manual 2.3.5.37
+#define U_SIZE_EMRSMALLTEXTOUT (sizeof(U_EMRSMALLTEXTOUT))
+
+/* Index 109 (not implemented )
+EMF manual 2.3.11.2
+*/
+
+/* Index 110 */
+/** EMF manual 2.3.6.3
+
+ followed by
+ uint8_t Data[1]; //!< Data for printer driver
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_CBDATA cbDriver; //!< Number of bytes in driver name (note, BYTES, not CHARACTERS)
+ U_CBDATA cbData; //!< Number of bytes in data
+ uint16_t Driver[1]; //!< Driver name in uint16_t characters, null terminated
+} U_EMRNAMEDESCAPE,
+ *PU_EMRNAMEDESCAPE; //!< EMF manual 2.3.6.3
+#define U_SIZE_EMRNAMEDESCAPE (sizeof(U_EMR) + 2*sizeof(U_CBDATA))
+
+/* Index 111-113 (not implemented )
+ EMF manual 2.3.8.1
+ EMF manual 2.3.11.15
+ EMF manual 2.3.11.16
+*/
+
+/* Index 114 */
+/** EMF manual 2.3.1.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL cDest; //!< Destination W & H in logical units
+ U_BLEND Blend; //!< Blend Function
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_XFORM xformSrc; //!< Transform to apply to source
+ U_COLORREF crBkColorSrc; //!< Background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ U_POINTL cSrc; //!< Source W & H in logical units
+ //!< Record may include optional DIB bitmap
+} U_EMRALPHABLEND,
+ *PU_EMRALPHABLEND; //!< EMF manual 2.3.1.1
+#define U_SIZE_EMRALPHABLEND (sizeof(U_EMRALPHABLEND))
+
+/* Index 115 (see 17) */
+
+/* Index 116 */
+/** EMF manual 2.3.1.8
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_POINTL Dest; //!< Destination UL corner in logical units
+ U_POINTL cDest; //!< Destination W & H in logical units
+ uint32_t TColor; //!< Bitmap color to be treated as transparent
+ U_POINTL Src; //!< Source UL corner in logical units
+ U_XFORM xformSrc; //!< Transform to apply to source
+ U_COLORREF crBkColorSrc; //!< Background color
+ uint32_t iUsageSrc; //!< DIBcolors Enumeration
+ U_OFFBMISRC offBmiSrc; //!< Offset in bytes to U_BITMAPINFO (within bitmapbuffer)
+ U_CBBMISRC cbBmiSrc; //!< Size in bytes of U_BITMAPINFO
+ U_OFFBITSSRC offBitsSrc; //!< Offset in bytes to the bitmap (within bitmapbuffer)
+ U_CBBITS cbBitsSrc; //!< Size in bytes of bitmap
+ U_POINTL cSrc; //!< Source W & H in logical units
+ //!< Record may includes optional bitmapbuffer
+} U_EMRTRANSPARENTBLT,
+ *PU_EMRTRANSPARENTBLT; //!< EMF manual 2.3.1.8
+#define U_SIZE_EMRTRANSPARENTBLT (sizeof(U_EMRTRANSPARENTBLT))
+
+/* Index 117 (not a defined U_EMR record type ) */
+
+/* Index 118 */
+/** EMF manual 2.3.5.12
+
+ followed by
+ U_TRIVERTEX TriVert[1]; Array of TriVertex objects
+ uint32_t GradObj[1]; Array of gradient objects (each has 2 or 3 indices into TriVert array)
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ U_RECTL rclBounds; //!< Bounding rectangle in device units
+ U_NUM_TRIVERTEX nTriVert; //!< Number of TriVertex objects
+ U_NUM_GRADOBJ nGradObj; //!< Number of gradient triangle/rectangle objects
+ uint32_t ulMode; //!< Gradientfill Enumeration (determines Triangle/Rectangle)
+} U_EMRGRADIENTFILL,
+ *PU_EMRGRADIENTFILL; //!< EMF manual 2.3.5.12
+#define U_SIZE_EMRGRADIENTFILL (sizeof(U_EMRGRADIENTFILL))
+
+/* Index 119,120 (not implemented )
+EMF manual 2.3.11.18
+EMF manual 2.3.11.27
+*/
+
+/* Index 121 */
+/** EMF manual 2.3.11.1
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t dwAction; //!< ColorSpace Enumeration
+ uint32_t dwFlags; //!< ColorMatchToTarget Enumeration
+ U_CBNAME cbName; //!< Number of bytes in UTF16 name of the color profile
+ U_CBDATA cbData; //!< Number of bytes of the target profile
+ uint8_t Data[1]; //!< Data of size cbName+cbData: Name in UTF16 then color profile data
+} U_EMRCOLORMATCHTOTARGETW,
+ *PU_EMRCOLORMATCHTOTARGETW; //!< EMF manual 2.3.11.1
+#define U_SIZE_EMRCOLORMATCHTOTARGETW (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_CBNAME) + sizeof(U_CBDATA))
+
+/* Index 122 */
+/** EMF manual 2.3.7.3
+*/
+typedef struct {
+ U_EMR emr; //!< U_EMR
+ uint32_t ihCS; //!< Index of the logical color space object in the EMF object table
+ U_LOGCOLORSPACEW lcs; //!< Description of the color profile
+ uint32_t dwFlags; //!< If low bit set Data is present
+ U_CBDATA cbData; //!< Number of bytes of theData field.
+ uint8_t Data[1]; //!< (Optional, dwFlags & 1) color profile data
+} U_EMRCREATECOLORSPACEW,
+ *PU_EMRCREATECOLORSPACEW; //!< EMF manual 2.3.7.3
+#define U_SIZE_EMRCREATECOLORSPACEW (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(U_CBDATA))
+
+// records which are not documented, so we have no idea what to do with them
+#define U_SIZE_EMRUNDEFINED 2048
+
+// ************************************************************************************************
+// Utility function structures
+
+/**
+ Storage for keeping track of properties of the growing EMF file as records are added.
+*/
+typedef struct {
+ FILE *fp; //!< Open file
+ size_t allocated; //!< Size of the buffer
+ size_t used; //!< Amount consumed
+ uint32_t records; //!< Number of records already contained
+ uint16_t ignore; //!< size padding,not used
+ uint32_t PalEntries; //!< Number of PalEntries (set from U_EMREOF)
+ uint32_t chunk; //!< Number of bytes to add when more space is needed
+ char *buf; //!< Buffer for constructing the EMF in memory
+} EMFTRACK;
+
+/**
+ The various create functions need a place to put their handles, these are stored in the table below.
+ We don't actually do anything much with these handles, that is up to whatever program finally plays back the EMF, but
+ we do need to keep track of the numbers so that they are not accidentally reused. This structure is used for that,
+ and all *_set functions that touch a handle reference it.
+
+ Stock objects are not used in this limited model, so libUEMF cannot detect if a handle is still in use. Nor can it
+ tell when a handle has been deselected (by selecting another handle for the same type of graphic object, and thus
+ made deleteable). End user code must keep track of this for itself.
+*/
+typedef struct {
+ uint32_t *table; //!< Array Buffer for constructing the EMF in memory
+ uint32_t *stack; //!< handles are either on the stack or in the table
+ size_t allocated; //!< Slots in the buffer
+ size_t chunk; //!< Number to add if a realloc is required
+ uint32_t sptr; //!< Pointer to next available handle in the stack
+ uint32_t top; //!< Highest slot occupied (currently)
+ uint32_t peak; //!< Highest slot occupied (ever)
+} EMFHANDLES;
+
+/**
+ 2 x 2 matrix, used by xform_alt_set() function.
+*/
+typedef struct {
+ double M11; //!< Matrix element 1,1
+ double M12; //!< Matrix element 1,2
+ double M21; //!< Matrix element 2,1
+ double M22; //!< Matrix element 2,2
+} U_MAT2X2,
+ *PU_MAT2X2; //!< 2 x 2 matrix, used by xform_alt_set() function.
+
+// ************************************************************************************************
+// Prototypes
+
+//! \cond
+int memprobe(const void *buf, size_t size);
+void wchar8show(const char *src);
+void wchar16show(const uint16_t *src);
+void wchar32show(const uint32_t *src);
+void wchartshow(const wchar_t *src);
+void dumpeht(char *string, unsigned int *handle, EMFHANDLES *eht);
+
+
+char *U_emr_names(unsigned int idx);
+uint32_t *dx_set(int32_t height, uint32_t weight, uint32_t members);
+uint32_t emr_properties(uint32_t type);
+int emr_arc_points(PU_ENHMETARECORD record, int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size);
+int emr_arc_points_common(PU_RECTL rclBox, PU_POINTL ArcStart, PU_POINTL ArcEnd,
+ int *f1, int f2, PU_PAIRF center, PU_PAIRF start, PU_PAIRF end, PU_PAIRF size);
+int get_real_color_count(const char *Bmih);
+int get_real_color_icount(int Colors, int BitCount, int Width, int Height);
+int RGBA_to_DIB(char **px, uint32_t *cbPx, PU_RGBQUAD *ct, int *numCt,
+ const char *rgba_px, int w, int h, int stride, uint32_t colortype, int use_ct, int invert);
+int get_DIB_params( const char *record, uint32_t offBitsSrc, uint32_t offBmiSrc,
+ const char **px, const U_RGBQUAD **ct, uint32_t *numCt,
+ uint32_t *width, uint32_t *height, uint32_t *colortype, uint32_t *invert );
+int DIB_to_RGBA(const char *px, const U_RGBQUAD *ct, int numCt,
+ char **rgba_px, int w, int h, uint32_t colortype, int use_ct, int invert);
+char *RGBA_to_RGBA(char *rgba_px, int w, int h, int sl, int st, int *ew, int *eh);
+
+int device_size(const int xmm, const int ymm, const float dpmm, U_SIZEL *szlDev, U_SIZEL *szlMm);
+int drawing_size(const int xmm, const int yum, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame);
+
+int emf_start(const char *name, const uint32_t initsize, const uint32_t chunksize, EMFTRACK **et);
+int emf_finish(EMFTRACK *et, EMFHANDLES *eht);
+int emf_free(EMFTRACK **et);
+int emf_append(U_ENHMETARECORD *rec, EMFTRACK *et, int freerec);
+int emf_readdata(const char *filename, char **contents, size_t *length);
+FILE *emf_fopen(const char *filename, const int mode);
+
+
+/* use these instead*/
+int emf_htable_create(uint32_t initsize, uint32_t chunksize, EMFHANDLES **eht);
+int emf_htable_delete(uint32_t *ih, EMFHANDLES *eht);
+int emf_htable_insert(uint32_t *ih, EMFHANDLES *eht);
+int emf_htable_free(EMFHANDLES **eht);
+/* Deprecated forms */
+#define htable_create emf_htable_create
+#define htable_delete emf_htable_delete
+#define htable_insert emf_htable_insert
+#define htable_free emf_htable_free
+
+U_RECTL rectl_set(U_POINTL ul, U_POINTL lr);
+void rectli_set(PU_RECTL array, int index, U_POINTL ul, U_POINTL lr);
+U_SIZEL sizel_set(int32_t x, int32_t y);
+U_POINTL point32_set(int32_t x, int32_t y);
+#define point_set point32_set
+#define pointl_set point32_set
+U_POINT16 point16_set(int16_t x, int16_t y);
+U_PANOSE panose_set(uint8_t bFamilyType, uint8_t bSerifStyle, uint8_t bWeight, uint8_t bProportion,
+ uint8_t bContrast, uint8_t bStrokeVariation, uint8_t bArmStyle, uint8_t bLetterform,
+ uint8_t bMidline, uint8_t bXHeight );
+U_COLORREF colorref3_set(uint8_t red, uint8_t green, uint8_t blue);
+U_COLORREF colorref4_set(uint8_t red, uint8_t green, uint8_t blue, uint8_t reserved);
+U_RGBQUAD rgbquad_set(uint8_t red,uint8_t green, uint8_t blue, uint8_t reserved);
+U_LOGBRUSH logbrush_set(uint32_t lbStyle, U_COLORREF lbColor, int32_t lbHatch);
+U_XFORM xform_set(U_FLOAT eM11, U_FLOAT eM12, U_FLOAT eM21, U_FLOAT eM22, U_FLOAT eDx, U_FLOAT eDy);
+U_XFORM xform_alt_set(U_FLOAT scale, U_FLOAT ratio, U_FLOAT rot, U_FLOAT axisrot, U_FLOAT eDx, U_FLOAT eDy);
+U_LOGPEN logpen_set( uint32_t lopnStyle, U_POINT lopnWidth, U_COLORREF lopnColor );
+PU_EXTLOGPEN extlogpen_set(uint32_t elpPenStyle, uint32_t elpWidth, uint32_t elpBrushStyle,
+ U_COLORREF elpColor, int32_t elpHatch, U_NUM_STYLEENTRY elpNumEntries, U_STYLEENTRY *elpStyleEntry );
+U_LOGFONT_PANOSE logfont_panose_set(U_LOGFONT elfLogFont, uint16_t *elfFullName,
+ uint16_t *elfStyle, uint32_t elfStyleSize, U_PANOSE elfPanose);
+U_LOGFONT logfont_set( int32_t lfHeight, int32_t lfWidth, int32_t lfEscapement, int32_t lfOrientation,
+ int32_t lfWeight, uint8_t lfItalic, uint8_t lfUnderline, uint8_t lfStrikeOut,
+ uint8_t lfCharSet, uint8_t lfOutPrecision, uint8_t lfClipPrecision,
+ uint8_t lfQuality, uint8_t lfPitchAndFamily, uint16_t *lfFaceName);
+char *emrtext_set(U_POINTL ptlReference, U_NUM_STR NumString, uint32_t cbChar, void *String, uint32_t fOptions, U_RECTL rcl, uint32_t *Dx);
+U_LOGPLTNTRY logpltntry_set(uint8_t peReserved,uint8_t peRed,uint8_t peGreen,uint8_t peBlue);
+PU_LOGPALETTE logpalette_set(U_NUM_LOGPLTNTRY palNumEntries,PU_LOGPLTNTRY *palPalEntry);
+U_RGNDATAHEADER rgndataheader_set( U_NUM_RECTL nCount, U_RECTL rcBound);
+PU_RGNDATA rgndata_set( U_RGNDATAHEADER rdh, PU_RECTL Buffer);
+U_BITMAPINFOHEADER bitmapinfoheader_set(int32_t biWidth, int32_t biHeight,
+ uint16_t biPlanes, uint16_t biBitCount, uint32_t biCompression,
+ uint32_t biSizeImage, int32_t biXPelsPerMeter,
+ int32_t biYPelsPerMeter, U_NUM_RGBQUAD biClrUsed, uint32_t biClrImportant);
+PU_BITMAPINFO bitmapinfo_set(U_BITMAPINFOHEADER BmiHeader, PU_RGBQUAD BmiColors);
+U_LOGCOLORSPACEA logcolorspacea_set(int32_t lcsCSType, int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints, U_LCS_GAMMARGB lcsGammaRGB, char *lcsFilename);
+U_LOGCOLORSPACEW logcolorspacew_set(int32_t lcsCSType, int32_t lcsIntent,
+ U_CIEXYZTRIPLE lcsEndpoints, U_LCS_GAMMARGB lcsGammaRGB, uint16_t *lcsFilename);
+U_COLORADJUSTMENT coloradjustment_set(uint16_t Size, uint16_t Flags, uint16_t IlluminantIndex,
+ uint16_t RedGamma, uint16_t GreenGamma, uint16_t BlueGamma,
+ uint16_t ReferenceBlack, uint16_t ReferenceWhite,
+ int16_t Contrast, int16_t Brightness, int16_t Colorfulness, int16_t RedGreenTint);
+U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set( uint32_t dwFlags, uint8_t iPixelType, uint8_t cColorBits,
+ uint8_t cRedBits, uint8_t cRedShift,
+ uint8_t cGreenBits, uint8_t cGreenShift,
+ uint8_t cBlueBits, uint8_t cBlueShift,
+ uint8_t cAlphaBits, uint8_t cAlphaShift,
+ uint8_t cAccumBits, uint8_t cAccumRedBits, uint8_t cAccumGreenBits, uint8_t cAccumBlueBits,
+ uint8_t cAccumAlphaBits, uint8_t cDepthBits, uint8_t cStencilBits,
+ uint8_t cAuxBuffers, uint8_t iLayerType, uint8_t bReserved, uint32_t dwLayerMask,
+ uint32_t dwVisibleMask, uint32_t dwDamageMask);
+
+PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform);
+PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform);
+PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform);
+PU_POINT point16_to_point(PU_POINT16 points, int count);
+PU_POINT16 point_to_point16(PU_POINT points, int count);
+
+U_RECT findbounds(uint32_t count, PU_POINT pts, uint32_t width);
+U_RECT findbounds16(uint32_t count, PU_POINT16 pts, uint32_t width);
+char *emr_dup(const char *emr);
+
+char *textcomment_set(const char *string);
+
+// These generate the handle and then call the underlying function
+char *deleteobject_set(uint32_t *ihObject, EMFHANDLES *eht);
+char *selectobject_set(uint32_t ihObject, EMFHANDLES *eht);
+char *createpen_set(uint32_t *ihPen, EMFHANDLES *eht, U_LOGPEN lopn );
+char *extcreatepen_set(uint32_t *ihPen, EMFHANDLES *eht,
+ PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, PU_EXTLOGPEN elp);
+char *createbrushindirect_set(uint32_t *ihBrush, EMFHANDLES *eht, U_LOGBRUSH lb );
+char *createdibpatternbrushpt_set(uint32_t *ihBrush, EMFHANDLES *eht, uint32_t iUsage,
+ PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px);
+char *createmonobrush_set(uint32_t *ihBrush, EMFHANDLES *eht, uint32_t iUsage,
+ PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px);
+char *extcreatefontindirectw_set(uint32_t *ihFont, EMFHANDLES *eht, const char *elf, const char *elfw);
+char *createpalette_set(uint32_t *ihPal, EMFHANDLES *eht, U_LOGPALETTE lgpl);
+char *setpaletteentries_set(uint32_t *ihPal, EMFHANDLES *eht, uint32_t iStart, U_NUM_LOGPLTNTRY cEntries, PU_LOGPLTNTRY aPalEntries);
+char *fillrgn_set(uint32_t *ihBrush, EMFHANDLES *eht, U_RECTL rclBounds,PU_RGNDATA RgnData);
+char *framergn_set(uint32_t *ihBrush, EMFHANDLES *eht, U_RECTL rclBounds, U_SIZEL szlStroke, PU_RGNDATA RgnData);
+char *createcolorspace_set(uint32_t *ihCS, EMFHANDLES *eht, U_LOGCOLORSPACEA lcs);
+char *createcolorspacew_set(uint32_t *ihCS, EMFHANDLES *eht, U_LOGCOLORSPACEW lcs, uint32_t dwFlags, U_CBDATA cbData, uint8_t *Data);
+
+char *U_EMRHEADER_set( const U_RECTL rclBounds, const U_RECTL rclFrame, U_PIXELFORMATDESCRIPTOR* const pfmtDesc,
+ U_CBSTR nDesc, uint16_t* const Description, const U_SIZEL szlDevice, const U_SIZEL szlMillimeters,
+ const uint32_t bOpenGL);
+char *U_EMRPOLYBEZIER_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points);
+char *U_EMRPOLYGON_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points);
+char *U_EMRPOLYLINE_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points);
+char *U_EMRPOLYBEZIERTO_set(const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points);
+char *U_EMRPOLYLINETO_set( const U_RECTL rclBounds, const uint32_t count, const U_POINTL *points);
+
+char *U_EMRPOLYPOLYLINE_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,
+ const uint32_t cptl, const U_POINTL *points);
+char *U_EMRPOLYPOLYGON_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,
+ const uint32_t cptl, const U_POINTL *points);
+char *U_EMRSETWINDOWEXTEX_set(const U_SIZEL szlExtent);
+char *U_EMRSETWINDOWORGEX_set(const U_POINTL ptlOrigin);
+char *U_EMRSETVIEWPORTEXTEX_set(const U_SIZEL szlExtent);
+char *U_EMRSETVIEWPORTORGEX_set(const U_POINTL ptlOrigin);
+char *U_EMRSETBRUSHORGEX_set(const U_POINTL ptlOrigin);
+char *U_EMREOF_set(const U_CBPLENTRIES cbPalEntries, const PU_LOGPLTNTRY PalEntries, EMFTRACK *et);
+char *U_EMRSETPIXELV_set(const U_POINTL ptlPixel, const U_COLORREF crColor);
+char *U_EMRSETMAPPERFLAGS_set(void);
+char *U_EMRSETMAPMODE_set(const uint32_t iMode);
+char *U_EMRSETBKMODE_set(const uint32_t iMode);
+char *U_EMRSETPOLYFILLMODE_set(const uint32_t iMode);
+char *U_EMRSETROP2_set(const uint32_t iMode);
+char *U_EMRSETSTRETCHBLTMODE_set(const uint32_t iMode);
+char *U_EMRSETTEXTALIGN_set(const uint32_t iMode);
+char *U_EMRSETCOLORADJUSTMENT_set(const U_COLORADJUSTMENT ColorAdjustment);
+char *U_EMRSETTEXTCOLOR_set(const U_COLORREF crColor);
+char *U_EMRSETBKCOLOR_set(const U_COLORREF crColor);
+char *U_EMROFFSETCLIPRGN_set(const U_POINTL ptl);
+char *U_EMRMOVETOEX_set(const U_POINTL ptl);
+char *U_EMRSETMETARGN_set(void);
+char *U_EMREXCLUDECLIPRECT_set(const U_RECTL rclClip);
+char *U_EMRINTERSECTCLIPRECT_set(const U_RECTL rclClip);
+char *U_EMRSCALEVIEWPORTEXTEX_set(const int32_t xNum, const int32_t xDenom, const int32_t yNum, const int32_t yDenom);
+char *U_EMRSCALEWINDOWEXTEX_set(const int32_t xNum, const int32_t xDenom, const int32_t yNum, const int32_t yDenom);
+char *U_EMRSAVEDC_set(void);
+char *U_EMRRESTOREDC_set(const int32_t iRelative);
+char *U_EMRSETWORLDTRANSFORM_set(const U_XFORM xform);
+char *U_EMRMODIFYWORLDTRANSFORM_set(const U_XFORM xform, const uint32_t iMode);
+char *U_EMRSELECTOBJECT_set(const uint32_t ihObject); // better to call selectobject_set()
+char *U_EMRCREATEPEN_set(const uint32_t ihPen, const U_LOGPEN lopn );
+char *U_EMRCREATEBRUSHINDIRECT_set(const uint32_t ihBrush, const U_LOGBRUSH lb);
+char *U_EMRDELETEOBJECT_set(const uint32_t ihObject); // better to call deleteobject_set()
+char *U_EMRANGLEARC_set(const U_POINTL ptlCenter, const uint32_t nRadius, const U_FLOAT eStartAngle, const U_FLOAT eSweepAngle);
+char *U_EMRELLIPSE_set(const U_RECTL rclBox);
+char *U_EMRRECTANGLE_set(const U_RECTL rclBox);
+char *U_EMRROUNDRECT_set(const U_RECTL rclBox, const U_SIZEL szlCorner);
+char *U_EMRARC_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd);
+char *U_EMRCHORD_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd);
+char *U_EMRPIE_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd);
+char *U_EMRSELECTPALETTE_set(const uint32_t ihPal);
+char *U_EMRCREATEPALETTE_set(const uint32_t ihPal, const U_LOGPALETTE lgpl);
+char *U_EMRSETPALETTEENTRIES_set(const uint32_t ihPal, const uint32_t iStart, const U_NUM_LOGPLTNTRY cEntries, const PU_LOGPLTNTRY aPalEntries);
+char *U_EMRRESIZEPALETTE_set(const uint32_t ihPal, const uint32_t cEntries);
+char *U_EMRREALIZEPALETTE_set(void);
+char *U_EMREXTFLOODFILL_set(const U_POINTL ptlStart, const U_COLORREF crColor, const uint32_t iMode);
+char *U_EMRLINETO_set(const U_POINTL ptl);
+char *U_EMRARCTO_set(const U_RECTL rclBox, const U_POINTL ptlStart, const U_POINTL ptlEnd);
+char *U_EMRPOLYDRAW_set(const U_RECTL rclBounds,const U_NUM_POINTL cptl,const U_POINTL *aptl,const uint8_t *abTypes);
+char *U_EMRSETARCDIRECTION_set(const uint32_t iArcDirection);
+char *U_EMRSETMITERLIMIT_set(const uint32_t eMiterLimit);
+char *U_EMRBEGINPATH_set(void);
+char *U_EMRENDPATH_set(void);
+char *U_EMRCLOSEFIGURE_set(void);
+char *U_EMRFILLPATH_set(const U_RECTL rclBox);
+char *U_EMRSTROKEANDFILLPATH_set(const U_RECTL rclBox);
+char *U_EMRSTROKEPATH_set(const U_RECTL rclBox);
+char *U_EMRFLATTENPATH_set(void);
+char *U_EMRWIDENPATH_set(void);
+char *U_EMRSELECTCLIPPATH_set(const uint32_t iMode);
+char *U_EMRABORTPATH_set(void);
+// EMR_ENDEF69
+char *U_EMRCOMMENT_set(const U_CBDATA cbData, const char *Data);
+char *U_EMRFILLRGN_set(const U_RECTL rclBounds, const uint32_t ihBrush, const PU_RGNDATA RgnData);
+char *U_EMRFRAMERGN_set(const U_RECTL rclBounds, const uint32_t ihBrush, const U_SIZEL szlStroke, const PU_RGNDATA RgnData);
+char *U_EMRINVERTRGN_set(const PU_RGNDATA RgnData);
+char *U_EMRPAINTRGN_set(const PU_RGNDATA RgnData);
+char *U_EMREXTSELECTCLIPRGN_set(const uint32_t iMode, const PU_RGNDATA RgnData);
+char *U_EMRBITBLT_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest,
+ const U_POINTL Src, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc,
+ const uint32_t iUsageSrc, const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+char *U_EMRSTRETCHBLT_set(U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest,
+ const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+char *U_EMRMASKBLT_set(U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest,
+ const U_POINTL Src, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc,
+ const U_POINTL Mask, const uint32_t iUsageMask,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px,
+ const PU_BITMAPINFO BmiMsk, const uint32_t cbMsk, char *Msk);
+char *U_EMRPLGBLT_set(const U_RECTL rclBounds, const PU_POINTL aptlDst,
+ const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc,
+ const U_POINTL Mask, const uint32_t iUsageMask,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px,
+ const PU_BITMAPINFO BmiMsk, const uint32_t cbMsk, char *Msk);
+char *U_EMRSETDIBITSTODEVICE_set(const U_RECTL rclBounds, const U_POINTL Dest,
+ const U_POINTL Src, const U_POINTL cSrc, const uint32_t iUsageSrc,
+ const uint32_t iStartScan, const uint32_t cScans,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+char *U_EMRSTRETCHDIBITS_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest,
+ const U_POINTL Src, const U_POINTL cSrc, const uint32_t iUsageSrc,
+ const uint32_t dwRop,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+char *U_EMREXTCREATEFONTINDIRECTW_set( uint32_t ihFont, const char *elf, const char *elfw);
+char *U_EMREXTTEXTOUTA_set(U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext);
+char *U_EMREXTTEXTOUTW_set(U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext);
+char *U_EMRPOLYBEZIER16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYGON16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYLINE16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYBEZIERTO16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYLINETO16_set(const U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYPOLYLINE16_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYPOLYGON16_set(const U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points);
+char *U_EMRPOLYDRAW16_set(const U_RECTL rclBounds,const U_NUM_POINT16 cpts, const U_POINT16 *aptl, const uint8_t *abTypes);
+char *U_EMRCREATEMONOBRUSH_set(const uint32_t ihBrush, const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px);
+char *U_EMRCREATEDIBPATTERNBRUSHPT_set(const uint32_t ihBrush, const uint32_t iUsage,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, const char *Px);
+char *U_EMREXTCREATEPEN_set(const uint32_t ihPen, const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px, const PU_EXTLOGPEN elp );
+// U_EMRPOLYTEXTOUTA_set 96 NOT IMPLEMENTED, denigrated after Windows NT
+// U_EMRPOLYTEXTOUTW_set 97 NOT IMPLEMENTED, denigrated after Windows NT
+char *U_EMRSETICMMODE_set(const uint32_t iMode);
+char *U_EMRCREATECOLORSPACE_set(const uint32_t ihCS, const U_LOGCOLORSPACEA lcs);
+char *U_EMRSETCOLORSPACE_set(const uint32_t ihCS );
+char *U_EMRDELETECOLORSPACE_set(const uint32_t ihCS);
+// U_EMRGLSRECORD_set 102 Not implemented
+// U_EMRGLSBOUNDEDRECORD_set 103 Not implemented
+char *U_EMRPIXELFORMAT_set(const U_PIXELFORMATDESCRIPTOR pfd);
+char *U_EMRSMALLTEXTOUT_set(const U_POINTL Dest, const U_NUM_STR cChars, const uint32_t fuOptions, const uint32_t iGraphicsMode,
+ const U_FLOAT exScale, const U_FLOAT eyScale, const U_RECTL rclBounds, const char *TextString);
+// U_EMRDRAWESCAPE_set 105 Not implemented
+// U_EMREXTESCAPE_set 106 Not implemented
+// U_EMRUNDEF107_set 107 Not implemented
+// U_EMRSMALLTEXTOUT_set 108
+// U_EMRFORCEUFIMAPPING_set 109 Not implemented
+// U_EMRNAMEDESCAPE_set 110 Not implemented
+// U_EMRCOLORCORRECTPALETTE_set 111 Not implemented
+// U_EMRSETICMPROFILEA_set 112 Not implemented
+// U_EMRSETICMPROFILEW_set 113 Not implemented
+
+
+char *U_EMRALPHABLEND_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest,
+ const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc,
+ const U_BLEND Blend,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+char *U_EMRSETLAYOUT_set(const uint32_t iMode);
+char *U_EMRTRANSPARENTBLT_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest,
+ const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc,
+ const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, const uint32_t TColor,
+ const PU_BITMAPINFO Bmi, const uint32_t cbPx, char *Px);
+// U_EMRUNDEF117_set 117 Not implemented
+char *U_EMRGRADIENTFILL_set(const U_RECTL rclBounds, const U_NUM_TRIVERTEX nTriVert, const U_NUM_GRADOBJ nGradObj,
+ const uint32_t ulMode, const PU_TRIVERTEX TriVert, const uint32_t *GradObj );
+// U_EMRSETLINKEDUFIS_set 119 Not implemented
+// U_EMRSETTEXTJUSTIFICATION_set 120 Not implemented (denigrated)
+// U_EMRCOLORMATCHTOTARGETW_set 121 Not implemented
+char *U_EMRCREATECOLORSPACEW_set(const uint32_t ihCS, const U_LOGCOLORSPACEW lcs, const uint32_t dwFlags,
+ const U_CBDATA cbData, const uint8_t *Data);
+
+//! \endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UEMF_ */
diff --git a/src/3rdparty/libuemf/uemf_endian.c b/src/3rdparty/libuemf/uemf_endian.c
new file mode 100644
index 000000000..f746553f1
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_endian.c
@@ -0,0 +1,2270 @@
+/**
+ @file uemf_endian.c
+
+ @brief Functions for converting EMF records between Big Endian and Little Endian byte orders.
+
+ EMF files use Little Endian order.
+ On a Big Endian machine the data must be converted to/from Little Endian when it is writen to/read from a file.
+ On a Little Endian machine no conversion is required, but it is good to be able to test the routines on either platform.
+ When "torev" is true these routines convert from the native byte order to the reverse.
+ When "torev" is false these routines convert from the reverse byte order to the native.
+ Routines that do not use that variable swap byte order, and the way in which they do so does not depend
+ on the native byte order.
+
+ The only function here which should be called directly is U_emf_endian(), and then,except for testing purposes, only on a BE machine.
+
+ Many variables are initialized to zero even though they will always be set because
+ some versions of gcc give spurious "may be used uninitialized" warnings otherwise.
+*/
+
+/*
+File: uemf_endian.c
+Version: 0.0.21
+Date: 23-APR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "uemf.h"
+#include "uemf_endian.h"
+
+// hide almost everuything in here from Doxygen
+//! \cond
+
+/* **********************************************************************************************
+ These functions convert standard objects used in the EMR records.
+*********************************************************************************************** */
+
+void U_swap2(void *ul, unsigned int count){
+ uint8_t ctmp;
+ uint8_t *cl = (uint8_t *) ul;
+ for(; count; count--,cl+=2){
+ ctmp = *cl;
+ *cl = *(cl+1);
+ *(cl+1) = ctmp;
+ }
+}
+
+/* Note: U_swap4 is also used by uwmf_endian.c, in cases where the 32 bit data is not aligned on a 4 byte boundary */
+void U_swap4(void *ul, unsigned int count){
+ uint8_t ctmp;
+ uint8_t *cl = (uint8_t *) ul;
+ for(; count; count--,cl+=4){
+ ctmp = *(cl+0);
+ *(cl+0) = *(cl+3);
+ *(cl+3) = ctmp;
+ ctmp = *(cl+1);
+ *(cl+1) = *(cl+2);
+ *(cl+2) = ctmp;
+ }
+}
+
+/**
+ U_COLORREF and U_RGBQUAD do NOT need to be swapped, they are always stored in memory in the proper order.
+*/
+
+/**
+ \brief Convert rect and rectl objects from Upper Left and Lower Right corner points.
+ \param rect U_RECTL object
+ \param count number to convert
+*/
+void rectl_swap(
+ PU_RECTL rect,
+ unsigned int count
+ ){
+ U_swap4(rect,4*count);
+}
+
+/**
+ \brief Convert a U_SIZEL object.
+ \param sz U_SizeL object
+ \param count number to convert
+*/
+void sizel_swap(
+ PU_SIZEL sz,
+ unsigned int count
+ ){
+ U_swap4(sz,2*count);
+}
+
+/**
+ \brief Convert a U_POINTL object
+ \param pt U_POINTL object
+ \param count number to convert
+*/
+void pointl_swap(
+ PU_POINTL pt,
+ unsigned int count
+ ){
+ U_swap4(pt,2*count);
+}
+
+/**
+ \brief Convert a U_POINT16 object
+ \param pt U_POINT16 object
+ \param count number to convert
+*/
+void point16_swap(
+ PU_POINT16 pt,
+ unsigned int count
+ ){
+ U_swap2(pt,2*count);
+}
+
+
+
+/**
+ \brief Convert a U_TRIVERTEX object.
+ \param tv U_TRIVERTEX object.
+ \param count number to convert
+*/
+void trivertex_swap(
+ PU_TRIVERTEX tv,
+ unsigned int count
+ ){
+ for(;count; count--, tv++){
+ U_swap4(tv,2); /* x,y */
+ U_swap2(&(tv->Red),4); /* Red, Green, Blue, Alpha */
+ }
+}
+
+/**
+ \brief Convert a U_GRADIENT3 object.
+ \param tv U_GRADIENT3 object.
+ \param count number to convert
+*/
+void gradient3_swap(
+ PU_GRADIENT3 g3,
+ unsigned int count
+ ){
+ U_swap4(g3,3*count);
+}
+
+/**
+ \brief Convert a U_GRADIENT4 object.
+ \param tv U_GRADIENT4 object.
+ \param count number to convert
+*/
+void gradient4_swap(
+ PU_GRADIENT4 g4,
+ unsigned int count
+ ){
+ U_swap4(g4,2*count); //a gradient4 object has 2 int4's, NOT 4!
+}
+
+/**
+ \brief Convert a U_LOGBRUSH object.
+ \param lb U_LOGBRUSH object.
+*/
+void logbrush_swap(
+ PU_LOGBRUSH lb
+ ){
+ U_swap4(&(lb->lbStyle),1); // lbStyle
+ // ordered bytes: lbColor
+ U_swap4(&(lb->lbHatch),1); // lbHatch
+}
+
+/**
+ \brief Convert a U_XFORM object.
+ \param xform U_XFORM object
+*/
+void xform_swap(
+ PU_XFORM xform
+ ){
+ U_swap4(xform,6);
+}
+
+
+/**
+ \brief Convert a U_CIEXYZTRIPLE object
+ \param cie3 U_CIEXYZTRIPLE object
+*/
+void ciexyztriple_swap(
+ PU_CIEXYZTRIPLE cie3
+ ){
+ U_swap4(cie3,9);
+}
+/**
+ \brief Convert a U_LOGCOLORSPACEA object.
+ \param lcsa U_LOGCOLORSPACEA object
+*/
+void logcolorspacea_swap(
+ PU_LOGCOLORSPACEA lcsa
+ ){
+ U_swap4(lcsa,5); // lcsSignature lcsVersion lcsSize lcsCSType lcsIntent
+ ciexyztriple_swap(&(lcsa->lcsEndpoints));
+ // ordered bytes: lcsGammaRGB
+ // ordered bytes: lcsFilename
+}
+
+/**
+
+ \brief Convert a U_LOGCOLORSPACEW object.
+ \param lcsa U_LOGCOLORSPACEW object
+*/
+void logcolorspacew_swap(
+ PU_LOGCOLORSPACEW lcsa
+ ){
+ U_swap4(lcsa,5); // lcsSignature lcsVersion lcsSize lcsCSType lcsIntent
+ ciexyztriple_swap(&(lcsa->lcsEndpoints));
+ // ordered bytes: lcsGammaRGB
+ // UTF-16LE, already in order: lcsFilename
+}
+
+
+/**
+ \brief Convert a U_LOGFONT object.
+ \param lf U_LOGFONT object
+*/
+void logfont_swap(
+ PU_LOGFONT lf
+ ){
+ U_swap4(lf,5); // lfHeight lfWidth lfEscapement lfOrientation lfWeight
+ // ordered bytes: lfItalic lfUnderline lfStrikeOut lfCharSet lfOutPrecision lfClipPrecision lfQuality lfPitchAndFamily
+ // UTF16-LE, already in order
+}
+
+/**
+ \brief Convert a U_LOGFONT_PANOSE object.
+ \return U_LOGFONT_PANOSE object
+*/
+void logfont_panose_swap(
+ PU_LOGFONT_PANOSE lfp
+ ){
+ logfont_swap(&(lfp->elfLogFont)); // elfLogFont
+ // UTF-16LE, already in order: elfFullName
+ // UTF-16LE, already in order: elfStyle
+ U_swap4(&(lfp->elfVersion),4); // elfVersion elfStyleSize elfMatch elfReserved
+ // ordered bytes: elfVendorId
+ U_swap4(&(lfp->elfCulture),1); // elfCulture
+ // ordered bytes: elfPanose
+}
+
+/**
+ \brief Convert a U_BITMAPINFOHEADER object.
+ \param Bmi U_BITMAPINFOHEADER object
+*/
+void bitmapinfoheader_swap(
+ PU_BITMAPINFOHEADER Bmi
+ ){
+ U_swap4(Bmi,3); // biSize biWidth biHeight
+ U_swap2(&(Bmi->biPlanes),2); // biPlanes biBitCount
+ U_swap4(&(Bmi->biCompression),6); // biCompression biSizeImage biXPelsPerMeter biYPelsPerMeter biClrUsed biClrImportant
+}
+
+
+/**
+ \brief Convert a Pointer to a U_BITMAPINFO object.
+ \param Bmi Pointer to a U_BITMAPINFO object
+*/
+void bitmapinfo_swap(
+ const char *Bmi
+ ){
+ PU_BITMAPINFO pBmi = (PU_BITMAPINFO)Bmi;
+ bitmapinfoheader_swap(&(pBmi->bmiHeader)); // bmIHeader
+ // ordered bytes: bmiColors
+}
+
+/**
+ \brief Swap the ordered bytes in a DIB and verify that the sizes are OK
+
+ \return 1 on success, 0 on failure
+ \param record EMF record that contains a DIB pixel array
+ \param iUsage DIBcolors Enumeration
+ \param offBmi offset from the start of the record to the start of the bitmapinfo structure
+ \param cbBmi declared space for the bitmapinfo structure in the record
+ \param offBits offset from the start of the record to the start of the bitmap
+ \param cbBits declared space for the bitmap in the record (amount used may be less than this)
+ \param blimit one byte past the end of the record.
+ \param torev 1 for native to reversed, 0 for reversed to native
+
+ This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag
+ of bytes, and there is no possible way to derive from the known width and height how big it should be.
+*/
+int DIB_swap(
+ const char *record,
+ uint32_t iUsage,
+ uint32_t offBmi,
+ uint32_t cbBmi,
+ uint32_t offBits,
+ uint32_t cbBits,
+ const char *blimit,
+ int torev
+ ){
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int bs;
+ int usedbytes;
+
+ if(!cbBmi)return(1); // No DIB in a record where it is optional
+ if(IS_MEM_UNSAFE(record, offBmi + cbBmi, blimit))return(0);
+ if(cbBits && IS_MEM_UNSAFE(record, offBits + cbBits, blimit))return(0);
+ if(iUsage == U_DIB_RGB_COLORS){
+ uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params
+ // next call returns pointers and values, but allocates no memory
+ if(torev){
+ dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
+ &numCt, &width, &height, &colortype, &invert);
+ }
+ bitmapinfo_swap(record + offBmi); // byte ordered fields in bitmapinfo
+ if(!torev){
+ dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
+ &numCt, &width, &height, &colortype, &invert);
+ }
+
+ // sanity checking
+ if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels
+ if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit
+
+ if(dibparams ==U_BI_RGB){
+ // this is the only DIB type where we can calculate how big it should be when stored in the EMF file
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = width*bs;
+ }
+ if(IS_MEM_UNSAFE(record+offBits, usedbytes, blimit))return(0);
+ }
+ }
+ else {
+ bitmapinfo_swap(record + offBmi);
+ }
+ return(1);
+}
+
+/**
+ \brief Convert a pointer to a U_EXTLOGPEN object.
+ \param elp PU_EXTLOGPEN object
+ \param blimit one byte past the end of the record
+*/
+int extlogpen_swap(
+ PU_EXTLOGPEN elp,
+ const char *blimit,
+ int torev
+ ){
+ int count=0;
+ U_swap4(elp,3); // elpPenStyle elpWidth elpBrushStyle
+ // ordered bytes: elpColor
+ if(torev){
+ count = elp->elpNumEntries;
+ }
+ U_swap4(&(elp->elpHatch),2); // elpHatch elpNumEntries
+ if(!torev){
+ count = elp->elpNumEntries;
+ }
+ if(IS_MEM_UNSAFE(&(elp->elpStyleEntry), count*4, blimit))return(0);
+ U_swap4(&(elp->elpStyleEntry),count); // elpStyleEntry[]
+ return(1);
+}
+
+/**
+ \brief Convert a U_LOGPEN object.
+ \param lp U_LOGPEN object
+
+*/
+void logpen_swap(
+ PU_LOGPEN lp
+ ){
+ U_swap4(lp,1); // lopnStyle
+ pointl_swap(&(lp->lopnWidth),1); // lopnWidth
+ // ordered bytes: lopnColor
+}
+
+
+/**
+ \brief Convert a pointer to a U_LOGPALETTE object.
+ \param lp Pointer to a U_LOGPALETTE object.
+*/
+void logpalette_swap(
+ PU_LOGPALETTE lp
+ ){
+ U_swap2(lp,2); // palVersion palNumEntries
+ // ordered bytes: palPalEntry[]
+}
+
+/**
+ \brief Convert a U_RGNDATAHEADER object.
+ \param rdh U_RGNDATAHEADER object
+*/
+void rgndataheader_swap(
+ PU_RGNDATAHEADER rdh
+ ){
+ U_swap4(rdh,4); // dwSize iType nCount nRgnSize
+ rectl_swap(&(rdh->rclBounds),1); // rclBounds
+}
+
+/**
+ \return 1 on success, 0 on failure
+ \brief Convert a pointer to a U_RGNDATA object.
+ \param rd pointer to a U_RGNDATA object.
+ \param cbRgnData size of the U_RGNDATA object.
+*/
+int rgndata_swap(
+ PU_RGNDATA rd,
+ int cbRgnData,
+ int torev
+ ){
+ int count = 0;
+ if(torev){
+ count = rd->rdh.nCount;
+ }
+ rgndataheader_swap(&(rd->rdh));
+ if(!torev){
+ count = rd->rdh.nCount;
+ }
+ if(4*count + (int)sizeof(U_RGNDATAHEADER) > cbRgnData)return(0);
+ U_swap4(rd->Buffer,4*count);
+ return(1);
+}
+
+/**
+ \brief Convert a U_COLORADJUSTMENT object.
+ \param ca U_COLORADJUSTMENT object.
+*/
+void coloradjustment_swap(
+ PU_COLORADJUSTMENT ca
+ ){
+ U_swap2(ca,12); // caSize caFlags caIlluminantIndex caRedGamma caGreenGamma caBlueGamma caReferenceBlack caReferenceWhite caContrast caBrightness caColorfulness caRedGreenTint
+}
+
+/**
+ \brief Convert a pointer to a U_PIXELFORMATDESCRIPTOR object.
+ \param pfd pointer to a U_PIXELFORMATDESCRIPTOR object.
+*/
+void pixelformatdescriptor_swap(
+ PU_PIXELFORMATDESCRIPTOR pfd
+ ){
+ U_swap2(pfd,2); // nSize nVersion
+ U_swap4(&(pfd->dwFlags),1); // dwFlags
+ // ordered bytes: iPixelType cColorBits cRedBits cRedShift cGreenBits cGreenShift cBlueBits cBlueShift cAlphaBits cAlphaShift cAccumBits cAccumRedBits cAccumGreenBits cAccumBlueBits cAccumAlphaBits cDepthBits cStencilBits cAuxBuffers iLayerType bReserved
+ U_swap4(&(pfd->dwLayerMask),3); // dwLayerMask dwVisibleMask dwDamageMask
+}
+
+/**
+ \brief Convert a Pointer to a U_EMRTEXT record
+ \param pemt Pointer to a U_EMRTEXT record
+ \param record Pointer to the start of the record which contains this U_EMRTEXT
+ \param blimit one byte past the end of the record.
+ \param torev 1 for native to reversed, 0 for reversed to native
+*/
+int emrtext_swap(
+ PU_EMRTEXT pemt,
+ char *record,
+ const char *blimit,
+ int torev
+ ){
+ int off;
+ uint32_t count=0;
+ uint32_t offDx=0;
+ uint32_t fOptions=0;
+ pointl_swap(&(pemt->ptlReference),1); // ptlReference
+ if(torev){
+ count = pemt->nChars;
+ fOptions = pemt->fOptions;
+ }
+ U_swap4(&(pemt->nChars),3); // nChars offString fOptions
+ if(!torev){
+ count = pemt->nChars;
+ fOptions = pemt->fOptions;
+ }
+ off = sizeof(U_EMRTEXT);
+ if(!(fOptions & U_ETO_NO_RECT)){
+ if(IS_MEM_UNSAFE(pemt, sizeof(U_RECTL), blimit))return(0);
+ rectl_swap((PU_RECTL)((char *)pemt + off),1); // optional rectangle
+ off+=sizeof(U_RECTL);
+ }
+ if(torev){
+ offDx = *(uint32_t *)((char *)pemt +off);
+ }
+ // ordered bytes OR UTF16-LE: the string at offString
+ if(IS_MEM_UNSAFE(pemt, off + 4, blimit))return(0);
+ U_swap4(((char *)pemt+off),1); // offDx
+ if(!torev){
+ offDx = *(uint32_t *)((char *)pemt +off);
+ }
+ if(IS_MEM_UNSAFE(record, count*4, blimit))return(0);
+ U_swap4((record + offDx),count); // Dx[], offset with respect to the Record, NOT the object
+ return(1);
+}
+
+
+
+/* **********************************************************************************************
+These functions contain shared code used by various U_EMR*_swap functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+
+
+ These all have this form:
+
+ void core1_swap(char *record, int torev){
+
+ but some do not actually use torev.
+
+
+
+*********************************************************************************************** */
+
+// all core*_swap call this, U_EMRSETMARGN_swap and some others all it directly
+// numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype
+int core5_swap(char *record, int torev){
+ UNUSED_PARAMETER(torev);
+ if(!record)return(0);
+ PU_EMR pEmr = (PU_EMR)(record);
+ U_swap4(pEmr,2); // iType nSize
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER_swap
+int core1_swap(char *record, int torev){
+ int count=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (record);
+ if(torev){
+ count = pEmr->cptl;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1 ); // rclBounds
+ U_swap4(&(pEmr->cptl),1); // cptl
+ if(!torev){
+ count = pEmr->cptl;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->aptl), count*sizeof(U_POINTL), blimit))return(0);
+ pointl_swap((pEmr->aptl),count); // aptl[]
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE_swap
+int core2_swap(char *record, int torev){
+ int count=0;
+ int nPolys=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYPOLYLINE pEmr = (PU_EMRPOLYPOLYLINE) (record);
+ if(torev){
+ count = pEmr->cptl;
+ nPolys = pEmr->nPolys;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->nPolys),2); // nPolys cptl
+ if(!torev){
+ count = pEmr->cptl;
+ nPolys = pEmr->nPolys;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->aPolyCounts), nPolys*4, blimit))return(0);
+ U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[]
+ record += sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys;
+ if(IS_MEM_UNSAFE(record, count*sizeof(U_POINTL), blimit))return(0);
+ pointl_swap((PU_POINT)(record), count); // paptl[]
+ return(1);
+}
+
+
+// Functions with the same form starting with U_EMRSETMAPMODE_swap
+int core3_swap(char *record, int torev){
+ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(record);
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->iMode),1); // iMode
+ return(1);
+}
+
+// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_swap, also U_EMRFILLPATH_swap,
+int core4_swap(char *record, int torev){
+ PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( record);
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBox),1); // rclBox
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER16_swap
+int core6_swap(char *record, int torev){
+ int count=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (record);
+ if(torev){
+ count = pEmr->cpts;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cpts),1); // cpts
+ if(!torev){
+ count = pEmr->cpts;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->apts), count*sizeof(U_POINT16), blimit))return(0);
+ point16_swap((pEmr->apts),count); // apts[]
+ return(1);
+}
+
+
+// Records with the same form starting with U_EMRSETWINDOWEXTEX_swap, that is, all with two uint32_t values after the emr
+int core7_swap(char *record, int torev){
+ PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (record);
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->pair),2);
+ return(1);
+}
+
+// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one
+int core8_swap(char *record, int torev){
+ const char *blimit = NULL;
+ PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (record);
+ if(torev){
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->iGraphicsMode),1); // iGraphicsMode
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->exScale),2); // exScale eyScale
+ if(!torev){
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!emrtext_swap(&(pEmr->emrtext),record,blimit,torev))return(0);
+ return(1);
+}
+
+// Functions that take a rect and a pair of points, starting with U_EMRARC_swap
+int core9_swap(char *record, int torev){
+ PU_EMRARC pEmr = (PU_EMRARC) (record);
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBox),1); // rclBox
+ U_swap4(&(pEmr->ptlStart),4); // ptlStart ptlEnd
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE16_swap
+int core10_swap(char *record, int torev){
+ int count=0;
+ int nPolys=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (record);
+ if(torev){
+ count = pEmr->cpts;
+ nPolys = pEmr->nPolys;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->nPolys),2); // nPolys cpts
+ if(!torev){
+ count = pEmr->cpts;
+ nPolys = pEmr->nPolys;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->aPolyCounts), nPolys*4, blimit))return(0);
+ U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[]
+ record += sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys;
+ if(IS_MEM_UNSAFE(record, count*sizeof(U_POINT16), blimit))return(0);
+ point16_swap((PU_POINT16)(record), count); // apts[]
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRINVERTRGN_swap and U_EMRPAINTRGN_swap,
+int core11_swap(char *record, int torev){
+ int cbRgnData=0;
+ const char *blimit = NULL;
+ PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN)(record);
+ if(torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cbRgnData),1); // cbRgnData
+ if(!torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_swap(pEmr->RgnData, cbRgnData, torev));
+}
+
+
+// common code for U_EMRCREATEMONOBRUSH_swap and U_EMRCREATEDIBPATTERNBRUSHPT_swap,
+int core12_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMI offBmi = 0;
+ U_CBBMI cbBmi = 0;
+ U_OFFBITS offBits = 0;
+ U_CBBITS cbBits = 0;
+ uint32_t iUsage = 0;
+ PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (record);
+ if(torev){
+ offBmi = pEmr->offBmi;
+ cbBmi = pEmr->cbBmi;
+ offBits = pEmr->offBits;
+ cbBits = pEmr->cbBits;
+ iUsage = pEmr->iUsage;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->ihBrush),6); // ihBrush iUsage offBmi cbBmi offBits cbBits
+ if(!torev){
+ offBmi = pEmr->offBmi;
+ cbBmi = pEmr->cbBmi;
+ offBits = pEmr->offBits;
+ cbBits = pEmr->cbBits;
+ iUsage = pEmr->iUsage;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0);
+ }
+ // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise).
+ return(1);
+}
+
+// common code for U_EMRALPHABLEND_swap and U_EMRTRANSPARENTBLT_swap,
+int core13_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),2); // Dest cDest
+ pointl_swap(&(pEmr->Dest),2); // Dest cDest
+ // ordered bytes: Blend
+ pointl_swap(&(pEmr->Src),2); // Src
+ xform_swap( &(pEmr->xformSrc)); // xformSrc
+ // ordered bytes: crBkColorSrc
+ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise).
+ return(1);
+}
+
+/* **********************************************************************************************
+These are the core EMR_swap functions, each converts a particular type of record.
+All operate in place on the chunk of memory holding that record.
+Some of these have offsets or counts which, if corrupt or evil would result in access outside
+ the record. These cases return a status value of 0 if that happens, 1 on success. Other
+ records which do not have these issues do not return a status value.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+/**
+ All of the record level (hidden) functions have this form:
+ \brief Convert a pointer to a U_EMR_whatever record which has not been implemented.
+ \param record pointer to a buffer holding the EMR record
+ \param torev 1 for native to reversed, 0 for reversed to native
+*/
+int U_EMRNOTIMPLEMENTED_swap(char *record, int torev){
+ fprintf(stderr,"EMF WARNING: could not swap data bytes on record because that type has not been implemented!\n");
+ return(core5_swap(record, torev));
+}
+
+// U_EMRHEADER 1
+int U_EMRHEADER_swap(char *record, int torev){
+ int nDesc,offDesc,nSize,cbPix,offPix;
+ nDesc = offDesc = nSize = cbPix = offPix = 0;
+ PU_EMRHEADER pEmr = (PU_EMRHEADER)(record);
+ if(torev){
+ nSize = pEmr->emr.nSize;
+ nDesc = pEmr->nDescription;
+ offDesc = pEmr->offDescription;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),2); // rclBounds rclFrame
+ U_swap4(&(pEmr->dSignature), 4); // dSignature nVersion nBytes nRecords
+ U_swap2(&(pEmr->nHandles), 2); // nHandlessReserved
+ U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries
+ if(!torev){
+ nSize = pEmr->emr.nSize;
+ nDesc = pEmr->nDescription;
+ offDesc = pEmr->offDescription;
+ }
+ // UTF16-LE Description
+ sizel_swap(&(pEmr->szlDevice), 2); // szlDevice szlMillimeters
+ if((nDesc && (offDesc >= 100)) ||
+ (!offDesc && nSize >= 100)
+ ){
+ if(torev){
+ cbPix = pEmr->cbPixelFormat;
+ offPix = pEmr->offPixelFormat;
+ }
+ U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat
+ U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL
+ if(!torev){
+ cbPix = pEmr->cbPixelFormat;
+ offPix = pEmr->offPixelFormat;
+ }
+ if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat));
+ if((nDesc && (offDesc >= 108)) ||
+ (cbPix && (offPix >=108)) ||
+ (!offDesc && !cbPix && nSize >= 108)
+ ){
+ sizel_swap(&(pEmr->szlMicrometers), 1); // szlMicrometers
+ }
+ }
+ return(1);
+}
+
+// U_EMRPOLYBEZIER 2
+int U_EMRPOLYBEZIER_swap(char *record, int torev){
+ return(core1_swap(record, torev));
+}
+
+// U_EMRPOLYGON 3
+int U_EMRPOLYGON_swap(char *record, int torev){
+ return(core1_swap(record, torev));
+}
+
+
+// U_EMRPOLYLINE 4
+int U_EMRPOLYLINE_swap(char *record, int torev){
+ return(core1_swap(record, torev));
+}
+
+// U_EMRPOLYBEZIERTO 5
+int U_EMRPOLYBEZIERTO_swap(char *record, int torev){
+ return(core1_swap(record, torev));
+}
+
+// U_EMRPOLYLINETO 6
+int U_EMRPOLYLINETO_swap(char *record, int torev){
+ return(core1_swap(record, torev));
+}
+
+// U_EMRPOLYPOLYLINE 7
+int U_EMRPOLYPOLYLINE_swap(char *record, int torev){
+ return(core2_swap(record, torev));
+}
+
+// U_EMRPOLYPOLYGON 8
+int U_EMRPOLYPOLYGON_swap(char *record, int torev){
+ return(core2_swap(record, torev));
+}
+
+// U_EMRSETWINDOWEXTEX 9
+int U_EMRSETWINDOWEXTEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRSETWINDOWORGEX 10
+int U_EMRSETWINDOWORGEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRSETVIEWPORTEXTEX 11
+int U_EMRSETVIEWPORTEXTEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRSETVIEWPORTORGEX 12
+int U_EMRSETVIEWPORTORGEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRSETBRUSHORGEX 13
+int U_EMRSETBRUSHORGEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMREOF 14
+int U_EMREOF_swap(char *record, int torev){
+ int off=0;
+ int cbPalEntries=0;
+ const char *blimit = NULL;
+ PU_EMREOF pEmr = (PU_EMREOF)(record);
+ if(torev){
+ blimit = record + pEmr->emr.nSize;
+ cbPalEntries = pEmr->cbPalEntries;
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->cbPalEntries),2); // cbPalEntries offPalEntries
+ if(!torev){
+ blimit = record + pEmr->emr.nSize;
+ cbPalEntries = pEmr->cbPalEntries;
+ }
+ if(cbPalEntries){
+ if(IS_MEM_UNSAFE(record, pEmr->offPalEntries + 2*2, blimit))return(0); // 2 16 bit values in U_LOGPALLETE
+ logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries));
+ // U_LOGPLTNTRY values in pallette are ordered data
+ }
+ off = sizeof(U_EMREOF) + 4 * cbPalEntries;
+ if(IS_MEM_UNSAFE(record, off + 4, blimit))return(0);
+ U_swap4(record + off,1); // nSizeLast
+ return(1);
+}
+
+
+// U_EMRSETPIXELV 15
+int U_EMRSETPIXELV_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(record);
+ pointl_swap(&(pEmr->ptlPixel),1); // ptlPixel
+ // ordered bytes: crColor
+ return(1);
+}
+
+
+// U_EMRSETMAPPERFLAGS 16
+int U_EMRSETMAPPERFLAGS_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(record);
+ U_swap4(&(pEmr->dwFlags),1); // dwFlags
+ return(1);
+}
+
+
+// U_EMRSETMAPMODE 17
+int U_EMRSETMAPMODE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETBKMODE 18
+int U_EMRSETBKMODE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETPOLYFILLMODE 19
+int U_EMRSETPOLYFILLMODE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETROP2 20
+int U_EMRSETROP2_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETSTRETCHBLTMODE 21
+int U_EMRSETSTRETCHBLTMODE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETTEXTALIGN 22
+int U_EMRSETTEXTALIGN_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETCOLORADJUSTMENT 23
+int U_EMRSETCOLORADJUSTMENT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(record);
+ coloradjustment_swap(&(pEmr->ColorAdjustment));
+ return(1);
+}
+
+// U_EMRSETTEXTCOLOR 24
+int U_EMRSETTEXTCOLOR_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ // ordered bytes: crColor
+ return(1);
+}
+
+// U_EMRSETBKCOLOR 25
+int U_EMRSETBKCOLOR_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ // ordered bytes: crColor
+ return(1);
+}
+
+// U_EMROFFSETCLIPRGN 26
+int U_EMROFFSETCLIPRGN_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRMOVETOEX 27
+int U_EMRMOVETOEX_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRSETMETARGN 28
+int U_EMRSETMETARGN_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMREXCLUDECLIPRECT 29
+int U_EMREXCLUDECLIPRECT_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRINTERSECTCLIPRECT 30
+int U_EMRINTERSECTCLIPRECT_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRSCALEVIEWPORTEXTEX 31
+int U_EMRSCALEVIEWPORTEXTEX_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRSCALEWINDOWEXTEX 32
+int U_EMRSCALEWINDOWEXTEX_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRSAVEDC 33
+int U_EMRSAVEDC_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRRESTOREDC 34
+int U_EMRRESTOREDC_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETWORLDTRANSFORM 35
+int U_EMRSETWORLDTRANSFORM_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(record);
+ xform_swap(&(pEmr->xform));
+ return(1);
+}
+
+// U_EMRMODIFYWORLDTRANSFORM 36
+int U_EMRMODIFYWORLDTRANSFORM_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(record);
+ xform_swap(&(pEmr->xform)); // xform
+ U_swap4(&(pEmr->iMode),1); // iMode
+ return(1);
+}
+
+// U_EMRSELECTOBJECT 37
+int U_EMRSELECTOBJECT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(record);
+ U_swap4(&(pEmr->ihObject),1); // ihObject
+ return(1);
+}
+
+// U_EMRCREATEPEN 38
+int U_EMRCREATEPEN_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(record);
+ U_swap4(&(pEmr->ihPen),1); // ihPen
+ logpen_swap(&(pEmr->lopn)); // lopn
+ return(1);
+}
+
+// U_EMRCREATEBRUSHINDIRECT 39
+int U_EMRCREATEBRUSHINDIRECT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(record);
+ U_swap4(&(pEmr->ihBrush),1); // ihBrush
+ logbrush_swap(&(pEmr->lb)); // lb
+ return(1);
+}
+
+// U_EMRDELETEOBJECT 40
+int U_EMRDELETEOBJECT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(record);
+ U_swap4(&(pEmr->ihObject),1); // ihObject
+ return(1);
+}
+
+// U_EMRANGLEARC 41
+int U_EMRANGLEARC_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(record);
+ pointl_swap(&(pEmr->ptlCenter),1); // ptlCenter
+ U_swap4(&(pEmr->nRadius),3); // nRadius eStartAngle eSweepAngle
+ return(1);
+}
+
+// U_EMRELLIPSE 42
+int U_EMRELLIPSE_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRRECTANGLE 43
+int U_EMRRECTANGLE_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRROUNDRECT 44
+int U_EMRROUNDRECT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(record);
+ rectl_swap(&(pEmr->rclBox),1); // rclBox
+ sizel_swap(&(pEmr->szlCorner), 1); // szlCorner
+ return(1);
+}
+
+// U_EMRARC 45
+int U_EMRARC_swap(char *record, int torev){
+ return(core9_swap(record, torev));
+}
+
+// U_EMRCHORD 46
+int U_EMRCHORD_swap(char *record, int torev){
+ return(core9_swap(record, torev));
+}
+
+// U_EMRPIE 47
+int U_EMRPIE_swap(char *record, int torev){
+ return(core9_swap(record, torev));
+}
+
+// U_EMRSELECTPALETTE 48
+int U_EMRSELECTPALETTE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRCREATEPALETTE 49
+int U_EMRCREATEPALETTE_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(record);
+ U_swap4(&(pEmr->ihPal),1); // ihPal
+ logpalette_swap( (PU_LOGPALETTE)&(pEmr->lgpl) ); // lgpl
+ return(1);
+}
+
+// U_EMRSETPALETTEENTRIES 50
+int U_EMRSETPALETTEENTRIES_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(record);
+ U_swap4(&(pEmr->ihPal),3); // ihPal iStart cEntries
+ // ordered bytes: aPalEntries[]
+ return(1);
+}
+
+// U_EMRRESIZEPALETTE 51
+int U_EMRRESIZEPALETTE_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRREALIZEPALETTE 52
+int U_EMRREALIZEPALETTE_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMREXTFLOODFILL 53
+int U_EMREXTFLOODFILL_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(record);
+ pointl_swap(&(pEmr->ptlStart),1); // ptlStart
+ // ordered bytes: crColor
+ U_swap4(&(pEmr->iMode),1); // iMode
+ return(1);
+}
+
+// U_EMRLINETO 54
+int U_EMRLINETO_swap(char *record, int torev){
+ return(core7_swap(record, torev));
+}
+
+// U_EMRARCTO 55
+int U_EMRARCTO_swap(char *record, int torev){
+ return(core9_swap(record, torev));
+}
+
+// U_EMRPOLYDRAW 56
+int U_EMRPOLYDRAW_swap(char *record, int torev){
+ int count=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(record);
+
+ if(torev){
+ count = pEmr->cptl;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cptl),1); // cptl
+ if(!torev){
+ count = pEmr->cptl;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->aptl), count*sizeof(U_POINTL), blimit))return(0);
+ pointl_swap(pEmr->aptl,count); // aptl[]
+ // single byte data abTypes
+ return(1);
+}
+
+// U_EMRSETARCDIRECTION 57
+int U_EMRSETARCDIRECTION_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRSETMITERLIMIT 58
+int U_EMRSETMITERLIMIT_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+
+// U_EMRBEGINPATH 59
+int U_EMRBEGINPATH_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRENDPATH 60
+int U_EMRENDPATH_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRCLOSEFIGURE 61
+int U_EMRCLOSEFIGURE_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRFILLPATH 62
+int U_EMRFILLPATH_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRSTROKEANDFILLPATH 63
+int U_EMRSTROKEANDFILLPATH_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRSTROKEPATH 64
+int U_EMRSTROKEPATH_swap(char *record, int torev){
+ return(core4_swap(record, torev));
+}
+
+// U_EMRFLATTENPATH 65
+int U_EMRFLATTENPATH_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRWIDENPATH 66
+int U_EMRWIDENPATH_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRSELECTCLIPPATH 67
+int U_EMRSELECTCLIPPATH_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRABORTPATH 68
+int U_EMRABORTPATH_swap(char *record, int torev){
+ return(core5_swap(record, torev));
+}
+
+// U_EMRUNDEF69 69
+#define U_EMRUNDEF69_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific)
+int U_EMRCOMMENT_swap(char *record, int torev){
+ int cbData = 0;
+ const char *blimit = NULL;
+ PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(record);
+ if(torev){
+ cbData = pEmr->cbData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->cbData),1); // cbData
+ if(!torev){
+ cbData = pEmr->cbData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE(record, cbData + sizeof(U_SIZE_EMRCOMMENT), blimit))return(0);
+ // program specific data, presumably byte ordered, otherwise, not portable
+ return(1);
+}
+
+// U_EMRFILLRGN 71
+int U_EMRFILLRGN_swap(char *record, int torev){
+ int cbRgnData=0;
+ const char *blimit = NULL;
+ PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(record);
+ if(torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush
+ if(!torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_swap(pEmr->RgnData, cbRgnData, torev));
+}
+
+// U_EMRFRAMERGN 72
+int U_EMRFRAMERGN_swap(char *record, int torev){
+ int cbRgnData=0;
+ const char *blimit = NULL;
+ PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(record);
+ if(torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush
+ sizel_swap(&(pEmr->szlStroke), 1); // szlStroke
+ if(!torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_swap(pEmr->RgnData, cbRgnData, torev));
+}
+
+// U_EMRINVERTRGN 73
+int U_EMRINVERTRGN_swap(char *record, int torev){
+ return(core11_swap(record, torev));
+}
+
+// U_EMRPAINTRGN 74
+int U_EMRPAINTRGN_swap(char *record, int torev){
+ return(core11_swap(record, torev));
+}
+
+// U_EMREXTSELECTCLIPRGN 75
+int U_EMREXTSELECTCLIPRGN_swap(char *record, int torev){
+ int cbRgnData=0;
+ const char *blimit = NULL;
+ PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN)(record);
+ if(torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->cbRgnData),2); // cbRgnData iMode
+ if(!torev){
+ cbRgnData= pEmr->cbRgnData;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_swap(pEmr->RgnData, cbRgnData, torev));
+}
+
+// U_EMRBITBLT 76
+int U_EMRBITBLT_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),2); // Dest cDest
+ U_swap4(&(pEmr->dwRop),1); // dwRop
+ pointl_swap(&(pEmr->Src),1); // Src
+ xform_swap(&(pEmr->xformSrc)); // xformSrc
+ // ordered bytes: crBkColorSrc
+ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise).
+ return(1);
+}
+
+// U_EMRSTRETCHBLT 77
+int U_EMRSTRETCHBLT_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),2); // Dest cDest
+ U_swap4(&(pEmr->dwRop),1); // dwRop
+ pointl_swap(&(pEmr->Src),1); // Src
+ xform_swap(&(pEmr->xformSrc)); // xformSrc
+ // ordered bytes: crBkColorSrc
+ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc
+ pointl_swap(&(pEmr->cSrc),1); // cSrc
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise).
+ return(1);
+}
+
+// U_EMRMASKBLT 78
+int U_EMRMASKBLT_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ U_OFFBMIMSK offBmiMask = 0;
+ U_CBBMIMSK cbBmiMask = 0;
+ U_OFFBITSMSK offBitsMask = 0;
+ U_CBBITSMSK cbBitsMask = 0;
+ uint32_t iUsageMask = 0;
+ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ offBmiMask = pEmr->offBmiMask;
+ cbBmiMask = pEmr->cbBmiMask;
+ offBitsMask = pEmr->offBitsMask;
+ cbBitsMask = pEmr->cbBitsMask;
+ iUsageMask = pEmr->iUsageMask;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),2); // Dest cDest
+ U_swap4(&(pEmr->dwRop),1); // dwRop
+ pointl_swap(&(pEmr->Src),1); // Src
+ xform_swap(&(pEmr->xformSrc)); // xformSrc
+ // ordered bytes: crBkColorSrc
+ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc
+ pointl_swap(&(pEmr->Mask),1); // Mask
+ U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ offBmiMask = pEmr->offBmiMask;
+ cbBmiMask = pEmr->cbBmiMask;
+ offBitsMask = pEmr->offBitsMask;
+ cbBitsMask = pEmr->cbBitsMask;
+ iUsageMask = pEmr->iUsageMask;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0);
+ }
+ return(1);
+}
+
+// U_EMRPLGBLT 79
+int U_EMRPLGBLT_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ U_OFFBMIMSK offBmiMask = 0;
+ U_CBBMIMSK cbBmiMask = 0;
+ U_OFFBITSMSK offBitsMask = 0;
+ U_CBBITSMSK cbBitsMask = 0;
+ uint32_t iUsageMask = 0;
+ PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ offBmiMask = pEmr->offBmiMask;
+ cbBmiMask = pEmr->cbBmiMask;
+ offBitsMask = pEmr->offBitsMask;
+ cbBitsMask = pEmr->cbBitsMask;
+ iUsageMask = pEmr->iUsageMask;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(pEmr->aptlDst,3); // aptlDst[]
+ pointl_swap(&(pEmr->Src),2); // Src cSrc
+ xform_swap(&(pEmr->xformSrc)); // xformSrc
+ // ordered bytes: crBkColorSrc
+ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc
+ pointl_swap(&(pEmr->Mask),1); // Mask
+ U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ offBmiMask = pEmr->offBmiMask;
+ cbBmiMask = pEmr->cbBmiMask;
+ offBitsMask = pEmr->offBitsMask;
+ cbBitsMask = pEmr->cbBitsMask;
+ iUsageMask = pEmr->iUsageMask;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0);
+ }
+ return(1);
+}
+
+// U_EMRSETDIBITSTODEVICE 80
+int U_EMRSETDIBITSTODEVICE_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),1); // Dest
+ pointl_swap(&(pEmr->Src),2); // Src cSrc
+ U_swap4(&(pEmr->offBmiSrc),7); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc iStartScan cScans
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ return(1);
+}
+
+// U_EMRSTRETCHDIBITS 81
+int U_EMRSTRETCHDIBITS_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMISRC offBmiSrc = 0;
+ U_CBBMISRC cbBmiSrc = 0;
+ U_OFFBITSSRC offBitsSrc = 0;
+ U_CBBITSSRC cbBitsSrc = 0;
+ uint32_t iUsageSrc = 0;
+ PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (record);
+ if(torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ pointl_swap(&(pEmr->Dest),1); // Dest
+ pointl_swap(&(pEmr->Src),2); // Src cSrc
+ U_swap4(&(pEmr->offBmiSrc),6); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc dwRop
+ pointl_swap(&(pEmr->cDest),1); // cDest
+ if(!torev){
+ offBmiSrc = pEmr->offBmiSrc;
+ cbBmiSrc = pEmr->cbBmiSrc;
+ offBitsSrc = pEmr->offBitsSrc;
+ cbBitsSrc = pEmr->cbBitsSrc;
+ iUsageSrc = pEmr->iUsageSrc;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0);
+ }
+ return(1);
+}
+
+// U_EMREXTCREATEFONTINDIRECTW 82
+int U_EMREXTCREATEFONTINDIRECTW_swap(char *record, int torev){
+ int nSize = 0;
+ PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (record);
+ if(torev){
+ nSize = pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->ihFont),1); // ihFont
+ if(!torev){
+ nSize = pEmr->emr.nSize;
+ }
+ if(nSize == U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE){
+ logfont_panose_swap(&(pEmr->elfw));
+ }
+ else { // logfont or logfontExDv (which starts with logfont, which can be swapped, and the rest is already in byte order
+ logfont_swap( (PU_LOGFONT) &(pEmr->elfw));
+ }
+ return(1);
+}
+
+// U_EMREXTTEXTOUTA 83
+int U_EMREXTTEXTOUTA_swap(char *record, int torev){
+ return(core8_swap(record, torev));
+}
+
+// U_EMREXTTEXTOUTW 84
+int U_EMREXTTEXTOUTW_swap(char *record, int torev){
+ return(core8_swap(record, torev));
+}
+
+// U_EMRPOLYBEZIER16 85
+/**
+ \brief Convert a pointer to a U_EMR_POLYBEZIER16 record.
+ \param record pointer to a buffer holding the EMR record
+*/
+int U_EMRPOLYBEZIER16_swap(char *record, int torev){
+ return(core6_swap(record, torev));
+}
+
+// U_EMRPOLYGON16 86
+int U_EMRPOLYGON16_swap(char *record, int torev){
+ return(core6_swap(record, torev));
+}
+
+// U_EMRPOLYLINE16 87
+int U_EMRPOLYLINE16_swap(char *record, int torev){
+ return(core6_swap(record, torev));
+}
+
+// U_EMRPOLYBEZIERTO16 88
+int U_EMRPOLYBEZIERTO16_swap(char *record, int torev){
+ return(core6_swap(record, torev));
+}
+
+// U_EMRPOLYLINETO16 89
+/**
+ \brief Convert a pointer to a U_EMR_POLYLINETO16 record.
+ \param record pointer to a buffer holding the EMR record
+*/
+int U_EMRPOLYLINETO16_swap(char *record, int torev){
+ return(core6_swap(record, torev));
+}
+
+// U_EMRPOLYPOLYLINE16 90
+int U_EMRPOLYPOLYLINE16_swap(char *record, int torev){
+ return(core10_swap(record, torev));
+}
+
+// U_EMRPOLYPOLYGON16 91
+int U_EMRPOLYPOLYGON16_swap(char *record, int torev){
+ return(core10_swap(record, torev));
+}
+
+
+// U_EMRPOLYDRAW16 92
+int U_EMRPOLYDRAW16_swap(char *record, int torev){
+ int count=0;
+ const char *blimit = NULL;
+ PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(record);
+ if(torev){
+ count = pEmr->cpts;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->cpts),1); // cpts
+ if(!torev){
+ count = pEmr->cpts;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(IS_MEM_UNSAFE((pEmr->apts), count*sizeof(U_POINT16), blimit))return(0);
+ point16_swap(pEmr->apts,count); // apts[]
+ // single byte data abTypes
+ return(1);
+}
+
+// U_EMRCREATEMONOBRUSH 93
+int U_EMRCREATEMONOBRUSH_swap(char *record, int torev){
+ return(core12_swap(record, torev));
+}
+
+// U_EMRCREATEDIBPATTERNBRUSHPT_swap 94
+int U_EMRCREATEDIBPATTERNBRUSHPT_swap(char *record, int torev){
+ return(core12_swap(record, torev));
+}
+
+
+// U_EMREXTCREATEPEN 95
+int U_EMREXTCREATEPEN_swap(char *record, int torev){
+ const char *blimit = NULL;
+ U_OFFBMI offBmi = 0;
+ U_CBBMI cbBmi = 0;
+ U_OFFBITS offBits = 0;
+ U_CBBITS cbBits = 0;
+ PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(record);
+ if(torev){
+ offBmi = pEmr->offBmi;
+ cbBmi = pEmr->cbBmi;
+ offBits = pEmr->offBits;
+ cbBits = pEmr->cbBits;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0);
+ }
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->ihPen),5); // ihPen offBmi cbBmi offBits cbBits
+ if(!torev){
+ offBmi = pEmr->offBmi;
+ cbBmi = pEmr->cbBmi;
+ offBits = pEmr->offBits;
+ cbBits = pEmr->cbBits;
+ blimit = record + pEmr->emr.nSize;
+ if(!DIB_swap(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0);
+ }
+ return(extlogpen_swap((PU_EXTLOGPEN) &(pEmr->elp), blimit, torev));
+}
+
+// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTA_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRSETICMMODE 98
+int U_EMRSETICMMODE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRCREATECOLORSPACE 99
+int U_EMRCREATECOLORSPACE_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(record);
+ U_swap4(&(pEmr->ihCS),1); // ihCS
+ logcolorspacea_swap(&(pEmr->lcs)); // lcs
+ return(1);
+}
+
+// U_EMRSETCOLORSPACE 100
+int U_EMRSETCOLORSPACE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRDELETECOLORSPACE 101
+int U_EMRDELETECOLORSPACE_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRGLSRECORD 102 Not implemented
+#define U_EMRGLSRECORD_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRGLSBOUNDEDRECORD 103 Not implemented
+#define U_EMRGLSBOUNDEDRECORD_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRPIXELFORMAT 104
+int U_EMRPIXELFORMAT_swap(char *record, int torev){
+ if(!core5_swap(record, torev))return(0);
+ PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(record);
+ pixelformatdescriptor_swap(&(pEmr->pfd)); // pfd
+ return(1);
+}
+
+// U_EMRDRAWESCAPE 105 Not implemented
+#define U_EMRDRAWESCAPE_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMREXTESCAPE 106 Not implemented
+#define U_EMREXTESCAPE_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRUNDEF107 107 Not implemented
+#define U_EMRUNDEF107_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRSMALLTEXTOUT 108
+int U_EMRSMALLTEXTOUT_swap(char *record, int torev){
+ int roff=sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields
+ int fuOptions = 0;
+ int cChars = 0;
+ const char *blimit = NULL;
+ PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(record);
+ if(torev){
+ fuOptions = pEmr->fuOptions;
+ cChars = pEmr->cChars;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ pointl_swap(&(pEmr->Dest),1); // Dest
+ U_swap4(&(pEmr->cChars),5); // cChars fuOptions iGraphicsMode exScale eyScale
+ if(!torev){
+ fuOptions = pEmr->fuOptions;
+ cChars = pEmr->cChars;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!(fuOptions & U_ETO_NO_RECT)){
+ if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL), blimit))return(0);
+ rectl_swap( (PU_RECTL) (record + roff),1); // rclBounds
+ }
+ if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL) + cChars, blimit))return(0);
+ // ordered bytes or UTF16-LE TextString
+ return(1);
+}
+
+// U_EMRFORCEUFIMAPPING 109 Not implemented
+#define U_EMRFORCEUFIMAPPING_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRNAMEDESCAPE 110 Not implemented
+#define U_EMRNAMEDESCAPE_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRCOLORCORRECTPALETTE 111 Not implemented
+#define U_EMRCOLORCORRECTPALETTE_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRSETICMPROFILEA 112 Not implemented
+#define U_EMRSETICMPROFILEA_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRSETICMPROFILEW 113 Not implemented
+#define U_EMRSETICMPROFILEW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRALPHABLEND 114
+int U_EMRALPHABLEND_swap(char *record, int torev){
+ return(core13_swap(record, torev));
+}
+
+// U_EMRSETLAYOUT 115
+int U_EMRSETLAYOUT_swap(char *record, int torev){
+ return(core3_swap(record, torev));
+}
+
+// U_EMRTRANSPARENTBLT 116
+int U_EMRTRANSPARENTBLT_swap(char *record, int torev){
+ return(core13_swap(record, torev));
+}
+
+
+// U_EMRUNDEF117 117 Not implemented
+#define U_EMRUNDEF117_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRGRADIENTFILL 118
+int U_EMRGRADIENTFILL_swap(char *record, int torev){
+ int nTriVert=0;
+ int nGradObj=0;
+ int ulMode=0;
+ const char *blimit = NULL;
+ PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(record);
+ if(torev){
+ nTriVert = pEmr->nTriVert;
+ nGradObj = pEmr->nGradObj;
+ ulMode = pEmr->ulMode;
+ blimit = record + pEmr->emr.nSize;
+ }
+ if(!core5_swap(record, torev))return(0);
+ rectl_swap(&(pEmr->rclBounds),1); // rclBounds
+ U_swap4(&(pEmr->nTriVert),3); // nTriVert nGradObj ulMode
+ if(!torev){
+ nTriVert = pEmr->nTriVert;
+ nGradObj = pEmr->nGradObj;
+ ulMode = pEmr->ulMode;
+ blimit = record + pEmr->emr.nSize;
+ }
+ record += sizeof(U_EMRGRADIENTFILL);
+ if(IS_MEM_UNSAFE(record, nTriVert*sizeof(U_TRIVERTEX), blimit))return(0);
+ if(nTriVert){
+ trivertex_swap((PU_TRIVERTEX)(record),nTriVert); // TriVert[]
+ }
+ record += nTriVert * sizeof(U_TRIVERTEX);
+ if(nGradObj){
+ if( ulMode == U_GRADIENT_FILL_TRIANGLE){
+ if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT3), blimit))return(0);
+ gradient3_swap((PU_GRADIENT3)(record), nGradObj); // GradObj[]
+ }
+ else if(ulMode == U_GRADIENT_FILL_RECT_H || ulMode == U_GRADIENT_FILL_RECT_V){
+ if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT4), blimit))return(0);
+ gradient4_swap((PU_GRADIENT4)(record), nGradObj); // GradObj[]
+ }
+ }
+ return(1);
+}
+
+// U_EMRSETLINKEDUFIS 119 Not implemented
+#define U_EMRSETLINKEDUFIS_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated)
+#define U_EMRSETTEXTJUSTIFICATION_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+// U_EMRCOLORMATCHTOTARGETW 121 Not implemented
+#define U_EMRCOLORMATCHTOTARGETW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented.
+
+// U_EMRCREATECOLORSPACEW 122
+int U_EMRCREATECOLORSPACEW_swap(char *record, int torev){
+ PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(record);
+ if(!core5_swap(record, torev))return(0);
+ U_swap4(&(pEmr->ihCS),1); // ihCS
+ logcolorspacew_swap(&(pEmr->lcs)); // lcs
+ U_swap4(&(pEmr->dwFlags),2); // dwFlags cbData
+ // ordered bytes: Data
+ return(1);
+}
+
+//! \endcond
+
+/**
+ \brief Checks the declared size of a record for consistency
+ \return 0 on failure, 1 on success
+ \param record pointer to the start of the EMF record in memory
+ \param blimit pointer to one byte after the EMF record in memory
+ \param nSize number of bytes in the record, read from the record
+ \param iType type of the record, read from the record
+ \param torev 1 for native to reversed, 0 for reversed to native
+
+ Normally this would be called immediately after reading the data from a file.
+ Verifies that the declared size is consistent with this type of record.
+*/
+int U_emf_record_sizeok(const char *record, const char *blimit, uint32_t *nSize, uint32_t *iType, int torev){
+ uint32_t rsize=0;
+ if(!nSize || !iType)return(0); // programming error
+
+ /* Check that COMMON data in record can be touched without an access violation. If it cannot be
+ this is either a corrupt EMF or one engineered to cause a buffer overflow. Pointer math
+ could wrap so check both sides of the range, and fail any indications of such a wrap.
+ */
+ if(IS_MEM_UNSAFE(record, sizeof(U_EMR), blimit))return(0);
+
+ PU_ENHMETARECORD pEmr = (PU_ENHMETARECORD)(record);
+ *iType = pEmr->iType;
+ *nSize = pEmr->nSize;
+ if(!torev){
+ U_swap4(iType,1);
+ U_swap4(nSize,1);
+ }
+
+ /* Check that the FULL record size is OK, abort if not. */
+ if(IS_MEM_UNSAFE(record, *nSize, blimit))return(0);
+
+ switch (*iType)
+ {
+ // next line, ancient EMF files used a smaller header, to be safe, test for that
+ case U_EMR_HEADER: rsize = U_SIZE_EMRHEADER_MIN; break;
+ case U_EMR_POLYBEZIER: rsize = U_SIZE_EMRPOLYBEZIER; break;
+ case U_EMR_POLYGON: rsize = U_SIZE_EMRPOLYGON; break;
+ case U_EMR_POLYLINE: rsize = U_SIZE_EMRPOLYLINE; break;
+ case U_EMR_POLYBEZIERTO: rsize = U_SIZE_EMRPOLYBEZIERTO; break;
+ case U_EMR_POLYLINETO: rsize = U_SIZE_EMRPOLYLINETO; break;
+ case U_EMR_POLYPOLYLINE: rsize = U_SIZE_EMRPOLYPOLYLINE; break;
+ case U_EMR_POLYPOLYGON: rsize = U_SIZE_EMRPOLYPOLYGON; break;
+ case U_EMR_SETWINDOWEXTEX: rsize = U_SIZE_EMRSETWINDOWEXTEX; break;
+ case U_EMR_SETWINDOWORGEX: rsize = U_SIZE_EMRSETWINDOWORGEX; break;
+ case U_EMR_SETVIEWPORTEXTEX: rsize = U_SIZE_EMRSETVIEWPORTEXTEX; break;
+ case U_EMR_SETVIEWPORTORGEX: rsize = U_SIZE_EMRSETVIEWPORTORGEX; break;
+ case U_EMR_SETBRUSHORGEX: rsize = U_SIZE_EMRSETBRUSHORGEX; break;
+ case U_EMR_EOF: rsize = U_SIZE_EMREOF; break;
+ case U_EMR_SETPIXELV: rsize = U_SIZE_EMRSETPIXELV; break;
+ case U_EMR_SETMAPPERFLAGS: rsize = U_SIZE_EMRSETMAPPERFLAGS; break;
+ case U_EMR_SETMAPMODE: rsize = U_SIZE_EMRSETMAPMODE; break;
+ case U_EMR_SETBKMODE: rsize = U_SIZE_EMRSETBKMODE; break;
+ case U_EMR_SETPOLYFILLMODE: rsize = U_SIZE_EMRSETPOLYFILLMODE; break;
+ case U_EMR_SETROP2: rsize = U_SIZE_EMRSETROP2; break;
+ case U_EMR_SETSTRETCHBLTMODE: rsize = U_SIZE_EMRSETSTRETCHBLTMODE; break;
+ case U_EMR_SETTEXTALIGN: rsize = U_SIZE_EMRSETTEXTALIGN; break;
+ case U_EMR_SETCOLORADJUSTMENT: rsize = U_SIZE_EMRSETCOLORADJUSTMENT; break;
+ case U_EMR_SETTEXTCOLOR: rsize = U_SIZE_EMRSETTEXTCOLOR; break;
+ case U_EMR_SETBKCOLOR: rsize = U_SIZE_EMRSETBKCOLOR; break;
+ case U_EMR_OFFSETCLIPRGN: rsize = U_SIZE_EMROFFSETCLIPRGN; break;
+ case U_EMR_MOVETOEX: rsize = U_SIZE_EMRMOVETOEX; break;
+ case U_EMR_SETMETARGN: rsize = U_SIZE_EMRSETMETARGN; break;
+ case U_EMR_EXCLUDECLIPRECT: rsize = U_SIZE_EMREXCLUDECLIPRECT; break;
+ case U_EMR_INTERSECTCLIPRECT: rsize = U_SIZE_EMRINTERSECTCLIPRECT; break;
+ case U_EMR_SCALEVIEWPORTEXTEX: rsize = U_SIZE_EMRSCALEVIEWPORTEXTEX; break;
+ case U_EMR_SCALEWINDOWEXTEX: rsize = U_SIZE_EMRSCALEWINDOWEXTEX; break;
+ case U_EMR_SAVEDC: rsize = U_SIZE_EMRSAVEDC; break;
+ case U_EMR_RESTOREDC: rsize = U_SIZE_EMRRESTOREDC; break;
+ case U_EMR_SETWORLDTRANSFORM: rsize = U_SIZE_EMRSETWORLDTRANSFORM; break;
+ case U_EMR_MODIFYWORLDTRANSFORM: rsize = U_SIZE_EMRMODIFYWORLDTRANSFORM; break;
+ case U_EMR_SELECTOBJECT: rsize = U_SIZE_EMRSELECTOBJECT; break;
+ case U_EMR_CREATEPEN: rsize = U_SIZE_EMRCREATEPEN; break;
+ case U_EMR_CREATEBRUSHINDIRECT: rsize = U_SIZE_EMRCREATEBRUSHINDIRECT; break;
+ case U_EMR_DELETEOBJECT: rsize = U_SIZE_EMRDELETEOBJECT; break;
+ case U_EMR_ANGLEARC: rsize = U_SIZE_EMRANGLEARC; break;
+ case U_EMR_ELLIPSE: rsize = U_SIZE_EMRELLIPSE; break;
+ case U_EMR_RECTANGLE: rsize = U_SIZE_EMRRECTANGLE; break;
+ case U_EMR_ROUNDRECT: rsize = U_SIZE_EMRROUNDRECT; break;
+ case U_EMR_ARC: rsize = U_SIZE_EMRARC; break;
+ case U_EMR_CHORD: rsize = U_SIZE_EMRCHORD; break;
+ case U_EMR_PIE: rsize = U_SIZE_EMRPIE; break;
+ case U_EMR_SELECTPALETTE: rsize = U_SIZE_EMRSELECTPALETTE; break;
+ case U_EMR_CREATEPALETTE: rsize = U_SIZE_EMRCREATEPALETTE; break;
+ case U_EMR_SETPALETTEENTRIES: rsize = U_SIZE_EMRSETPALETTEENTRIES; break;
+ case U_EMR_RESIZEPALETTE: rsize = U_SIZE_EMRRESIZEPALETTE; break;
+ case U_EMR_REALIZEPALETTE: rsize = U_SIZE_EMRREALIZEPALETTE; break;
+ case U_EMR_EXTFLOODFILL: rsize = U_SIZE_EMREXTFLOODFILL; break;
+ case U_EMR_LINETO: rsize = U_SIZE_EMRLINETO; break;
+ case U_EMR_ARCTO: rsize = U_SIZE_EMRARCTO; break;
+ case U_EMR_POLYDRAW: rsize = U_SIZE_EMRPOLYDRAW; break;
+ case U_EMR_SETARCDIRECTION: rsize = U_SIZE_EMRSETARCDIRECTION; break;
+ case U_EMR_SETMITERLIMIT: rsize = U_SIZE_EMRSETMITERLIMIT; break;
+ case U_EMR_BEGINPATH: rsize = U_SIZE_EMRBEGINPATH; break;
+ case U_EMR_ENDPATH: rsize = U_SIZE_EMRENDPATH; break;
+ case U_EMR_CLOSEFIGURE: rsize = U_SIZE_EMRCLOSEFIGURE; break;
+ case U_EMR_FILLPATH: rsize = U_SIZE_EMRFILLPATH; break;
+ case U_EMR_STROKEANDFILLPATH: rsize = U_SIZE_EMRSTROKEANDFILLPATH; break;
+ case U_EMR_STROKEPATH: rsize = U_SIZE_EMRSTROKEPATH; break;
+ case U_EMR_FLATTENPATH: rsize = U_SIZE_EMRFLATTENPATH; break;
+ case U_EMR_WIDENPATH: rsize = U_SIZE_EMRWIDENPATH; break;
+ case U_EMR_SELECTCLIPPATH: rsize = U_SIZE_EMRSELECTCLIPPATH; break;
+ case U_EMR_ABORTPATH: rsize = U_SIZE_EMRABORTPATH; break;
+ case U_EMR_UNDEF69: rsize = U_SIZE_EMRUNDEFINED; break;
+ case U_EMR_COMMENT: rsize = U_SIZE_EMRCOMMENT; break;
+ case U_EMR_FILLRGN: rsize = U_SIZE_EMRFILLRGN; break;
+ case U_EMR_FRAMERGN: rsize = U_SIZE_EMRFRAMERGN; break;
+ case U_EMR_INVERTRGN: rsize = U_SIZE_EMRINVERTRGN; break;
+ case U_EMR_PAINTRGN: rsize = U_SIZE_EMRPAINTRGN; break;
+ case U_EMR_EXTSELECTCLIPRGN: rsize = U_SIZE_EMREXTSELECTCLIPRGN; break;
+ case U_EMR_BITBLT: rsize = U_SIZE_EMRBITBLT; break;
+ case U_EMR_STRETCHBLT: rsize = U_SIZE_EMRSTRETCHBLT; break;
+ case U_EMR_MASKBLT: rsize = U_SIZE_EMRMASKBLT; break;
+ case U_EMR_PLGBLT: rsize = U_SIZE_EMRPLGBLT; break;
+ case U_EMR_SETDIBITSTODEVICE: rsize = U_SIZE_EMRSETDIBITSTODEVICE; break;
+ case U_EMR_STRETCHDIBITS: rsize = U_SIZE_EMRSTRETCHDIBITS; break;
+ case U_EMR_EXTCREATEFONTINDIRECTW: rsize = U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT; break;
+ case U_EMR_EXTTEXTOUTA: rsize = U_SIZE_EMREXTTEXTOUTA; break;
+ case U_EMR_EXTTEXTOUTW: rsize = U_SIZE_EMREXTTEXTOUTW; break;
+ case U_EMR_POLYBEZIER16: rsize = U_SIZE_EMRPOLYBEZIER16; break;
+ case U_EMR_POLYGON16: rsize = U_SIZE_EMRPOLYGON16; break;
+ case U_EMR_POLYLINE16: rsize = U_SIZE_EMRPOLYLINE16; break;
+ case U_EMR_POLYBEZIERTO16: rsize = U_SIZE_EMRPOLYBEZIERTO16; break;
+ case U_EMR_POLYLINETO16: rsize = U_SIZE_EMRPOLYLINETO16; break;
+ case U_EMR_POLYPOLYLINE16: rsize = U_SIZE_EMRPOLYPOLYLINE16; break;
+ case U_EMR_POLYPOLYGON16: rsize = U_SIZE_EMRPOLYPOLYGON16; break;
+ case U_EMR_POLYDRAW16: rsize = U_SIZE_EMRPOLYDRAW16; break;
+ case U_EMR_CREATEMONOBRUSH: rsize = U_SIZE_EMRCREATEMONOBRUSH; break;
+ case U_EMR_CREATEDIBPATTERNBRUSHPT: rsize = U_SIZE_EMRCREATEDIBPATTERNBRUSHPT; break;
+ case U_EMR_EXTCREATEPEN: rsize = U_SIZE_EMREXTCREATEPEN; break;
+ case U_EMR_POLYTEXTOUTA: rsize = U_SIZE_EMRPOLYTEXTOUTA; break;
+ case U_EMR_POLYTEXTOUTW: rsize = U_SIZE_EMRPOLYTEXTOUTW; break;
+ case U_EMR_SETICMMODE: rsize = U_SIZE_EMRSETICMMODE; break;
+ case U_EMR_CREATECOLORSPACE: rsize = U_SIZE_EMRCREATECOLORSPACE; break;
+ case U_EMR_SETCOLORSPACE: rsize = U_SIZE_EMRSETCOLORSPACE; break;
+ case U_EMR_DELETECOLORSPACE: rsize = U_SIZE_EMRDELETECOLORSPACE; break;
+ case U_EMR_GLSRECORD: rsize = U_SIZE_EMRGLSRECORD; break;
+ case U_EMR_GLSBOUNDEDRECORD: rsize = U_SIZE_EMRGLSBOUNDEDRECORD; break;
+ case U_EMR_PIXELFORMAT: rsize = U_SIZE_EMRPIXELFORMAT; break;
+ case U_EMR_DRAWESCAPE: rsize = U_SIZE_EMRDRAWESCAPE; break;
+ case U_EMR_EXTESCAPE: rsize = U_SIZE_EMREXTESCAPE; break;
+ case U_EMR_UNDEF107: rsize = U_SIZE_EMRUNDEFINED; break;
+ case U_EMR_SMALLTEXTOUT: rsize = U_SIZE_EMRSMALLTEXTOUT; break;
+// case U_EMR_FORCEUFIMAPPING: rsize = U_SIZE_EMRFORCEUFIMAPPING; break;
+ case U_EMR_NAMEDESCAPE: rsize = U_SIZE_EMRNAMEDESCAPE; break;
+// case U_EMR_COLORCORRECTPALETTE: rsize = U_SIZE_EMRCOLORCORRECTPALETTE; break;
+// case U_EMR_SETICMPROFILEA: rsize = U_SIZE_EMRSETICMPROFILEA; break;
+// case U_EMR_SETICMPROFILEW: rsize = U_SIZE_EMRSETICMPROFILEW; break;
+ case U_EMR_ALPHABLEND: rsize = U_SIZE_EMRALPHABLEND; break;
+ case U_EMR_SETLAYOUT: rsize = U_SIZE_EMRSETLAYOUT; break;
+ case U_EMR_TRANSPARENTBLT: rsize = U_SIZE_EMRTRANSPARENTBLT; break;
+ case U_EMR_UNDEF117: rsize = U_SIZE_EMRUNDEFINED; break;
+ case U_EMR_GRADIENTFILL: rsize = U_SIZE_EMRGRADIENTFILL; break;
+// case U_EMR_SETLINKEDUFIS: rsize = U_SIZE_EMRSETLINKEDUFIS; break;
+// case U_EMR_SETTEXTJUSTIFICATION: rsize = U_SIZE_EMRSETTEXTJUSTIFICATION; break;
+ case U_EMR_COLORMATCHTOTARGETW: rsize = U_SIZE_EMRCOLORMATCHTOTARGETW; break;
+ case U_EMR_CREATECOLORSPACEW: rsize = U_SIZE_EMRCREATECOLORSPACEW; break;
+ default: rsize = U_SIZE_EMRNOTIMPLEMENTED; break;
+ } //end of switch
+ // record's declared size must be more than the minimum size for this type of record
+ if(*nSize < rsize){
+ return(0);
+ }
+ return(1);
+}
+
+
+/**
+ \brief Convert an entire EMF in memory from Big Endian to Little Endian.
+ \return 0 on failure, 1 on success
+ \param contents pointer to the buffer holding the entire EMF in memory
+ \param length number of bytes in the buffer
+ \param torev 1 for native to reversed, 0 for reversed to native
+
+ Normally this would be called immediately before writing the data to a file
+ or immediately after reading the data from a file.
+*/
+int U_emf_endian(char *contents, size_t length, int torev){
+ uint32_t off;
+ uint32_t OK, recnum, iType;
+ char *record;
+ const char *blimit = contents + length; /* should never wrap since it describes a structure in memory */
+ int rstatus=1;
+
+ record = contents;
+ OK = 1;
+ off = 0;
+ recnum = 0;
+ while(OK){
+
+ if(!U_emf_record_sizeok(record, blimit, &off, &iType, torev)){
+ return(0);
+ }
+
+ switch (iType)
+ {
+ case U_EMR_HEADER: rstatus=U_EMRHEADER_swap(record, torev); break;
+ case U_EMR_POLYBEZIER: rstatus=U_EMRPOLYBEZIER_swap(record, torev); break;
+ case U_EMR_POLYGON: rstatus=U_EMRPOLYGON_swap(record, torev); break;
+ case U_EMR_POLYLINE: rstatus=U_EMRPOLYLINE_swap(record, torev); break;
+ case U_EMR_POLYBEZIERTO: rstatus=U_EMRPOLYBEZIERTO_swap(record, torev); break;
+ case U_EMR_POLYLINETO: rstatus=U_EMRPOLYLINETO_swap(record, torev); break;
+ case U_EMR_POLYPOLYLINE: rstatus=U_EMRPOLYPOLYLINE_swap(record, torev); break;
+ case U_EMR_POLYPOLYGON: rstatus=U_EMRPOLYPOLYGON_swap(record, torev); break;
+ case U_EMR_SETWINDOWEXTEX: rstatus=U_EMRSETWINDOWEXTEX_swap(record, torev); break;
+ case U_EMR_SETWINDOWORGEX: rstatus=U_EMRSETWINDOWORGEX_swap(record, torev); break;
+ case U_EMR_SETVIEWPORTEXTEX: rstatus=U_EMRSETVIEWPORTEXTEX_swap(record, torev); break;
+ case U_EMR_SETVIEWPORTORGEX: rstatus=U_EMRSETVIEWPORTORGEX_swap(record, torev); break;
+ case U_EMR_SETBRUSHORGEX: rstatus=U_EMRSETBRUSHORGEX_swap(record, torev); break;
+ case U_EMR_EOF:
+ rstatus=U_EMREOF_swap(record, torev);
+ OK = 0; /* Exit triggered here */
+ break;
+ case U_EMR_SETPIXELV: rstatus=U_EMRSETPIXELV_swap(record, torev); break;
+ case U_EMR_SETMAPPERFLAGS: rstatus=U_EMRSETMAPPERFLAGS_swap(record, torev); break;
+ case U_EMR_SETMAPMODE: rstatus=U_EMRSETMAPMODE_swap(record, torev); break;
+ case U_EMR_SETBKMODE: rstatus=U_EMRSETBKMODE_swap(record, torev); break;
+ case U_EMR_SETPOLYFILLMODE: rstatus=U_EMRSETPOLYFILLMODE_swap(record, torev); break;
+ case U_EMR_SETROP2: rstatus=U_EMRSETROP2_swap(record, torev); break;
+ case U_EMR_SETSTRETCHBLTMODE: rstatus=U_EMRSETSTRETCHBLTMODE_swap(record, torev); break;
+ case U_EMR_SETTEXTALIGN: rstatus=U_EMRSETTEXTALIGN_swap(record, torev); break;
+ case U_EMR_SETCOLORADJUSTMENT: rstatus=U_EMRSETCOLORADJUSTMENT_swap(record, torev); break;
+ case U_EMR_SETTEXTCOLOR: rstatus=U_EMRSETTEXTCOLOR_swap(record, torev); break;
+ case U_EMR_SETBKCOLOR: rstatus=U_EMRSETBKCOLOR_swap(record, torev); break;
+ case U_EMR_OFFSETCLIPRGN: rstatus=U_EMROFFSETCLIPRGN_swap(record, torev); break;
+ case U_EMR_MOVETOEX: rstatus=U_EMRMOVETOEX_swap(record, torev); break;
+ case U_EMR_SETMETARGN: rstatus=U_EMRSETMETARGN_swap(record, torev); break;
+ case U_EMR_EXCLUDECLIPRECT: rstatus=U_EMREXCLUDECLIPRECT_swap(record, torev); break;
+ case U_EMR_INTERSECTCLIPRECT: rstatus=U_EMRINTERSECTCLIPRECT_swap(record, torev); break;
+ case U_EMR_SCALEVIEWPORTEXTEX: rstatus=U_EMRSCALEVIEWPORTEXTEX_swap(record, torev); break;
+ case U_EMR_SCALEWINDOWEXTEX: rstatus=U_EMRSCALEWINDOWEXTEX_swap(record, torev); break;
+ case U_EMR_SAVEDC: rstatus=U_EMRSAVEDC_swap(record, torev); break;
+ case U_EMR_RESTOREDC: rstatus=U_EMRRESTOREDC_swap(record, torev); break;
+ case U_EMR_SETWORLDTRANSFORM: rstatus=U_EMRSETWORLDTRANSFORM_swap(record, torev); break;
+ case U_EMR_MODIFYWORLDTRANSFORM: rstatus=U_EMRMODIFYWORLDTRANSFORM_swap(record, torev); break;
+ case U_EMR_SELECTOBJECT: rstatus=U_EMRSELECTOBJECT_swap(record, torev); break;
+ case U_EMR_CREATEPEN: rstatus=U_EMRCREATEPEN_swap(record, torev); break;
+ case U_EMR_CREATEBRUSHINDIRECT: rstatus=U_EMRCREATEBRUSHINDIRECT_swap(record, torev); break;
+ case U_EMR_DELETEOBJECT: rstatus=U_EMRDELETEOBJECT_swap(record, torev); break;
+ case U_EMR_ANGLEARC: rstatus=U_EMRANGLEARC_swap(record, torev); break;
+ case U_EMR_ELLIPSE: rstatus=U_EMRELLIPSE_swap(record, torev); break;
+ case U_EMR_RECTANGLE: rstatus=U_EMRRECTANGLE_swap(record, torev); break;
+ case U_EMR_ROUNDRECT: rstatus=U_EMRROUNDRECT_swap(record, torev); break;
+ case U_EMR_ARC: rstatus=U_EMRARC_swap(record, torev); break;
+ case U_EMR_CHORD: rstatus=U_EMRCHORD_swap(record, torev); break;
+ case U_EMR_PIE: rstatus=U_EMRPIE_swap(record, torev); break;
+ case U_EMR_SELECTPALETTE: rstatus=U_EMRSELECTPALETTE_swap(record, torev); break;
+ case U_EMR_CREATEPALETTE: rstatus=U_EMRCREATEPALETTE_swap(record, torev); break;
+ case U_EMR_SETPALETTEENTRIES: rstatus=U_EMRSETPALETTEENTRIES_swap(record, torev); break;
+ case U_EMR_RESIZEPALETTE: rstatus=U_EMRRESIZEPALETTE_swap(record, torev); break;
+ case U_EMR_REALIZEPALETTE: rstatus=U_EMRREALIZEPALETTE_swap(record, torev); break;
+ case U_EMR_EXTFLOODFILL: rstatus=U_EMREXTFLOODFILL_swap(record, torev); break;
+ case U_EMR_LINETO: rstatus=U_EMRLINETO_swap(record, torev); break;
+ case U_EMR_ARCTO: rstatus=U_EMRARCTO_swap(record, torev); break;
+ case U_EMR_POLYDRAW: rstatus=U_EMRPOLYDRAW_swap(record, torev); break;
+ case U_EMR_SETARCDIRECTION: rstatus=U_EMRSETARCDIRECTION_swap(record, torev); break;
+ case U_EMR_SETMITERLIMIT: rstatus=U_EMRSETMITERLIMIT_swap(record, torev); break;
+ case U_EMR_BEGINPATH: rstatus=U_EMRBEGINPATH_swap(record, torev); break;
+ case U_EMR_ENDPATH: rstatus=U_EMRENDPATH_swap(record, torev); break;
+ case U_EMR_CLOSEFIGURE: rstatus=U_EMRCLOSEFIGURE_swap(record, torev); break;
+ case U_EMR_FILLPATH: rstatus=U_EMRFILLPATH_swap(record, torev); break;
+ case U_EMR_STROKEANDFILLPATH: rstatus=U_EMRSTROKEANDFILLPATH_swap(record, torev); break;
+ case U_EMR_STROKEPATH: rstatus=U_EMRSTROKEPATH_swap(record, torev); break;
+ case U_EMR_FLATTENPATH: rstatus=U_EMRFLATTENPATH_swap(record, torev); break;
+ case U_EMR_WIDENPATH: rstatus=U_EMRWIDENPATH_swap(record, torev); break;
+ case U_EMR_SELECTCLIPPATH: rstatus=U_EMRSELECTCLIPPATH_swap(record, torev); break;
+ case U_EMR_ABORTPATH: rstatus=U_EMRABORTPATH_swap(record, torev); break;
+ case U_EMR_UNDEF69: rstatus=U_EMRUNDEF69_swap(record, torev); break;
+ case U_EMR_COMMENT: rstatus=U_EMRCOMMENT_swap(record, torev); break;
+ case U_EMR_FILLRGN: rstatus=U_EMRFILLRGN_swap(record, torev); break;
+ case U_EMR_FRAMERGN: rstatus=U_EMRFRAMERGN_swap(record, torev); break;
+ case U_EMR_INVERTRGN: rstatus=U_EMRINVERTRGN_swap(record, torev); break;
+ case U_EMR_PAINTRGN: rstatus=U_EMRPAINTRGN_swap(record, torev); break;
+ case U_EMR_EXTSELECTCLIPRGN: rstatus=U_EMREXTSELECTCLIPRGN_swap(record, torev);break;
+ case U_EMR_BITBLT: rstatus=U_EMRBITBLT_swap(record, torev); break;
+ case U_EMR_STRETCHBLT: rstatus=U_EMRSTRETCHBLT_swap(record, torev); break;
+ case U_EMR_MASKBLT: rstatus=U_EMRMASKBLT_swap(record, torev); break;
+ case U_EMR_PLGBLT: rstatus=U_EMRPLGBLT_swap(record, torev); break;
+ case U_EMR_SETDIBITSTODEVICE: rstatus=U_EMRSETDIBITSTODEVICE_swap(record, torev); break;
+ case U_EMR_STRETCHDIBITS: rstatus=U_EMRSTRETCHDIBITS_swap(record, torev); break;
+ case U_EMR_EXTCREATEFONTINDIRECTW: rstatus=U_EMREXTCREATEFONTINDIRECTW_swap(record, torev); break;
+ case U_EMR_EXTTEXTOUTA: rstatus=U_EMREXTTEXTOUTA_swap(record, torev); break;
+ case U_EMR_EXTTEXTOUTW: rstatus=U_EMREXTTEXTOUTW_swap(record, torev); break;
+ case U_EMR_POLYBEZIER16: rstatus=U_EMRPOLYBEZIER16_swap(record, torev); break;
+ case U_EMR_POLYGON16: rstatus=U_EMRPOLYGON16_swap(record, torev); break;
+ case U_EMR_POLYLINE16: rstatus=U_EMRPOLYLINE16_swap(record, torev); break;
+ case U_EMR_POLYBEZIERTO16: rstatus=U_EMRPOLYBEZIERTO16_swap(record, torev); break;
+ case U_EMR_POLYLINETO16: rstatus=U_EMRPOLYLINETO16_swap(record, torev); break;
+ case U_EMR_POLYPOLYLINE16: rstatus=U_EMRPOLYPOLYLINE16_swap(record, torev); break;
+ case U_EMR_POLYPOLYGON16: rstatus=U_EMRPOLYPOLYGON16_swap(record, torev); break;
+ case U_EMR_POLYDRAW16: rstatus=U_EMRPOLYDRAW16_swap(record, torev); break;
+ case U_EMR_CREATEMONOBRUSH: rstatus=U_EMRCREATEMONOBRUSH_swap(record, torev); break;
+ case U_EMR_CREATEDIBPATTERNBRUSHPT: rstatus=U_EMRCREATEDIBPATTERNBRUSHPT_swap(record, torev); break;
+ case U_EMR_EXTCREATEPEN: rstatus=U_EMREXTCREATEPEN_swap(record, torev); break;
+ case U_EMR_POLYTEXTOUTA: rstatus=U_EMRPOLYTEXTOUTA_swap(record, torev); break;
+ case U_EMR_POLYTEXTOUTW: rstatus=U_EMRPOLYTEXTOUTW_swap(record, torev); break;
+ case U_EMR_SETICMMODE: rstatus=U_EMRSETICMMODE_swap(record, torev); break;
+ case U_EMR_CREATECOLORSPACE: rstatus=U_EMRCREATECOLORSPACE_swap(record, torev); break;
+ case U_EMR_SETCOLORSPACE: rstatus=U_EMRSETCOLORSPACE_swap(record, torev); break;
+ case U_EMR_DELETECOLORSPACE: rstatus=U_EMRDELETECOLORSPACE_swap(record, torev); break;
+ case U_EMR_GLSRECORD: rstatus=U_EMRGLSRECORD_swap(record, torev); break;
+ case U_EMR_GLSBOUNDEDRECORD: rstatus=U_EMRGLSBOUNDEDRECORD_swap(record, torev); break;
+ case U_EMR_PIXELFORMAT: rstatus=U_EMRPIXELFORMAT_swap(record, torev); break;
+ case U_EMR_DRAWESCAPE: rstatus=U_EMRDRAWESCAPE_swap(record, torev); break;
+ case U_EMR_EXTESCAPE: rstatus=U_EMREXTESCAPE_swap(record, torev); break;
+ case U_EMR_UNDEF107: rstatus=U_EMRUNDEF107_swap(record, torev); break;
+ case U_EMR_SMALLTEXTOUT: rstatus=U_EMRSMALLTEXTOUT_swap(record, torev); break;
+ case U_EMR_FORCEUFIMAPPING: rstatus=U_EMRFORCEUFIMAPPING_swap(record, torev); break;
+ case U_EMR_NAMEDESCAPE: rstatus=U_EMRNAMEDESCAPE_swap(record, torev); break;
+ case U_EMR_COLORCORRECTPALETTE: rstatus=U_EMRCOLORCORRECTPALETTE_swap(record, torev); break;
+ case U_EMR_SETICMPROFILEA: rstatus=U_EMRSETICMPROFILEA_swap(record, torev); break;
+ case U_EMR_SETICMPROFILEW: rstatus=U_EMRSETICMPROFILEW_swap(record, torev); break;
+ case U_EMR_ALPHABLEND: rstatus=U_EMRALPHABLEND_swap(record, torev); break;
+ case U_EMR_SETLAYOUT: rstatus=U_EMRSETLAYOUT_swap(record, torev); break;
+ case U_EMR_TRANSPARENTBLT: rstatus=U_EMRTRANSPARENTBLT_swap(record, torev); break;
+ case U_EMR_UNDEF117: rstatus=U_EMRUNDEF117_swap(record, torev); break;
+ case U_EMR_GRADIENTFILL: rstatus=U_EMRGRADIENTFILL_swap(record, torev); break;
+ case U_EMR_SETLINKEDUFIS: rstatus=U_EMRSETLINKEDUFIS_swap(record, torev); break;
+ case U_EMR_SETTEXTJUSTIFICATION: rstatus=U_EMRSETTEXTJUSTIFICATION_swap(record, torev); break;
+ case U_EMR_COLORMATCHTOTARGETW: rstatus=U_EMRCOLORMATCHTOTARGETW_swap(record, torev); break;
+ case U_EMR_CREATECOLORSPACEW: rstatus=U_EMRCREATECOLORSPACEW_swap(record, torev); break;
+ default: rstatus=U_EMRNOTIMPLEMENTED_swap(record, torev); break;
+ } //end of switch
+ if(!rstatus){
+ return(rstatus);
+ }
+ record += off;
+ recnum++;
+ } //end of while
+
+ return(1);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uemf_endian.h b/src/3rdparty/libuemf/uemf_endian.h
new file mode 100644
index 000000000..9dbcec455
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_endian.h
@@ -0,0 +1,59 @@
+/**
+ @file uemf_endian.h
+
+ @brief Defintions and prototype for function for converting EMF records between Big Endian and Little Endian byte orders.
+*/
+
+/*
+File: uemf_endian.h
+Version: 0.0.4
+Date: 24-MAR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UEMF_ENDIAN_
+#define _UEMF_ENDIAN_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup U_Endian Byte order identification
+
+ There is no way for the preprocessor, in general, to figure out endianness. So the command line must define
+ WORDS_BIGENDIAN for a big endian machine. Otherwise we assume is is little endian. If it is something
+ else this code won't work in any case.
+
+ @{
+*/
+
+#ifdef WORDS_BIGENDIAN
+#define U_BYTE_SWAP 1 //!< byte swapping into metafile is required
+#define U_IS_BE 1 //!< this machine is big endian
+#define U_IS_LE 0 //!< this machine is not little endian
+#else
+#define U_BYTE_SWAP 0 //!< byte swapping into metafile is not required
+#define U_IS_BE 0 //!< this machine is not big endian
+#define U_IS_LE 1 //!< this machine is little endian
+#endif
+
+#define U_XE 0 //!< do not rearrange endian for target
+#define U_LE 1 //!< target is Little Endian
+#define U_BE 2 //!< target is Big Endian
+#define U_RP 4 //!< replicate first instance
+#define U_XX 0xFF //!< may be used to terminate a list of these target entries
+/** @} */
+
+//! \cond
+// prototypes
+int U_emf_endian(char *contents, size_t length, int torev);
+int U_emf_record_sizeok(const char *record, const char *blimit, uint32_t *nSize, uint32_t *iType, int torev);
+//! \endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UEMF_ENDIAN_ */
diff --git a/src/3rdparty/libuemf/uemf_print.c b/src/3rdparty/libuemf/uemf_print.c
new file mode 100644
index 000000000..28fe0b7c3
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_print.c
@@ -0,0 +1,2704 @@
+/**
+ @file uemf_print.c
+
+ @brief Functions for printing EMF records
+*/
+
+/*
+File: uemf_print.c
+Version: 0.0.21
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h> /* for offsetof() macro */
+#include <string.h>
+#include "uemf.h"
+#include "upmf_print.h"
+#include "uemf_safe.h"
+
+//! \cond
+#define UNUSED(x) (void)(x)
+/* This bit of code is used all over the place, so reduce it to a DEFINITION */
+#define IF_MEM_UNSAFE_PRINT_AND_RETURN(A,B,C) if(IS_MEM_UNSAFE(A,B,C)){printf(" record corruption HERE\n"); return; }
+
+/* one needed prototype */
+void U_swap4(void *ul, unsigned int count);
+//! \endcond
+
+/**
+ \brief calculate a CRC32 value for record
+ \returns CRC32 value calculated for record
+ \param record pointer to the first byte
+ \param Size number of bytes in the record
+
+Code based on example crc32b here:
+ http://www.hackersdelight.org/hdcodetxt/crc.c.txt
+*/
+uint32_t lu_crc32(const char *record, uint32_t Size){
+ const unsigned char *message = record;
+ uint32_t i, j;
+ uint32_t crc, mask;
+
+ crc = 0xFFFFFFFF;
+ for(i=0;i<Size;i++){ // over all bytes
+ crc = crc ^ *message++;
+ for (j = 0; j < 8; j++) { // over all bits
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ }
+ return ~crc;
+}
+
+/**
+ \brief Print some number of hex bytes
+ \param buf pointer to the first byte
+ \param num number of bytes
+*/
+void hexbytes_print(uint8_t *buf,unsigned int num){
+ for(; num; num--,buf++){
+ printf("%2.2X",*buf);
+ }
+}
+
+
+/* **********************************************************************************************
+ These functions print standard objects used in the EMR records.
+ The low level ones do not append EOL.
+*********************************************************************************************** */
+
+
+
+/**
+ \brief Print a U_COLORREF object.
+ \param color U_COLORREF object
+*/
+void colorref_print(
+ U_COLORREF color
+ ){
+ printf("{%u,%u,%u} ",color.Red,color.Green,color.Blue);
+}
+
+
+/**
+ \brief Print a U_RGBQUAD object.
+ \param color U_RGBQUAD object
+*/
+void rgbquad_print(
+ U_RGBQUAD color
+ ){
+ printf("{%u,%u,%u,%u} ",color.Blue,color.Green,color.Red,color.Reserved);
+}
+
+/**
+ \brief Print rect and rectl objects from Upper Left and Lower Right corner points.
+ \param rect U_RECTL object
+*/
+void rectl_print(
+ U_RECTL rect
+ ){
+ printf("{%d,%d,%d,%d} ",rect.left,rect.top,rect.right,rect.bottom);
+}
+
+/**
+ \brief Print a U_SIZEL object.
+ \param sz U_SizeL object
+*/
+void sizel_print(
+ U_SIZEL sz
+ ){
+ printf("{%d,%d} ",sz.cx ,sz.cy);
+}
+
+/**
+ \brief Print a U_POINTL object
+ \param pt U_POINTL object
+*/
+void pointl_print(
+ U_POINTL pt
+ ){
+ printf("{%d,%d} ",pt.x ,pt.y);
+}
+
+/**
+ \brief Print a pointer to a U_POINT16 object
+ \param pt pointer to a U_POINT16 object
+ Warning - WMF data may contain unaligned U_POINT16, do not call
+ this routine with a pointer to such data!
+*/
+void point16_print(
+ U_POINT16 pt
+ ){
+ printf("{%d,%d} ",pt.x ,pt.y);
+}
+
+/**
+ \brief Print a U_LCS_GAMMA object
+ \param lg U_LCS_GAMMA object
+*/
+void lcs_gamma_print(
+ U_LCS_GAMMA lg
+ ){
+ uint8_t tmp;
+ tmp = lg.ignoreHi; printf("ignoreHi:%u ",tmp);
+ tmp = lg.intPart ; printf("intPart :%u ",tmp);
+ tmp = lg.fracPart; printf("fracPart:%u ",tmp);
+ tmp = lg.ignoreLo; printf("ignoreLo:%u ",tmp);
+}
+
+/**
+ \brief Print a U_LCS_GAMMARGB object
+ \param lgr U_LCS_GAMMARGB object
+*/
+void lcs_gammargb_print(
+ U_LCS_GAMMARGB lgr
+ ){
+ printf("lcsGammaRed:"); lcs_gamma_print(lgr.lcsGammaRed );
+ printf("lcsGammaGreen:"); lcs_gamma_print(lgr.lcsGammaGreen);
+ printf("lcsGammaBlue:"); lcs_gamma_print(lgr.lcsGammaBlue );
+}
+
+/**
+ \brief Print a U_TRIVERTEX object.
+ \param tv U_TRIVERTEX object.
+*/
+void trivertex_print(
+ U_TRIVERTEX tv
+ ){
+ printf("{{%d,%d},{%u,%u,%u,%u}} ",tv.x,tv.y,tv.Red,tv.Green,tv.Blue,tv.Alpha);
+}
+
+/**
+ \brief Print a U_GRADIENT3 object.
+ \param g3 U_GRADIENT3 object.
+*/
+void gradient3_print(
+ U_GRADIENT3 g3
+ ){
+ printf("{%u,%u,%u} ",g3.Vertex1,g3.Vertex2,g3.Vertex3);
+}
+
+/**
+ \brief Print a U_GRADIENT4 object.
+ \param g4 U_GRADIENT4 object.
+*/
+void gradient4_print(
+ U_GRADIENT4 g4
+ ){
+ printf("{%u,%u} ",g4.UpperLeft,g4.LowerRight);
+}
+
+/**
+ \brief Print a U_LOGBRUSH object.
+ \param lb U_LOGBRUSH object.
+*/
+void logbrush_print(
+ U_LOGBRUSH lb
+ ){
+ printf("lbStyle:0x%8.8X ", lb.lbStyle);
+ printf("lbColor:"); colorref_print(lb.lbColor);
+ printf("lbHatch:0x%8.8X ", lb.lbHatch);
+}
+
+/**
+ \brief Print a U_XFORM object.
+ \param xform U_XFORM object
+*/
+void xform_print(
+ U_XFORM xform
+ ){
+ printf("{%f,%f.%f,%f,%f,%f} ",xform.eM11,xform.eM12,xform.eM21,xform.eM22,xform.eDx,xform.eDy);
+}
+
+/**
+ \brief Print a U_CIEXYZ object
+ \param ciexyz U_CIEXYZ object
+*/
+void ciexyz_print(
+ U_CIEXYZ ciexyz
+ ){
+ printf("{%d,%d.%d} ",ciexyz.ciexyzX,ciexyz.ciexyzY,ciexyz.ciexyzZ);
+
+}
+
+/**
+ \brief Print a U_CIEXYZTRIPLE object
+ \param cie3 U_CIEXYZTRIPLE object
+*/
+void ciexyztriple_print(
+ U_CIEXYZTRIPLE cie3
+ ){
+ printf("{Red:"); ciexyz_print(cie3.ciexyzRed );
+ printf(", Green:"); ciexyz_print(cie3.ciexyzGreen);
+ printf(", Blue:"); ciexyz_print(cie3.ciexyzBlue );
+ printf("} ");
+}
+/**
+ \brief Print a U_LOGCOLORSPACEA object.
+ \param lcsa U_LOGCOLORSPACEA object
+*/
+void logcolorspacea_print(
+ U_LOGCOLORSPACEA lcsa
+ ){
+ printf("lcsSignature:%u ",lcsa.lcsSignature);
+ printf("lcsVersion:%u ", lcsa.lcsVersion );
+ printf("lcsSize:%u ", lcsa.lcsSize );
+ printf("lcsCSType:%d ", lcsa.lcsCSType );
+ printf("lcsIntent:%d ", lcsa.lcsIntent );
+ printf("lcsEndpoints:"); ciexyztriple_print(lcsa.lcsEndpoints);
+ printf("lcsGammaRGB: "); lcs_gammargb_print(lcsa.lcsGammaRGB );
+ printf("filename:%s ", lcsa.lcsFilename );
+}
+
+/**
+
+ \brief Print a U_LOGCOLORSPACEW object.
+ \param lcsa U_LOGCOLORSPACEW object
+*/
+void logcolorspacew_print(
+ U_LOGCOLORSPACEW lcsa
+ ){
+ char *string;
+ printf("lcsSignature:%d ",lcsa.lcsSignature);
+ printf("lcsVersion:%d ", lcsa.lcsVersion );
+ printf("lcsSize:%d ", lcsa.lcsSize );
+ printf("lcsCSType:%d ", lcsa.lcsCSType );
+ printf("lcsIntent:%d ", lcsa.lcsIntent );
+ printf("lcsEndpoints:"); ciexyztriple_print(lcsa.lcsEndpoints);
+ printf("lcsGammaRGB: "); lcs_gammargb_print(lcsa.lcsGammaRGB );
+ string = U_Utf16leToUtf8(lcsa.lcsFilename, U_MAX_PATH, NULL);
+ printf("filename:%s ", string );
+ free(string);
+}
+
+/**
+ \brief Print a U_PANOSE object.
+ \param panose U_PANOSE object
+*/
+void panose_print(
+ U_PANOSE panose
+ ){
+ printf("bFamilyType:%u ", panose.bFamilyType );
+ printf("bSerifStyle:%u ", panose.bSerifStyle );
+ printf("bWeight:%u ", panose.bWeight );
+ printf("bProportion:%u ", panose.bProportion );
+ printf("bContrast:%u ", panose.bContrast );
+ printf("bStrokeVariation:%u ",panose.bStrokeVariation);
+ printf("bArmStyle:%u ", panose.bArmStyle );
+ printf("bLetterform:%u ", panose.bLetterform );
+ printf("bMidline:%u ", panose.bMidline );
+ printf("bXHeight:%u ", panose.bXHeight );
+}
+
+/**
+ \brief Print a U_LOGFONT object.
+ \param lf U_LOGFONT object
+*/
+void logfont_print(
+ U_LOGFONT lf
+ ){
+ char *string;
+ printf("lfHeight:%d ", lf.lfHeight );
+ printf("lfWidth:%d ", lf.lfWidth );
+ printf("lfEscapement:%d ", lf.lfEscapement );
+ printf("lfOrientation:%d ", lf.lfOrientation );
+ printf("lfWeight:%d ", lf.lfWeight );
+ printf("lfItalic:0x%2.2X ", lf.lfItalic );
+ printf("lfUnderline:0x%2.2X ", lf.lfUnderline );
+ printf("lfStrikeOut:0x%2.2X ", lf.lfStrikeOut );
+ printf("lfCharSet:0x%2.2X ", lf.lfCharSet );
+ printf("lfOutPrecision:0x%2.2X ", lf.lfOutPrecision );
+ printf("lfClipPrecision:0x%2.2X ", lf.lfClipPrecision );
+ printf("lfQuality:0x%2.2X ", lf.lfQuality );
+ printf("lfPitchAndFamily:0x%2.2X ", lf.lfPitchAndFamily);
+ string = U_Utf16leToUtf8(lf.lfFaceName, U_LF_FACESIZE, NULL);
+ printf("lfFaceName:%s ", string );
+ free(string);
+}
+
+/**
+ \brief Print a U_LOGFONT_PANOSE object.
+ \return U_LOGFONT_PANOSE object
+*/
+void logfont_panose_print(
+ U_LOGFONT_PANOSE lfp
+ ){
+ char *string;
+ printf("elfLogFont:"); logfont_print(lfp.elfLogFont);
+ string = U_Utf16leToUtf8(lfp.elfFullName, U_LF_FULLFACESIZE, NULL);
+ printf("elfFullName:%s ", string );
+ free(string);
+ string = U_Utf16leToUtf8(lfp.elfStyle, U_LF_FACESIZE, NULL);
+ printf("elfStyle:%s ", string );
+ free(string);
+ printf("elfVersion:%u " ,lfp.elfVersion );
+ printf("elfStyleSize:%u " ,lfp.elfStyleSize);
+ printf("elfMatch:%u " ,lfp.elfMatch );
+ printf("elfReserved:%u " ,lfp.elfReserved );
+ printf("elfVendorId:"); hexbytes_print((uint8_t *)lfp.elfVendorId,U_ELF_VENDOR_SIZE); printf(" ");
+ printf("elfCulture:%u " ,lfp.elfCulture );
+ printf("elfPanose:"); panose_print(lfp.elfPanose);
+}
+
+/**
+ \brief Print a pointer to U_BITMAPINFOHEADER object.
+
+ This may be called indirectly from WMF _print routines, where problems could occur
+ if the data was passed as the struct or a pointer to the struct, as the struct may not
+ be aligned in memory.
+
+ \returns Actual number of color table entries.
+ \param Bmih pointer to a U_BITMAPINFOHEADER object
+*/
+int bitmapinfoheader_print(
+ const char *Bmih
+ ){
+ uint32_t utmp4;
+ int32_t tmp4;
+ int16_t tmp2;
+ int Colors, BitCount, Width, Height, RealColors;
+
+ /* DIB from a WMF may not be properly aligned on a 4 byte boundary, will be aligned on a 2 byte boundary */
+
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSize), 4); printf("biSize:%u " ,utmp4 );
+ memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biWidth), 4); printf("biWidth:%d " ,tmp4 );
+ Width = tmp4;
+ memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biHeight), 4); printf("biHeight:%d " ,tmp4 );
+ Height = tmp4;
+ memcpy(&tmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biPlanes), 2); printf("biPlanes:%u " ,tmp2 );
+ memcpy(&tmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2); printf("biBitCount:%u " ,tmp2 );
+ BitCount = tmp2;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biCompression), 4); printf("biCompression:%u " ,utmp4 );
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSizeImage), 4); printf("biSizeImage:%u " ,utmp4 );
+ memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biXPelsPerMeter), 4); printf("biXPelsPerMeter:%d " ,tmp4 );
+ memcpy(&tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biYPelsPerMeter), 4); printf("biYPelsPerMeter:%d " ,tmp4 );
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrUsed), 4); printf("biClrUsed:%u " ,utmp4 );
+ Colors = utmp4;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrImportant), 4); printf("biClrImportant:%u " ,utmp4 );
+ RealColors = get_real_color_icount(Colors, BitCount, Width, Height);
+ printf("ColorEntries:%d ",RealColors);
+ return(RealColors);
+}
+
+
+/**
+ \brief Print a Pointer to a U_BITMAPINFO object.
+ \param Bmi Pointer to a U_BITMAPINFO object
+ \param blimit Pointer to the first byte after after this record
+ This may be called from WMF _print routines, where problems could occur
+ if the data was passed as the struct or a pointer to the struct, as the struct may not
+ be aligned in memory.
+*/
+void bitmapinfo_print(
+ const char *Bmi,
+ const char *blimit
+ ){
+ int i,k;
+ int ClrUsed;
+ U_RGBQUAD BmiColor;
+ printf("BmiHeader: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(Bmi, offsetof(U_BITMAPINFO,bmiHeader) + sizeof(U_BITMAPINFOHEADER), blimit);
+ ClrUsed = bitmapinfoheader_print(Bmi + offsetof(U_BITMAPINFO,bmiHeader));
+ if(ClrUsed){
+ k= offsetof(U_BITMAPINFO,bmiColors);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(Bmi, offsetof(U_BITMAPINFO,bmiColors) + ClrUsed*sizeof(U_RGBQUAD), blimit);
+ for(i=0; i<ClrUsed; i++, k+= sizeof(U_RGBQUAD)){
+ memcpy(&BmiColor, Bmi+k, sizeof(U_RGBQUAD));
+ printf("%d:",i); rgbquad_print(BmiColor);
+ }
+ }
+}
+
+/**
+ \brief Print a U_BLEND object.
+ \param blend a U_BLEND object
+*/
+void blend_print(
+ U_BLEND blend
+ ){
+ printf("Operation:%u " ,blend.Operation);
+ printf("Flags:%u " ,blend.Flags );
+ printf("Global:%u " ,blend.Global );
+ printf("Op:%u " ,blend.Op );
+}
+
+/**
+ \brief Print a pointer to a U_EXTLOGPEN object.
+ \param elp PU_EXTLOGPEN object
+*/
+void extlogpen_print(
+ PU_EXTLOGPEN elp
+ ){
+ unsigned int i;
+ U_STYLEENTRY *elpStyleEntry;
+ printf("elpPenStyle:0x%8.8X " ,elp->elpPenStyle );
+ printf("elpWidth:%u " ,elp->elpWidth );
+ printf("elpBrushStyle:0x%8.8X " ,elp->elpBrushStyle);
+ printf("elpColor"); colorref_print(elp->elpColor);
+ printf("elpHatch:%d " ,elp->elpHatch );
+ printf("elpNumEntries:%u " ,elp->elpNumEntries);
+ if(elp->elpNumEntries){
+ printf("elpStyleEntry:");
+ elpStyleEntry = (uint32_t *) elp->elpStyleEntry;
+ for(i=0;i<elp->elpNumEntries;i++){
+ printf("%d:%u ",i,elpStyleEntry[i]);
+ }
+ }
+}
+
+/**
+ \brief Print a U_LOGPEN object.
+ \param lp U_LOGPEN object
+
+*/
+void logpen_print(
+ U_LOGPEN lp
+ ){
+ printf("lopnStyle:0x%8.8X " ,lp.lopnStyle );
+ printf("lopnWidth:"); pointl_print( lp.lopnWidth );
+ printf("lopnColor:"); colorref_print(lp.lopnColor );
+}
+
+/**
+ \brief Print a U_LOGPLTNTRY object.
+ \param lpny Ignore U_LOGPLTNTRY object.
+*/
+void logpltntry_print(
+ U_LOGPLTNTRY lpny
+ ){
+ printf("peReserved:%u " ,lpny.peReserved );
+ printf("peRed:%u " ,lpny.peRed );
+ printf("peGreen:%u " ,lpny.peGreen );
+ printf("peBlue:%u " ,lpny.peBlue );
+}
+
+/**
+ \brief Print a pointer to a U_LOGPALETTE object.
+ \param lp Pointer to a U_LOGPALETTE object.
+*/
+void logpalette_print(
+ PU_LOGPALETTE lp
+ ){
+ int i;
+ PU_LOGPLTNTRY palPalEntry;
+ printf("palVersion:%u ", lp->palVersion );
+ printf("palNumEntries:%u ", lp->palNumEntries );
+ if(lp->palNumEntries){
+ palPalEntry = (PU_LOGPLTNTRY) &(lp->palPalEntry);
+ for(i=0;i<lp->palNumEntries;i++){
+ printf("%d:",i); logpltntry_print(palPalEntry[i]);
+ }
+ }
+}
+
+/**
+ \brief Print a U_RGNDATAHEADER object.
+ \param rdh U_RGNDATAHEADER object
+*/
+void rgndataheader_print(
+ U_RGNDATAHEADER rdh
+ ){
+ printf("dwSize:%u ", rdh.dwSize );
+ printf("iType:%u ", rdh.iType );
+ printf("nCount:%u ", rdh.nCount );
+ printf("nRgnSize:%u ", rdh.nRgnSize );
+ printf("rclBounds:"); rectl_print(rdh.rclBounds );
+}
+
+/**
+ \brief Print a pointer to a U_RGNDATA object.
+ \param rd pointer to a U_RGNDATA object.
+ \param limit pointer that sets upper limit for data examination
+*/
+void rgndata_print(
+ PU_RGNDATA rd,
+ const char *blimit
+ ){
+ unsigned int i;
+ PU_RECTL rects;
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(rd, sizeof(U_RGNDATAHEADER), blimit);
+ printf("rdh: "); rgndataheader_print(rd->rdh ); printf(" rects: ");
+ if(rd->rdh.nCount){
+ rects = (PU_RECTL) &(rd->Buffer);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(rects, rd->rdh.nCount * sizeof(U_RECTL), blimit);
+ for(i=0;i<rd->rdh.nCount;i++){
+ printf("%d:",i); rectl_print(rects[i]);
+ }
+ }
+}
+
+/**
+ \brief Print a U_COLORADJUSTMENT object.
+ \param ca U_COLORADJUSTMENT object.
+*/
+void coloradjustment_print(
+ U_COLORADJUSTMENT ca
+ ){
+ printf("caSize:%u " ,ca.caSize );
+ printf("caFlags:0x%4.4X " ,ca.caFlags );
+ printf("caIlluminantIndex:%u " ,ca.caIlluminantIndex);
+ printf("caRedGamma:%u " ,ca.caRedGamma );
+ printf("caGreenGamma:%u " ,ca.caGreenGamma );
+ printf("caBlueGamma:%u " ,ca.caBlueGamma );
+ printf("caReferenceBlack:%u " ,ca.caReferenceBlack );
+ printf("caReferenceWhite:%u " ,ca.caReferenceWhite );
+ printf("caContrast:%d " ,ca.caContrast );
+ printf("caBrightness:%d " ,ca.caBrightness );
+ printf("caColorfulness:%d " ,ca.caColorfulness );
+ printf("caRedGreenTint:%d " ,ca.caRedGreenTint );
+}
+
+/**
+ \brief Print a U_PIXELFORMATDESCRIPTOR object.
+ \param pfd U_PIXELFORMATDESCRIPTOR object
+*/
+void pixelformatdescriptor_print(
+ U_PIXELFORMATDESCRIPTOR pfd
+ ){
+ printf("nSize:%u " ,pfd.nSize );
+ printf("nVersion:%u " ,pfd.nVersion );
+ printf("dwFlags:0x%8.8X " ,pfd.dwFlags );
+ printf("iPixelType:%u " ,pfd.iPixelType );
+ printf("cColorBits:%u " ,pfd.cColorBits );
+ printf("cRedBits:%u " ,pfd.cRedBits );
+ printf("cRedShift:%u " ,pfd.cRedShift );
+ printf("cGreenBits:%u " ,pfd.cGreenBits );
+ printf("cGreenShift:%u " ,pfd.cGreenShift );
+ printf("cBlueBits:%u " ,pfd.cBlueBits );
+ printf("cBlueShift:%u " ,pfd.cBlueShift );
+ printf("cAlphaBits:%u " ,pfd.cAlphaBits );
+ printf("cAlphaShift:%u " ,pfd.cAlphaShift );
+ printf("cAccumBits:%u " ,pfd.cAccumBits );
+ printf("cAccumRedBits:%u " ,pfd.cAccumRedBits );
+ printf("cAccumGreenBits:%u " ,pfd.cAccumGreenBits );
+ printf("cAccumBlueBits:%u " ,pfd.cAccumBlueBits );
+ printf("cAccumAlphaBits:%u " ,pfd.cAccumAlphaBits );
+ printf("cDepthBits:%u " ,pfd.cDepthBits );
+ printf("cStencilBits:%u " ,pfd.cStencilBits );
+ printf("cAuxBuffers:%u " ,pfd.cAuxBuffers );
+ printf("iLayerType:%u " ,pfd.iLayerType );
+ printf("bReserved:%u " ,pfd.bReserved );
+ printf("dwLayerMask:%u " ,pfd.dwLayerMask );
+ printf("dwVisibleMask:%u " ,pfd.dwVisibleMask );
+ printf("dwDamageMask:%u " ,pfd.dwDamageMask );
+}
+
+/**
+ \brief Print a Pointer to a U_EMRTEXT record
+ \param emt Pointer to a U_EMRTEXT record
+ \param record Pointer to the start of the record which contains this U_ERMTEXT
+ \param blimit Pointer to the first byte after after this record
+ \param type 0 for 8 bit character, anything else for 16
+*/
+void emrtext_print(
+ const char *emt,
+ const char *record,
+ const char *blimit,
+ int type
+ ){
+ unsigned int i,off;
+ char *string;
+ PU_EMRTEXT pemt = (PU_EMRTEXT) emt;
+ // constant part
+ printf("ptlReference:"); pointl_print(pemt->ptlReference);
+ printf("nChars:%u " ,pemt->nChars );
+ printf("offString:%u " ,pemt->offString );
+ if(pemt->offString){
+ if(!type){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(record, pemt->offString + pemt->nChars*sizeof(char), blimit);
+ printf("string8:<%s> ",record + pemt->offString);
+ }
+ else {
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(record, pemt->offString + pemt->nChars*2*sizeof(char), blimit);
+ string = U_Utf16leToUtf8((uint16_t *)(record + pemt->offString), pemt->nChars, NULL);
+ printf("string16:<%s> ",string);
+ free(string);
+ }
+ }
+ printf("fOptions:0x%8.8X " ,pemt->fOptions );
+ off = sizeof(U_EMRTEXT);
+ if(!(pemt->fOptions & U_ETO_NO_RECT)){
+ printf("rcl"); rectl_print( *((U_RECTL *)(emt+off)) );
+ off += sizeof(U_RECTL);
+ }
+ printf("offDx:%u " , *((U_OFFDX *)(emt+off)) ); off = *(U_OFFDX *)(emt+off);
+ printf("Dx:");
+ for(i=0; i<pemt->nChars; i++, off+=sizeof(uint32_t)){
+ printf("%d:", *((uint32_t *)(record+off)) );
+ }
+}
+
+
+
+
+// hide these from Doxygen
+//! @cond
+/* **********************************************************************************************
+These functions contain shared code used by various U_EMR*_print functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+
+
+ These are (mostly) ordered by U_EMR_* index number.
+
+ The exceptions:
+ void core3_print(const char *name, const char *label, const char *contents)
+ void core7_print(const char *name, const char *field1, const char *field2, const char *contents)
+ void core8_print(const char *name, const char *contents, int type)
+
+
+*********************************************************************************************** */
+
+
+// Functions with the same form starting with U_EMRPOLYBEZIER_print
+void core1_print(const char *name, const char *contents){
+ unsigned int i;
+ UNUSED(name);
+ PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYBEZIER)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" cptl: %d\n",pEmr->cptl );
+ printf(" Points: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aptl, pEmr->cptl*sizeof(U_POINTL), blimit);
+ for(i=0;i<pEmr->cptl; i++){
+ printf("[%d]:",i); pointl_print(pEmr->aptl[i]);
+ }
+ printf("\n");
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE_print
+void core2_print(const char *name, const char *contents){
+ unsigned int i;
+ UNUSED(name);
+ PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYPOLYGON)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" nPolys: %d\n",pEmr->nPolys );
+ printf(" cptl: %d\n",pEmr->cptl );
+ printf(" Counts: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aPolyCounts, pEmr->nPolys*sizeof(U_POLYCOUNTS), blimit);
+ for(i=0;i<pEmr->nPolys; i++){
+ printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] );
+ }
+ printf("\n");
+ PU_POINTL paptl = (PU_POINTL)((char *)pEmr->aPolyCounts + sizeof(uint32_t)* pEmr->nPolys);
+ printf(" Points: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(paptl, pEmr->cptl*sizeof(U_POINTL), blimit);
+ for(i=0;i<pEmr->cptl; i++){
+ printf(" [%d]:",i); pointl_print(paptl[i]);
+ }
+ printf("\n");
+}
+
+
+// Functions with the same form starting with U_EMRSETMAPMODE_print
+void core3_print(const char *name, const char *label, const char *contents){
+ UNUSED(name);
+ /* access violation is impossible for these because there are no counts or offsets */
+ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETMAPMODE)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ if(!strcmp(label,"crColor:")){
+ printf(" %-15s ",label); colorref_print(*(U_COLORREF *)&(pEmr->iMode)); printf("\n");
+ }
+ else if(!strcmp(label,"iMode:")){
+ printf(" %-15s 0x%8.8X\n",label,pEmr->iMode );
+ }
+ else {
+ printf(" %-15s %d\n",label,pEmr->iMode );
+ }
+}
+
+// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_print, also U_EMRFILLPATH_print,
+void core4_print(const char *name, const char *contents){
+ UNUSED(name);
+ PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRELLIPSE)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n");
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER16_print
+void core6_print(const char *name, const char *contents){
+ UNUSED(name);
+ unsigned int i;
+ PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYBEZIER16)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" cpts: %d\n",pEmr->cpts );
+ printf(" Points: ");
+ PU_POINT16 papts = (PU_POINT16)(&(pEmr->apts));
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(papts, pEmr->cpts*sizeof(U_POINT16), blimit);
+ for(i=0; i<pEmr->cpts; i++){
+ printf(" [%d]:",i); point16_print(papts[i]);
+ }
+ printf("\n");
+}
+
+
+// Records with the same form starting with U_EMRSETWINDOWEXTEX_print
+// CAREFUL, in the _set equivalents all functions with two uint32_t values are mapped here, and member names differ, consequently
+// print routines must supply the names of the two arguments. These cannot be null. If the second one is
+// empty the values are printed as a pair {x,y}, otherwise each is printed with its own label on a separate line.
+void core7_print(const char *name, const char *field1, const char *field2, const char *contents){
+ UNUSED(name);
+ PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRGENERICPAIR)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ if(*field2){
+ printf(" %-15s %d\n",field1,pEmr->pair.x);
+ printf(" %-15s %d\n",field2,pEmr->pair.y);
+ }
+ else {
+ printf(" %-15s {%d,%d}\n",field1,pEmr->pair.x,pEmr->pair.y);
+ }
+}
+
+// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one
+void core8_print(const char *name, const char *contents, int type){
+ UNUSED(name);
+ PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents);
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" iGraphicsMode: %u\n",pEmr->iGraphicsMode );
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" exScale: %f\n",pEmr->exScale );
+ printf(" eyScale: %f\n",pEmr->eyScale );
+ printf(" emrtext: ");
+ emrtext_print(contents + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents,blimit,type);
+ printf("\n");
+}
+
+// Functions that take a rect and a pair of points, starting with U_EMRARC_print
+void core9_print(const char *name, const char *contents){
+ UNUSED(name);
+ PU_EMRARC pEmr = (PU_EMRARC) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRARC)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n");
+ printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n");
+ printf(" ptlEnd: "); pointl_print(pEmr->ptlEnd); printf("\n");
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE16_print
+void core10_print(const char *name, const char *contents){
+ UNUSED(name);
+ unsigned int i;
+ PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYPOLYLINE16)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" nPolys: %d\n",pEmr->nPolys );
+ printf(" cpts: %d\n",pEmr->cpts );
+ printf(" Counts: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->aPolyCounts), pEmr->nPolys*sizeof(U_POLYCOUNTS), blimit);
+ for(i=0;i<pEmr->nPolys; i++){
+ printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] );
+ }
+ printf("\n");
+ printf(" Points: ");
+ PU_POINT16 papts = (PU_POINT16)((char *)pEmr->aPolyCounts + pEmr->nPolys*sizeof(U_POLYCOUNTS) );
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(papts, pEmr->cpts*sizeof(U_POINT16), blimit);
+ for(i=0; i<pEmr->cpts; i++){
+ printf(" [%d]:",i); point16_print(papts[i]);
+ }
+ printf("\n");
+
+}
+
+// Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print,
+void core11_print(const char *name, const char *contents){
+ UNUSED(name);
+ PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRINVERTRGN)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" cbRgnData: %d\n",pEmr->cbRgnData);
+ printf(" RegionData:");
+ const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit);
+ rgndata_print(pEmr->RgnData, minptr);
+ printf("\n");
+}
+
+
+// common code for U_EMRCREATEMONOBRUSH_print and U_EMRCREATEDIBPATTERNBRUSHPT_print,
+void core12_print(const char *name, const char *contents){
+ UNUSED(name);
+ PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATEMONOBRUSH)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" ihBrush: %u\n",pEmr->ihBrush );
+ printf(" iUsage : %u\n",pEmr->iUsage );
+ printf(" offBmi : %u\n",pEmr->offBmi );
+ printf(" cbBmi : %u\n",pEmr->cbBmi );
+ if(pEmr->cbBmi){
+ printf(" bitmap:");
+ bitmapinfo_print(contents + pEmr->offBmi, blimit);
+ printf("\n");
+ }
+ printf(" offBits: %u\n",pEmr->offBits );
+ printf(" cbBits : %u\n",pEmr->cbBits );
+}
+
+// common code for U_EMRALPHABLEND_print and U_EMRTRANSPARENTBLT_print,
+void core13_print(const char *name, const char *contents){
+ UNUSED(name);
+ PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRALPHABLEND)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n");
+ printf(" Blend: "); blend_print(pEmr->Blend); printf("\n");
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n");
+ printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n");
+ printf(" iUsageSrc: %u\n",pEmr->iUsageSrc );
+ printf(" offBmiSrc: %u\n",pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n",pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" bitmap:");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n",pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n",pEmr->cbBitsSrc );
+}
+//! @endcond
+
+/* **********************************************************************************************
+These are the core EMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+/**
+ \brief Print a pointer to a U_EMR_whatever record which has not been implemented.
+ \param name name of this type of record
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents){
+ UNUSED(name);
+ UNUSED(contents);
+ printf(" Not Implemented!\n");
+}
+
+// U_EMRHEADER 1
+/**
+ \brief Print a pointer to a U_EMR_HEADER record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRHEADER_print(const char *contents){
+ char *string;
+ int p1len;
+
+ PU_EMRHEADER pEmr = (PU_EMRHEADER)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRHEADER)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" rclFrame: "); rectl_print( pEmr->rclFrame); printf("\n");
+ printf(" dSignature: 0x%8.8X\n", pEmr->dSignature );
+ printf(" nVersion: 0x%8.8X\n", pEmr->nVersion );
+ printf(" nBytes: %d\n", pEmr->nBytes );
+ printf(" nRecords: %d\n", pEmr->nRecords );
+ printf(" nHandles: %d\n", pEmr->nHandles );
+ printf(" sReserved: %d\n", pEmr->sReserved );
+ printf(" nDescription: %d\n", pEmr->nDescription );
+ printf(" offDescription: %d\n", pEmr->offDescription);
+ if(pEmr->offDescription){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->offDescription + pEmr->nDescription*2*sizeof(char), blimit);
+ string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL);
+ printf(" Desc. A: %s\n",string);
+ free(string);
+ p1len = 2 + 2*wchar16len((uint16_t *)((char *) pEmr + pEmr->offDescription));
+ string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription + p1len), pEmr->nDescription, NULL);
+ printf(" Desc. B: %s\n",string);
+ free(string);
+ }
+ printf(" nPalEntries: %d\n", pEmr->nPalEntries );
+ printf(" szlDevice: {%d,%d} \n", pEmr->szlDevice.cx,pEmr->szlDevice.cy);
+ printf(" szlMillimeters: {%d,%d} \n", pEmr->szlMillimeters.cx,pEmr->szlMillimeters.cy);
+ if((pEmr->nDescription && (pEmr->offDescription >= 100)) ||
+ (!pEmr->offDescription && pEmr->emr.nSize >= 100)
+ ){
+ printf(" cbPixelFormat: %d\n", pEmr->cbPixelFormat );
+ printf(" offPixelFormat: %d\n", pEmr->offPixelFormat);
+ if(pEmr->cbPixelFormat){
+ printf(" PFD:");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->offPixelFormat + sizeof(U_PIXELFORMATDESCRIPTOR), blimit);
+ pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + pEmr->offPixelFormat));
+ printf("\n");
+ }
+ printf(" bOpenGL: %d\n",pEmr->bOpenGL );
+ if((pEmr->nDescription && (pEmr->offDescription >= 108)) ||
+ (pEmr->cbPixelFormat && (pEmr->offPixelFormat >=108)) ||
+ (!pEmr->offDescription && !pEmr->cbPixelFormat && pEmr->emr.nSize >= 108)
+ ){
+ printf(" szlMicrometers: {%d,%d} \n", pEmr->szlMicrometers.cx,pEmr->szlMicrometers.cy);
+ }
+ }
+}
+
+// U_EMRPOLYBEZIER 2
+/**
+ \brief Print a pointer to a U_EMR_POLYBEZIER record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYBEZIER_print(const char *contents){
+ core1_print("U_EMRPOLYBEZIER", contents);
+}
+
+// U_EMRPOLYGON 3
+/**
+ \brief Print a pointer to a U_EMR_POLYGON record.
+ \param contents pointer to a buffer holding all EMR records
+ */
+void U_EMRPOLYGON_print(const char *contents){
+ core1_print("U_EMRPOLYGON", contents);
+}
+
+
+// U_EMRPOLYLINE 4
+/**
+ \brief Print a pointer to a U_EMR_POLYLINE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYLINE_print(const char *contents){
+ core1_print("U_EMRPOLYLINE", contents);
+}
+
+// U_EMRPOLYBEZIERTO 5
+/**
+ \brief Print a pointer to a U_EMR_POLYBEZIERTO record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYBEZIERTO_print(const char *contents){
+ core1_print("U_EMRPOLYBEZIERTO", contents);
+}
+
+// U_EMRPOLYLINETO 6
+/**
+ \brief Print a pointer to a U_EMR_POLYLINETO record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYLINETO_print(const char *contents){
+ core1_print("U_EMRPOLYLINETO", contents);
+}
+
+// U_EMRPOLYPOLYLINE 7
+/**
+ \brief Print a pointer to a U_EMR_POLYPOLYLINE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYPOLYLINE_print(const char *contents){
+ core2_print("U_EMRPOLYPOLYLINE", contents);
+}
+
+// U_EMRPOLYPOLYGON 8
+/**
+ \brief Print a pointer to a U_EMR_POLYPOLYGON record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYPOLYGON_print(const char *contents){
+ core2_print("U_EMRPOLYPOLYGON", contents);
+}
+
+// U_EMRSETWINDOWEXTEX 9
+/**
+ \brief Print a pointer to a U_EMR_SETWINDOWEXTEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETWINDOWEXTEX_print(const char *contents){
+ core7_print("U_EMRSETWINDOWEXTEX", "szlExtent:","",contents);
+}
+
+// U_EMRSETWINDOWORGEX 10
+/**
+ \brief Print a pointer to a U_EMR_SETWINDOWORGEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETWINDOWORGEX_print(const char *contents){
+ core7_print("U_EMRSETWINDOWORGEX", "ptlOrigin:","",contents);
+}
+
+// U_EMRSETVIEWPORTEXTEX 11
+/**
+ \brief Print a pointer to a U_EMR_SETVIEWPORTEXTEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETVIEWPORTEXTEX_print(const char *contents){
+ core7_print("U_EMRSETVIEWPORTEXTEX", "szlExtent:","",contents);
+}
+
+// U_EMRSETVIEWPORTORGEX 12
+/**
+ \brief Print a pointer to a U_EMR_SETVIEWPORTORGEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETVIEWPORTORGEX_print(const char *contents){
+ core7_print("U_EMRSETVIEWPORTORGEX", "ptlOrigin:","",contents);
+}
+
+// U_EMRSETBRUSHORGEX 13
+/**
+ \brief Print a pointer to a U_EMR_SETBRUSHORGEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETBRUSHORGEX_print(const char *contents){
+ core7_print("U_EMRSETBRUSHORGEX", "ptlOrigin:","",contents);
+}
+
+// U_EMREOF 14
+/**
+ \brief Print a pointer to a U_EMR_EOF record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREOF_print(const char *contents){
+ PU_EMREOF pEmr = (PU_EMREOF)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMREOF)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" cbPalEntries: %u\n", pEmr->cbPalEntries );
+ printf(" offPalEntries: %u\n", pEmr->offPalEntries);
+ if(pEmr->cbPalEntries){
+ printf(" PE:");
+ logpalette_print( (PU_LOGPALETTE)(contents + pEmr->offPalEntries));
+ printf("\n");
+ }
+}
+
+
+// U_EMRSETPIXELV 15
+/**
+ \brief Print a pointer to a U_EMR_SETPIXELV record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETPIXELV_print(const char *contents){
+ PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETPIXELV)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ptlPixel: "); pointl_print( pEmr->ptlPixel); printf("\n");
+ printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n");
+}
+
+
+// U_EMRSETMAPPERFLAGS 16
+/**
+ \brief Print a pointer to a U_EMR_SETMAPPERFLAGS record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETMAPPERFLAGS_print(const char *contents){
+ PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETMAPPERFLAGS)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" dwFlags: 0x%8.8X\n",pEmr->dwFlags);
+}
+
+
+// U_EMRSETMAPMODE 17
+/**
+ \brief Print a pointer to a U_EMR_SETMAPMODE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETMAPMODE_print(const char *contents){
+ core3_print("U_EMRSETMAPMODE", "iMode:", contents);
+}
+
+// U_EMRSETBKMODE 18
+/**
+ \brief Print a pointer to a U_EMR_SETBKMODE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETBKMODE_print(const char *contents){
+ core3_print("U_EMRSETBKMODE", "iMode:", contents);
+}
+
+// U_EMRSETPOLYFILLMODE 19
+/**
+ \brief Print a pointer to a U_EMR_SETPOLYFILLMODE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETPOLYFILLMODE_print(const char *contents){
+ core3_print("U_EMRSETPOLYFILLMODE", "iMode:", contents);
+}
+
+// U_EMRSETROP2 20
+/**
+ \brief Print a pointer to a U_EMR_SETROP2 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETROP2_print(const char *contents){
+ core3_print("U_EMRSETROP2", "dwRop:", contents);
+}
+
+// U_EMRSETSTRETCHBLTMODE 21
+/**
+ \brief Print a pointer to a U_EMR_SETSTRETCHBLTMODE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETSTRETCHBLTMODE_print(const char *contents){
+ core3_print("U_EMRSETSTRETCHBLTMODE", "iMode:", contents);
+}
+
+// U_EMRSETTEXTALIGN 22
+/**
+ \brief Print a pointer to a U_EMR_SETTEXTALIGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETTEXTALIGN_print(const char *contents){
+ core3_print("U_EMRSETTEXTALIGN", "iMode:", contents);
+}
+
+// U_EMRSETCOLORADJUSTMENT 23
+/**
+ \brief Print a pointer to a U_EMR_SETCOLORADJUSTMENT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETCOLORADJUSTMENT_print(const char *contents){
+ PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETCOLORADJUSTMENT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ColorAdjustment:");
+ coloradjustment_print(pEmr->ColorAdjustment);
+ printf("\n");
+}
+
+// U_EMRSETTEXTCOLOR 24
+/**
+ \brief Print a pointer to a U_EMR_SETTEXTCOLOR record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETTEXTCOLOR_print(const char *contents){
+ core3_print("U_EMRSETTEXTCOLOR", "crColor:", contents);
+}
+
+// U_EMRSETBKCOLOR 25
+/**
+ \brief Print a pointer to a U_EMR_SETBKCOLOR record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETBKCOLOR_print(const char *contents){
+ core3_print("U_EMRSETBKCOLOR", "crColor:", contents);
+}
+
+// U_EMROFFSETCLIPRGN 26
+/**
+ \brief Print a pointer to a U_EMR_OFFSETCLIPRGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMROFFSETCLIPRGN_print(const char *contents){
+ core7_print("U_EMROFFSETCLIPRGN", "ptl:","",contents);
+}
+
+// U_EMRMOVETOEX 27
+/**
+ \brief Print a pointer to a U_EMR_MOVETOEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRMOVETOEX_print(const char *contents){
+ core7_print("U_EMRMOVETOEX", "ptl:","",contents);
+}
+
+// U_EMRSETMETARGN 28
+/**
+ \brief Print a pointer to a U_EMR_SETMETARGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETMETARGN_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMREXCLUDECLIPRECT 29
+/**
+ \brief Print a pointer to a U_EMR_EXCLUDECLIPRECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXCLUDECLIPRECT_print(const char *contents){
+ core4_print("U_EMREXCLUDECLIPRECT", contents);
+}
+
+// U_EMRINTERSECTCLIPRECT 30
+/**
+ \brief Print a pointer to a U_EMR_INTERSECTCLIPRECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRINTERSECTCLIPRECT_print(const char *contents){
+ core4_print("U_EMRINTERSECTCLIPRECT", contents);
+}
+
+// U_EMRSCALEVIEWPORTEXTEX 31
+/**
+ \brief Print a pointer to a U_EMR_SCALEVIEWPORTEXTEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSCALEVIEWPORTEXTEX_print(const char *contents){
+ core4_print("U_EMRSCALEVIEWPORTEXTEX", contents);
+}
+
+
+// U_EMRSCALEWINDOWEXTEX 32
+/**
+ \brief Print a pointer to a U_EMR_SCALEWINDOWEXTEX record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSCALEWINDOWEXTEX_print(const char *contents){
+ core4_print("U_EMRSCALEWINDOWEXTEX", contents);
+}
+
+// U_EMRSAVEDC 33
+/**
+ \brief Print a pointer to a U_EMR_SAVEDC record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSAVEDC_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRRESTOREDC 34
+/**
+ \brief Print a pointer to a U_EMR_RESTOREDC record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRRESTOREDC_print(const char *contents){
+ core3_print("U_EMRRESTOREDC", "iRelative:", contents);
+}
+
+// U_EMRSETWORLDTRANSFORM 35
+/**
+ \brief Print a pointer to a U_EMR_SETWORLDTRANSFORM record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETWORLDTRANSFORM_print(const char *contents){
+ PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETWORLDTRANSFORM)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" xform:");
+ xform_print(pEmr->xform);
+ printf("\n");
+}
+
+// U_EMRMODIFYWORLDTRANSFORM 36
+/**
+ \brief Print a pointer to a U_EMR_MODIFYWORLDTRANSFORM record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents){
+ PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRMODIFYWORLDTRANSFORM)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" xform:");
+ xform_print(pEmr->xform);
+ printf("\n");
+ printf(" iMode: %u\n", pEmr->iMode );
+}
+
+// U_EMRSELECTOBJECT 37
+/**
+ \brief Print a pointer to a U_EMR_SELECTOBJECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSELECTOBJECT_print(const char *contents){
+ PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSELECTOBJECT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ if(pEmr->ihObject & U_STOCK_OBJECT){
+ printf(" StockObject: 0x%8.8X\n", pEmr->ihObject );
+ }
+ else {
+ printf(" ihObject: %u\n", pEmr->ihObject );
+ }
+}
+
+// U_EMRCREATEPEN 38
+/**
+ \brief Print a pointer to a U_EMR_CREATEPEN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATEPEN_print(const char *contents){
+ PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATEPEN)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ihPen: %u\n", pEmr->ihPen );
+ printf(" lopn: "); logpen_print(pEmr->lopn); printf("\n");
+}
+
+// U_EMRCREATEBRUSHINDIRECT 39
+/**
+ \brief Print a pointer to a U_EMR_CREATEBRUSHINDIRECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATEBRUSHINDIRECT_print(const char *contents){
+ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATEBRUSHINDIRECT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ihBrush: %u\n", pEmr->ihBrush );
+ printf(" lb: "); logbrush_print(pEmr->lb); printf("\n");
+}
+
+// U_EMRDELETEOBJECT 40
+/**
+ \brief Print a pointer to a U_EMR_DELETEOBJECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRDELETEOBJECT_print(const char *contents){
+ PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRDELETEOBJECT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ihObject: %u\n", pEmr->ihObject );
+}
+
+// U_EMRANGLEARC 41
+/**
+ \brief Print a pointer to a U_EMR_ANGLEARC record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRANGLEARC_print(const char *contents){
+ PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRANGLEARC)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ptlCenter: "), pointl_print(pEmr->ptlCenter ); printf("\n");
+ printf(" nRadius: %u\n", pEmr->nRadius );
+ printf(" eStartAngle: %f\n", pEmr->eStartAngle );
+ printf(" eSweepAngle: %f\n", pEmr->eSweepAngle );
+}
+
+// U_EMRELLIPSE 42
+/**
+ \brief Print a pointer to a U_EMR_ELLIPSE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRELLIPSE_print(const char *contents){
+ core4_print("U_EMRELLIPSE", contents);
+}
+
+// U_EMRRECTANGLE 43
+/**
+ \brief Print a pointer to a U_EMR_RECTANGLE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRRECTANGLE_print(const char *contents){
+ core4_print("U_EMRRECTANGLE", contents);
+}
+
+// U_EMRROUNDRECT 44
+/**
+ \brief Print a pointer to a U_EMR_ROUNDRECT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRROUNDRECT_print(const char *contents){
+ PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRROUNDRECT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" rclBox: "), rectl_print(pEmr->rclBox ); printf("\n");
+ printf(" szlCorner: "), sizel_print(pEmr->szlCorner ); printf("\n");
+}
+
+// U_EMRARC 45
+/**
+ \brief Print a pointer to a U_EMR_ARC record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRARC_print(const char *contents){
+ core9_print("U_EMRARC", contents);
+}
+
+// U_EMRCHORD 46
+/**
+ \brief Print a pointer to a U_EMR_CHORD record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCHORD_print(const char *contents){
+ core9_print("U_EMRCHORD", contents);
+}
+
+// U_EMRPIE 47
+/**
+ \brief Print a pointer to a U_EMR_PIE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPIE_print(const char *contents){
+ core9_print("U_EMRPIE", contents);
+}
+
+// U_EMRSELECTPALETTE 48
+/**
+ \brief Print a pointer to a U_EMR_SELECTPALETTE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSELECTPALETTE_print(const char *contents){
+ core3_print("U_EMRSELECTPALETTE", "ihPal:", contents);
+}
+
+// U_EMRCREATEPALETTE 49
+/**
+ \brief Print a pointer to a U_EMR_CREATEPALETTE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATEPALETTE_print(const char *contents){
+ PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATEPALETTE)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ihPal: %u\n",pEmr->ihPal);
+ printf(" lgpl: "), logpalette_print( (PU_LOGPALETTE)&(pEmr->lgpl) ); printf("\n");
+}
+
+// U_EMRSETPALETTEENTRIES 50
+/**
+ \brief Print a pointer to a U_EMR_SETPALETTEENTRIES record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETPALETTEENTRIES_print(const char *contents){
+ unsigned int i;
+ PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETPALETTEENTRIES)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" ihPal: %u\n",pEmr->ihPal);
+ printf(" iStart: %u\n",pEmr->iStart);
+ printf(" cEntries: %u\n",pEmr->cEntries);
+ if(pEmr->cEntries){
+ printf(" PLTEntries:");
+ PU_LOGPLTNTRY aPalEntries = (PU_LOGPLTNTRY) &(pEmr->aPalEntries);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(aPalEntries, pEmr->cEntries*sizeof(U_LOGPLTNTRY), blimit);
+ for(i=0; i<pEmr->cEntries; i++){
+ printf("%d:",i); logpltntry_print(aPalEntries[i]);
+ }
+ printf("\n");
+ }
+}
+
+// U_EMRRESIZEPALETTE 51
+/**
+ \brief Print a pointer to a U_EMR_RESIZEPALETTE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRRESIZEPALETTE_print(const char *contents){
+ core7_print("U_EMRRESIZEPALETTE", "ihPal:","cEntries",contents);
+}
+
+// U_EMRREALIZEPALETTE 52
+/**
+ \brief Print a pointer to a U_EMR_REALIZEPALETTE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRREALIZEPALETTE_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMREXTFLOODFILL 53
+/**
+ \brief Print a pointer to a U_EMR_EXTFLOODFILL record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTFLOODFILL_print(const char *contents){
+ PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMREXTFLOODFILL)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n");
+ printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n");
+ printf(" iMode: %u\n",pEmr->iMode);
+}
+
+// U_EMRLINETO 54
+/**
+ \brief Print a pointer to a U_EMR_LINETO record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRLINETO_print(const char *contents){
+ core7_print("U_EMRLINETO", "ptl:","",contents);
+}
+
+// U_EMRARCTO 55
+/**
+ \brief Print a pointer to a U_EMR_ARCTO record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRARCTO_print(const char *contents){
+ core9_print("U_EMRARCTO", contents);
+}
+
+// U_EMRPOLYDRAW 56
+/**
+ \brief Print a pointer to a U_EMR_POLYDRAW record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYDRAW_print(const char *contents){
+ unsigned int i;
+ PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYDRAW)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" cptl: %d\n",pEmr->cptl );
+ printf(" Points: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aptl, pEmr->cptl*sizeof(U_POINTL), blimit);
+ for(i=0;i<pEmr->cptl; i++){
+ printf(" [%d]:",i);
+ pointl_print(pEmr->aptl[i]);
+ }
+ printf("\n");
+ printf(" Types: ");
+ const char *abTypes = (const char *) pEmr->aptl + pEmr->cptl*sizeof(U_POINTL);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(abTypes, pEmr->cptl, blimit);
+ for(i=0;i<pEmr->cptl; i++){
+ printf(" [%d]:%u ",i,((uint8_t *)abTypes)[i]);
+ }
+ printf("\n");
+}
+
+// U_EMRSETARCDIRECTION 57
+/**
+ \brief Print a pointer to a U_EMR_SETARCDIRECTION record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETARCDIRECTION_print(const char *contents){
+ core3_print("U_EMRSETARCDIRECTION","arcDirection:", contents);
+}
+
+// U_EMRSETMITERLIMIT 58
+/**
+ \brief Print a pointer to a U_EMR_SETMITERLIMIT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETMITERLIMIT_print(const char *contents){
+ core3_print("U_EMRSETMITERLIMIT", "eMiterLimit:", contents);
+}
+
+
+// U_EMRBEGINPATH 59
+/**
+ \brief Print a pointer to a U_EMR_BEGINPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRBEGINPATH_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRENDPATH 60
+/**
+ \brief Print a pointer to a U_EMR_ENDPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRENDPATH_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRCLOSEFIGURE 61
+/**
+ \brief Print a pointer to a U_EMR_CLOSEFIGURE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCLOSEFIGURE_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRFILLPATH 62
+/**
+ \brief Print a pointer to a U_EMR_FILLPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRFILLPATH_print(const char *contents){
+ core4_print("U_EMRFILLPATH", contents);
+}
+
+// U_EMRSTROKEANDFILLPATH 63
+/**
+ \brief Print a pointer to a U_EMR_STROKEANDFILLPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSTROKEANDFILLPATH_print(const char *contents){
+ core4_print("U_EMRSTROKEANDFILLPATH", contents);
+}
+
+// U_EMRSTROKEPATH 64
+/**
+ \brief Print a pointer to a U_EMR_STROKEPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSTROKEPATH_print(const char *contents){
+ core4_print("U_EMRSTROKEPATH", contents);
+}
+
+// U_EMRFLATTENPATH 65
+/**
+ \brief Print a pointer to a U_EMR_FLATTENPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRFLATTENPATH_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRWIDENPATH 66
+/**
+ \brief Print a pointer to a U_EMR_WIDENPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRWIDENPATH_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRSELECTCLIPPATH 67
+/**
+ \brief Print a pointer to a U_EMR_SELECTCLIPPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSELECTCLIPPATH_print(const char *contents){
+ core3_print("U_EMRSELECTCLIPPATH", "iMode:", contents);
+}
+
+// U_EMRABORTPATH 68
+/**
+ \brief Print a pointer to a U_EMR_ABORTPATH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRABORTPATH_print(const char *contents){
+ UNUSED(contents);
+}
+
+// U_EMRUNDEF69 69
+#define U_EMRUNDEF69_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF69",A) //!< Not implemented.
+
+// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific)
+/**
+ \brief Print a pointer to a U_EMR_COMMENT record.
+ \param contents pointer to a location in memory holding the comment record
+ \param off offset in bytes to the first byte in this record (needed for EMF+ record printing)
+
+ EMF+ records, if any, are stored in EMF comment records.
+*/
+void U_EMRCOMMENT_print(const char *contents, size_t off){
+ char *string;
+ char *src;
+ uint32_t cIdent,cIdent2,cbData;
+ size_t loff;
+ int recsize;
+ static int recnum=0;
+
+ PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCOMMENT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+
+ /* There are several different types of comments */
+
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT), blimit);
+ cbData = pEmr->cbData;
+ printf(" cbData: %d\n",cbData );
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMR) + sizeof(U_CBDATA) + cbData, blimit);
+ src = (char *)&(pEmr->Data); // default
+ if(cbData >= 4){
+ /* Since the comment is just a big bag of bytes the emf endian code cannot safely touch
+ any of its payload. This is the only record type with that limitation. So the record
+ may appear at this stage with the wrong endianness. Try to determine
+ what the contents are even if more byte swapping is required. */
+ cIdent = *(uint32_t *)(src);
+ if(U_BYTE_SWAP){ U_swap4(&(cIdent),1); }
+ if( cIdent == U_EMR_COMMENT_PUBLIC ){
+ printf(" cIdent: Public\n");
+ PU_EMRCOMMENT_PUBLIC pEmrp = (PU_EMRCOMMENT_PUBLIC) pEmr;
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_PUBLIC), blimit);
+ cIdent2 = pEmrp->pcIdent;
+ if(U_BYTE_SWAP){ U_swap4(&(cIdent2),1); }
+ printf(" pcIdent: 0x%8.8x\n",cIdent2);
+ src = (char *)&(pEmrp->Data);
+ cbData -= 8;
+ }
+ else if(cIdent == U_EMR_COMMENT_SPOOL ){
+ printf(" cIdent: Spool\n");
+ PU_EMRCOMMENT_SPOOL pEmrs = (PU_EMRCOMMENT_SPOOL) pEmr;
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_SPOOL), blimit);
+ cIdent2 = pEmrs->esrIdent;
+ if(U_BYTE_SWAP){ U_swap4(&(cIdent2),1); }
+ printf(" esrIdent: 0x%8.8x\n",cIdent2);
+ src = (char *)&(pEmrs->Data);
+ cbData -= 8;
+ }
+ else if(cIdent == U_EMR_COMMENT_EMFPLUSRECORD){
+ printf(" cIdent: EMF+\n");
+ PU_EMRCOMMENT_EMFPLUS pEmrpl = (PU_EMRCOMMENT_EMFPLUS) pEmr;
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_EMFPLUS), blimit);
+ src = (char *)&(pEmrpl->Data);
+ loff = 16; /* Header size of the header part of an EMF+ comment record */
+ while(loff < cbData + 12){ // EMF+ records may not fill the entire comment, cbData value includes cIdent, but not U_EMR or cbData
+ recsize = U_pmf_onerec_print(src, blimit, recnum, loff + off);
+ if(recsize==0){ break; }
+ else if(recsize<0){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ loff += recsize;
+ src += recsize;
+ recnum++;
+ }
+ return;
+ }
+ else {
+ printf(" cIdent: not (Public or Spool or EMF+)\n");
+ }
+ }
+ if(cbData){ // The data may not be printable, but try it just in case
+ string = malloc(cbData + 1);
+ (void)strncpy(string, src, cbData);
+ string[cbData] = '\0'; // it might not be terminated - it might not even be text!
+ printf(" Data: <%s>\n",string);
+ free(string);
+ }
+}
+
+// U_EMRFILLRGN 71
+/**
+ \brief Print a pointer to a U_EMR_FILLRGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRFILLRGN_print(const char *contents){
+ PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRFILLRGN)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" cbRgnData: %u\n",pEmr->cbRgnData);
+ printf(" ihBrush: %u\n",pEmr->ihBrush);
+ const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData + sizeof(U_RGNDATAHEADER)),blimit);
+ printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n");
+}
+
+// U_EMRFRAMERGN 72
+/**
+ \brief Print a pointer to a U_EMR_FRAMERGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRFRAMERGN_print(const char *contents){
+ PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRFRAMERGN)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n");
+ printf(" cbRgnData: %u\n",pEmr->cbRgnData);
+ printf(" ihBrush: %u\n",pEmr->ihBrush);
+ printf(" szlStroke: "), sizel_print(pEmr->szlStroke ); printf("\n");
+ const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit);
+ printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n");
+}
+
+// U_EMRINVERTRGN 73
+/**
+ \brief Print a pointer to a U_EMR_INVERTRGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRINVERTRGN_print(const char *contents){
+ core11_print("U_EMRINVERTRGN", contents);
+}
+
+// U_EMRPAINTRGN 74
+/**
+ \brief Print a pointer to a U_EMR_PAINTRGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPAINTRGN_print(const char *contents){
+ core11_print("U_EMRPAINTRGN", contents);
+}
+
+// U_EMREXTSELECTCLIPRGN 75
+/**
+ \brief Print a pointer to a U_EMR_EXTSELECTCLIPRGN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTSELECTCLIPRGN_print(const char *contents){
+ PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents);
+ if(pEmr->emr.nSize < U_SIZE_EMREXTSELECTCLIPRGN){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" cbRgnData: %u\n",pEmr->cbRgnData);
+ printf(" iMode: %u\n",pEmr->iMode);
+ if(pEmr->iMode == U_RGN_COPY && !pEmr->cbRgnData){
+ printf(" RegionData: none (Clip region becomes NULL)\n");
+ }
+ else {
+ const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit);
+ printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n");
+ }
+
+}
+
+// U_EMRBITBLT 76
+/**
+ \brief Print a pointer to a U_EMR_BITBLT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRBITBLT_print(const char *contents){
+ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRBITBLT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n");
+ printf(" dwRop : 0x%8.8X\n", pEmr->dwRop );
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n");
+ printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n");
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+}
+
+// U_EMRSTRETCHBLT 77
+/**
+ \brief Print a pointer to a U_EMR_STRETCHBLT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSTRETCHBLT_print(const char *contents){
+ PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSTRETCHBLT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n");
+ printf(" dwRop : 0x%8.8X\n", pEmr->dwRop );
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n");
+ printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n");
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+ printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n");
+}
+
+// U_EMRMASKBLT 78
+/**
+ \brief Print a pointer to a U_EMR_MASKBLT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRMASKBLT_print(const char *contents){
+ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRMASKBLT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n");
+ printf(" dwRop : 0x%8.8X\n", pEmr->dwRop );
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n");
+ printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n");
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" Src bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+ printf(" Mask: "); pointl_print(pEmr->Mask); printf("\n");
+ printf(" iUsageMask: %u\n", pEmr->iUsageMask );
+ printf(" offBmiMask: %u\n", pEmr->offBmiMask );
+ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask );
+ if(pEmr->cbBmiMask){
+ printf(" Mask bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiMask, blimit);
+ printf("\n");
+ }
+ printf(" offBitsMask: %u\n", pEmr->offBitsMask );
+ printf(" cbBitsMask: %u\n", pEmr->cbBitsMask );
+}
+
+// U_EMRPLGBLT 79
+/**
+ \brief Print a pointer to a U_EMR_PLGBLT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPLGBLT_print(const char *contents){
+ PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPLGBLT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" aptlDst(UL): "); pointl_print(pEmr->aptlDst[0]); printf("\n");
+ printf(" aptlDst(UR): "); pointl_print(pEmr->aptlDst[1]); printf("\n");
+ printf(" aptlDst(LL): "); pointl_print(pEmr->aptlDst[2]); printf("\n");
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n");
+ printf(" xformSrc: "); xform_print( pEmr->xformSrc); printf("\n");
+ printf(" crBkColorSrc: "); colorref_print( pEmr->crBkColorSrc); printf("\n");
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" Src bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+ printf(" Mask: "); pointl_print(pEmr->Mask); printf("\n");
+ printf(" iUsageMsk: %u\n", pEmr->iUsageMask );
+ printf(" offBmiMask: %u\n", pEmr->offBmiMask );
+ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask );
+ if(pEmr->cbBmiMask){
+ printf(" Mask bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiMask, blimit);
+ printf("\n");
+ }
+ printf(" offBitsMask: %u\n", pEmr->offBitsMask );
+ printf(" cbBitsMask: %u\n", pEmr->cbBitsMask );
+}
+
+// U_EMRSETDIBITSTODEVICE 80
+/**
+ \brief Print a pointer to a U_EMRSETDIBITSTODEVICE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETDIBITSTODEVICE_print(const char *contents){
+ PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSETDIBITSTODEVICE)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n");
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" Src bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" iStartScan: %u\n", pEmr->iStartScan );
+ printf(" cScans : %u\n", pEmr->cScans );
+}
+
+// U_EMRSTRETCHDIBITS 81
+/**
+ \brief Print a pointer to a U_EMR_STRETCHDIBITS record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSTRETCHDIBITS_print(const char *contents){
+ PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSTRETCHDIBITS)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" Src: "); pointl_print(pEmr->Src); printf("\n");
+ printf(" cSrc: "); pointl_print(pEmr->cSrc); printf("\n");
+ printf(" offBmiSrc: %u\n", pEmr->offBmiSrc );
+ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc );
+ if(pEmr->cbBmiSrc){
+ printf(" Src bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmiSrc, blimit);
+ printf("\n");
+ }
+ printf(" offBitsSrc: %u\n", pEmr->offBitsSrc );
+ printf(" cbBitsSrc: %u\n", pEmr->cbBitsSrc );
+ printf(" iUsageSrc: %u\n", pEmr->iUsageSrc );
+ printf(" dwRop : 0x%8.8X\n", pEmr->dwRop );
+ printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n");
+}
+
+// U_EMREXTCREATEFONTINDIRECTW_print 82
+/**
+ \brief Print a pointer to a U_EMR_EXTCREATEFONTINDIRECTW record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents){
+ PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents);
+ if(pEmr->emr.nSize < U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT){ // smallest variant
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" ihFont: %u\n",pEmr->ihFont );
+ printf(" Font: ");
+ if(pEmr->emr.nSize == U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE){ // holds logfont_panose
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->elfw), sizeof(U_PANOSE), blimit);
+ logfont_panose_print(pEmr->elfw);
+ }
+ else { // holds logfont or logfontExDv. The latter isn't supported but it starts with logfont, so use that
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->elfw), sizeof(U_LOGFONT), blimit);
+ logfont_print( *(PU_LOGFONT) &(pEmr->elfw));
+ }
+ printf("\n");
+}
+
+// U_EMREXTTEXTOUTA 83
+/**
+ \brief Print a pointer to a U_EMR_EXTTEXTOUTA record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTTEXTOUTA_print(const char *contents){
+ core8_print("U_EMREXTTEXTOUTA", contents, 0);
+}
+
+// U_EMREXTTEXTOUTW 84
+/**
+ \brief Print a pointer to a U_EMR_EXTTEXTOUTW record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTTEXTOUTW_print(const char *contents){
+ core8_print("U_EMREXTTEXTOUTW", contents, 1);
+}
+
+// U_EMRPOLYBEZIER16 85
+/**
+ \brief Print a pointer to a U_EMR_POLYBEZIER16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYBEZIER16_print(const char *contents){
+ core6_print("U_EMRPOLYBEZIER16", contents);
+}
+
+// U_EMRPOLYGON16 86
+/**
+ \brief Print a pointer to a U_EMR_POLYGON16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYGON16_print(const char *contents){
+ core6_print("U_EMRPOLYGON16", contents);
+}
+
+// U_EMRPOLYLINE16 87
+/**
+ \brief Print a pointer to a U_EMR_POLYLINE16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYLINE16_print(const char *contents){
+ core6_print("U_EMRPOLYLINE16", contents);
+}
+
+// U_EMRPOLYBEZIERTO16 88
+/**
+ \brief Print a pointer to a U_EMR_POLYBEZIERTO16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYBEZIERTO16_print(const char *contents){
+ core6_print("U_EMRPOLYBEZIERTO16", contents);
+}
+
+// U_EMRPOLYLINETO16 89
+/**
+ \brief Print a pointer to a U_EMR_POLYLINETO16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYLINETO16_print(const char *contents){
+ core6_print("U_EMRPOLYLINETO16", contents);
+}
+
+// U_EMRPOLYPOLYLINE16 90
+/**
+ \brief Print a pointer to a U_EMR_POLYPOLYLINE16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYPOLYLINE16_print(const char *contents){
+ core10_print("U_EMRPOLYPOLYLINE16", contents);
+}
+
+// U_EMRPOLYPOLYGON16 91
+/**
+ \brief Print a pointer to a U_EMR_POLYPOLYGON16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYPOLYGON16_print(const char *contents){
+ core10_print("U_EMRPOLYPOLYGON16", contents);
+}
+
+
+// U_EMRPOLYDRAW16 92
+/**
+ \brief Print a pointer to a U_EMR_POLYDRAW16 record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPOLYDRAW16_print(const char *contents){
+ unsigned int i;
+ PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPOLYDRAW16)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" cpts: %d\n",pEmr->cpts );
+ printf(" Points: ");
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->apts, pEmr->cpts*sizeof(U_POINT16), blimit);
+ for(i=0;i<pEmr->cpts; i++){
+ printf(" [%d]:",i);
+ point16_print(pEmr->apts[i]);
+ }
+ printf("\n");
+ printf(" Types: ");
+ const char *abTypes = (const char *) pEmr->apts + pEmr->cpts*sizeof(U_POINT16);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(abTypes, pEmr->cpts, blimit);
+ for(i=0;i<pEmr->cpts; i++){
+ printf(" [%d]:%u ",i,((uint8_t *)abTypes)[i]);
+ }
+ printf("\n");
+}
+
+// U_EMRCREATEMONOBRUSH 93
+/**
+ \brief Print a pointer to a U_EMR_CREATEMONOBRUSH record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATEMONOBRUSH_print(const char *contents){
+ core12_print("U_EMRCREATEMONOBRUSH", contents);
+}
+
+// U_EMRCREATEDIBPATTERNBRUSHPT_print 94
+/**
+ \brief Print a pointer to a U_EMR_CREATEDIBPATTERNBRUSHPT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents){
+ core12_print("U_EMRCREATEDIBPATTERNBRUSHPT", contents);
+}
+
+
+// U_EMREXTCREATEPEN 95
+/**
+ \brief Print a pointer to a U_EMR_EXTCREATEPEN record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMREXTCREATEPEN_print(const char *contents){
+ PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMREXTCREATEPEN)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" ihPen: %u\n", pEmr->ihPen );
+ printf(" offBmi: %u\n", pEmr->offBmi );
+ printf(" cbBmi: %u\n", pEmr->cbBmi );
+ if(pEmr->cbBmi){
+ printf(" bitmap: ");
+ bitmapinfo_print(contents + pEmr->offBmi, blimit);
+ printf("\n");
+ }
+ printf(" offBits: %u\n", pEmr->offBits );
+ printf(" cbBits: %u\n", pEmr->cbBits );
+ printf(" elp: "); extlogpen_print((PU_EXTLOGPEN) &(pEmr->elp)); printf("\n");
+}
+
+// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTA",A) //!< Not implemented.
+// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRPOLYTEXTOUTW",A) //!< Not implemented.
+
+// U_EMRSETICMMODE 98
+/**
+ \brief Print a pointer to a U_EMR_SETICMMODE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETICMMODE_print(const char *contents){
+ core3_print("U_EMRSETICMMODE", "iMode:", contents);
+}
+
+// U_EMRCREATECOLORSPACE 99
+/**
+ \brief Print a pointer to a U_EMR_CREATECOLORSPACE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATECOLORSPACE_print(const char *contents){
+ PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATECOLORSPACE)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ printf(" ihCS: %u\n", pEmr->ihCS );
+ printf(" ColorSpace: "); logcolorspacea_print(pEmr->lcs); printf("\n");
+}
+
+// U_EMRSETCOLORSPACE 100
+/**
+ \brief Print a pointer to a U_EMR_SETCOLORSPACE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETCOLORSPACE_print(const char *contents){
+ core3_print("U_EMRSETCOLORSPACE", "ihCS:", contents);
+}
+
+// U_EMRDELETECOLORSPACE 101
+/**
+ \brief Print a pointer to a U_EMR_DELETECOLORSPACE record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRDELETECOLORSPACE_print(const char *contents){
+ core3_print("U_EMRDELETECOLORSPACE", "ihCS:", contents);
+}
+
+// U_EMRGLSRECORD 102 Not implemented
+#define U_EMRGLSRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSRECORD",A) //!< Not implemented.
+// U_EMRGLSBOUNDEDRECORD 103 Not implemented
+#define U_EMRGLSBOUNDEDRECORD_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRGLSBOUNDEDRECORD",A) //!< Not implemented.
+
+// U_EMRPIXELFORMAT 104
+/**
+ \brief Print a pointer to a U_EMR_PIXELFORMAT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRPIXELFORMAT_print(const char *contents){
+ PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRPIXELFORMAT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->pfd), sizeof(U_PIXELFORMATDESCRIPTOR), blimit);
+ printf(" Pfd: "); pixelformatdescriptor_print(pEmr->pfd); printf("\n");
+}
+
+// U_EMRDRAWESCAPE 105 Not implemented
+#define U_EMRDRAWESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRDRAWESCAPE",A) //!< Not implemented.
+// U_EMREXTESCAPE 106 Not implemented
+#define U_EMREXTESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMREXTESCAPE",A) //!< Not implemented.
+// U_EMRUNDEF107 107 Not implemented
+#define U_EMRUNDEF107_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF107",A) //!< Not implemented.
+
+// U_EMRSMALLTEXTOUT 108
+/**
+ \brief Print a pointer to a U_EMR_SMALLTEXTOUT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSMALLTEXTOUT_print(const char *contents){
+ int roff;
+ char *string;
+ PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRSMALLTEXTOUT)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n");
+ printf(" cChars: %u\n", pEmr->cChars );
+ printf(" fuOptions: 0x%8.8X\n", pEmr->fuOptions );
+ printf(" iGraphicsMode: 0x%8.8X\n", pEmr->iGraphicsMode );
+ printf(" exScale: %f\n", pEmr->exScale );
+ printf(" eyScale: %f\n", pEmr->eyScale );
+ roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields
+ if(!(pEmr->fuOptions & U_ETO_NO_RECT)){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff, blimit);
+ printf(" rclBounds: "); rectl_print( *(PU_RECTL) (contents + roff)); printf("\n");
+ roff += sizeof(U_RECTL);
+ }
+ if(pEmr->fuOptions & U_ETO_SMALL_CHARS){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff + pEmr->cChars*sizeof(char), blimit);
+ printf(" Text8: <%.*s>\n",pEmr->cChars,contents+roff); /* May not be null terminated */
+ }
+ else {
+ string = U_Utf16leToUtf8((uint16_t *)(contents+roff), pEmr->cChars, NULL);
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff + pEmr->cChars*2*sizeof(char), blimit);
+ printf(" Text16: <%s>\n",contents+roff);
+ free(string);
+ }
+}
+
+// U_EMRFORCEUFIMAPPING 109 Not implemented
+#define U_EMRFORCEUFIMAPPING_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRFORCEUFIMAPPING",A) //!< Not implemented.
+// U_EMRNAMEDESCAPE 110 Not implemented
+#define U_EMRNAMEDESCAPE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRNAMEDESCAPE",A) //!< Not implemented.
+// U_EMRCOLORCORRECTPALETTE 111 Not implemented
+#define U_EMRCOLORCORRECTPALETTE_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRCOLORCORRECTPALETTE",A) //!< Not implemented.
+// U_EMRSETICMPROFILEA 112 Not implemented
+#define U_EMRSETICMPROFILEA_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEA",A) //!< Not implemented.
+// U_EMRSETICMPROFILEW 113 Not implemented
+#define U_EMRSETICMPROFILEW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRSETICMPROFILEW",A) //!< Not implemented.
+
+// U_EMRALPHABLEND 114
+/**
+ \brief Print a pointer to a U_EMR_ALPHABLEND record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRALPHABLEND_print(const char *contents){
+ core13_print("U_EMRALPHABLEND", contents);
+}
+
+// U_EMRSETLAYOUT 115
+/**
+ \brief Print a pointer to a U_EMR_SETLAYOUT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRSETLAYOUT_print(const char *contents){
+ core3_print("U_EMRSETLAYOUT", "iMode:", contents);
+}
+
+// U_EMRTRANSPARENTBLT 116
+/**
+ \brief Print a pointer to a U_EMR_TRANSPARENTBLT record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRTRANSPARENTBLT_print(const char *contents){
+ core13_print("U_EMRTRANSPARENTBLT", contents);
+}
+
+// U_EMRUNDEF117 117 Not implemented
+#define U_EMRUNDEF117_print(A) U_EMRNOTIMPLEMENTED_print("U_EMRUNDEF117",A) //!< Not implemented.
+// U_EMRGRADIENTFILL 118
+/**
+ \brief Print a pointer to a U_EMR_GRADIENTFILL record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRGRADIENTFILL_print(const char *contents){
+ unsigned int i;
+ PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRGRADIENTFILL)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n");
+ printf(" nTriVert: %u\n", pEmr->nTriVert );
+ printf(" nGradObj: %u\n", pEmr->nGradObj );
+ printf(" ulMode: %u\n", pEmr->ulMode );
+ contents += sizeof(U_EMRGRADIENTFILL);
+ if(pEmr->nTriVert){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nTriVert*sizeof(U_TRIVERTEX), blimit);
+ printf(" TriVert: ");
+ for(i=0; i<pEmr->nTriVert; i++, contents+=sizeof(U_TRIVERTEX)){
+ trivertex_print(*(PU_TRIVERTEX)(contents));
+ }
+ printf("\n");
+ }
+ if(pEmr->nGradObj){
+ printf(" GradObj: ");
+ if( pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nGradObj*sizeof(U_GRADIENT3), blimit);
+ for(i=0; i<pEmr->nGradObj; i++, contents+=sizeof(U_GRADIENT3)){
+ gradient3_print(*(PU_GRADIENT3)(contents));
+ }
+ }
+ else if(pEmr->ulMode == U_GRADIENT_FILL_RECT_H ||
+ pEmr->ulMode == U_GRADIENT_FILL_RECT_V){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nGradObj*sizeof(U_GRADIENT4), blimit);
+ for(i=0; i<pEmr->nGradObj; i++, contents+=sizeof(U_GRADIENT4)){
+ gradient4_print(*(PU_GRADIENT4)(contents));
+ }
+ }
+ else { printf("invalid ulMode value!"); }
+ printf("\n");
+ }
+}
+
+// U_EMRSETLINKEDUFIS 119 Not implemented
+#define U_EMRSETLINKEDUFIS_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETLINKEDUFIS",A) //!< Not implemented.
+// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated)
+#define U_EMRSETTEXTJUSTIFICATION_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_SETTEXTJUSTIFICATION",A) //!< Not implemented.
+// U_EMRCOLORMATCHTOTARGETW 121 Not implemented
+#define U_EMRCOLORMATCHTOTARGETW_print(A) U_EMRNOTIMPLEMENTED_print("U_EMR_COLORMATCHTOTARGETW",A) //!< Not implemented.
+
+// U_EMRCREATECOLORSPACEW 122
+/**
+ \brief Print a pointer to a U_EMR_CREATECOLORSPACEW record.
+ \param contents pointer to a buffer holding all EMR records
+*/
+void U_EMRCREATECOLORSPACEW_print(const char *contents){
+ unsigned int i;
+ PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents);
+ if(pEmr->emr.nSize < sizeof(U_EMRCREATECOLORSPACEW)){
+ printf(" record corruption HERE\n");
+ return;
+ }
+ const char *blimit = contents + pEmr->emr.nSize;
+ printf(" ihCS: %u\n", pEmr->ihCS );
+ printf(" ColorSpace: "); logcolorspacew_print(pEmr->lcs); printf("\n");
+ printf(" dwFlags: 0x%8.8X\n", pEmr->dwFlags );
+ printf(" cbData: %u\n", pEmr->cbData );
+ printf(" Data(hexvalues):");
+ if(pEmr->dwFlags & 1){
+ IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->cbData, blimit);
+ for(i=0; i<pEmr->cbData; i++){
+ printf("[%d]:%2.2X ",i,pEmr->Data[i]);
+ }
+ }
+ printf("\n");
+}
+
+/**
+ \brief Print any record in an emf
+ \returns record length for a normal record, 0 for EMREOF, -1 for a bad record
+ \param contents pointer to a buffer holding all EMR records
+ \param blimit pointer to the byte after the last byte in the buffer holding all EMR records
+ \param recnum number of this record in contents
+ \param off offset to this record in contents
+*/
+int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){
+ PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off);
+ uint32_t nSize;
+ uint32_t iType;
+ const char *record = contents + off;
+
+ if(record < contents)return(-1); // offset wrapped
+
+ /* Check that COMMON data in record can be touched without an access violation. If it cannot be
+ this is either a corrupt EMF or one engineered to cause a buffer overflow. Pointer math
+ could wrap so check both sides of the range.
+ */
+ if(!U_emf_record_sizeok(record, blimit, &nSize, &iType, 1))return(-1);
+
+ uint32_t crc;
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, EMF crc values must be calculated on Little Endian form
+ char *swapbuf=malloc(nSize);
+ if(!swapbuf)return(-1);
+ memcpy(swapbuf,record,nSize);
+ U_emf_endian(swapbuf,nSize,1); // BE to LE
+ crc=lu_crc32(swapbuf,nSize);
+ free(swapbuf);
+#else
+ crc=lu_crc32(record,nSize);
+#endif
+ printf("%-30srecord:%5d type:%-4d offset:%8d rsize:%8d crc32:%8.8X\n",
+ U_emr_names(iType),recnum,iType,(int) off,nSize,crc);
+
+ fflush(stdout);
+
+ /* print the record header before checking further.
+ Note if this is a corrupt record, but continue anyway.
+ The _print routines will stop at the actual problem and print another corrupt message.
+ */
+ if(!U_emf_record_safe(record)){printf("WARNING: Corrupt record. Emitting fields above the problem.\n");}
+
+ switch (lpEMFR->iType)
+ {
+ case U_EMR_HEADER: U_EMRHEADER_print(record); break;
+ case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(record); break;
+ case U_EMR_POLYGON: U_EMRPOLYGON_print(record); break;
+ case U_EMR_POLYLINE: U_EMRPOLYLINE_print(record); break;
+ case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(record); break;
+ case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(record); break;
+ case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(record); break;
+ case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(record); break;
+ case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(record); break;
+ case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(record); break;
+ case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(record); break;
+ case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(record); break;
+ case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(record); break;
+ case U_EMR_EOF: U_EMREOF_print(record); nSize=0; break;
+ case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(record); break;
+ case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(record); break;
+ case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(record); break;
+ case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(record); break;
+ case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(record); break;
+ case U_EMR_SETROP2: U_EMRSETROP2_print(record); break;
+ case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(record); break;
+ case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(record); break;
+ case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(record); break;
+ case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(record); break;
+ case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(record); break;
+ case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(record); break;
+ case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(record); break;
+ case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(record); break;
+ case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(record); break;
+ case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(record); break;
+ case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(record); break;
+ case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(record); break;
+ case U_EMR_SAVEDC: U_EMRSAVEDC_print(record); break;
+ case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(record); break;
+ case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(record); break;
+ case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(record); break;
+ case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(record); break;
+ case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(record); break;
+ case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(record); break;
+ case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(record); break;
+ case U_EMR_ANGLEARC: U_EMRANGLEARC_print(record); break;
+ case U_EMR_ELLIPSE: U_EMRELLIPSE_print(record); break;
+ case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(record); break;
+ case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(record); break;
+ case U_EMR_ARC: U_EMRARC_print(record); break;
+ case U_EMR_CHORD: U_EMRCHORD_print(record); break;
+ case U_EMR_PIE: U_EMRPIE_print(record); break;
+ case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(record); break;
+ case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(record); break;
+ case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(record); break;
+ case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(record); break;
+ case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(record); break;
+ case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(record); break;
+ case U_EMR_LINETO: U_EMRLINETO_print(record); break;
+ case U_EMR_ARCTO: U_EMRARCTO_print(record); break;
+ case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(record); break;
+ case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(record); break;
+ case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(record); break;
+ case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(record); break;
+ case U_EMR_ENDPATH: U_EMRENDPATH_print(record); break;
+ case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(record); break;
+ case U_EMR_FILLPATH: U_EMRFILLPATH_print(record); break;
+ case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(record); break;
+ case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(record); break;
+ case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(record); break;
+ case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(record); break;
+ case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(record); break;
+ case U_EMR_ABORTPATH: U_EMRABORTPATH_print(record); break;
+ case U_EMR_UNDEF69: U_EMRUNDEF69_print(record); break;
+ case U_EMR_COMMENT: U_EMRCOMMENT_print(record, off); break;
+ case U_EMR_FILLRGN: U_EMRFILLRGN_print(record); break;
+ case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(record); break;
+ case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(record); break;
+ case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(record); break;
+ case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(record); break;
+ case U_EMR_BITBLT: U_EMRBITBLT_print(record); break;
+ case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(record); break;
+ case U_EMR_MASKBLT: U_EMRMASKBLT_print(record); break;
+ case U_EMR_PLGBLT: U_EMRPLGBLT_print(record); break;
+ case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(record); break;
+ case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(record); break;
+ case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(record); break;
+ case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(record); break;
+ case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(record); break;
+ case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(record); break;
+ case U_EMR_POLYGON16: U_EMRPOLYGON16_print(record); break;
+ case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(record); break;
+ case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(record); break;
+ case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(record); break;
+ case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(record); break;
+ case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(record); break;
+ case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(record); break;
+ case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(record); break;
+ case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(record); break;
+ case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(record); break;
+ case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(record); break;
+ case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(record); break;
+ case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(record); break;
+ case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(record); break;
+ case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(record); break;
+ case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(record); break;
+ case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(record); break;
+ case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(record); break;
+ case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(record); break;
+ case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(record); break;
+ case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(record); break;
+ case U_EMR_UNDEF107: U_EMRUNDEF107_print(record); break;
+ case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(record); break;
+ case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(record); break;
+ case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(record); break;
+ case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(record); break;
+ case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(record); break;
+ case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(record); break;
+ case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(record); break;
+ case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(record); break;
+ case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(record); break;
+ case U_EMR_UNDEF117: U_EMRUNDEF117_print(record); break;
+ case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(record); break;
+ case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(record); break;
+ case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(record); break;
+ case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(record); break;
+ case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(record); break;
+ default: U_EMRNOTIMPLEMENTED_print("?",record); break;
+ } //end of switch
+ return(nSize);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uemf_print.h b/src/3rdparty/libuemf/uemf_print.h
new file mode 100644
index 000000000..088a8a302
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_print.h
@@ -0,0 +1,177 @@
+/**
+ @file uemf_print.h
+
+ @brief Prototypes for functions for printing records from EMF files.
+*/
+
+/*
+File: uemf_print.h
+Version: 0.0.9
+Date: 21-MAY-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UEMF_PRINT_
+#define _UEMF_PRINT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//! \cond
+/* prototypes for miscellaneous */
+uint32_t lu_crc32(const char *record, uint32_t Size);
+
+/* prototypes for objects used in EMR records */
+void hexbytes_print(uint8_t *buf,unsigned int num);
+void colorref_print(U_COLORREF color);
+void rgbquad_print(U_RGBQUAD color);
+void rectl_print(U_RECTL rect);
+void sizel_print(U_SIZEL sz);
+void pointl_print(U_POINTL pt);
+void point16_print(U_POINT16 pt);
+void lcs_gamma_print(U_LCS_GAMMA lg);
+void lcs_gammargb_print(U_LCS_GAMMARGB lgr);
+void trivertex_print(U_TRIVERTEX tv);
+void gradient3_print(U_GRADIENT3 g3);
+void gradient4_print(U_GRADIENT4 g4);
+void logbrush_print(U_LOGBRUSH lb);
+void xform_print(U_XFORM xform);
+void ciexyz_print(U_CIEXYZ ciexyz);
+void ciexyztriple_print(U_CIEXYZTRIPLE cie3);
+void logcolorspacea_print(U_LOGCOLORSPACEA lcsa);
+void logcolorspacew_print(U_LOGCOLORSPACEW lcsa);
+void panose_print(U_PANOSE panose);
+void logfont_print(U_LOGFONT lf);
+void logfont_panose_print(U_LOGFONT_PANOSE lfp);
+void bitmapinfoheader_print(const char *Bmih);
+void bitmapinfo_print(const char *Bmi, const char *blimit);
+void blend_print(U_BLEND blend);
+void extlogpen_print(const PU_EXTLOGPEN elp);
+void logpen_print(U_LOGPEN lp);
+void logpltntry_print(U_LOGPLTNTRY lpny);
+void logpalette_print(const PU_LOGPALETTE lp);
+void rgndataheader_print(U_RGNDATAHEADER rdh);
+void rgndata_print(const PU_RGNDATA rd, const char *blimit);
+void coloradjustment_print(U_COLORADJUSTMENT ca);
+void pixelformatdescriptor_print(U_PIXELFORMATDESCRIPTOR pfd);
+void emrtext_print(const char *emt, const char *record, const char *blimit, int type);
+
+/* prototypes for EMR records */
+void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents, int recnum, int off);
+void U_EMRHEADER_print(const char *contents);
+void U_EMRPOLYBEZIER_print(const char *contents);
+void U_EMRPOLYGON_print(const char *contents);
+void U_EMRPOLYLINE_print(const char *contents);
+void U_EMRPOLYBEZIERTO_print(const char *contents);
+void U_EMRPOLYLINETO_print(const char *contents);
+void U_EMRPOLYPOLYLINE_print(const char *contents);
+void U_EMRPOLYPOLYGON_print(const char *contents);
+void U_EMRSETWINDOWEXTEX_print(const char *contents);
+void U_EMRSETWINDOWORGEX_print(const char *contents);
+void U_EMRSETVIEWPORTEXTEX_print(const char *contents);
+void U_EMRSETVIEWPORTORGEX_print(const char *contents);
+void U_EMRSETBRUSHORGEX_print(const char *contents);
+void U_EMREOF_print(const char *contents);
+void U_EMRSETPIXELV_print(const char *contents);
+void U_EMRSETMAPPERFLAGS_print(const char *contents);
+void U_EMRSETMAPMODE_print(const char *contents);
+void U_EMRSETBKMODE_print(const char *contents);
+void U_EMRSETPOLYFILLMODE_print(const char *contents);
+void U_EMRSETROP2_print(const char *contents);
+void U_EMRSETSTRETCHBLTMODE_print(const char *contents);
+void U_EMRSETTEXTALIGN_print(const char *contents);
+void U_EMRSETCOLORADJUSTMENT_print(const char *contents);
+void U_EMRSETTEXTCOLOR_print(const char *contents);
+void U_EMRSETBKCOLOR_print(const char *contents);
+void U_EMROFFSETCLIPRGN_print(const char *contents);
+void U_EMRMOVETOEX_print(const char *contents);
+void U_EMRSETMETARGN_print(const char *contents);
+void U_EMREXCLUDECLIPRECT_print(const char *contents);
+void U_EMRINTERSECTCLIPRECT_print(const char *contents);
+void U_EMRSCALEVIEWPORTEXTEX_print(const char *contents);
+void U_EMRSCALEWINDOWEXTEX_print(const char *contents);
+void U_EMRSAVEDC_print(const char *contents);
+void U_EMRRESTOREDC_print(const char *contents);
+void U_EMRSETWORLDTRANSFORM_print(const char *contents);
+void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents);
+void U_EMRSELECTOBJECT_print(const char *contents);
+void U_EMRCREATEPEN_print(const char *contents);
+void U_EMRCREATEBRUSHINDIRECT_print(const char *contents);
+void U_EMRDELETEOBJECT_print(const char *contents);
+void U_EMRANGLEARC_print(const char *contents);
+void U_EMRELLIPSE_print(const char *contents);
+void U_EMRRECTANGLE_print(const char *contents);
+void U_EMRROUNDRECT_print(const char *contents);
+void U_EMRARC_print(const char *contents);
+void U_EMRCHORD_print(const char *contents);
+void U_EMRPIE_print(const char *contents);
+void U_EMRSELECTPALETTE_print(const char *contents);
+void U_EMRCREATEPALETTE_print(const char *contents);
+void U_EMRSETPALETTEENTRIES_print(const char *contents);
+void U_EMRRESIZEPALETTE_print(const char *contents);
+void U_EMRREALIZEPALETTE_print(const char *contents);
+void U_EMREXTFLOODFILL_print(const char *contents);
+void U_EMRLINETO_print(const char *contents);
+void U_EMRARCTO_print(const char *contents);
+void U_EMRPOLYDRAW_print(const char *contents);
+void U_EMRSETARCDIRECTION_print(const char *contents);
+void U_EMRSETMITERLIMIT_print(const char *contents);
+void U_EMRBEGINPATH_print(const char *contents);
+void U_EMRENDPATH_print(const char *contents);
+void U_EMRCLOSEFIGURE_print(const char *contents);
+void U_EMRFILLPATH_print(const char *contents);
+void U_EMRSTROKEANDFILLPATH_print(const char *contents);
+void U_EMRSTROKEPATH_print(const char *contents);
+void U_EMRFLATTENPATH_print(const char *contents);
+void U_EMRWIDENPATH_print(const char *contents);
+void U_EMRSELECTCLIPPATH_print(const char *contents);
+void U_EMRABORTPATH_print(const char *contents);
+void U_EMRCOMMENT_print(const char *contents, size_t off);
+void U_EMRFILLRGN_print(const char *contents);
+void U_EMRFRAMERGN_print(const char *contents);
+void U_EMRINVERTRGN_print(const char *contents);
+void U_EMRPAINTRGN_print(const char *contents);
+void U_EMREXTSELECTCLIPRGN_print(const char *contents);
+void U_EMRBITBLT_print(const char *contents);
+void U_EMRSTRETCHBLT_print(const char *contents);
+void U_EMRMASKBLT_print(const char *contents);
+void U_EMRPLGBLT_print(const char *contents);
+void U_EMRSETDIBITSTODEVICE_print(const char *contents);
+void U_EMRSTRETCHDIBITS_print(const char *contents);
+void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents);
+void U_EMREXTTEXTOUTA_print(const char *contents);
+void U_EMREXTTEXTOUTW_print(const char *contents);
+void U_EMRPOLYBEZIER16_print(const char *contents);
+void U_EMRPOLYGON16_print(const char *contents);
+void U_EMRPOLYLINE16_print(const char *contents);
+void U_EMRPOLYBEZIERTO16_print(const char *contents);
+void U_EMRPOLYLINETO16_print(const char *contents);
+void U_EMRPOLYPOLYLINE16_print(const char *contents);
+void U_EMRPOLYPOLYGON16_print(const char *contents);
+void U_EMRPOLYDRAW16_print(const char *contents);
+void U_EMRCREATEMONOBRUSH_print(const char *contents);
+void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents);
+void U_EMREXTCREATEPEN_print(const char *contents);
+void U_EMRSETICMMODE_print(const char *contents);
+void U_EMRCREATECOLORSPACE_print(const char *contents);
+void U_EMRSETCOLORSPACE_print(const char *contents);
+void U_EMRDELETECOLORSPACE_print(const char *contents);
+void U_EMRPIXELFORMAT_print(const char *contents);
+void U_EMRSMALLTEXTOUT_print(const char *contents);
+void U_EMRALPHABLEND_print(const char *contents);
+void U_EMRSETLAYOUT_print(const char *contents);
+void U_EMRTRANSPARENTBLT_print(const char *contents);
+void U_EMRGRADIENTFILL_print(const char *contents);
+void U_EMRCREATECOLORSPACEW_print(const char *contents);
+int U_emf_onerec_print(const char *contents, char *blimit, int recnum, int off);
+//! \endcond
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UEMF_PRINT_ */
diff --git a/src/3rdparty/libuemf/uemf_safe.c b/src/3rdparty/libuemf/uemf_safe.c
new file mode 100644
index 000000000..a3e050282
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_safe.c
@@ -0,0 +1,1204 @@
+/**
+ @file uemf_safe.c
+
+ @brief Functions for checking EMF records for memory issues.
+
+ EMF records come in a variety of sizes, and some types have variable sizes.
+ These functions check the record types and report if there are any issues
+ that could cause a memory access problem. All counts and offsets are examined
+ and the data structure checked so that no referenced byte is outside of the
+ declared size of the record.
+
+ Many variables are initialized to zero even though they will always be set because
+ some versions of gcc give spurious "may be used uninitialized" warnings otherwise.
+*/
+
+/*
+File: uemf_safe.c
+Version: 0.0.5
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h> /* for offsetof() macro */
+#include "uemf.h"
+#include "uemf_endian.h" // for u_emf_record_sizeok
+
+// hide almost everuything in here from Doxygen
+//! \cond
+
+/**
+ \brief Test a U_EXTLOGPEN object.
+ \param elp PU_EXTLOGPEN object
+ \param blimit one byte past the end of the record
+*/
+int extlogpen_safe(
+ PU_EXTLOGPEN elp,
+ const char *blimit
+ ){
+ int count=elp->elpNumEntries;
+ if(IS_MEM_UNSAFE(&(elp->elpStyleEntry), count*4, blimit))return(0);
+ return(1);
+}
+
+/**
+ \brief Test a U_EMRTEXT record
+ \param pemt Pointer to a U_EMRTEXT record
+ \param record Pointer to the start of the record which contains this U_EMRTEXT
+ \param blimit one byte past the end of the record.
+*/
+int emrtext_safe(
+ PU_EMRTEXT pemt,
+ const char *record,
+ const char *blimit
+ ){
+ int off;
+ uint32_t count = pemt->nChars;
+ uint32_t fOptions = pemt->fOptions;
+ uint32_t offDx = 0;
+ off = sizeof(U_EMRTEXT);
+ if(!(fOptions & U_ETO_NO_RECT)){
+ if(IS_MEM_UNSAFE(pemt, sizeof(U_RECTL), blimit))return(0);
+ off+=sizeof(U_RECTL);
+ }
+ offDx = *(uint32_t *)((char *)pemt +off);
+ if(IS_MEM_UNSAFE(pemt, off + 4, blimit))return(0);
+ if(IS_MEM_UNSAFE(record, offDx + count*4, blimit))return(0);
+ return(1);
+}
+
+/**
+ \return 1 on success, 0 on failure
+ \brief Test a U_RGNDATA object.
+ \param rd pointer to a U_RGNDATA object.
+ \param cbRgnData size of the U_RGNDATA object.
+*/
+int rgndata_safe(
+ PU_RGNDATA rd,
+ int cbRgnData
+ ){
+ int count = rd->rdh.nCount;
+ if(4*count + (int)sizeof(U_RGNDATAHEADER) > cbRgnData)return(0);
+ return(1);
+}
+
+
+/**
+ \return 1 on success, 0 on failure
+ \brief Test a U_BITMAPINFO object.
+ \param Bmi pointer to a U_BITMAPINFO object.
+ \param blimit one byte past the end of the record.
+*/
+int bitmapinfo_safe(
+ const char *Bmi,
+ const char *blimit
+ ){
+ int ClrUsed;
+ if(IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiHeader) + sizeof(U_BITMAPINFOHEADER), blimit))return(0);
+ ClrUsed = get_real_color_count(Bmi + offsetof(U_BITMAPINFO,bmiHeader));
+ if(ClrUsed && IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiColors) + ClrUsed*sizeof(U_RGBQUAD), blimit))return(0);
+ return(1);
+}
+
+/**
+ \brief Check that the bitmap in the specified DIB is compatible with the record size
+
+ \return 1 on success, 0 on failure
+ \param record EMF record that contains a DIB pixel array
+ \param iUsage DIBcolors Enumeration
+ \param offBmi offset from the start of the record to the start of the bitmapinfo structure
+ \param cbBmi declared space for the bitmapinfo structure in the record
+ \param offBits offset from the start of the record to the start of the bitmap
+ \param cbBits declared space for the bitmap in the record (amount used may be less than this)
+ \param blimit one byte past the end of the record.
+
+ This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag
+ of bytes, and there is no possible way to derive from the known width and height how big it should be.
+*/
+int DIB_safe(
+ const char *record,
+ uint32_t iUsage,
+ uint32_t offBmi,
+ uint32_t cbBmi,
+ uint32_t offBits,
+ uint32_t cbBits,
+ const char *blimit
+ ){
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int bs;
+ int usedbytes;
+
+ if(!cbBmi)return(1); // No DIB in a record where it is optional
+ if(IS_MEM_UNSAFE(record, offBmi + cbBmi, blimit))return(0);
+ if(!bitmapinfo_safe(record + offBmi, blimit))return(0); // checks the number of colors
+ if(cbBits && IS_MEM_UNSAFE(record, offBits + cbBits, blimit))return(0);
+ if(iUsage == U_DIB_RGB_COLORS){
+ uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params
+ // next call returns pointers and values, but allocates no memory
+ dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct,
+ &numCt, &width, &height, &colortype, &invert);
+
+ // sanity checking
+ if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels
+ if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit
+
+ if(dibparams ==U_BI_RGB){
+ // this is the only DIB type where we can calculate how big it should be when stored in the EMF file
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = width*bs;
+ }
+ if(IS_MEM_UNSAFE(record+offBits, usedbytes, blimit))return(0);
+ }
+ }
+ return(1);
+}
+
+
+/* **********************************************************************************************
+These functions contain shared code used by various U_EMR*_safe functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+
+
+ These all have this form:
+
+ void core1_safe(const char *record){
+
+ but some do not actually use torev.
+
+
+
+*********************************************************************************************** */
+
+// all core*_safe call this, U_EMRSETMARGN_safe and some others all it directly
+// numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype
+// sizeof(U_ENHMETARECORD) bytes in the record
+int core5_safe(const char *record, int minSize){
+ PU_EMR pEmr = (PU_EMR)(record);
+ if((int) pEmr->nSize < minSize)return(0);
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER_safe
+int core1_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYLINETO))return(0);
+ PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (record);
+ int count=pEmr->cptl;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->aptl, count*sizeof(U_POINTL), blimit))return(0);
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE_safe
+int core2_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYPOLYLINE))return(0);
+ PU_EMRPOLYPOLYLINE pEmr = (PU_EMRPOLYPOLYLINE) (record);
+ int count = pEmr->cptl;
+ int nPolys = pEmr->nPolys;
+ const char * blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->aPolyCounts, nPolys*4, blimit))return(0);
+ record += sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys;
+ if(IS_MEM_UNSAFE(record, count*sizeof(U_POINTL), blimit))return(0);
+ return(1);
+}
+
+
+// Functions with the same form starting with U_EMRSETMAPMODE_safe
+int core3_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSETMAPMODE))return(0);
+ return(1);
+}
+
+// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_safe, also U_EMRFILLPATH_safe,
+int core4_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRELLIPSE))return(0);
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYBEZIER16_safe
+int core6_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYBEZIER16))return(0);
+ PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (record);
+ int count=pEmr->cpts;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->apts, count*sizeof(U_POINT16), blimit))return(0);
+ return(1);
+}
+
+
+// Records with the same form starting with U_EMRSETWINDOWEXTEX_safe, that is, all with two uint32_t values after the emr
+int core7_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSETWINDOWEXTEX))return(0);
+ return(1);
+}
+
+// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one
+int core8_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMREXTTEXTOUTA))return(0);
+ PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ if(!emrtext_safe(&(pEmr->emrtext),record,blimit))return(0);
+ return(1);
+}
+
+// Functions that take a rect and a pair of points, starting with U_EMRARC_safe
+int core9_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRARC))return(0);
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRPOLYPOLYLINE16_safe
+int core10_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYPOLYLINE16))return(0);
+ PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (record);
+ int count = pEmr->cpts;
+ int nPolys = pEmr->nPolys;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->aPolyCounts, nPolys*4, blimit))return(0);
+ record += sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys;
+ if(IS_MEM_UNSAFE(record, count*sizeof(U_POINT16), blimit))return(0);
+ return(1);
+}
+
+// Functions with the same form starting with U_EMRINVERTRGN_safe and U_EMRPAINTRGN_safe,
+int core11_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRINVERTRGN))return(0);
+ PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN)(record);
+ int cbRgnData = pEmr->cbRgnData;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_safe(pEmr->RgnData, cbRgnData));
+}
+
+
+// common code for U_EMRCREATEMONOBRUSH_safe and U_EMRCREATEDIBPATTERNBRUSHPT_safe,
+int core12_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRCREATEMONOBRUSH))return(0);
+ PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMI offBmi = pEmr->offBmi;
+ U_CBBMI cbBmi = pEmr->cbBmi;
+ U_OFFBITS offBits = pEmr->offBits;
+ U_CBBITS cbBits = pEmr->cbBits;
+ uint32_t iUsage = pEmr->iUsage;
+ return(DIB_safe(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit));
+}
+
+// common code for U_EMRALPHABLEND_safe and U_EMRTRANSPARENTBLT_safe,
+int core13_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRALPHABLEND))return(0);
+ PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITS cbBitsSrc = pEmr->cbBitsSrc;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit));
+}
+
+/* **********************************************************************************************
+These are the core EMR_safe functions, each converts a particular type of record.
+All operate in place on the chunk of memory holding that record.
+Some of these have offsets or counts which, if corrupt or evil would result in access outside
+ the record. These cases return a status value of 0 if that happens, 1 on success. Other
+ records which do not have these issues do not return a status value.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+/**
+ All of the record level (hidden) functions have this form:
+ \brief Convert a pointer to a U_EMR_whatever record which has not been implemented.
+ \param record pointer to a buffer holding the EMR record
+ \param torev 1 for native to reversed, 0 for reversed to native
+*/
+int U_EMRNOTIMPLEMENTED_safe(const char *record){
+ fprintf(stderr,"EMF WARNING: could not safety check record because that type has not been implemented!\n");
+ return(core5_safe(record, sizeof(U_EMR)));
+}
+
+// U_EMRHEADER 1
+int U_EMRHEADER_safe(const char *record){
+ // use _MIN form so that it accepts very old EMF files
+ return(core5_safe(record, U_SIZE_EMRHEADER_MIN));
+}
+
+// U_EMRPOLYBEZIER 2
+int U_EMRPOLYBEZIER_safe(const char *record){
+ return(core1_safe(record));
+}
+
+// U_EMRPOLYGON 3
+int U_EMRPOLYGON_safe(const char *record){
+ return(core1_safe(record));
+}
+
+// U_EMRPOLYLINE 4
+int U_EMRPOLYLINE_safe(const char *record){
+ return(core1_safe(record));
+}
+
+// U_EMRPOLYBEZIERTO 5
+int U_EMRPOLYBEZIERTO_safe(const char *record){
+ return(core1_safe(record));
+}
+
+// U_EMRPOLYLINETO 6
+int U_EMRPOLYLINETO_safe(const char *record){
+ return(core1_safe(record));
+}
+
+// U_EMRPOLYPOLYLINE 7
+int U_EMRPOLYPOLYLINE_safe(const char *record){
+ return(core2_safe(record));
+}
+
+// U_EMRPOLYPOLYGON 8
+int U_EMRPOLYPOLYGON_safe(const char *record){
+ return(core2_safe(record));
+}
+
+// U_EMRSETWINDOWEXTEX 9
+int U_EMRSETWINDOWEXTEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRSETWINDOWORGEX 10
+int U_EMRSETWINDOWORGEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRSETVIEWPORTEXTEX 11
+int U_EMRSETVIEWPORTEXTEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRSETVIEWPORTORGEX 12
+int U_EMRSETVIEWPORTORGEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRSETBRUSHORGEX 13
+int U_EMRSETBRUSHORGEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMREOF 14
+int U_EMREOF_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMREOF))return(0);
+ PU_EMREOF pEmr = (PU_EMREOF)(record);
+ const char *blimit = record + pEmr->emr.nSize;
+ int cbPalEntries=pEmr->cbPalEntries;
+ if(cbPalEntries){
+ if(IS_MEM_UNSAFE(record, pEmr->offPalEntries + 2*2, blimit))return(0);// 2 16 bit values in U_LOGPALLETE
+ }
+ int off = sizeof(U_EMREOF) + 4 * cbPalEntries;
+ if(IS_MEM_UNSAFE(record, off + 4, blimit))return(0);
+ return(1);
+}
+
+
+// U_EMRSETPIXELV 15
+int U_EMRSETPIXELV_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETPIXELV));
+
+}
+
+
+// U_EMRSETMAPPERFLAGS 16
+int U_EMRSETMAPPERFLAGS_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETMAPPERFLAGS));
+}
+
+
+// U_EMRSETMAPMODE 17
+int U_EMRSETMAPMODE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETBKMODE 18
+int U_EMRSETBKMODE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETPOLYFILLMODE 19
+int U_EMRSETPOLYFILLMODE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETROP2 20
+int U_EMRSETROP2_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETSTRETCHBLTMODE 21
+int U_EMRSETSTRETCHBLTMODE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETTEXTALIGN 22
+int U_EMRSETTEXTALIGN_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETCOLORADJUSTMENT 23
+int U_EMRSETCOLORADJUSTMENT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETCOLORADJUSTMENT));
+}
+
+// U_EMRSETTEXTCOLOR 24
+int U_EMRSETTEXTCOLOR_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETTEXTCOLOR));
+}
+
+// U_EMRSETBKCOLOR 25
+int U_EMRSETBKCOLOR_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETBKCOLOR));
+}
+
+// U_EMROFFSETCLIPRGN 26
+int U_EMROFFSETCLIPRGN_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRMOVETOEX 27
+int U_EMRMOVETOEX_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRSETMETARGN 28
+int U_EMRSETMETARGN_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETMETARGN));
+}
+
+// U_EMREXCLUDECLIPRECT 29
+int U_EMREXCLUDECLIPRECT_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRINTERSECTCLIPRECT 30
+int U_EMRINTERSECTCLIPRECT_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRSCALEVIEWPORTEXTEX 31
+int U_EMRSCALEVIEWPORTEXTEX_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRSCALEWINDOWEXTEX 32
+int U_EMRSCALEWINDOWEXTEX_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRSAVEDC 33
+int U_EMRSAVEDC_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSAVEDC));
+}
+
+// U_EMRRESTOREDC 34
+int U_EMRRESTOREDC_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETWORLDTRANSFORM 35
+int U_EMRSETWORLDTRANSFORM_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETWORLDTRANSFORM));
+}
+
+// U_EMRMODIFYWORLDTRANSFORM 36
+int U_EMRMODIFYWORLDTRANSFORM_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRMODIFYWORLDTRANSFORM));
+}
+
+// U_EMRSELECTOBJECT 37
+int U_EMRSELECTOBJECT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSELECTOBJECT));
+}
+
+// U_EMRCREATEPEN 38
+int U_EMRCREATEPEN_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCREATEPEN));
+}
+
+// U_EMRCREATEBRUSHINDIRECT 39
+int U_EMRCREATEBRUSHINDIRECT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCREATEBRUSHINDIRECT));
+}
+
+// U_EMRDELETEOBJECT 40
+int U_EMRDELETEOBJECT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRDELETEOBJECT));
+
+}
+
+// U_EMRANGLEARC 41
+int U_EMRANGLEARC_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRANGLEARC));
+}
+
+// U_EMRELLIPSE 42
+int U_EMRELLIPSE_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRRECTANGLE 43
+int U_EMRRECTANGLE_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRROUNDRECT 44
+int U_EMRROUNDRECT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRROUNDRECT));
+}
+
+// U_EMRARC 45
+int U_EMRARC_safe(const char *record){
+ return(core9_safe(record));
+}
+
+// U_EMRCHORD 46
+int U_EMRCHORD_safe(const char *record){
+ return(core9_safe(record));
+}
+
+// U_EMRPIE 47
+int U_EMRPIE_safe(const char *record){
+ return(core9_safe(record));
+}
+
+// U_EMRSELECTPALETTE 48
+int U_EMRSELECTPALETTE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRCREATEPALETTE 49
+int U_EMRCREATEPALETTE_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCREATEPALETTE));
+}
+
+// U_EMRSETPALETTEENTRIES 50
+int U_EMRSETPALETTEENTRIES_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRSETPALETTEENTRIES));
+}
+
+// U_EMRRESIZEPALETTE 51
+int U_EMRRESIZEPALETTE_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRREALIZEPALETTE 52
+int U_EMRREALIZEPALETTE_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRREALIZEPALETTE));
+}
+
+// U_EMREXTFLOODFILL 53
+int U_EMREXTFLOODFILL_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMREXTFLOODFILL));
+}
+
+// U_EMRLINETO 54
+int U_EMRLINETO_safe(const char *record){
+ return(core7_safe(record));
+}
+
+// U_EMRARCTO 55
+int U_EMRARCTO_safe(const char *record){
+ return(core9_safe(record));
+}
+
+// U_EMRPOLYDRAW 56
+int U_EMRPOLYDRAW_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYDRAW))return(0);
+ PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(record);
+ int count = pEmr->cptl;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->aptl, count*sizeof(U_POINTL), blimit))return(0);
+ return(1);
+}
+
+// U_EMRSETARCDIRECTION 57
+int U_EMRSETARCDIRECTION_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRSETMITERLIMIT 58
+int U_EMRSETMITERLIMIT_safe(const char *record){
+ return(core3_safe(record));
+}
+
+
+// U_EMRBEGINPATH 59
+int U_EMRBEGINPATH_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRBEGINPATH));
+}
+
+// U_EMRENDPATH 60
+int U_EMRENDPATH_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRENDPATH));
+}
+
+// U_EMRCLOSEFIGURE 61
+int U_EMRCLOSEFIGURE_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCLOSEFIGURE));
+}
+
+// U_EMRFILLPATH 62
+int U_EMRFILLPATH_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRSTROKEANDFILLPATH 63
+int U_EMRSTROKEANDFILLPATH_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRSTROKEPATH 64
+int U_EMRSTROKEPATH_safe(const char *record){
+ return(core4_safe(record));
+}
+
+// U_EMRFLATTENPATH 65
+int U_EMRFLATTENPATH_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRFLATTENPATH));
+}
+
+// U_EMRWIDENPATH 66
+int U_EMRWIDENPATH_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRWIDENPATH));
+}
+
+// U_EMRSELECTCLIPPATH 67
+int U_EMRSELECTCLIPPATH_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRABORTPATH 68
+int U_EMRABORTPATH_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRABORTPATH));
+}
+
+// U_EMRUNDEF69 69
+#define U_EMRUNDEF69_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific)
+int U_EMRCOMMENT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRCOMMENT))return(0);
+ PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(record);
+ int cbData = pEmr->cbData;
+ const char *blimit =record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(record, cbData + sizeof(U_SIZE_EMRCOMMENT), blimit))return(0);
+ return(1);
+}
+
+// U_EMRFILLRGN 71
+int U_EMRFILLRGN_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRFILLRGN))return(0);
+ PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(record);
+ int cbRgnData = pEmr->cbRgnData;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_safe(pEmr->RgnData, cbRgnData));
+}
+
+// U_EMRFRAMERGN 72
+int U_EMRFRAMERGN_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRFRAMERGN))return(0);
+ PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(record);
+ int cbRgnData = pEmr->cbRgnData;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_safe(pEmr->RgnData, cbRgnData));
+}
+
+// U_EMRINVERTRGN 73
+int U_EMRINVERTRGN_safe(const char *record){
+ return(core11_safe(record));
+}
+
+// U_EMRPAINTRGN 74
+int U_EMRPAINTRGN_safe(const char *record){
+ return(core11_safe(record));
+}
+
+// U_EMREXTSELECTCLIPRGN 75
+int U_EMREXTSELECTCLIPRGN_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMREXTSELECTCLIPRGN))return(0);
+ PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN)(record);
+ int cbRgnData = pEmr->cbRgnData;
+ /* data size can be 0 with COPY mode, it means clear the clip region. */
+ if(pEmr->iMode == U_RGN_COPY && !cbRgnData)return(1);
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
+ return(rgndata_safe(pEmr->RgnData, cbRgnData));
+}
+
+// U_EMRBITBLT 76
+int U_EMRBITBLT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRBITBLT))return(0);
+ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITS cbBitsSrc = pEmr->cbBitsSrc;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit));
+}
+
+// U_EMRSTRETCHBLT 77
+int U_EMRSTRETCHBLT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSTRETCHBLT))return(0);
+ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITS cbBitsSrc = pEmr->cbBitsSrc;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit));
+}
+
+// U_EMRMASKBLT 78
+int U_EMRMASKBLT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRMASKBLT))return(0);
+ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBMIMSK offBmiMask = pEmr->offBmiMask;
+ U_CBBMIMSK cbBmiMask = pEmr->cbBmiMask;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc;
+ U_OFFBITSMSK offBitsMask = pEmr->offBitsMask;
+ U_CBBITSMSK cbBitsMask = pEmr->cbBitsMask;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ uint32_t iUsageMask = pEmr->iUsageMask;
+ if(!DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit))return(0);
+ return(DIB_safe(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit));
+}
+
+// U_EMRPLGBLT 79
+int U_EMRPLGBLT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPLGBLT))return(0);
+ PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBMIMSK offBmiMask = pEmr->offBmiMask;
+ U_CBBMIMSK cbBmiMask = pEmr->cbBmiMask;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc;
+ U_OFFBITSMSK offBitsMask = pEmr->offBitsMask;
+ U_CBBITSMSK cbBitsMask = pEmr->cbBitsMask;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ uint32_t iUsageMask = pEmr->iUsageMask;
+ if(!DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit))return(0);
+ return(DIB_safe(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit));
+}
+
+// U_EMRSETDIBITSTODEVICE 80
+int U_EMRSETDIBITSTODEVICE_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSETDIBITSTODEVICE))return(0);
+ PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit));
+}
+
+// U_EMRSTRETCHDIBITS 81
+int U_EMRSTRETCHDIBITS_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSTRETCHDIBITS))return(0);
+ PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc;
+ U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc;
+ U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc;
+ U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc;
+ uint32_t iUsageSrc = pEmr->iUsageSrc;
+ return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit));
+}
+
+// U_EMREXTCREATEFONTINDIRECTW 82
+int U_EMREXTCREATEFONTINDIRECTW_safe(const char *record){
+ /* Panose or logfont, LogFontExDv is not supported. Test smallest to largest */
+ if(core5_safe(record, U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT))return(1);
+ return(core5_safe(record, U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE));
+}
+
+// U_EMREXTTEXTOUTA 83
+int U_EMREXTTEXTOUTA_safe(const char *record){
+ return(core8_safe(record));
+}
+
+// U_EMREXTTEXTOUTW 84
+int U_EMREXTTEXTOUTW_safe(const char *record){
+ return(core8_safe(record));
+}
+
+// U_EMRPOLYBEZIER16 85
+/**
+ \brief Convert a pointer to a U_EMR_POLYBEZIER16 record.
+ \param record pointer to a buffer holding the EMR record
+*/
+int U_EMRPOLYBEZIER16_safe(const char *record){
+ return(core6_safe(record));
+}
+
+// U_EMRPOLYGON16 86
+int U_EMRPOLYGON16_safe(const char *record){
+ return(core6_safe(record));
+}
+
+// U_EMRPOLYLINE16 87
+int U_EMRPOLYLINE16_safe(const char *record){
+ return(core6_safe(record));
+}
+
+// U_EMRPOLYBEZIERTO16 88
+int U_EMRPOLYBEZIERTO16_safe(const char *record){
+ return(core6_safe(record));
+}
+
+// U_EMRPOLYLINETO16 89
+/**
+ \brief Convert a pointer to a U_EMR_POLYLINETO16 record.
+ \param record pointer to a buffer holding the EMR record
+*/
+int U_EMRPOLYLINETO16_safe(const char *record){
+ return(core6_safe(record));
+}
+
+// U_EMRPOLYPOLYLINE16 90
+int U_EMRPOLYPOLYLINE16_safe(const char *record){
+ return(core10_safe(record));
+}
+
+// U_EMRPOLYPOLYGON16 91
+int U_EMRPOLYPOLYGON16_safe(const char *record){
+ return(core10_safe(record));
+}
+
+
+// U_EMRPOLYDRAW16 92
+int U_EMRPOLYDRAW16_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRPOLYDRAW16))return(0);
+ PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(record);
+ int count = pEmr->cpts;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(pEmr->apts, count*sizeof(U_POINT16), blimit))return(0);
+ return(1);
+}
+
+// U_EMRCREATEMONOBRUSH 93
+int U_EMRCREATEMONOBRUSH_safe(const char *record){
+ return(core12_safe(record));
+}
+
+// U_EMRCREATEDIBPATTERNBRUSHPT_safe 94
+int U_EMRCREATEDIBPATTERNBRUSHPT_safe(const char *record){
+ return(core12_safe(record));
+}
+
+
+// U_EMREXTCREATEPEN 95
+int U_EMREXTCREATEPEN_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMREXTCREATEPEN))return(0);
+ PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(record);
+ const char *blimit = record + pEmr->emr.nSize;
+ U_OFFBMI offBmi = pEmr->offBmi;
+ U_CBBMI cbBmi = pEmr->cbBmi;
+ U_OFFBITS offBits = pEmr->offBits;
+ U_CBBITS cbBits = pEmr->cbBits;
+ if(!DIB_safe(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit))return(0);
+ return(extlogpen_safe((PU_EXTLOGPEN) &(pEmr->elp), blimit));
+}
+
+// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTA_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT
+#define U_EMRPOLYTEXTOUTW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRSETICMMODE 98
+int U_EMRSETICMMODE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRCREATECOLORSPACE 99
+int U_EMRCREATECOLORSPACE_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCREATECOLORSPACE));
+}
+
+// U_EMRSETCOLORSPACE 100
+int U_EMRSETCOLORSPACE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRDELETECOLORSPACE 101
+int U_EMRDELETECOLORSPACE_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRGLSRECORD 102 Not implemented
+#define U_EMRGLSRECORD_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRGLSBOUNDEDRECORD 103 Not implemented
+#define U_EMRGLSBOUNDEDRECORD_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRPIXELFORMAT 104
+int U_EMRPIXELFORMAT_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRPIXELFORMAT));
+}
+
+// U_EMRDRAWESCAPE 105 Not implemented
+#define U_EMRDRAWESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMREXTESCAPE 106 Not implemented
+#define U_EMREXTESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRUNDEF107 107 Not implemented
+#define U_EMRUNDEF107_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRSMALLTEXTOUT 108
+int U_EMRSMALLTEXTOUT_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRSMALLTEXTOUT))return(0);
+ PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(record);
+ int roff=sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields
+ int fuOptions = pEmr->fuOptions;
+ int cChars = pEmr->cChars;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(!(fuOptions & U_ETO_NO_RECT)){
+ if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL), blimit))return(0);
+ }
+ if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL) + cChars, blimit))return(0);
+ return(1);
+}
+
+// U_EMRFORCEUFIMAPPING 109 Not implemented
+#define U_EMRFORCEUFIMAPPING_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRNAMEDESCAPE 110 Not implemented
+#define U_EMRNAMEDESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRCOLORCORRECTPALETTE 111 Not implemented
+#define U_EMRCOLORCORRECTPALETTE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRSETICMPROFILEA 112 Not implemented
+#define U_EMRSETICMPROFILEA_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRSETICMPROFILEW 113 Not implemented
+#define U_EMRSETICMPROFILEW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRALPHABLEND 114
+int U_EMRALPHABLEND_safe(const char *record){
+ return(core13_safe(record));
+}
+
+// U_EMRSETLAYOUT 115
+int U_EMRSETLAYOUT_safe(const char *record){
+ return(core3_safe(record));
+}
+
+// U_EMRTRANSPARENTBLT 116
+int U_EMRTRANSPARENTBLT_safe(const char *record){
+ return(core13_safe(record));
+}
+
+
+// U_EMRUNDEF117 117 Not implemented
+#define U_EMRUNDEF117_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRGRADIENTFILL 118
+int U_EMRGRADIENTFILL_safe(const char *record){
+ if(!core5_safe(record, U_SIZE_EMRGRADIENTFILL))return(0);
+ PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(record);
+ int nTriVert = pEmr->nTriVert;
+ int nGradObj = pEmr->nGradObj;
+ int ulMode = pEmr->ulMode;
+ const char *blimit = record + pEmr->emr.nSize;
+ if(IS_MEM_UNSAFE(record, nTriVert*sizeof(U_TRIVERTEX), blimit))return(0);
+ record += nTriVert * sizeof(U_TRIVERTEX);
+ if(nGradObj){
+ if( ulMode == U_GRADIENT_FILL_TRIANGLE){
+ if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT3), blimit))return(0);
+ }
+ else if(ulMode == U_GRADIENT_FILL_RECT_H || ulMode == U_GRADIENT_FILL_RECT_V){
+ if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT4), blimit))return(0);
+ }
+ }
+ return(1);
+}
+
+// U_EMRSETLINKEDUFIS 119 Not implemented
+#define U_EMRSETLINKEDUFIS_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated)
+#define U_EMRSETTEXTJUSTIFICATION_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+// U_EMRCOLORMATCHTOTARGETW 121 Not implemented
+#define U_EMRCOLORMATCHTOTARGETW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented.
+
+// U_EMRCREATECOLORSPACEW 122
+int U_EMRCREATECOLORSPACEW_safe(const char *record){
+ return(core5_safe(record, U_SIZE_EMRCREATECOLORSPACEW));
+}
+
+//! \endcond
+
+/**
+ \brief Test an EMF record in memory from Big Endian to Little Endian.
+ \return 0 on failure, 1 on success
+ \param record pointer to the EMF record in memory
+
+ Normally this would be called immediately after reading a record from a file
+ and having called U_emf_record_sizeok().
+ It is NOT safe to call this routine without first calling U_emf_record_sizeok)()!
+ If the file has been converted from one endian to another calling this routine is
+ not necessary, because those routines also perform these checks.
+*/
+int U_emf_record_safe(const char *record){
+ int rstatus=1;
+
+ if(!record)return(0); // programming error
+
+ switch (U_EMRTYPE(record))
+ {
+ case U_EMR_HEADER: rstatus=U_EMRHEADER_safe(record); break;
+ case U_EMR_POLYBEZIER: rstatus=U_EMRPOLYBEZIER_safe(record); break;
+ case U_EMR_POLYGON: rstatus=U_EMRPOLYGON_safe(record); break;
+ case U_EMR_POLYLINE: rstatus=U_EMRPOLYLINE_safe(record); break;
+ case U_EMR_POLYBEZIERTO: rstatus=U_EMRPOLYBEZIERTO_safe(record); break;
+ case U_EMR_POLYLINETO: rstatus=U_EMRPOLYLINETO_safe(record); break;
+ case U_EMR_POLYPOLYLINE: rstatus=U_EMRPOLYPOLYLINE_safe(record); break;
+ case U_EMR_POLYPOLYGON: rstatus=U_EMRPOLYPOLYGON_safe(record); break;
+ case U_EMR_SETWINDOWEXTEX: rstatus=U_EMRSETWINDOWEXTEX_safe(record); break;
+ case U_EMR_SETWINDOWORGEX: rstatus=U_EMRSETWINDOWORGEX_safe(record); break;
+ case U_EMR_SETVIEWPORTEXTEX: rstatus=U_EMRSETVIEWPORTEXTEX_safe(record); break;
+ case U_EMR_SETVIEWPORTORGEX: rstatus=U_EMRSETVIEWPORTORGEX_safe(record); break;
+ case U_EMR_SETBRUSHORGEX: rstatus=U_EMRSETBRUSHORGEX_safe(record); break;
+ case U_EMR_EOF: rstatus=U_EMREOF_safe(record); break;
+ case U_EMR_SETPIXELV: rstatus=U_EMRSETPIXELV_safe(record); break;
+ case U_EMR_SETMAPPERFLAGS: rstatus=U_EMRSETMAPPERFLAGS_safe(record); break;
+ case U_EMR_SETMAPMODE: rstatus=U_EMRSETMAPMODE_safe(record); break;
+ case U_EMR_SETBKMODE: rstatus=U_EMRSETBKMODE_safe(record); break;
+ case U_EMR_SETPOLYFILLMODE: rstatus=U_EMRSETPOLYFILLMODE_safe(record); break;
+ case U_EMR_SETROP2: rstatus=U_EMRSETROP2_safe(record); break;
+ case U_EMR_SETSTRETCHBLTMODE: rstatus=U_EMRSETSTRETCHBLTMODE_safe(record); break;
+ case U_EMR_SETTEXTALIGN: rstatus=U_EMRSETTEXTALIGN_safe(record); break;
+ case U_EMR_SETCOLORADJUSTMENT: rstatus=U_EMRSETCOLORADJUSTMENT_safe(record); break;
+ case U_EMR_SETTEXTCOLOR: rstatus=U_EMRSETTEXTCOLOR_safe(record); break;
+ case U_EMR_SETBKCOLOR: rstatus=U_EMRSETBKCOLOR_safe(record); break;
+ case U_EMR_OFFSETCLIPRGN: rstatus=U_EMROFFSETCLIPRGN_safe(record); break;
+ case U_EMR_MOVETOEX: rstatus=U_EMRMOVETOEX_safe(record); break;
+ case U_EMR_SETMETARGN: rstatus=U_EMRSETMETARGN_safe(record); break;
+ case U_EMR_EXCLUDECLIPRECT: rstatus=U_EMREXCLUDECLIPRECT_safe(record); break;
+ case U_EMR_INTERSECTCLIPRECT: rstatus=U_EMRINTERSECTCLIPRECT_safe(record); break;
+ case U_EMR_SCALEVIEWPORTEXTEX: rstatus=U_EMRSCALEVIEWPORTEXTEX_safe(record); break;
+ case U_EMR_SCALEWINDOWEXTEX: rstatus=U_EMRSCALEWINDOWEXTEX_safe(record); break;
+ case U_EMR_SAVEDC: rstatus=U_EMRSAVEDC_safe(record); break;
+ case U_EMR_RESTOREDC: rstatus=U_EMRRESTOREDC_safe(record); break;
+ case U_EMR_SETWORLDTRANSFORM: rstatus=U_EMRSETWORLDTRANSFORM_safe(record); break;
+ case U_EMR_MODIFYWORLDTRANSFORM: rstatus=U_EMRMODIFYWORLDTRANSFORM_safe(record); break;
+ case U_EMR_SELECTOBJECT: rstatus=U_EMRSELECTOBJECT_safe(record); break;
+ case U_EMR_CREATEPEN: rstatus=U_EMRCREATEPEN_safe(record); break;
+ case U_EMR_CREATEBRUSHINDIRECT: rstatus=U_EMRCREATEBRUSHINDIRECT_safe(record); break;
+ case U_EMR_DELETEOBJECT: rstatus=U_EMRDELETEOBJECT_safe(record); break;
+ case U_EMR_ANGLEARC: rstatus=U_EMRANGLEARC_safe(record); break;
+ case U_EMR_ELLIPSE: rstatus=U_EMRELLIPSE_safe(record); break;
+ case U_EMR_RECTANGLE: rstatus=U_EMRRECTANGLE_safe(record); break;
+ case U_EMR_ROUNDRECT: rstatus=U_EMRROUNDRECT_safe(record); break;
+ case U_EMR_ARC: rstatus=U_EMRARC_safe(record); break;
+ case U_EMR_CHORD: rstatus=U_EMRCHORD_safe(record); break;
+ case U_EMR_PIE: rstatus=U_EMRPIE_safe(record); break;
+ case U_EMR_SELECTPALETTE: rstatus=U_EMRSELECTPALETTE_safe(record); break;
+ case U_EMR_CREATEPALETTE: rstatus=U_EMRCREATEPALETTE_safe(record); break;
+ case U_EMR_SETPALETTEENTRIES: rstatus=U_EMRSETPALETTEENTRIES_safe(record); break;
+ case U_EMR_RESIZEPALETTE: rstatus=U_EMRRESIZEPALETTE_safe(record); break;
+ case U_EMR_REALIZEPALETTE: rstatus=U_EMRREALIZEPALETTE_safe(record); break;
+ case U_EMR_EXTFLOODFILL: rstatus=U_EMREXTFLOODFILL_safe(record); break;
+ case U_EMR_LINETO: rstatus=U_EMRLINETO_safe(record); break;
+ case U_EMR_ARCTO: rstatus=U_EMRARCTO_safe(record); break;
+ case U_EMR_POLYDRAW: rstatus=U_EMRPOLYDRAW_safe(record); break;
+ case U_EMR_SETARCDIRECTION: rstatus=U_EMRSETARCDIRECTION_safe(record); break;
+ case U_EMR_SETMITERLIMIT: rstatus=U_EMRSETMITERLIMIT_safe(record); break;
+ case U_EMR_BEGINPATH: rstatus=U_EMRBEGINPATH_safe(record); break;
+ case U_EMR_ENDPATH: rstatus=U_EMRENDPATH_safe(record); break;
+ case U_EMR_CLOSEFIGURE: rstatus=U_EMRCLOSEFIGURE_safe(record); break;
+ case U_EMR_FILLPATH: rstatus=U_EMRFILLPATH_safe(record); break;
+ case U_EMR_STROKEANDFILLPATH: rstatus=U_EMRSTROKEANDFILLPATH_safe(record); break;
+ case U_EMR_STROKEPATH: rstatus=U_EMRSTROKEPATH_safe(record); break;
+ case U_EMR_FLATTENPATH: rstatus=U_EMRFLATTENPATH_safe(record); break;
+ case U_EMR_WIDENPATH: rstatus=U_EMRWIDENPATH_safe(record); break;
+ case U_EMR_SELECTCLIPPATH: rstatus=U_EMRSELECTCLIPPATH_safe(record); break;
+ case U_EMR_ABORTPATH: rstatus=U_EMRABORTPATH_safe(record); break;
+ case U_EMR_UNDEF69: rstatus=U_EMRUNDEF69_safe(record); break;
+ case U_EMR_COMMENT: rstatus=U_EMRCOMMENT_safe(record); break;
+ case U_EMR_FILLRGN: rstatus=U_EMRFILLRGN_safe(record); break;
+ case U_EMR_FRAMERGN: rstatus=U_EMRFRAMERGN_safe(record); break;
+ case U_EMR_INVERTRGN: rstatus=U_EMRINVERTRGN_safe(record); break;
+ case U_EMR_PAINTRGN: rstatus=U_EMRPAINTRGN_safe(record); break;
+ case U_EMR_EXTSELECTCLIPRGN: rstatus=U_EMREXTSELECTCLIPRGN_safe(record); break;
+ case U_EMR_BITBLT: rstatus=U_EMRBITBLT_safe(record); break;
+ case U_EMR_STRETCHBLT: rstatus=U_EMRSTRETCHBLT_safe(record); break;
+ case U_EMR_MASKBLT: rstatus=U_EMRMASKBLT_safe(record); break;
+ case U_EMR_PLGBLT: rstatus=U_EMRPLGBLT_safe(record); break;
+ case U_EMR_SETDIBITSTODEVICE: rstatus=U_EMRSETDIBITSTODEVICE_safe(record); break;
+ case U_EMR_STRETCHDIBITS: rstatus=U_EMRSTRETCHDIBITS_safe(record); break;
+ case U_EMR_EXTCREATEFONTINDIRECTW: rstatus=U_EMREXTCREATEFONTINDIRECTW_safe(record); break;
+ case U_EMR_EXTTEXTOUTA: rstatus=U_EMREXTTEXTOUTA_safe(record); break;
+ case U_EMR_EXTTEXTOUTW: rstatus=U_EMREXTTEXTOUTW_safe(record); break;
+ case U_EMR_POLYBEZIER16: rstatus=U_EMRPOLYBEZIER16_safe(record); break;
+ case U_EMR_POLYGON16: rstatus=U_EMRPOLYGON16_safe(record); break;
+ case U_EMR_POLYLINE16: rstatus=U_EMRPOLYLINE16_safe(record); break;
+ case U_EMR_POLYBEZIERTO16: rstatus=U_EMRPOLYBEZIERTO16_safe(record); break;
+ case U_EMR_POLYLINETO16: rstatus=U_EMRPOLYLINETO16_safe(record); break;
+ case U_EMR_POLYPOLYLINE16: rstatus=U_EMRPOLYPOLYLINE16_safe(record); break;
+ case U_EMR_POLYPOLYGON16: rstatus=U_EMRPOLYPOLYGON16_safe(record); break;
+ case U_EMR_POLYDRAW16: rstatus=U_EMRPOLYDRAW16_safe(record); break;
+ case U_EMR_CREATEMONOBRUSH: rstatus=U_EMRCREATEMONOBRUSH_safe(record); break;
+ case U_EMR_CREATEDIBPATTERNBRUSHPT: rstatus=U_EMRCREATEDIBPATTERNBRUSHPT_safe(record); break;
+ case U_EMR_EXTCREATEPEN: rstatus=U_EMREXTCREATEPEN_safe(record); break;
+ case U_EMR_POLYTEXTOUTA: rstatus=U_EMRPOLYTEXTOUTA_safe(record); break;
+ case U_EMR_POLYTEXTOUTW: rstatus=U_EMRPOLYTEXTOUTW_safe(record); break;
+ case U_EMR_SETICMMODE: rstatus=U_EMRSETICMMODE_safe(record); break;
+ case U_EMR_CREATECOLORSPACE: rstatus=U_EMRCREATECOLORSPACE_safe(record); break;
+ case U_EMR_SETCOLORSPACE: rstatus=U_EMRSETCOLORSPACE_safe(record); break;
+ case U_EMR_DELETECOLORSPACE: rstatus=U_EMRDELETECOLORSPACE_safe(record); break;
+ case U_EMR_GLSRECORD: rstatus=U_EMRGLSRECORD_safe(record); break;
+ case U_EMR_GLSBOUNDEDRECORD: rstatus=U_EMRGLSBOUNDEDRECORD_safe(record); break;
+ case U_EMR_PIXELFORMAT: rstatus=U_EMRPIXELFORMAT_safe(record); break;
+ case U_EMR_DRAWESCAPE: rstatus=U_EMRDRAWESCAPE_safe(record); break;
+ case U_EMR_EXTESCAPE: rstatus=U_EMREXTESCAPE_safe(record); break;
+ case U_EMR_UNDEF107: rstatus=U_EMRUNDEF107_safe(record); break;
+ case U_EMR_SMALLTEXTOUT: rstatus=U_EMRSMALLTEXTOUT_safe(record); break;
+ case U_EMR_FORCEUFIMAPPING: rstatus=U_EMRFORCEUFIMAPPING_safe(record); break;
+ case U_EMR_NAMEDESCAPE: rstatus=U_EMRNAMEDESCAPE_safe(record); break;
+ case U_EMR_COLORCORRECTPALETTE: rstatus=U_EMRCOLORCORRECTPALETTE_safe(record); break;
+ case U_EMR_SETICMPROFILEA: rstatus=U_EMRSETICMPROFILEA_safe(record); break;
+ case U_EMR_SETICMPROFILEW: rstatus=U_EMRSETICMPROFILEW_safe(record); break;
+ case U_EMR_ALPHABLEND: rstatus=U_EMRALPHABLEND_safe(record); break;
+ case U_EMR_SETLAYOUT: rstatus=U_EMRSETLAYOUT_safe(record); break;
+ case U_EMR_TRANSPARENTBLT: rstatus=U_EMRTRANSPARENTBLT_safe(record); break;
+ case U_EMR_UNDEF117: rstatus=U_EMRUNDEF117_safe(record); break;
+ case U_EMR_GRADIENTFILL: rstatus=U_EMRGRADIENTFILL_safe(record); break;
+ case U_EMR_SETLINKEDUFIS: rstatus=U_EMRSETLINKEDUFIS_safe(record); break;
+ case U_EMR_SETTEXTJUSTIFICATION: rstatus=U_EMRSETTEXTJUSTIFICATION_safe(record); break;
+ case U_EMR_COLORMATCHTOTARGETW: rstatus=U_EMRCOLORMATCHTOTARGETW_safe(record); break;
+ case U_EMR_CREATECOLORSPACEW: rstatus=U_EMRCREATECOLORSPACEW_safe(record); break;
+ default: rstatus=U_EMRNOTIMPLEMENTED_safe(record); break;
+ } //end of switch
+ return(rstatus);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uemf_safe.h b/src/3rdparty/libuemf/uemf_safe.h
new file mode 100644
index 000000000..0c9e3cc69
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_safe.h
@@ -0,0 +1,32 @@
+/**
+ @file uemf_safe.h
+
+ @brief Defintions and prototype for function for converting EMF records between Big Endian and Little Endian byte orders.
+*/
+
+/*
+File: uemf_endian.h
+Version: 0.0.2
+Date: 26-MAR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UEMF_SAFE_
+#define _UEMF_SAFE_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// prototypes
+int U_emf_record_safe(const char *record);
+int bitmapinfo_safe(const char *Bmi, const char *blimit);
+//! \endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UEMF_SAFE_ */
diff --git a/src/3rdparty/libuemf/uemf_utf.c b/src/3rdparty/libuemf/uemf_utf.c
new file mode 100644
index 000000000..5c6507818
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_utf.c
@@ -0,0 +1,720 @@
+/**
+ @file uemf_utf.c
+
+ @brief Functions for manipulating UTF and various types of text.
+
+
+ Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for
+ uninitialized data.
+
+ Compile with "SOL8" defined for Solaris 8 or 9 (Sparc).
+*/
+
+/*
+File: uemf_utf.c
+Version: 0.0.5
+Date: 29-JAN-2014
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <iconv.h>
+#include <wchar.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h> // for INT_MAX, INT_MIN
+#include <math.h> // for U_ROUND()
+#include "uemf_utf.h"
+
+//! \cond
+/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed
+to be used in end user code. */
+
+void U_swap2(void *ul, unsigned int count);
+//! \endcond
+
+/* ******************************************************************************************** */
+
+/** \cond */
+/* iconv() has a funny cast on some older systems, on most recent ones
+ it is just char **. This tries to work around the issue. If you build this
+ on another funky system this code may need to be modified, or define ICONV_CAST
+ on the compile line(but it may be tricky).
+*/
+#if _LIBICONV_VERSION == 0x0109
+# define ICONV_CAST (const char **)
+#endif // _LIBICONV_VERSION 0x0109
+#ifdef SOL8
+# define ICONV_CAST (const char **)
+#endif //SOL8
+#if !defined(ICONV_CAST)
+# define ICONV_CAST (char **)
+#endif //ICONV_CAST
+/** \endcond */
+
+/* **********************************************************************************************
+These functions are used for development and debugging and should be be includied in production code.
+*********************************************************************************************** */
+
+/**
+ \brief Dump a UTF8 string. Not for use in production code.
+ \param src string to examine
+*/
+void wchar8show(
+ const char *src
+ ){
+ if(!src){
+ printf("char show <NULL>\n");
+ }
+ else {
+ printf("char show\n");
+ size_t srclen = 0;
+ while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; }
+ }
+}
+
+/**
+ \brief Dump a UTF16 string. Not for use in production code.
+ \param src string to examine
+*/
+void wchar16show(
+ const uint16_t *src
+ ){
+ if(!src){
+ printf("uint16_t show <NULL>\n");
+ }
+ else {
+ printf("uint16_t show\n");
+ size_t srclen = 0;
+ while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; }
+ }
+}
+
+/**
+ \brief Dump a UTF32 string. Not for use in production code.
+*/
+void wchar32show(
+ const uint32_t *src
+ ){
+ if(!src){
+ printf("uint32_t show <NULL>\n");
+ }
+ else {
+ printf("uint32_t show\n");
+ size_t srclen = 0;
+ while(*src){ printf("%d %d %x\n",(int) srclen,*src,*src); srclen++; src++; }
+ }
+}
+
+/**
+ \brief Dump a wchar_t string. Not for use in production code.
+ \param src string to examine
+*/
+void wchartshow(
+ const wchar_t *src
+ ){
+ uint32_t val;
+ if(!src){
+ printf("wchar_t show <NULL>\n");
+ }
+ else {
+ printf("wchar_t show\n");
+ size_t srclen = 0;
+ if(!src)return;
+ while(*src){
+ val = *src; // because *src is wchar_t is not strictly an integer type, can cause warnings on next line
+ printf("%d %d %x\n",(int) srclen,val,val);
+ srclen++;
+ src++;
+ }
+ }
+}
+
+/* **********************************************************************************************
+These functions are used for character type conversions, Image conversions, and other
+utility operations
+*********************************************************************************************** */
+
+/**
+ \brief Find the number of (storage) characters in a 16 bit character string, not including terminator.
+ \param src string to examine
+*/
+size_t wchar16len(
+ const uint16_t *src
+ ){
+ size_t srclen = 0;
+ if(src){
+ while(*src){ srclen++; src++; }
+ }
+ return(srclen);
+}
+
+/**
+ \brief Find the number of (storage) characters in a 32 bit character string, not including terminator.
+ \param src string to examine
+*/
+size_t wchar32len(
+ const uint32_t *src
+ ){
+ size_t srclen = 0;
+ if(src){
+ while(*src){ srclen++; src++; }
+ }
+ return(srclen);
+}
+
+/**
+ \brief Strncpy for wchar16 (UTF16).
+ \param dst destination (already allocated)
+ \param src source
+ \param nchars number of characters to copy
+*/
+void wchar16strncpy(
+ uint16_t *dst,
+ const uint16_t *src,
+ size_t nchars
+ ){
+ if(src){
+ for(;nchars;nchars--,dst++,src++){
+ *dst = *src;
+ if(!*src)break;
+ }
+ }
+}
+
+/**
+ \brief Fill the output string with N characters, if the input string is shorter than N, pad with nulls.
+ \param dst destination (already allocated)
+ \param src source
+ \param nchars number of characters to copy
+
+*/
+void wchar16strncpypad(
+ uint16_t *dst,
+ const uint16_t *src,
+ size_t nchars
+ ){
+ if(src){
+ for(;*src && nchars;nchars--,dst++,src++){ *dst = *src; }
+ for(;nchars;nchars--,dst++){ *dst = 0; } // Pad the remainder
+ }
+}
+
+/* For the following converstion functions, remember that iconv() modifies ALL of its parameters,
+ so save a pointer to the destination buffer!!!!
+ It isn't clear that terminators are being
+ copied properly, so be sure allocated space is a bit larger and cleared.
+*/
+
+/**
+ \brief Convert a UTF32LE string to a UTF16LE string.
+ \returns pointer to new string or NULL if it fails
+ \param src wchar_t string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+uint16_t *U_Utf32leToUtf16le(
+ const uint32_t *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = 4*max; }
+ else { srclen = 4 + 4*wchar32len(src); } //include terminator, length in BYTES
+
+ dstlen = 2 + srclen; // this will always work, but may waste space
+ dst2 = dst = calloc(dstlen,1); // so there will be at least one terminator
+ if(dst){
+ iconv_t conv = iconv_open("UTF-16LE", "UTF-32LE");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=wchar16len((uint16_t *)dst2);
+ }
+ }
+ }
+ return((uint16_t *)dst2);
+}
+
+/**
+ \brief Convert a UTF16LE string to a UTF32LE string.
+ \return pointer to new string or NULL if it fails
+ \param src UTF16LE string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+uint32_t *U_Utf16leToUtf32le(
+ const uint16_t *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = 2*max; }
+ else { srclen = 2*wchar16len(src)+2; } // include terminator, length in BYTES
+ dstlen = 2*(2 + srclen); // This should always work
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-32LE", "UTF-16LE");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=wchar32len((uint32_t *)dst2);
+ }
+ }
+ }
+ return((uint32_t *) dst2);
+}
+
+/**
+ \brief Convert a Latin1 string to a UTF32LE string.
+ \return pointer to new string or NULL if it fails
+ \param src Latin1 string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+
+
+ U_EMR_EXTTEXTOUTA records are "8 bit ASCII". In theory that is ASCII in an 8
+ bit character, but numerous applications store Latin1 in them, and some
+ _may_ store UTF-8 in them. Since very vew Latin1 strings are valid UTF-8 strings,
+ call U_Utf8ToUtf32le first, and if it fails, then call this function.
+*/
+uint32_t *U_Latin1ToUtf32le(
+ const char *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = max; }
+ else { srclen = strlen(src)+1; } // include terminator, length in BYTES
+ dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-32LE", "LATIN1");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=wchar32len((uint32_t *)dst2);
+ }
+ }
+ }
+ return((uint32_t *) dst2);
+}
+
+/**
+ \brief Convert a UTF8 string to a UTF32LE string.
+ \return pointer to new string or NULL if it fails
+ \param src UTF8 string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+uint32_t *U_Utf8ToUtf32le(
+ const char *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = max; }
+ else { srclen = strlen(src)+1; } // include terminator, length in BYTES
+ dstlen = sizeof(uint32_t)*(1 + srclen); // This should always work but might waste some space
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-32LE", "UTF-8");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=wchar32len((uint32_t *)dst2);
+ }
+ }
+ }
+ return((uint32_t *) dst2);
+}
+
+/**
+ \brief Convert a UTF32LE string to a UTF8 string.
+ \return pointer to new string or NULL if it fails
+ \param src wchar_t string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+char *U_Utf32leToUtf8(
+ const uint32_t *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = 4*max; }
+ else { srclen = 4*(1 + wchar32len(src)); } //include terminator, length in BYTES
+ dstlen = 1 + srclen; // This should always work but might waste some space
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-8", "UTF-32LE");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=strlen(dst2);
+ }
+ }
+ }
+ return(dst2);
+}
+
+/**
+ \brief Convert a UTF-8 string to a UTF16-LE string.
+ \return pointer to new string or NULL if it fails
+ \param src UTF8 string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+uint16_t *U_Utf8ToUtf16le(
+ const char *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = max; }
+ else { srclen = strlen(src)+1; } // include terminator, length in BYTES
+ dstlen = 2 * (1 + srclen); // this will always work, but may waste space
+ dst2 = dst =calloc(dstlen,1); // so there will always be a terminator
+ if(dst){
+ iconv_t conv = iconv_open("UTF-16LE", "UTF-8");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=wchar16len((uint16_t *)dst2);
+ }
+ }
+ }
+ return((uint16_t *)dst2);
+}
+
+/**
+ \brief Convert a UTF16LE string to a UTF8 string.
+ \return pointer to new UTF8 string or NULL if it fails
+ \param src UTF16LE string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+char *U_Utf16leToUtf8(
+ const uint16_t *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst, *dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = 2*max; }
+ else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES
+ dstlen = 1 + 2*srclen; // this will always work, but may waste space
+ // worst case is all glyphs (==max) need 4 UTF-8 encoded bytes + terminator.
+ dst2 = dst = (char *) calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-8", "UTF-16LE");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=strlen(dst2);
+ dst = dst2;
+ dst2 = U_strdup(dst); // make a string of exactly the right size
+ free(dst); // free the one which was probably too big
+ }
+ }
+ }
+ return(dst2);
+}
+
+/**
+ \brief Convert a UTF16LE string to a LATIN1 string.
+ \return pointer to new UTF8 string or NULL if it fails
+ \param src UTF16LE string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+*/
+char *U_Utf16leToLatin1(
+ const uint16_t *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst, *dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+
+ if(!src)return(NULL);
+ if(max){ srclen = 2*max; }
+ else { srclen = 2*(1 +wchar16len(src)); } //include terminator, length in BYTES
+ dstlen = 1 + srclen; // this will always work as latin1 is always 1 byte/character
+ dst2 = dst = (char *) calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-16LE");
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=strlen(dst2);
+ dst = dst2;
+ dst2 = U_strdup(dst); // make a string of exactly the right size
+ free(dst); // free the one which was probably too big
+ }
+ }
+ }
+ return(dst2);
+}
+/**
+ \brief Put a single 16 bit character into UTF-16LE form.
+
+ Used in conjunction with U_Utf16leEdit(), because the character
+ representation would otherwise be dependent on machine Endianness.
+
+ \return UTF16LE representation of the character.
+ \param src 16 bit character
+
+*/
+uint16_t U_Utf16le(const uint16_t src){
+ uint16_t dst=src;
+#if U_BYTE_SWAP
+ U_swap2(&dst,1);
+#endif
+ return(dst);
+}
+
+/**
+ \brief Convert a UTF8 string to a Latin1 string.
+ \return pointer to new string or NULL if it fails
+ \param src Latin1 string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+
+
+ WMF uses latin1, others UTF-8, only some utf-8 can be converted to latin1.
+
+*/
+char *U_Utf8ToLatin1(
+ const char *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+ if(max){ srclen = max; }
+ else { srclen = strlen(src)+1; } // include terminator, length in BYTES
+ dstlen = (1 + srclen); // This should always work but might waste some space
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("LATIN1//TRANSLIT", "UTF-8"); // translate what can be, fill in with something close for the rest
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=strlen(dst2);
+ }
+ }
+ }
+ return((char *) dst2);
+}
+
+/**
+ \brief Convert a Latin1 string to a UTF8 string.
+ \return pointer to new string or NULL if it fails
+ \param src Latin1 string to convert
+ \param max number of characters to convert, if 0, until terminator
+ \param len number of characters in new string, NOT including terminator
+
+
+ WMF uses latin1, others UTF-8, all Latin1 should be able to convert to utf-8.
+
+*/
+char *U_Latin1ToUtf8(
+ const char *src,
+ size_t max,
+ size_t *len
+ ){
+ char *dst,*dst2;
+ char *src2 = (char *) src;
+ size_t srclen,dstlen,status;
+ if(max){ srclen = max; }
+ else { srclen = strlen(src)+1; } // include terminator, will waste some space
+ dstlen = (1 + 2*srclen); // This should always work because all latin1 convert to 1 or 2 byte UTF8, it might waste some space
+ dst2 = dst = calloc(dstlen,1);
+ if(dst){
+ iconv_t conv = iconv_open("UTF-8", "LATIN1"); // everything should translate
+ if ( conv == (iconv_t) -1){
+ free(dst2);
+ dst2=NULL;
+ }
+ else {
+ status = iconv(conv, ICONV_CAST &src2, &srclen, &dst, &dstlen);
+ iconv_close(conv);
+ if(status == (size_t) -1){
+ free(dst2);
+ dst2 = NULL;
+ }
+ else if(len){
+ *len=strlen(dst2);
+ }
+ }
+ }
+ return((char *) dst2);
+}
+
+/**
+ \brief Single character replacement in a UTF-16LE string.
+
+ Used solely for the Description field which contains
+ embedded nulls, which makes it difficult to manipulate. Use some other character and then swap it.
+
+ \return number of substitutions, or -1 if src is not defined
+ \param src UTF16LE string to edit
+ \param find character to replace
+ \param replace replacestitute character
+
+*/
+int U_Utf16leEdit(
+ uint16_t *src,
+ uint16_t find,
+ uint16_t replace
+ ){
+ int count=0;
+ if(!src)return(-1);
+ while(*src){
+ if(*src == find){ *src = replace; count++; }
+ src++;
+ }
+ return(count);
+}
+
+/**
+ \brief strdup for when strict C99 compliance is enforced
+ \returns duplicate string or NULL on error
+ \param s string to duplicate
+*/
+char *U_strdup(const char *s){
+ char *news=NULL;
+ size_t slen;
+ if(s){
+ slen = strlen(s) + 1; //include the terminator!
+ news = malloc(slen);
+ if(news){
+ memcpy(news,s,slen);
+ }
+ }
+ return(news);
+
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uemf_utf.h b/src/3rdparty/libuemf/uemf_utf.h
new file mode 100644
index 000000000..68452b687
--- /dev/null
+++ b/src/3rdparty/libuemf/uemf_utf.h
@@ -0,0 +1,55 @@
+/**
+ @file uemf_utf.h
+
+ @brief Prototypes for functions that manipulate UTF and various types of text.
+
+*/
+
+/*
+File: uemf_utf.h
+Version: 0.0.1
+Date: 04-DEC-2012
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2012 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UEMF_UTF_
+#define _UEMF_UTF_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "uemf_endian.h"
+
+void wchar8show(const char *src);
+void wchar16show(const uint16_t *src);
+void wchar32show(const uint32_t *src);
+void wchartshow(const wchar_t *src);
+
+size_t wchar16len(const uint16_t *src);
+size_t wchar32len(const uint32_t *src);
+void wchar16strncpy(uint16_t *dst, const uint16_t *src, size_t nchars);
+void wchar16strncpypad(uint16_t *dst, const uint16_t *src, size_t nchars);
+uint16_t *U_Utf8ToUtf16le( const char *src, size_t max, size_t *len );
+uint32_t *U_Utf8ToUtf32le( const char *src, size_t max, size_t *len );
+uint32_t *U_Latin1ToUtf32le( const char *src, size_t max, size_t *len );
+uint16_t *U_Utf32leToUtf16le( const uint32_t *src, size_t max, size_t *len );
+char *U_Utf32leToUtf8( const uint32_t *src, size_t max, size_t *len );
+uint32_t *U_Utf16leToUtf32le( const uint16_t *src, size_t max, size_t *len );
+char *U_Utf16leToUtf8( const uint16_t *src, size_t max, size_t *len );
+char *U_Utf16leToLatin1( const uint16_t *src, size_t max, size_t *len );
+char *U_Utf8ToLatin1( const char *src, size_t max, size_t *len );
+char *U_Latin1ToUtf8( const char *src, size_t max, size_t *len );
+uint16_t U_Utf16le(const uint16_t src);
+int U_Utf16leEdit( uint16_t *src, uint16_t find, uint16_t replace );
+char *U_strdup(const char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UEMF_UTF_ */
diff --git a/src/3rdparty/libuemf/upmf.c b/src/3rdparty/libuemf/upmf.c
new file mode 100644
index 000000000..5cb558ac6
--- /dev/null
+++ b/src/3rdparty/libuemf/upmf.c
@@ -0,0 +1,8660 @@
+/**
+ @file upmf.c
+
+ @brief Functions for manipulating EMF+ files and structures.
+
+ EMF+ is much more object based than is EMF or WMF, so the U_PMR_*_set and most U_PMF_*_set functions
+ return a pointer to a PseudoObject. PseudoObjects are structs that contain a data field to hold the
+ object in EMF+ file byte order, size information, and some type information. This is sufficient to allow
+ complex records to be built up from the various sorts of nested objects which they normally contain.
+ If something goes wrong a NULL pointer is returned and recsize is set to 0.
+
+ EMF+ does not use a separate set of endian functions, _get and _set routines convert from/to
+ the EMF+ file byte order on the fly.
+
+ WARNING: Microsoft's EMF+ documentation is little-endian for everything EXCEPT
+ bitfields, which are big-endian. See EMF+ manual section 1.3.2
+ That documentation also uses 0 as the MOST significant bit, N-1 as the least.
+ This code is little-endian throughout, and 0 is the LEAST significant bit
+
+*/
+
+/*
+File: upmf.c
+Version: 0.0.12
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <iconv.h>
+#include <wchar.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h> // for INT_MAX, INT_MIN
+#include <math.h> // for sin, cos, tan2, use U_ROUND() instead of roundf()
+#include <stddef.h> /* for offsetof() macro */
+#if 0
+#include <windef.h> //Not actually used, looking for collisions
+#include <winnt.h> //Not actually used, looking for collisions
+#include <wingdi.h> //Not actually used, looking for collisions
+#endif
+#include "upmf.h" // includes uemf.h
+#include "uemf_endian.h" // for U_swap* functions
+
+//! \cond
+
+/// things Doxygen should not process
+/* remove this after debugging is completed */
+void dumphex(uint8_t *buf,unsigned int num){
+ for(; num; num--,buf++){
+ printf("%2.2X",*buf);
+ }
+}
+
+
+/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed
+to be used in end user code. */
+
+void U_swap2(void *ul, unsigned int count);
+void U_swap4(void *ul, unsigned int count);
+//! \endcond
+
+/**
+ \brief Utility function for writing one or more EMF+ records in a PseudoObject to the EMF output file
+ \return 1 on success, 0 on error.
+ \param po U_PSEUDO_OBJ to write, it is deleted after it is written
+ \param sum U_PSEUDO_OBJ to use for scratch space
+ \param et EMFTRACK used to write records to EMF file
+*/
+int U_PMR_write(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *sum, EMFTRACK *et){
+ char *rec;
+ int status = 0;
+ sum->Used = 0; /* clean it out, retaining allocated memory */
+ sum = U_PO_append(sum, "EMF+", 4); /* indicates that this comment holds an EMF+ record */
+ if(!sum)goto end;
+ sum = U_PO_append(sum, po->Data, po->Used); /* the EMF+ record itself */
+ if(!sum)goto end;
+ U_PO_free(&po); /* delete the PseudoObject */
+ rec = U_EMRCOMMENT_set(sum->Used, sum->Data); /* stuff it into the EMF comment */
+ if(!emf_append((PU_ENHMETARECORD)rec, et, 1))goto end; /* write it to the EMF file, delete the record, check status */
+ status = 1;
+end:
+ return(status);
+}
+
+/**
+ \brief Utility function to draw a line.
+ \return 1 on success, 0 on error.
+ \param PenID Index of U_PMF_PEN object to use in the EMF+ object table (0-63, inclusive)
+ \param PathID Index of U_PMF_PATH object to use in the EMF+ object table (0-63, inclusive)
+ \param Start U_PMF_POINTF coordinates of start of line.
+ \param End U_PMF_POINTF coordinates of end of line.
+ \param Dashed Set if the line is dashed, clear if it is not.
+ \param sum PseudoObject used for scratch space
+ \param et EMFTRACK used to write records to EMF file
+
+*/
+int U_PMR_drawline(uint32_t PenID, uint32_t PathID, U_PMF_POINTF Start, U_PMF_POINTF End, int Dashed, U_PSEUDO_OBJ *sum, EMFTRACK *et){
+ U_DPSEUDO_OBJ *dpath;
+ U_PSEUDO_OBJ *poPath;
+ U_PSEUDO_OBJ *po;
+ int status=0;
+ int PTP_value = ( Dashed ? U_PTP_DashMode : U_PTP_None);
+ dpath = U_PATH_create(0, NULL, 0, 0); /* create an empty path*/
+ if(dpath){
+ if(U_PATH_moveto(dpath, Start, PTP_value) && U_PATH_lineto(dpath, End, PTP_value)){
+ poPath = U_PMF_PATH_set2(U_PMF_GRAPHICSVERSIONOBJ_set(2), dpath);
+ if(poPath){
+ po = U_PMR_OBJECT_PO_set(PathID, poPath);
+ U_PO_free(&poPath);
+ if(po){
+ U_PMR_write(po, sum, et);
+ po = U_PMR_DRAWPATH_set(PathID, PenID);
+ if(po){
+ U_PMR_write(po, sum, et);
+ status = 1;
+ }
+ }
+ }
+ }
+ U_DPO_free(&dpath);
+ }
+ return(status);
+}
+
+/**
+ \brief Utility function for drawing strings onto the baseline in one call.
+ \return 1 on success, 0 on error.
+ \param string Text to draw in UTF-8 format
+ \param Vpos StringAlignment Enumeration. Always drawn on baseline, but using one of these three modes.
+ \param FontID Index of U_PMF_FONT object to use in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param FormatID index of U_PMF_STRINGFORMAT object to use in the EMF+ Object Table.
+ \param Sfs StringFormat structure. Ignored values: StringAlignment, LineAlign, Flags
+ \param FontName Name of font to draw with
+ \param Height Height of font in pixels (positive)
+ \param fip U_FontInfoParams (ascent, descent, and so forth)
+ \param FontFlags FontStyle Flags
+ \param x X position in pixels of left side of EM box of first character
+ \param y Y position in pixels of baseline of first character
+ \param sum PseudoObject used for scratch space
+ \param et EMFTRACK used to write records to EMF file
+
+ EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
+
+ For most fonts Ascent and Descent are used to adjust the bounding box to properly position the
+ baseline. Some fonts, like Verdana, are strange and they position the baseline on the bottom of
+ the bounding box if that box has the same height as the font. For those fonts specify 0.0 for
+ both Ascent and Descent.
+*/
+int U_PMR_drawstring( const char *string, int Vpos, uint32_t FontID, const U_PSEUDO_OBJ *BrushID, uint32_t FormatID,
+ U_PMF_STRINGFORMAT Sfs, const char *FontName, U_FLOAT Height, U_FontInfoParams *fip, uint32_t FontFlags,
+ U_FLOAT x, U_FLOAT y, U_PSEUDO_OBJ *sum, EMFTRACK *et){
+ U_PSEUDO_OBJ *po;
+ U_PSEUDO_OBJ *poSF;
+ U_PSEUDO_OBJ *poFont;
+ U_PSEUDO_OBJ *poRect;
+ U_FLOAT rx,ry,rw,rh,rd;
+ uint16_t *UFontName;
+ uint16_t *Text16;
+ int slen;
+ int status = 0;
+ double aval, dval;
+
+ Sfs.Flags = U_SF_NoFitBlackBox + U_SF_NoClip;
+
+ if(Vpos < U_SA_Near || Vpos > U_SA_Far)return(0);
+ Sfs.StringAlignment = U_SA_Near; // Horizontal
+ Sfs.LineAlign = Vpos; // Vertical
+
+ UFontName = U_Utf8ToUtf16le(FontName, 0, NULL);
+ slen = strlen(FontName);
+ poFont = U_PMF_FONT_set(U_PMF_GRAPHICSVERSIONOBJ_set(2), Height, U_UT_World, FontFlags, slen, UFontName);
+ if(poFont){
+ po = U_PMR_OBJECT_PO_set(FontID, poFont); /* font to use */
+ if(po){
+ U_PMR_write(po, sum, et);
+
+ poSF = U_PMF_STRINGFORMAT_set(&Sfs, NULL);
+ if(poSF){
+ po = U_PMR_OBJECT_PO_set(FormatID, poSF);
+ U_PO_free(&poSF);
+ if(po){
+ U_PMR_write(po, sum, et);
+
+ rw = 4*Height*slen; /* This could probably be any value */
+ rh = Height;
+ rx = x;
+ if(fip->LineGap > -fip->Descent){ aval = fip->yMax; } // sylfaen, palatino
+ else { aval = fip->Ascent; } // others
+ if(fip->LineGap && (fip->LineGap < -fip->Descent)){ dval = ((double) (fip->Descent - fip->LineGap)) / ((double) fip->EmSize); } //shruti and some others
+ else { dval = ((double) fip->Descent ) / ((double) fip->EmSize); }
+ switch(Vpos){
+ case U_SA_Near:
+ rd = Height * aval / ((double) fip->EmSize);
+ break;
+ case U_SA_Center:
+ rd = 0.5 * ( Height * aval / ((double) fip->EmSize) + Height * ( 1.0 + dval));
+ break;
+ case U_SA_Far:
+ rd = Height * ( 1.0 + dval);
+ break;
+ }
+ ry = y - rd; /* draw from upper left corner, which is shifted to put baseline on y */
+ poRect = U_PMF_RECTF4_set(rx, ry, rw, rh);
+#if 0
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry}, (U_PMF_POINTF){x+100, ry}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry+rh}, (U_PMF_POINTF){x+100, ry+rh}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x-100, ry}, (U_PMF_POINTF){x-100, ry + Height * (double) fip->Ascent / ((double) fip->EmSize)}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 90, ry}, (U_PMF_POINTF){x- 90, ry - Height * (double) fip->Descent / ((double) fip->EmSize)}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 80, ry}, (U_PMF_POINTF){x- 80, ry + Height * (double) fip->yMax / ((double) fip->EmSize)}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 70, ry}, (U_PMF_POINTF){x- 70, ry - Height * (double) fip->yMin / ((double) fip->EmSize)}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 60, ry}, (U_PMF_POINTF){x- 60, ry + Height * (double) fip->LineGap / ((double) fip->EmSize)}, 0, sum, et);
+(void) U_PMR_drawline(OBJ_PEN_BLACK_1,OBJ_PATH_1, (U_PMF_POINTF){x- 50, ry}, (U_PMF_POINTF){x- 50, ry + Height * ( 1.0 - (((double) (fip->LineGap - fip->Descent)) / ((double) fip->EmSize)) )}, 0, sum, et);
+#endif
+
+ Text16 = U_Utf8ToUtf16le(string, 0, NULL);
+ slen = strlen(string);
+ po = U_PMR_DRAWSTRING_set(FontID, BrushID, FormatID, slen, poRect, Text16);
+ if(po){
+ U_PMR_write(po, sum, et);
+ status = 1; /* Success!!! */
+ }
+ U_PO_free(&poRect);
+ free(Text16);
+ }
+ }
+ }
+ U_PO_free(&poFont);
+ }
+ free(UFontName);
+ return(status);
+}
+
+/**
+ \brief Allocate and construct an array of U_POINT16 objects from a set of U_PMF_POINTF objects, endianness in and out is LE
+ \returns pointer to an array of U_POINT16 structures.
+ \param points pointer to the source U_POINT structures
+ \param count number of members in points
+
+ If a coordinate is out of range it saturates at boundary.
+*/
+U_PMF_POINT *POINTF_To_POINT16_LE(U_PMF_POINTF *points, int count){
+ U_PMF_POINT *newpts;
+ U_PMF_POINTF ptfl;
+ int i;
+ newpts = (U_PMF_POINT *) malloc(count * sizeof(U_PMF_POINT));
+
+ for(i=0; i<count; i++){
+ memcpy(&ptfl, &(points[i]), 8);
+ if(U_BYTE_SWAP){ U_swap4(&ptfl,2); } /* on BE platforms swap going in and coming out */
+ newpts[i].X = U_MNMX(ptfl.X, INT16_MIN, INT16_MAX);
+ newpts[i].Y = U_MNMX(ptfl.Y, INT16_MIN, INT16_MAX);
+ if(U_BYTE_SWAP){ U_swap2(&(newpts[i]),2); }
+ }
+ return(newpts);
+}
+
+/**
+ \brief Look up the name of the EMR+ record by type. Returns U_EMR_INVALID if out of range.
+
+ \return name of the PMR record, "U_EMR_INVALID" if out of range.
+ \param idx PMR record type WITHOUT the U_PMR_RECFLAG bit.
+
+*/
+char *U_pmr_names(unsigned int idx){
+ if(idx<U_PMR_MIN || idx > U_PMR_MAX){ idx = 0; }
+ static char *U_PMR_NAMES[U_PMR_MAX+1]={
+ "U_PMR_INVALID",
+ "U_PMR_Header",
+ "U_PMR_EndOfFile",
+ "U_PMR_Comment",
+ "U_PMR_GetDC",
+ "U_PMR_MultiFormatStart",
+ "U_PMR_MultiFormatSection",
+ "U_PMR_MultiFormatEnd",
+ "U_PMR_Object",
+ "U_PMR_Clear",
+ "U_PMR_FillRects",
+ "U_PMR_DrawRects",
+ "U_PMR_FillPolygon",
+ "U_PMR_DrawLines",
+ "U_PMR_FillEllipse",
+ "U_PMR_DrawEllipse",
+ "U_PMR_FillPie",
+ "U_PMR_DrawPie",
+ "U_PMR_DrawArc",
+ "U_PMR_FillRegion",
+ "U_PMR_FillPath",
+ "U_PMR_DrawPath",
+ "U_PMR_FillClosedCurve",
+ "U_PMR_DrawClosedCurve",
+ "U_PMR_DrawCurve",
+ "U_PMR_DrawBeziers",
+ "U_PMR_DrawImage",
+ "U_PMR_DrawImagePoints",
+ "U_PMR_DrawString",
+ "U_PMR_SetRenderingOrigin",
+ "U_PMR_SetAntiAliasMode",
+ "U_PMR_SetTextRenderingHint",
+ "U_PMR_SetTextContrast",
+ "U_PMR_SetInterpolationMode",
+ "U_PMR_SetPixelOffsetMode",
+ "U_PMR_SetCompositingMode",
+ "U_PMR_SetCompositingQuality",
+ "U_PMR_Save",
+ "U_PMR_Restore",
+ "U_PMR_BeginContainer",
+ "U_PMR_BeginContainerNoParams",
+ "U_PMR_EndContainer",
+ "U_PMR_SetWorldTransform",
+ "U_PMR_ResetWorldTransform",
+ "U_PMR_MultiplyWorldTransform",
+ "U_PMR_TranslateWorldTransform",
+ "U_PMR_ScaleWorldTransform",
+ "U_PMR_RotateWorldTransform",
+ "U_PMR_SetPageTransform",
+ "U_PMR_ResetClip",
+ "U_PMR_SetClipRect",
+ "U_PMR_SetClipPath",
+ "U_PMR_SetClipRegion",
+ "U_PMR_OffsetClip",
+ "U_PMR_DrawDriverstring",
+ "U_PMR_StrokeFillPath",
+ "U_PMR_SerializableObject",
+ "U_PMR_SetTSGraphics",
+ "U_PMR_SetTSClip"
+ };
+ return(U_PMR_NAMES[idx]);
+}
+
+/**
+ \brief Convert from PseudoObject OID to ObjectType enumeration.
+ \returns OT value on success, 0 if no match
+ \param OID PseudoObject OID (based on EMF+ manual chapter number. )
+
+ Only OTs that may be stored in the EMF+ object table are supported.
+*/
+
+int U_OID_To_OT(uint32_t OID){
+ int otype;
+ if( OID==U_PMF_BRUSH_OID ){ otype = U_OT_Brush; }
+ else if(OID==U_PMF_PEN_OID ){ otype = U_OT_Pen; }
+ else if(OID==U_PMF_PATH_OID ){ otype = U_OT_Path; }
+ else if(OID==U_PMF_REGION_OID ){ otype = U_OT_Region; }
+ else if(OID==U_PMF_IMAGE_OID ){ otype = U_OT_Image; }
+ else if(OID==U_PMF_FONT_OID ){ otype = U_OT_Font; }
+ else if(OID==U_PMF_STRINGFORMAT_OID ){ otype = U_OT_StringFormat; }
+ else if(OID==U_PMF_IMAGEATTRIBUTES_OID){ otype = U_OT_ImageAttributes; }
+ else if(OID==U_PMF_CUSTOMLINECAP_OID ){ otype = U_OT_CustomLineCap; }
+ else { otype = U_OT_Invalid; }
+ return(otype);
+}
+
+/**
+ \brief Convert from PseudoObject OID to BrushType enumeration.
+ \returns BT value on success, -1 if no match
+ \param OID PseudoObject OID (based on EMF+ manual chapter number. )
+
+ Only OIDs that map to BT's are supported.
+*/
+
+int U_OID_To_BT(uint32_t OID){
+ int otype;
+ if( OID==U_PMF_HATCHBRUSHDATA_OID ){ otype = U_BT_HatchFill; }
+ else if(OID==U_PMF_LINEARGRADIENTBRUSHDATA_OID ){ otype = U_BT_LinearGradient; }
+ else if(OID==U_PMF_PATHGRADIENTBRUSHDATA_OID ){ otype = U_BT_PathGradient; }
+ else if(OID==U_PMF_SOLIDBRUSHDATA_OID ){ otype = U_BT_SolidColor; }
+ else if(OID==U_PMF_TEXTUREBRUSHDATA_OID ){ otype = U_BT_TextureFill; }
+ else { otype = -1; }
+ return(otype);
+}
+
+/**
+ \brief Convert from PseudoObject OID to CustomLineCapDataType Enumeration.
+ \returns BT value on success, -1 if no match
+ \param OID PseudoObject OID (based on EMF+ manual chapter number. )
+
+ Only OIDs that map to CLCDT's are supported.
+*/
+
+int U_OID_To_CLCDT(uint32_t OID){
+ int otype;
+ if( OID==U_PMF_CUSTOMLINECAPDATA_OID ){ otype = U_CLCDT_Default; }
+ else if(OID==U_PMF_CUSTOMLINECAPARROWDATA_OID ){ otype = U_CLCDT_AdjustableArrow; }
+ else { otype = -1; }
+ return(otype);
+}
+
+/**
+ \brief Convert from PseudoObject OID to ImageDataType Enumeration.
+ \returns BT value on success, -1 if no match
+ \param OID PseudoObject OID (based on EMF+ manual chapter number. )
+
+ Only OIDs that map to IDT's are supported.
+*/
+
+int U_OID_To_IDT(uint32_t OID){
+ int otype;
+ if( OID==U_PMF_BITMAP_OID ){ otype = U_IDT_Bitmap; }
+ else if(OID==U_PMF_METAFILE_OID ){ otype = U_IDT_Metafile; }
+ else { otype = -1; }
+ return(otype);
+}
+
+/**
+ \brief Convert from PseudoObject OID to RegionNodeDataType Enumeration.
+ \returns BT value on success, -1 if no match
+ \param OID PseudoObject OID (based on EMF+ manual chapter number. )
+
+ Only OIDs that map to RNDT's are supported.
+*/
+
+int U_OID_To_RNDT(uint32_t OID){
+ int otype;
+ if( OID==U_PMF_REGIONNODECHILDNODES_OID ){ otype = U_RNDT_Kids; } /* there are 5 types, which must be specified separately */
+ else if(OID==U_PMF_RECTF_OID ){ otype = U_RNDT_Rect; }
+ else if(OID==U_PMF_REGIONNODEPATH_OID ){ otype = U_RNDT_Path; }
+ else { otype = -1; }
+ return(otype);
+}
+
+/**
+ \brief Append data to an U_OBJ_ACCUM structure.
+ \param oa pointer to the U_OBJ_ACCUM structure
+ \param data data to add
+ \param size bytes in data
+ \param Type object type
+ \param Id Object ID
+ \returns 0 on success, !0 on error. -1 on Type change, -2 on Id change
+
+ Safe to test for Id, Type changes by calling with size=0.
+*/
+int U_OA_append(U_OBJ_ACCUM *oa, const char *data, int size, int Type, int Id){
+ int tail;
+ if(!oa)return(2);
+ if(oa->used){
+ if(oa->Type != Type)return(-1);
+ if(oa->Id != Id)return(-2);
+ }
+ tail = oa->used;
+ if(oa->used + size >= oa->space){
+ oa->space += size;
+ char *newaccum = (char *) realloc(oa->accum, oa->space);
+ if(!newaccum){
+ oa->space -= size; /* put it back the way it was */
+ return(1);
+ }
+ oa->accum = newaccum;
+ }
+ memcpy(oa->accum + tail,data,size);
+ oa->used += size;
+ oa->Type = Type;
+ oa->Id = Id;
+ return(0);
+}
+
+
+/**
+ \brief Clear an U_OBJ_ACCUM structure. Accumulated storage is retained.
+ \param oa pointer to the U_OBJ_ACCUM structure
+ \returns 0 on success, !0 on error.
+*/
+int U_OA_clear(U_OBJ_ACCUM *oa){
+ if(!oa)return(2);
+ oa->used=0;
+ /* Type and Id may be ignored as they are reset on the first append */
+ return(0);
+}
+
+/**
+ \brief Release an U_OBJ_ACCUM structure. Accumulated storage is free'd.
+ \param oa pointer to the U_OBJ_ACCUM structure
+ \returns 0 on success, !0 on error.
+*/
+int U_OA_release(U_OBJ_ACCUM *oa){
+ if(!oa)return(2);
+ oa->used=0;
+ oa->space = 0;
+ if(oa->accum)free(oa->accum);
+ oa->accum=NULL;
+ return(0);
+}
+
+/**
+ \brief Create and set an U_PSEUDO_OBJ
+ \returns pointer to the U_PSEUDO_OBJ, NULL on error
+ \param Data Data to copy into the PseudoObject's data. If NULL, space is allocated, but is cleared instead of filled.
+ \param Size Number of bytes to allocate for Data (may be >Use if padding is present)
+ \param Use Number of data bytes in Data (whether or not Data is actually copied)
+ \param Type Type numbers are from manual section: 1.2.3.47 -> 0x01020347
+
+ If Data is NULL and Size is 0 an empty PseudoObject is created. One byte of storage
+ is allocated for Data, Size is set to 1, and Used to 0.
+
+ If Data is NULL and Size is !0 a zero filled PseudoObject is created.
+
+ If Data is !Null and Size is !0 a data filled PseudoObject is created.
+*/
+U_PSEUDO_OBJ *U_PO_create(char *Data, size_t Size, size_t Use, uint32_t Type){
+ if(Use>Size)return(NULL);
+ size_t tSize = (Size ? Size : 1);
+ U_PSEUDO_OBJ *po = (U_PSEUDO_OBJ *)malloc(sizeof(U_PSEUDO_OBJ));
+ if(po){
+ po->Data = malloc(tSize);
+ if(po->Data){
+ po->Size = tSize;
+ po->Used = Use;
+ po->Type = Type;
+ if(Data){ memcpy(po->Data, Data, Use); } /* if Use < Size uninitialized bytes will be present! */
+ else { memset(po->Data, 0, tSize); }
+ }
+ else {
+ free(po);
+ po=NULL;
+ }
+ }
+ return(po);
+}
+
+/**
+ \brief Append data to a U_PSEUDO_OBJ object and return it
+ \returns pointer to the U_PSEUDO_OBJ object, NULL on error
+ \param po PseudoObject to append to. Cannot be NULL.
+ \param Data Data to copy into the PseudoObject's data. If NULL, space is allocated (if necessary) and cleared instead of filled.
+ \param Size Number of data bytes in Data
+*/
+U_PSEUDO_OBJ *U_PO_append(U_PSEUDO_OBJ *po, const char *Data, size_t Size){
+ /* po cannot be NULL,as in U_PO_po_append(), because there would be no way to determine the TYPE of the resulting PO */
+ if(po){
+ if(!po->Data || po->Used + Size > po->Size){
+ po->Size = po->Used + Size;
+ char *newData = realloc(po->Data, po->Size);
+ if(!newData){
+ po->Size -= Size; /* put it back the way it was*/
+ po=NULL; /* skip the rest of the actions, does not affect po in caller */
+ }
+ else {
+ po->Data = newData;
+ }
+ }
+ if(po){ /* po->Data ready to append new data */
+ if(Data){ memcpy(po->Data + po->Used, Data, Size); }
+ else { memset(po->Data + po->Used, 0, Size); }
+ po->Used += Size;
+ }
+ }
+ return(po);
+}
+
+/**
+ \brief Append data to a U_PSEUDO_OBJ object and return it
+ \returns pointer to the U_PSEUDO_OBJ object, NULL on error
+ \param po PseudoObject to append to. May be NULL.
+ \param Src PseudoObject to append.
+ \param StripE Set: leading Elements in Src->Data is not copied, Clear: it is copied.
+*/
+U_PSEUDO_OBJ *U_PO_po_append(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *Src, int StripE){
+ if(!Src){ return(NULL); }
+ if((StripE && (Src->Used == 4)) || !Src->Used){ return(po); } /* appending nothing is not an error */
+ char *Data = Src->Data;
+ size_t Size = Src->Used; /* append only what is used */
+ U_PSEUDO_OBJ *ipo = po;
+ if(StripE){ Size -= 4; }
+ if(!ipo){
+ ipo = U_PO_create(NULL, 0, 0, Src->Type); /* create an empty pseudoobject */
+ }
+ if(ipo){
+ if(!ipo->Data || ipo->Used + Size > ipo->Size){
+ ipo->Size = ipo->Used + Size;
+ char *newData = realloc(ipo->Data, ipo->Size);
+ if(!newData){
+ if(ipo != po)U_PO_free(&ipo);
+ }
+ else {
+ ipo->Data = newData;
+ }
+ }
+ if(ipo){
+ if(Data){
+ if(StripE){ memcpy(ipo->Data + ipo->Used, Data + 4, Size); } /* Size is already 4 less, skip the leading Elements value */
+ else { memcpy(ipo->Data + ipo->Used, Data, Size); } /* copy everything */
+ }
+ else { memset(ipo->Data + ipo->Used, 0, Size); } /* set everything */
+ ipo->Used += Size;
+ }
+ }
+ return(ipo);
+}
+
+/**
+ \brief Free an U_PSEUDO_OBJ structure. All associated memory is released.
+ \param po Address of a pointer to the U_PSEUDO_OBJ structure, Pointer is set to NULL.
+ \returns 1 on success, 0 on error.
+*/
+int U_PO_free(U_PSEUDO_OBJ **po){
+ if(!po)return(0);
+ if(!*po)return(1);
+ if((*po)->Data)free((*po)->Data);
+ free(*po);
+ *po=NULL;
+ return(1);
+}
+
+/** \brief create a PseudoObject with data in the correct byte order for an EMF+ file.
+ \returns The PseudoObject on success, NULL on error.
+
+ \param Type the type of the PseudoObject that is created. Allowed values are in U_PID_Values.
+ \param List an array of U_SERIAL_DESC structures containing the data to store.
+
+ The U_PMF_SERIAL_set() function should not ever be called directly by end user code.
+
+ Each U_SERIAL_DESC element in List consists of Data fields and a description of that data. List is terminated
+ by the first U_SERIAL_DESC element having a TE value of U_XX.
+
+ Data fields: an array of a basic type of Units bytes repeated Reps times with the target byte order
+ described in TE.
+
+ Ptrs: Address of the first byte of the data fields.
+
+ Units: Number of bytes of in each data field unit
+
+ Reps: Number of repeats of the unit in data fields.
+ If a Ptr is NULL, and Units*Reps is not zero, then Units*Reps 0x00 bytes are stored.
+ If a Ptr is NULL, and Units*Reps is zero, this U_SERIAL_DESC is ignored.
+ if a Ptr is NOT NULL, and Units * Reps is not zero, then the data is stored in the indicated byte order.
+ If a Ptr is NOT NULL, and Units or Reps is zero an error is signaled.
+
+ TE: (Target Endian) the byte order in which to store each unit of a data field as defined in U_Endian.
+ Byte swapping is only enabled when Units is 2 or 4. In addition to the byte order values U_XE, U_LE,
+ and U_BE, and the array terminator U_XX, the value may also be U_RP. U_RP means there is only a
+ single unit in the data fields, but it is to be copied to the target Reps times. That is, the data
+ was passed in with a form of run length encoding.
+
+ Creates an empty PseudoObject if all pointers are NULL and all sizes are zero.
+ */
+U_PSEUDO_OBJ *U_PMF_SERIAL_set(uint32_t Type, const U_SERIAL_DESC *List){
+ U_PSEUDO_OBJ *po=NULL;
+ size_t Total=0;
+ size_t FSize;
+ char *cptr;
+ char *hptr;
+ const U_SERIAL_DESC *lptr;
+ if(!List)return(NULL);
+ for(lptr=List; lptr->TE != U_XX; lptr++){
+ if(!(lptr->Units * lptr->Reps) && lptr->Ptr)return(po);
+ Total += lptr->Units * lptr->Reps;
+ }
+ po = U_PO_create(NULL, Total, Total, Type);
+ if(po){
+ cptr = po->Data;
+ for(lptr=List; lptr->TE != U_XX; lptr++){
+ FSize = lptr->Units * lptr->Reps;
+ if(FSize){ /* Ptr is not NULL, that would have been detected already */
+ hptr = cptr;
+ if(lptr->TE & U_RP){ U_PMF_REPCPY_DSTSHIFT(&cptr, lptr->Ptr, lptr->Units, lptr->Reps); }
+ else { U_PMF_MEMCPY_DSTSHIFT(&cptr, lptr->Ptr, FSize); }
+ if(((lptr->TE & U_LE) && U_IS_BE) || ((lptr->TE & U_BE) && U_IS_LE)){
+ if(lptr->Units==2){ U_swap2(hptr,lptr->Reps); }
+ else if(lptr->Units==4){ U_swap4(hptr,lptr->Reps); }
+ }
+ }
+ }
+ }
+ return(po);
+}
+
+/**
+ \brief Create U_DPSEUDO_OBJ's for the Points and Types of a path
+ \param Elements Number of elements in Points. May be zero, which creates an empty path.
+ \param Points Array of U_PMF_POINTF values.
+ \param First Apply to first point, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. Must have U_PPT_Start set.
+ \param Others Apply to all other points, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration. Must have U_PPT_Line or U_PPT_Bezier set.
+ \returns pointer to the DU_PSEUDO_OBJ object, NULL on error
+*/
+U_DPSEUDO_OBJ *U_PATH_create(int Elements, const U_PMF_POINTF *Points, uint8_t First, uint8_t Others){
+ if(Elements){
+ if(!Points){ return(NULL); }
+ if( (First & U_PPT_MASK) != U_PPT_Start ){ return(NULL); }
+ if(!(Others & U_PPT_Bezier)){ return(NULL); } /* will pass if either line or bezier is set */
+ }
+
+ U_DPSEUDO_OBJ *Path = (U_DPSEUDO_OBJ *)calloc(sizeof(U_DPSEUDO_OBJ),1); /* make poTypes and poPoints NULL */
+ const U_SERIAL_DESC List[] = { {NULL,0,0,U_XX} };
+ if(Path){
+ Path->Elements = Elements;
+ Path->poPoints = U_PMF_SERIAL_set(U_PMF_RAW_OID, List); /* Empty PO to hold points as raw data */
+ if(!Elements){
+ Path->poTypes = U_PMF_SERIAL_set(U_PMF_RAW_OID, List); /* Empty PO to hold types as raw data */
+ }
+ else {
+ Path->poPoints = U_PO_append(Path->poPoints, (char *)Points, Elements*sizeof(U_PMF_POINTF));
+ if(Path->poPoints){
+ U_PSEUDO_OBJ *tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First | U_PPT_Start, Others); /* PO holding types, has leading Elements value */
+ Path->poTypes = U_PO_po_append(NULL, tpo, U_PMF_DROP_ELEMENTS); /* remove the leading Elements value*/
+ U_PO_free(&tpo);
+ if(!Path->poTypes){ U_PO_free(&Path->poPoints); }
+ }
+ if(!Path->poPoints){ U_DPO_free(&Path); }
+ }
+ }
+ return(Path);
+}
+
+/**
+ \brief Free U_DPSEUDO_OBJ's
+ \returns 1 on success, 0 on error.
+*/
+int U_DPO_free(U_DPSEUDO_OBJ **dpo){
+ if(!dpo){ return(0); }
+ if(!*dpo){ return(1); }
+ U_DPSEUDO_OBJ *kpo = *dpo;
+ if(kpo->poPoints){ U_PO_free(&kpo->poPoints); }
+ if(kpo->poTypes){ U_PO_free(&kpo->poTypes); }
+ free(*dpo);
+ *dpo=NULL;
+ return(1);
+}
+
+/**
+ \brief Clear U_DPSEUDO_OBJ's. Memory is retained, Elements and Used values are set to 0.
+ \returns 1 on success, 0 on error.
+
+ It is much more efficient to clear a DPO and reuse it than to free that DPO and create another.
+*/
+int U_DPO_clear(U_DPSEUDO_OBJ *dpo){
+ if(!dpo){ return(0); }
+ if(dpo->poPoints){ dpo->poPoints->Used = 0; }
+ if(dpo->poTypes){ dpo->poTypes->Used = 0; }
+ dpo->Elements = 0;
+ return(1);
+}
+
+/**
+ \brief Append a "moveto" point to a path
+ \param Path Address of a DoublePseudoObject holding the path to append to.
+ \param Point Point to move to.
+ \param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath)
+ \returns 1 on success, 0 on error.
+*/
+int U_PATH_moveto(U_DPSEUDO_OBJ *Path, U_PMF_POINTF Point, uint8_t Flags){
+ if(!Path){ return(0); }
+ U_PSEUDO_OBJ *tpo;
+ U_PSEUDO_OBJ *tpo2;
+ uint8_t Type = (Flags & U_PTP_NotClose) | U_PPT_Start;
+
+ tpo = U_PMF_POINTF_set(1, &Point);
+ if(!tpo){ return(0); }
+ tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poPoints = tpo2;
+
+
+ tpo = U_PMF_PATHPOINTTYPE_set(1, &Type);
+ if(!tpo){ return(0); }
+ tpo2= U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poTypes = tpo2;
+
+ Path->Elements++;
+ return(1);
+}
+
+/**
+ \brief Append a "lineto" point to a path
+ \param Path Address of a DoublePseudoObject holding the path to append to.
+ \param Point U_PMF_POINTF point to draw to.
+ \param Flags Flags may be (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, U_PTP_CloseSubpath)
+ \returns 1 on success, 0 on error.
+*/
+int U_PATH_lineto(U_DPSEUDO_OBJ *Path, U_PMF_POINTF Point, uint8_t Flags){
+ if(!Path || !Path->Elements){ return(0); } /* must be at least one point to extend from */
+ if(Path->poTypes->Data[Path->Elements - 1] & U_PTP_CloseSubpath){ return(0); } /* cannot extend a closed subpath */
+ U_PSEUDO_OBJ *tpo;
+ U_PSEUDO_OBJ *tpo2;
+ uint8_t Type = (Flags & U_PTP_NotClose) | U_PPT_Line;
+ tpo = U_PMF_POINTF_set(1, &Point);
+ if(!tpo){ return(0); }
+ tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poPoints = tpo2;
+
+
+ tpo = U_PMF_PATHPOINTTYPE_set(1, &Type);
+ if(!tpo){ return(0); }
+ tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poTypes = tpo2;
+
+ Path->Elements++;
+ return(1);
+}
+
+/**
+ \brief Set the closepath bit in the last point
+ \param Path Address of a DoublePseudoObject holding the path to act upon.
+ \returns 1 on success, 0 on error.
+*/
+int U_PATH_closepath(U_DPSEUDO_OBJ *Path){
+ if(!Path || !Path->poTypes){ return(0); }
+ uint32_t Elements = Path->Elements;
+ uint8_t *Type = (uint8_t *)(Path->poTypes->Data) + Elements - 1;
+ if(*Type & U_PPT_Start){ return(0); } /* single point closed path makes no sense */
+ *Type = *Type | U_PTP_CloseSubpath;
+ return(1);
+}
+
+/**
+ \brief Append a "polylineto" set of point to a path
+ \param Path Address of a DoublePseudoObject holding the path to append to.
+ \param Elements number of Points and Flags
+ \param Points Line points.
+ \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath)
+ \param StartSeg If set, use U_PPT_Start PathPointType enumeration for first point, otherwise use U_PPT_Line.
+ \returns 1 on success, 0 on error.
+*/
+int U_PATH_polylineto(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg){
+ if(!Path || !Points){ return(0); }
+ if(!Elements){ return(1); } /* harmless - do nothing */
+ U_PSEUDO_OBJ *tpo;
+ U_PSEUDO_OBJ *tpo2;
+ uint8_t First, Others;
+
+ tpo = U_PMF_POINTF_set(Elements, Points);
+ tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poPoints = tpo2;
+
+ if(StartSeg){ First = (Flags & U_PTP_NotClose) | U_PPT_Start; }
+ else { First = (Flags & U_PTP_NotClose) | U_PPT_Line; }
+ Others = (Flags & U_PTP_NotClose) | U_PPT_Line;
+ tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First, Others);
+ if(!tpo){ return(0); }
+ tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poTypes = tpo2;
+
+ Path->Elements += Elements;
+ return(1);
+}
+
+
+/**
+ \brief Append a "polybezierto" set of point to a path
+ \param Path Address of a DoublePseudoObject holding the path to append to.
+ \param Elements number of Points
+ \param Points Bezier points. Optional starting point, then N sets of 3, example: [P1] (Q12A Q12B P2) (Q23A Q23B P3).
+ \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath)
+ \param StartSeg If set, use U_PPT_Start PathPointType enumeration for first point, otherwise use U_PPT_Bezier.
+ \returns 1 on success, 0 on error.
+
+ If Start is set Elements must be 1 + multiple of 3. Ie, P1 Q12A Q12B P2 Q23A Q23B P3
+
+ If Start is clear Elements must be a multiple of 3. Ie, (P1, already in path) Q12A Q12B P2 Q23A Q23B P3
+*/
+int U_PATH_polybezierto(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg){
+ if(!Path || !Points){ return(0); }
+ if(!Elements){
+ if(StartSeg){ return(0); } /* cannot have both a NEW segment and ZERO points */
+ else{ return(1); } /* harmless - do nothing */
+ }
+ if(StartSeg && ((Elements - 1) % 3)){ return(0); } /* new segment must be 1 + N*3 points */
+ if(!StartSeg && (Elements % 3)){ return(0); } /* extend segment must be N*3 points */
+ U_PSEUDO_OBJ *tpo;
+ U_PSEUDO_OBJ *tpo2;
+ uint8_t First, Others;
+
+ tpo = U_PMF_POINTF_set(Elements, Points);
+ tpo2 = U_PO_po_append(Path->poPoints, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poPoints = tpo2;
+
+ if(StartSeg){ First = (Flags & U_PTP_NotClose) | U_PPT_Start; }
+ else { First = (Flags & U_PTP_NotClose) | U_PPT_Bezier; }
+ Others = (Flags & U_PTP_NotClose) | U_PPT_Bezier;
+ tpo = U_PMF_PATHPOINTTYPE_set2(Elements, First, Others);
+ if(!tpo){ return(0); }
+ tpo2 = U_PO_po_append(Path->poTypes, tpo, U_PMF_DROP_ELEMENTS);
+ U_PO_free(&tpo);
+ if(!tpo2)return(0);
+ Path->poTypes = tpo2;
+
+ Path->Elements += Elements;
+ return(1);
+}
+
+/**
+ \brief Append a "polygon" set of points to a path.
+ \param Path Address of a DoublePseudoObject holding the path to append to.
+ \param Elements number of Points and Flags
+ \param Points Line points.
+ \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath)
+ \returns 1 on success, 0 on error.
+*/
+int U_PATH_polygon(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags){
+ int status = U_PATH_polylineto(Path, Elements, Points, Flags, U_SEG_NEW);
+ if(status){
+ status = U_PATH_closepath(Path);
+ }
+ return(status);
+}
+
+//! \cond
+// These are not exposed in the API
+/* Parameterized Ellipse coordinates */
+U_PMF_POINTF U_eparam(U_FLOAT a, U_FLOAT b, U_PMF_POINTF *center, double Ang, double Theta){
+ U_PMF_POINTF point;
+ point.X = center->X + a*cos(Theta)*cos(Ang) - b*sin(Theta)*sin(Ang);
+ point.Y = center->Y + a*sin(Theta)*cos(Ang) + b*cos(Theta)*sin(Ang);
+ return(point);
+}
+
+/* Parameterized Ellipse derivative */
+U_PMF_POINTF U_eparam2(U_FLOAT a, U_FLOAT b, double Ang, double Theta){
+ U_PMF_POINTF point;
+ point.X = -a*cos(Theta)*sin(Ang) - b*sin(Theta)*cos(Ang);
+ point.Y = -a*sin(Theta)*sin(Ang) + b*cos(Theta)*cos(Ang);
+ return(point);
+}
+
+double U_aparam(double Ang1, double Ang2){
+ double Alpha;
+ double t2;
+ t2 = tan((Ang2 - Ang1)/2.0);
+ t2 *= t2;
+ Alpha = sin(Ang2 - Ang1) * (sqrt(4 + 3*t2) -1.0)/3.0;
+ return(Alpha);
+}
+
+/* Parameterized Bezier point Q1 or Q2 derivative */
+U_PMF_POINTF U_qparam(double Alpha, double a, double b, U_PMF_POINTF *Point, double Ang, double Theta, int mode){
+ U_PMF_POINTF Q, Prime;
+ Prime = U_eparam2(a,b,Ang,Theta);
+ if(mode==1){ /* Q1, anything else is Q2*/
+ Q.X = Point->X + Alpha * Prime.X;
+ Q.Y = Point->Y + Alpha * Prime.Y;
+ }
+ else {
+ Q.X = Point->X - Alpha * Prime.X;
+ Q.Y = Point->Y - Alpha * Prime.Y;
+ }
+ return(Q);
+}
+//! \endcond
+
+/**
+ \brief Append an "arcto" set of points to a path (Bezier points are calculated, and these are appended
+ \param Path Address of a pointer to the U_PSEUDO_OBJ that holds points
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rot Rotation angle to apply to coordinate system (Start and Rect), positive is degrees clockwise
+ \param Rect U_PMF_RECTF that defines the bounding rectangle.
+ \param Flags Flags (U_PTP_None, U_PTP_DashMode, U_PTP_PathMarker, U_PTP_NoBit, but NOT U_PTP_CloseSubpath)
+ \param StartSeg If set, the arc starts a new segment, if clear, continue the existing segment. Starting a new segment does not automatically apply U_PATH_closepath to the existing path.
+ \returns 1 on success, 0 on error.
+
+ Based on Luc Maisonobe's work, http://www.spaceroots.org/documents/ellipse/
+*/
+int U_PATH_arcto(U_DPSEUDO_OBJ *Path, U_FLOAT Start, U_FLOAT Sweep, U_FLOAT Rot, U_PMF_RECTF *Rect, uint8_t Flags, int StartSeg){
+ U_PMF_POINTF Bz[3];
+ U_PMF_POINTF Center;
+ U_PMF_POINTF P1,P2;
+ double a, b;
+ int done = 0;
+ int fpoint = 0;
+ double L1, L2; /* These are degrees CounterClockwise from 3:00 */
+ double Ang1, Ang2; /* These are parametric angles, derived from L1, L2*/
+ double Alpha; /* Dimensionless number used for Q1, Q2 */
+ double Theta; /* Rot in radians */
+ double Slop; /* do not let rounding errors cause spurious end points */
+ if(!Path){ return(0); }
+ if((Sweep > 360.0) || (Sweep < -360.0)){ return(0); }
+ /* Start should be between 0 and 360 degrees, but it does not really matter because sin, and cos will accept anything */
+ /* the sign on Sweep and Start is correct bacause LM's derivation has y positive up, but GDI+ has y positive down. */
+ a = Rect->Width/2.0;
+ b = Rect->Height/2.0;
+ if(!a || !b){ return(0); }
+ Center.X = Rect->X + a;
+ Center.Y = Rect->Y + b;
+ /* convert to radians */
+ Start = (2.0 * U_PI * Start)/360.0;
+ Sweep = (2.0 * U_PI * Sweep)/360.0;
+ Theta = (2.0 * U_PI * Rot )/360.0;
+ Slop = Sweep/100000.0;
+ L1 = Start;
+
+ while(!done){
+ if(Sweep < 0){
+ L2 = L1 - U_PI/2.0;
+ if(L2 <= Sweep + Start - Slop){ L2 = Sweep + Start; done = 1; }
+ else {done = 0; }
+ }
+ else {
+ L2 = L1 + U_PI/2.0;
+ if(L2 >= Sweep + Start + Slop){ L2 = Sweep + Start; done = 1; }
+ else {done = 0; }
+ }
+ Ang1 = atan2(sin(L1)/b, cos(L1)/a);
+ Ang2 = atan2(sin(L2)/b, cos(L2)/a);
+ Alpha = U_aparam(Ang1, Ang2);
+ P1 = U_eparam(a, b, &Center, Ang1, Theta); /* P1 */
+ P2 = U_eparam(a, b, &Center, Ang2, Theta); /* P2 */
+ Bz[0] = U_qparam(Alpha, a, b, &P1, Ang1, Theta, 1); /* Q1 */
+ Bz[1] = U_qparam(Alpha, a, b, &P2, Ang2, Theta, 2); /* Q2 */
+ Bz[2] = P2;
+ if(!fpoint){
+ if(StartSeg){ U_PATH_moveto(Path, P1, Flags); }
+ else { U_PATH_lineto(Path, P1, Flags); }
+ fpoint = 1;
+ }
+ U_PATH_polybezierto(Path, 3, Bz, Flags, U_SEG_OLD );
+ L1 = L2;
+ }
+ return(1);
+}
+
+/**
+ \brief Allocate and construct an array of U_PMF_POINTF objects which have been subjected to a U_XFORM
+ \returns pointer to an array of U_PMF_POINTF structures.
+ \param points pointer to the source U_PMF_POINTF structures
+ \param count number of members in points
+ \param xform U_XFORM to apply
+
+*/
+U_PMF_POINTF *pointfs_transform(U_PMF_POINTF *points, int count, U_XFORM xform){
+ U_PMF_POINTF *newpts=NULL;;
+ int i;
+ float X,Y;
+ newpts = (U_PMF_POINTF *) malloc(count * sizeof(U_PMF_POINTF));
+ if(newpts){
+ for(i=0; i<count; i++){
+ X = points[i].X;
+ Y = points[i].Y;
+ newpts[i].X = U_ROUND(X * xform.eM11 + Y * xform.eM21 + xform.eDx);
+ newpts[i].Y = U_ROUND(X * xform.eM12 + Y * xform.eM22 + xform.eDy);
+ }
+ }
+ return(newpts);
+}
+
+/**
+ \brief Allocate and construct an array of U_PMF_RECTF objects which have been subjected to a U_XFORM
+ \returns pointer to an array of U_PMF_RECTF structures.
+ \param Rects pointer to the source U_PMF_RECTF structures
+ \param Count number of members in Rects
+ \param Xform U_XFORM to apply. Rotation is ignored, only translation is applied.
+
+*/
+U_PMF_RECTF *rectfs_transform(U_PMF_RECTF *Rects, int Count, U_XFORM Xform){
+ U_PMF_RECTF *newRects;
+ int i;
+ newRects = (U_PMF_RECTF *) malloc(Count * sizeof(U_PMF_RECTF));
+ if(newRects){
+ for(i=0; i<Count; i++){
+ newRects[i].X = U_ROUND(Rects[i].X + Xform.eDx);
+ newRects[i].Y = U_ROUND(Rects[i].Y + Xform.eDy);
+ newRects[i].Width = U_ROUND(Rects[i].Width);
+ newRects[i].Height = U_ROUND(Rects[i].Height);
+ }
+ }
+ return(newRects);
+}
+
+/**
+ \brief Utility function calculate the transformation matrix needed to make a gradient run precisely corner to corner of a rectangle
+ \param Angle Rotation in degrees clockwise of the gradient. 0 is horizontal gradient.
+ \param w Width of the rectangle
+ \param h Height of the rectangle
+ \param x X coordinate of upper left corner of rectangle
+ \param y Y coordinate of upper left corner of rectangle
+ \param Periods Periods of gradient corner to corner. 1.0 is one, corner to corner.
+ \return Transformation matrix. All values are zero if Periods, w, or h are less than or equal to zero.
+*/
+U_PMF_TRANSFORMMATRIX tm_for_gradrect(U_FLOAT Angle, U_FLOAT w, U_FLOAT h, U_FLOAT x, U_FLOAT y, U_FLOAT Periods){
+//! \cond
+#define CLOSE_TO_IS_REALLY_ZERO(A) ((A) > 1.0e-10 || (A) < -1.0e-10 ? (A) : 0.0) //! \hideinitializer
+//! \endcond
+ U_PMF_TRANSFORMMATRIX tm;
+ double dang = Angle * 2*U_PI /360.0;
+ double scale;
+ double cd,sd;
+ if((Periods <=0.0) || (w <= 0.0) || (h <= 0.0)){
+ tm.m11 = tm.m12 = tm.m21 = tm.m22 = tm.dX = tm.dY = 0.0;
+ }
+ else {
+ /*
+ scale is gradient period divided by w
+ The scale value sets the gradient period to match exactly with the inscribed (w,h) rectangle
+ in the direction specified by the angle.
+ The numberator of scale is the max of the four dot product values of the rotated X basis unit vector with (w,h),
+ with each of the vectors {w,h}, {-w,h}, {-w,-h}, {w,h}. Those vectors run from each corner in turn
+ to the opposite corner. The one most parallel to the rotated unit vector will have both terms positive.
+
+ Trig results like cos(pi/2) are not stable between platforms due to minor differences in the
+ implementation. Detect these and make them zero, which then allows binary comparison of output files.
+ Otherwise the binary comparisons between platforms would fail because of a bunch of insignificant digits.
+ */
+ cd = CLOSE_TO_IS_REALLY_ZERO(cos(dang));
+ sd = CLOSE_TO_IS_REALLY_ZERO(sin(dang));
+ scale = (w*fabs(cd) + h*fabs(sd))/(w*Periods);
+ tm.m11 = scale * cd;
+ tm.m12 = -scale * sd;
+ tm.m21 = scale * sd;
+ tm.m22 = scale * cd;
+ /* offset is to one corner of the square, depending on which quadrant the rotation selects. */
+ if(cos(dang)>=0){
+ tm.dX = x;
+ if(sin(dang)>=0){tm.dY = y + h; } // LL corner
+ else { tm.dY = y; } // UL corner
+ }
+ else {
+ tm.dX = x + w;
+ if(sin(dang)>=0){ tm.dY = y + h; } // LR corner
+ else { tm.dY = y; } // UR corner
+ }
+ }
+ return tm;
+#undef CLOSE_TO_IS_REALLY_ZERO
+}
+/**
+ \brief Create a U_PSEUDO_OBJ containing a U_PMR_FILLPATH and U_PMR_DRAWPATH records.
+ \returns pointer to U_PSEUDO_OBJ or NULL on error.
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+*/
+U_PSEUDO_OBJ *U_PMR_drawfill(uint32_t PathID, uint32_t PenID, const U_PSEUDO_OBJ *BrushID){
+ U_PSEUDO_OBJ *po = U_PMR_FILLPATH_set(PathID, BrushID);
+ if(po){
+ U_PSEUDO_OBJ *tpo = U_PMR_DRAWPATH_set(PathID, PenID);
+ po = U_PO_po_append(po, tpo, U_PMF_KEEP_ELEMENTS);
+ U_PO_free(&tpo);
+ }
+ return(po);
+}
+
+
+
+/**
+ \brief Extract a single data field from a source.
+ \returns 1 on success, 0 on error.
+ \param Src where the data is coming from. It is incremented by the number of bytes retrieved.
+ \param Dst where the data will be stored. This must either be NULL (in which case the Src
+ is advanced and nothing is stored, or it must be allocated to Reps * Units bytes!!!!
+ \param Units number of bytes in each unit of the data field
+ \param Reps number of repeats of units in the data field.
+ If a Ptr is NULL, then Units*Reps 0 bytes are stored.
+ If a Ptr is NOT NULL, and Units or Reps, is zero an error is signaled.
+ If a Ptr is NULL and Units*Reps is 0, nothing happens.
+ \param SE logical (Source Endian). Only relevant for Sizes of 2 or 4
+ Indicates when Bytes may need to be rearranged when they are retrieved.
+ U_XE no change (this is used when the data has already been set to the proper orientation or it is not known)
+ U_LE source is Little Endian
+ U_BE source is Big Endian.
+ U_XX error
+
+*/
+int U_PMF_SERIAL_get(const char **Src, void *Dst, size_t Units, size_t Reps, int SE){
+ if(!Src || !*Src || SE == U_XX){ return(0); }
+ U_PMF_MEMCPY_SRCSHIFT(Dst, Src, Units * Reps);
+ if(!Dst){ return(1); } /* "fake" get, no data was retrieved, so we are done */
+ if(SE == U_XE){ return(1); }
+ if(SE == U_LE && U_IS_LE){ return(1); }
+ if(SE == U_BE && U_IS_BE){ return(1); }
+ /* need to swap */
+ if( Units==2){ U_swap2(Dst,Reps); }
+ else if(Units==4){ U_swap4(Dst,Reps); }
+ return(1);
+}
+
+/**
+ \brief Conditionally extract an array of data from a source, allocating space to hold it.
+ \returns 1 on success, 0 on error.
+ \param Src where the data is coming from. It is incremented by the number of bytes retrieved.
+ \param Dst Caller must free. Where the pointer to the data will be stored. Reps * Units bytes will be allocated,
+ \param Units number of bytes in each unit of the data field
+ \param Reps number of repeats of units in the data field.
+ If a Ptr is NULL, then Units*Reps 0 bytes are stored.
+ If a Ptr is NOT NULL, and Units or Reps, is zero an error is signaled.
+ If a Ptr is NULL and Units*Reps is 0, nothing happens.
+ \param SE logical (Source Endian). Only relevant for Sizes of 2 or 4
+ Indicates when Bytes may need to be rearranged when they are retrieved.
+ U_XE no change (this is used when the data has already been set to the proper orientation or it is not known)
+ U_LE source is Little Endian
+ U_BE source is Big Endian.
+ U_XX error
+ \param Cond Store the data into *Dst if true, set *Dst to NULL otherwise.
+
+*/
+int U_PMF_SERIAL_array_copy_get(const char **Src, void **Dst, size_t Units, size_t Reps, int SE, int Cond){
+ if(!Src || !*Src || !Dst || SE == U_XX){ return(0); }
+ if(!Cond){
+ *Src += Units * Reps;
+ *Dst = NULL;
+ return(1);
+ }
+ *Dst = malloc(Units * Reps);
+ if(!*Dst){ return(1); } /* "fake" get, no data was retrieved, so we are done */
+ U_PMF_MEMCPY_SRCSHIFT(*Dst, Src, Units * Reps);
+ if(SE == U_XE){ return(1); }
+ if(SE == U_LE && U_IS_LE){ return(1); }
+ if(SE == U_BE && U_IS_BE){ return(1); }
+ /* need to swap */
+ if( Units==2){ U_swap2(*Dst,Reps); }
+ else if(Units==4){ U_swap4(*Dst,Reps); }
+ return(1);
+}
+
+
+
+/**
+ \brief Calculate the length in bytes of a relative path object composed of U_PMF_INTEGER7 and U_PMF_INTER15 values
+ \return >=0 length == success, <0 error
+ \param contents Start of a relative path consisting of int7 and int15 X,Y pairs.
+ \param Elements number of relative X,Y pairs in the object
+*/
+int U_PMF_LEN_REL715(const char *contents, int Elements){
+ int length=0;
+ Elements *= 2; /* N pairs = 2N values */
+ for( ; Elements; Elements--){
+ /* X or Y value */
+ if(*contents & U_TEST_INT7){ contents +=2; length +=2; } //int15
+ else { contents +=1; length +=1; } //int7
+ }
+ return(length);
+}
+
+/**
+ \brief Calculate the length in bytes of objects which are a 4 byte Count followed by Count * float bytes
+ \return >=0 length == success, <0 error
+ Object types whose size may be derived with this function are:
+ U_PMF_COMPOUNDLINEDATA
+ U_PMF_DASHEDLINEDATA
+*/
+int U_PMF_LEN_FLOATDATA(const char *contents){
+ int Size;
+ U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE);
+ Size = 4*Size + 4;
+ return(Size);
+}
+
+/**
+ \brief Calculate the length in bytes of objects which are a 4 byte count followed by count bytes
+ \return >=0 length == success, <0 error
+ Object types whose size may be derived with this function are:
+ U_PMF_BOUNDARYPATHDATA
+ U_PMF_BOUNDARYPOINTDATA
+ U_PMF_CUSTOMSTARTCAPDATA
+ U_PMF_PATH
+ U_PMF_LINEPATH
+ U_PMF_REGIONNODEPATH
+*/
+int U_PMF_LEN_BYTEDATA(const char *contents){
+ int Size;
+ U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE);
+ Size += 4;
+ return(Size);
+}
+
+/**
+ \brief Create a string containing the curly bracket form of the 16 byte GUID value
+ \return number of bytes in record, 0 on error
+ \param GUID pointer to the 16 unsigned bytes
+ \return string in curly bracket form.
+ http://msdn.microsoft.com/en-us/library/cc230316.aspx
+
+ Text form is Data1-Data2-Data3-Data4, the first 3 are stored as little endian integers, the last as a string (big endian).
+*/
+char *U_PMF_CURLYGUID_set(uint8_t *GUID){
+ char *string=malloc(64);
+ if(string){
+ sprintf(string,"{%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X}",
+ GUID[3],GUID[2],GUID[1],GUID[0],
+ GUID[5],GUID[4],
+ GUID[7],GUID[6],
+ GUID[8],GUID[9],
+ GUID[10],GUID[11],GUID[12],GUID[13],GUID[14],GUID[15]
+ );
+ }
+ return(string);
+}
+
+/**
+ \brief Identify a known curly GUID
+ \param string Curly GUID form.
+ \return EmageEffects Enumerator
+
+ EMF+ manual 2.1.3.1, Microsoft name: ImageEffects Identifier
+*/
+int U_PMF_KNOWNCURLYGUID_set(const char *string){
+ int status;
+ if( !strcmp(string,"{633C80A4-1843-482B-9EF2-BE2834C5FDD4}")){ status = U_IEE_BlurEffectGuid; }
+ else if(!strcmp(string,"{D3A1DBE1-8EC4-4C17-9F4C-EA97AD1C343D}")){ status = U_IEE_BrightnessContrastEffectGuid; }
+ else if(!strcmp(string,"{537E597D-251E-48DA-9664-29CA496B70F8}")){ status = U_IEE_ColorBalanceEffectGuid; }
+ else if(!strcmp(string,"{DD6A0022-58E4-4A67-9D9B-D48EB881A53D}")){ status = U_IEE_ColorCurveEffectGuid; }
+ else if(!strcmp(string,"{A7CE72A9-0F7F-40D7-B3CC-D0C02D5C3212}")){ status = U_IEE_ColorLookupTableEffectGuid; }
+ else if(!strcmp(string,"{718F2615-7933-40E3-A511-5F68FE14DD74}")){ status = U_IEE_ColorMatrixEffectGuid; }
+ else if(!strcmp(string,"{8B2DD6C3-EB07-4D87-A5F0-7108E26A9C5F}")){ status = U_IEE_HueSaturationLightnessEffectGuid;}
+ else if(!strcmp(string,"{99C354EC-2A31-4F3A-8C34-17A803B33A25}")){ status = U_IEE_LevelsEffectGuid; }
+ else if(!strcmp(string,"{74D29D05-69A4-4266-9549-3CC52836B632}")){ status = U_IEE_RedEyeCorrectionEffectGuid; }
+ else if(!strcmp(string,"{63CBF3EE-C526-402C-8F71-62C540BF5142}")){ status = U_IEE_SharpenEffectGuid; }
+ else if(!strcmp(string,"{1077AF00-2848-4441-9489-44AD4C2D7A2C}")){ status = U_IEE_TintEffectGuid; }
+ else { status = U_IEE_Unknown; }
+ return(status);
+}
+
+/** \brief Load a GUID from text format into EMF+ file binary format.
+ \param string Curly GUID as text, minus the barckets and dashes.
+ \return GUID in EMF+ file binary format.
+
+
+This accepts a string that is 16 bytes long = 32 characters hex (no dash spaces or brackets) as text.
+Text form is; Data1|Data2|Data3|Data4, first three are stored as little endian integers of 4,2,2 bytes, respectively,
+last is stored like a string (big endian), after conversion from text hex to binary.
+
+This function is not normally called by end user code.
+*/
+uint8_t *U_LOAD_GUID(char *string){
+ uint32_t Data1,tData2,tData3,tByte;
+ uint16_t Data2,Data3;
+ char *Data4 = string + 16;
+ uint8_t *hold = malloc(16);
+ char *lf = (char *) hold;
+ int i;
+ if(hold){
+ Data1=tData2=tData3=0;
+ if(3 != sscanf(string + 0,"%8X",&Data1) +
+ sscanf(string + 8,"%4X",&tData2) +
+ sscanf(string + 12,"%4X",&tData3)){
+ free(hold);
+ hold = NULL;
+ goto bye;
+ }
+ Data2=tData2;
+ Data3=tData3;
+ U_PMF_MEMCPY_DSTSHIFT(&lf, &Data1, 4);
+ U_PMF_MEMCPY_DSTSHIFT(&lf, &Data2, 2);
+ U_PMF_MEMCPY_DSTSHIFT(&lf, &Data3, 2);
+ if(U_IS_BE){ /* these fields are stored little endian */
+ U_swap4(hold,1);
+ U_swap2(hold+4,2);
+ }
+ /* remainder is converted byte by byte and stored in that order */
+ for(i=0;i<8;i++,Data4+=2,lf++){
+ if(1 != sscanf(Data4,"%2X",&tByte)){
+ free(hold);
+ hold = NULL;
+ goto bye;
+ }
+ *lf=tByte;
+ }
+ }
+bye:
+ return(hold);
+}
+
+/**
+ \brief Generate the 16 byte form from OID of the ImageEffects Identifier
+ \param OID OID of the ImageEffects Identifier
+ \return pointer to 16 byte buffer holding the long GUID binary form, or NULL on error.
+
+ EMF+ manual 2.1.3.1, Microsoft name: ImageEffects Identifier
+*/
+uint8_t *U_OID_To_GUID(uint32_t OID){
+ uint8_t *lf = NULL;
+ if( OID == U_PMF_IE_BLUR_OID ){ lf = U_LOAD_GUID("633C80A41843482B9EF2BE2834C5FDD4"); }
+ else if(OID == U_PMF_IE_BRIGHTNESSCONTRAST_OID ){ lf = U_LOAD_GUID("D3A1DBE18EC44C179F4CEA97AD1C343D"); }
+ else if(OID == U_PMF_IE_COLORBALANCE_OID ){ lf = U_LOAD_GUID("537E597D251E48DA966429CA496B70F8"); }
+ else if(OID == U_PMF_IE_COLORCURVE_OID ){ lf = U_LOAD_GUID("DD6A002258E44A679D9BD48EB881A53D"); }
+ else if(OID == U_PMF_IE_COLORLOOKUPTABLE_OID ){ lf = U_LOAD_GUID("A7CE72A90F7F40D7B3CCD0C02D5C3212"); }
+ else if(OID == U_PMF_IE_COLORMATRIX_OID ){ lf = U_LOAD_GUID("718F2615793340E3A5115F68FE14DD74"); }
+ else if(OID == U_PMF_IE_HUESATURATIONLIGHTNESS_OID){ lf = U_LOAD_GUID("8B2DD6C3EB074D87A5F07108E26A9C5F"); }
+ else if(OID == U_PMF_IE_LEVELS_OID ){ lf = U_LOAD_GUID("99C354EC2A314F3A8C3417A803B33A25"); }
+ else if(OID == U_PMF_IE_REDEYECORRECTION_OID ){ lf = U_LOAD_GUID("74D29D0569A4426695493CC52836B632"); }
+ else if(OID == U_PMF_IE_SHARPEN_OID ){ lf = U_LOAD_GUID("63CBF3EEC526402C8F7162C540BF5142"); }
+ else if(OID == U_PMF_IE_TINT_OID ){ lf = U_LOAD_GUID("1077AF0028484441948944AD4C2D7A2C"); }
+ return(lf);
+}
+
+/**
+ \brief copy data and shift source pointer by the amount of data moved
+ \param Dst Destination in memory
+ \param Src Source in memory
+ \param Size Number of bytes to move
+*/
+void U_PMF_MEMCPY_SRCSHIFT(void *Dst, const char **Src, size_t Size){
+ if(Dst)memcpy(Dst, *Src, Size);
+ *Src += Size;
+}
+
+/**
+ \brief copy data and shift destination pointer by the amount of data moved
+ \param Dst Destination in memory (this must not be NULL)
+ \param Src Source in memory (if this is NULL, fill with that many zero bytes instead)
+ \param Size Number of bytes to move
+*/
+void U_PMF_MEMCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size){
+ if(Src){ memcpy(*Dst, Src, Size); }
+ else { memset(*Dst, 0, Size); }
+ *Dst += Size;
+}
+
+/**
+ \brief Copy the single instance at Src repeatedly to Dst.
+ \param Dst Destination in memory
+ \param Src Source in memory (if this is NULL, fill with that many zero bytes instead)
+ \param Size number of bytes in single instance that is template.
+ \param Reps Number of instances of the template to opy
+*/
+void U_PMF_REPCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size, size_t Reps){
+ for(;Reps;Reps--){
+ if(Src){ memcpy(*Dst, Src, Size); }
+ else { memset(*Dst, 0, Size); }
+ *Dst += Size;
+ }
+}
+
+/**
+ \brief save pointer to data and shift source pointer by the amount of data moved
+ \param Dst Destination in memory
+ \param Src Source in memory or NULL. If NULL Dst is set to NULL.
+ \param Size Number of bytes to move
+*/
+void U_PMF_PTRSAV_SHIFT(const char **Dst, const char **Src, size_t Size){
+ if(*Src){
+ if(Dst)*Dst = *Src;
+ *Src += Size;
+ }
+ else {
+ if(Dst)*Dst = NULL;
+ }
+}
+
+/**
+ \brief save pointer to data and shift source pointer by the amount of data moved
+ \return 1 on sucess, 0 on error
+ \param Dst Destination in memory
+ \param Src Source in memory or NULL. If NULL Dst is set to NULL.
+ \param Doit Assign if true, otherwise, set to NULL
+*/
+int U_PMF_PTRSAV_COND(const char **Dst, const char *Src, int Doit){
+ if(!Dst){ return(0); }
+ if(Src && Doit){ *Dst = Src; }
+ else { *Dst = NULL; }
+ return(1);
+}
+/*
+
+ =====================================================================================
+ start of U_PMF_*_get() functions
+
+*/
+
+/**
+ \brief Get the 16 bit unsigned Flags field from a header.
+ \param contents Record from which to extract data, will be incremented by header size.
+ \return Flags field
+
+ In many records the only value needed from the header is Flags. Rather than mapping
+ the entire Header and returning it, in these instances this function may be called to
+ just get this one value.
+*/
+uint16_t U_PMF_HEADERFLAGS_get(const char *contents){
+ uint16_t Flags;
+ const char *cptr = contents + offsetof(U_PMF_CMN_HDR,Flags);
+ U_PMF_SERIAL_get(&cptr, &Flags, 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/
+ return(Flags);
+}
+
+/**
+ \brief Retrieve whichever header fields are requested. NULL pointers do not retrieve.
+ \param contents Record from which to extract data, will be incremented by header size.
+ \param Type Record type
+ \param Flags Record flags
+ \param Size Records size
+ \param Datasize Data size
+ \return 1 on success, 0 on failure.
+*/
+int U_PMF_HEADERFIELDS_get(const char *contents,
+ uint16_t *Type, uint16_t *Flags, uint32_t *Size, uint32_t *Datasize){
+ if(!contents){ return(0); }
+ U_PMF_SERIAL_get(&contents, Type, 2, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Datasize, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get the entire EMF+ record header.
+ \param contents Record from which to extract data, will be offset by header size.
+ \param Header Location to store data (may be NULL)
+ \returns 1
+ If Header is Null, nothing is stored but contents is still offset.
+*/
+int U_PMF_CMN_HDR_get(const char **contents, U_PMF_CMN_HDR *Header){
+ if(!contents || !*contents){ return(0); }
+ if(Header){
+ U_PMF_SERIAL_get(contents, &(Header->Type), 2, 1, U_LE);
+ U_PMF_SERIAL_get(contents, &(Header->Flags), 2, 1, U_LE); /* EMF+ manual documents it as BE, but this code implements it as LE*/
+ U_PMF_SERIAL_get(contents, &(Header->Size), 4, 1, U_LE);
+ U_PMF_SERIAL_get(contents, &(Header->DataSize), 4, 1, U_LE);
+ }
+ else {
+ *contents += sizeof(U_PMF_CMN_HDR);
+ }
+ return(1);
+}
+
+/**
+ \brief return the size in bytes of the EMF+ record
+ \param contents Record from which to extract data, will not be modified.
+ \returns size, or 0 if contents is Null
+*/
+int U_PMF_RECORD_SIZE_get(const char *contents){
+ if(!contents){ return(0); }
+ int Size;
+ const char *from = contents + 4;
+ U_PMF_SERIAL_get(&from, &Size, 4, 1, U_LE);
+ return(Size);
+}
+
+/**
+ \brief Return the size of a PenData object from an EMF+ record.
+ \param PenData Address in memory where the PenData object starts.
+ \returns size of the object in bytes
+*/
+int U_PMF_LEN_PENDATA(const char *PenData){
+ uint32_t Flags;
+ int length=12; /* Flags, Unit, Width */
+ U_PMF_SERIAL_get(&PenData, &Flags, 4, 1, U_LE);
+ PenData += 8; /* skip Unit and Width */
+ length += U_PMF_LEN_OPTPENDATA(PenData, Flags);
+ return(length);
+}
+
+/**
+ \brief Return the size of an OptPenData object from an EMF+ record.
+ \param PenData Address in memory where the PenData object starts.
+ \param Flags PenData Flags that indicate which fields are present.
+ \returns size of the object in bytes
+*/
+int U_PMF_LEN_OPTPENDATA(const char *PenData, uint32_t Flags){
+ int length=0;
+ if(Flags & U_PD_Transform){ length += sizeof(U_PMF_TRANSFORMMATRIX); }
+ if(Flags & U_PD_StartCap){ length += sizeof(int32_t); }
+ if(Flags & U_PD_EndCap){ length += sizeof(int32_t); }
+ if(Flags & U_PD_Join){ length += sizeof(uint32_t); }
+ if(Flags & U_PD_MiterLimit){ length += sizeof(U_FLOAT); }
+ if(Flags & U_PD_LineStyle){ length += sizeof(int32_t); }
+ if(Flags & U_PD_DLCap){ length += sizeof(int32_t); }
+ if(Flags & U_PD_DLOffset){ length += sizeof(int32_t); }
+ if(Flags & U_PD_DLData){ length += U_PMF_LEN_FLOATDATA(PenData + length); }
+ if(Flags & U_PD_NonCenter){ length += sizeof(int32_t); }
+ if(Flags & U_PD_CLData){ length += U_PMF_LEN_FLOATDATA(PenData + length); }
+ if(Flags & U_PD_CustomStartCap){ length += U_PMF_LEN_BYTEDATA(PenData + length); }
+ if(Flags & U_PD_CustomEndCap){ length += U_PMF_LEN_BYTEDATA(PenData + length); }
+ return(length);
+}
+
+/**
+ \brief Create and set a U_PMF_BRUSH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Bd U_PSEUDO_OBJ containing one of the 5 types of Brush data
+
+ EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object
+*/
+U_PSEUDO_OBJ *U_PMF_BRUSH_set(uint32_t Version, const U_PSEUDO_OBJ *Bd){
+ if(!Bd){ return(NULL); }
+ int32_t Type = U_OID_To_BT(Bd->Type);
+ if(Type < 0){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&Type, 4, 1, U_LE},
+ {Bd->Data, Bd->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BRUSH_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CUSTOMLINECAP PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Ld U_PSEUDO_OBJ containing one of the 2 types of Linecap data
+
+ EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAP_set(uint32_t Version, const U_PSEUDO_OBJ *Ld){
+ if(!Ld){ return(NULL); }
+ int32_t Type = U_OID_To_CLCDT(Ld->Type);
+ if(Type<0){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&Type, 4, 1, U_LE},
+ {Ld->Data, Ld->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAP_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_FONT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param EmSize em size in units of SizeUnit
+ \param SizeUnit UnitType enumeration
+ \param FSFlags FontStyle flags
+ \param Length Number of Unicode Characters in FamilyName
+ \param Font Unicode (UTF-16LE) fontname
+
+ EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object
+*/
+U_PSEUDO_OBJ *U_PMF_FONT_set(uint32_t Version, U_FLOAT EmSize, uint32_t SizeUnit,
+ int32_t FSFlags, uint32_t Length, const uint16_t *Font){
+ uint32_t cbFont = 2 * wchar16len(Font); /* this need not be 2*Length parameter */
+ uint32_t pad = (0x3 & cbFont ? 2 : 0);
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&EmSize, 4, 1, U_LE},
+ {&SizeUnit,4, 1, U_LE},
+ {&FSFlags, 4, 1, U_LE},
+ {NULL, 4, 1, U_LE}, /* NULL is for Reserved field */
+ {&Length, 4, 1, U_LE},
+ {Font, cbFont, 1, U_LE},
+ {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* Entire record must be a multiple of 4 */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FONT_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IMAGE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Id U_PSEUDO_OBJ containing one of the 2 types of image data
+
+ EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object
+*/
+U_PSEUDO_OBJ *U_PMF_IMAGE_set(uint32_t Version, const U_PSEUDO_OBJ *Id){
+ if(!Id){ return(NULL); }
+ int32_t Type = U_OID_To_IDT(Id->Type);
+ if(Type<0){ return(NULL);}
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&Type, 4, 1, U_LE},
+ {Id->Data, Id->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IMAGE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IMAGEATTRIBUTES PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param WrapMode WrapMode object
+ \param ClampColor EmfPlusARGB object
+ \param ObjectClamp ObjectClamp Identifiers
+
+ EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object
+*/
+U_PSEUDO_OBJ *U_PMF_IMAGEATTRIBUTES_set(uint32_t Version, uint32_t WrapMode, uint32_t ClampColor, uint32_t ObjectClamp){
+ uint32_t Reserved=0;
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&Reserved, 4, 1, U_LE},
+ {&WrapMode, 4, 1, U_LE},
+ {&ClampColor, 4, 1, U_LE},
+ {&ObjectClamp, 4, 1, U_LE},
+ {&Reserved, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IMAGEATTRIBUTES_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Points U_PSEUDO_OBJ containing array of points (of type PMFPointR, PMFPoint, or PMFPointF, determined by U_PPF_P and U_PPF_C bits in Flags)
+ \param Types U_PSEUDO_OBJ containing array of types (U_PMF_PATHPOINTTYPE or U_PMF_PATHPOINTTYPERLE, determined by U_PPF_R big in Flags)
+
+ EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATH_set(uint32_t Version, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Types){
+ int ctype, RelAbs, rtype;
+ int pad;
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(Types){
+ if( Types->Type == (U_PMF_PATHPOINTTYPERLE_OID | U_PMF_ARRAY_OID)){ rtype = 1; }
+ else if(Types->Type == (U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID)){ rtype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ uint16_t Flags = (rtype ? U_PPF_R : 0) | (ctype ? U_PPF_C : 0)| (RelAbs ? U_PPF_P : 0);
+ pad = (0x3 & (Points->Used + Types->Used));
+ if(pad){ pad = 4 - pad; }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE },
+ {Points->Data, 4, 1, U_XE }, /* Elements from Points */
+ {&Flags, 2, 1, U_LE },
+ {NULL, 2, 1, U_LE }, /* Reserved field */
+ {Points->Data + 4, Points->Used - 4, 1, U_XE }, /* omit Points Elements */
+ {Types->Data +4, Types->Used - 4, 1, U_XE }, /* omit Types Elements */
+ {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List);
+ return(po);
+}
+
+
+/**
+ \brief Create and set a U_PMF_PATH PseudoObject that uses U_PMF_POINTF coordinates
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Path U_DPSEUDO_OBJ containing a path.
+
+ EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATH_set2(uint32_t Version, const U_DPSEUDO_OBJ *Path){
+ if(!Path || !Path->Elements){ return(NULL); }
+ uint16_t Flags = 0;
+ int pad = (0x3 & Path->Elements);
+ if(pad){ pad = 4 - pad; }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE },
+ {&Path->Elements, 4, 1, U_LE },
+ {&Flags, 2, 1, U_LE },
+ {NULL, 2, 1, U_LE }, /* Reserved field */
+ {Path->poPoints->Data, 4, 2*Path->Elements,U_XE }, /* raw OID, so no leading Elements to omit */
+ {Path->poTypes->Data, 1, Path->Elements, U_XE }, /* raw OID, so no leading Elements to omit */
+ {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PATH PseudoObject that uses U_PMF_POINT (int 16) coordinates
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Path U_DPSEUDO_OBJ containing a path.
+
+ EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATH_set3(uint32_t Version, const U_DPSEUDO_OBJ *Path){
+ if(!Path || !Path->Elements){return(NULL); }
+ uint16_t Flags = U_PPF_C;
+ int pad = (0x3 & Path->Elements);
+ if(pad){ pad = 4 - pad; }
+ U_PMF_POINT *Points16 = POINTF_To_POINT16_LE((U_PMF_POINTF *)Path->poPoints->Data, Path->Elements);
+ if(!Points16){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE },
+ {&Path->Elements, 4, 1, U_LE },
+ {&Flags, 2, 1, U_LE },
+ {NULL, 2, 1, U_LE }, /* Reserved field */
+ {Points16, 2, 2*Path->Elements,U_XE }, /* raw data, so no leading Elements to omit */
+ {Path->poTypes->Data, 1, Path->Elements, U_XE }, /* raw data, so no leading Elements to omit */
+ {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* if no padding is needed the Units will be zero and nothing will happen */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATH_OID, List);
+ free(Points16);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PEN PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param PenData U_PSEUDO_OBJ containing U_PMF_PENDATA object
+ \param Brush U_PSEUDO_OBJ containing U_PMF_BRUSH object
+
+ EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object
+*/
+U_PSEUDO_OBJ *U_PMF_PEN_set(uint32_t Version, const U_PSEUDO_OBJ *PenData, const U_PSEUDO_OBJ *Brush){
+ if(!PenData || (PenData->Type != U_PMF_PENDATA_OID)){ return(NULL); }
+ if(!Brush || (Brush->Type != U_PMF_BRUSH_OID) ){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {NULL, 4, 1, U_LE},
+ {PenData->Data, PenData->Used, 1, U_XE},
+ {Brush->Data, Brush->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PEN_OID, List);
+ return(po);
+}
+
+
+/**
+ \brief Create and set a U_PMF_REGION PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Version EmfPlusGraphicsVersion object
+ \param Count Number of CHILD nodes. This is one less than the total number of U_PMF_REGIONNODE objects in Nodes.
+ \param Nodes U_PSEUDO_OBJ containing U_PMF_REGIONNODE object (Nodes defining region, may be a single element or a binary tree)
+
+ EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object
+*/
+U_PSEUDO_OBJ *U_PMF_REGION_set(uint32_t Version, uint32_t Count, const U_PSEUDO_OBJ *Nodes){
+ if(!Nodes || Nodes->Type != U_PMF_REGIONNODE_OID)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Version, 4, 1, U_LE},
+ {&Count, 4, 1, U_LE},
+ {Nodes->Data, Nodes->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGION_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_STRINGFORMAT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Sfs pointer to U_PMF_STRINGFORMAT structure, with no variable part
+ \param Sfd (optional) U_PSEUDO_OBJ containing U_PMF_STRINGFORMATDATA object
+
+ EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object
+*/
+U_PSEUDO_OBJ *U_PMF_STRINGFORMAT_set(U_PMF_STRINGFORMAT *Sfs, const U_PSEUDO_OBJ *Sfd){
+ if(!Sfs){ return(NULL); }
+ if(Sfd){
+ if((!Sfs->TabStopCount && !Sfs->RangeCount) || (Sfd->Type != U_PMF_STRINGFORMATDATA_OID))return(NULL);
+ }
+ else {
+ if(Sfs->TabStopCount || Sfs->RangeCount)return(NULL);
+ }
+ const U_SERIAL_DESC List[] = {
+ {&Sfs->Version, 4, 1, U_LE},
+ {&Sfs->Flags, 4, 1, U_LE},
+ {&Sfs->Language, 4, 1, U_LE},
+ {&Sfs->StringAlignment, 4, 1, U_LE},
+ {&Sfs->LineAlign, 4, 1, U_LE},
+ {&Sfs->DigitSubstitution, 4, 1, U_LE},
+ {&Sfs->DigitLanguage, 4, 1, U_LE},
+ {&Sfs->FirstTabOffset, 4, 1, U_LE},
+ {&Sfs->HotkeyPrefix, 4, 1, U_LE},
+ {&Sfs->LeadingMargin, 4, 1, U_LE},
+ {&Sfs->TrailingMargin, 4, 1, U_LE},
+ {&Sfs->Tracking, 4, 1, U_LE},
+ {&Sfs->Trimming, 4, 1, U_LE},
+ {&Sfs->TabStopCount, 4, 1, U_LE},
+ {&Sfs->RangeCount, 4, 1, U_LE},
+ {(Sfd ? Sfd->Data : NULL), (Sfd ? Sfd->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_STRINGFORMAT_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a PMF_4NUM PseudoObject (used for BrushID's)
+ \return Pointer to PseudoObject, NULL on error
+ \param BrushID U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+
+*/
+U_PSEUDO_OBJ *U_PMF_4NUM_set(uint32_t BrushID){
+ if(BrushID>63){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&BrushID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_4NUM_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_ARGB PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Alpha Alpha (0-255)
+ \param Red Red color (0-255)
+ \param Green Green color (0-255)
+ \param Blue Blue color (0-255)
+
+ EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object
+*/
+U_PSEUDO_OBJ *U_PMF_ARGB_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue){
+ const U_SERIAL_DESC List[] = {
+ {&Blue, 1, 1, U_XE},
+ {&Green, 1, 1, U_XE},
+ {&Red, 1, 1, U_XE},
+ {&Alpha, 1, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_ARGB_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an Array of U_PMF_ARGB valus in a PseudoObject
+ \return Pointer to PseudoObject containing the count, followed by the array of colors, NULL on error
+ \param Count Number of entries in Colors
+ \param Colors Array of ARGB values
+
+ EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object
+*/
+U_PSEUDO_OBJ *U_PMF_ARGBN_set(uint32_t Count, U_PMF_ARGB *Colors){
+ const U_SERIAL_DESC List[] = {
+ {&Count, 4, 1, U_LE},
+ {Colors, 4, Count, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_ARGB_OID | U_PMF_ARRAY_OID, List);
+ return(po);
+}
+
+/**
+ \brief Set a U_PMF_ARGB object
+ \return Object
+ \param Alpha Alpha (0-255)
+ \param Red Red color (0-255)
+ \param Green Green color (0-255)
+ \param Blue Blue color (0-255)
+
+ EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object
+*/
+U_PMF_ARGB U_PMF_ARGBOBJ_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue){
+ U_PMF_ARGB argb;
+ char *ptr = (char *) &argb;
+ U_PMF_MEMCPY_DSTSHIFT(&ptr, &Blue, 1);
+ U_PMF_MEMCPY_DSTSHIFT(&ptr, &Green, 1);
+ U_PMF_MEMCPY_DSTSHIFT(&ptr, &Red, 1);
+ U_PMF_MEMCPY_DSTSHIFT(&ptr, &Alpha, 1);
+ return(argb);
+}
+
+/**
+ \brief Create and set a U_PMF_BITMAP PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Bs pointer to U_PMF_BITMAP structure, with no variable part
+ \param Bm U_PSEUDO_OBJ containing an U_PMF_BITMAPDATA or U_PMF_COMPRESSEDIMAGE object
+
+ EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object
+*/
+U_PSEUDO_OBJ *U_PMF_BITMAP_set(const U_PMF_BITMAP *Bs, const U_PSEUDO_OBJ *Bm){
+ if(!Bs)return(NULL);
+ if(Bm->Type != U_PMF_BITMAPDATA_OID &&
+ Bm->Type != U_PMF_COMPRESSEDIMAGE_OID )return(NULL);
+ uint32_t Pad = UP4(Bm->Used) - Bm->Used; /* undocumented padding, must be present for at least PNG */
+ const U_SERIAL_DESC List[] = {
+ {Bs, 4, 5, U_LE},
+ {Bm->Data, Bm->Used, 1, U_XE},
+ {NULL, (Pad ? Pad : 0), (Pad ? 1 : 0), U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BITMAP_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_BITMAPDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Ps (optional) U_PSEUDO_OBJ containing a U_PMF_PALETTE structure
+ \param cbBm Bytes in Bm
+ \param Bm An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration.
+
+ EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object
+*/
+U_PSEUDO_OBJ *U_PMF_BITMAPDATA_set( const U_PSEUDO_OBJ *Ps, int cbBm, const char *Bm){
+ if(Ps && (Ps->Type != U_PMF_PALETTE_OID))return(NULL);
+ if(!Bm && cbBm)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {(Ps ? Ps->Data : NULL), (Ps ? Ps->Used : 0), (Ps ? 1 : 0), U_LE},
+ {Bm, cbBm, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BITMAPDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_BLENDCOLORS PseudoObject
+ \return Pointer to PseudoObject, NULL on Positions and Colors
+ \param Elements number of elements in Positions, must agree with the number of Colors.
+ \param Positions positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0.
+ \param Colors U_PSEUDO_OBJ containing an array of U_PMF_ARGB objects: object colors at positions on gradient line
+
+ EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object
+*/
+U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_PSEUDO_OBJ *Colors){
+ if(!Colors || !Positions || Colors->Type != (U_PMF_ARGB_OID | U_PMF_ARRAY_OID)){ return(NULL); }
+ uint32_t CElements = (Colors->Used - 4)/4;
+ if(CElements != Elements){ return(NULL); }
+ const U_SERIAL_DESC List[] = {
+ {&CElements, 4, 1, U_LE},
+ {Positions, 4, CElements, U_LE},
+ {Colors->Data + 4, Colors->Used - 4, 1, U_XE}, /* omit Elements part of this PseudoObject */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BLENDCOLORS_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_BLENDCOLORS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements members in osition, inluding Start and End (0.0 - 1.0)
+ \param StartColor Start Color (U_PMF_ARGB)
+ \param EndColor End Color (U_PMF_ARGB)
+
+ EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object
+
+
+ Positions always start at 0.0 and always end at 1.0. It is not well documented but other
+ start and end values generally do not work.
+*/
+U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_linear_set(uint32_t Elements, U_PMF_ARGB StartColor, U_PMF_ARGB EndColor){
+ double dP,dR,dG,dB,dA,P,R,G,B,A;
+ U_FLOAT StartPos = 0.0;
+ U_FLOAT EndPos = 1.0;
+ U_FLOAT *Positions;
+ U_FLOAT *pP;
+ U_PMF_ARGB *Colors;
+ U_PMF_ARGB *pC;
+ unsigned int i;
+ if(Elements <= 2 ){ return(NULL); }
+ pP = Positions = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT));
+ if(!Positions){ return(NULL); }
+ pC = Colors = (U_PMF_ARGB *)malloc(Elements *sizeof(U_PMF_ARGB));
+ if(!Colors){
+ free(Positions);
+ return(NULL);
+ }
+ dP = (EndPos - StartPos )/(float)(Elements - 1);
+ dB = ((double)EndColor.Blue - (double)StartColor.Blue )/(double)(Elements - 1);
+ dG = ((double)EndColor.Green - (double)StartColor.Green)/(double)(Elements - 1);
+ dR = ((double)EndColor.Red - (double)StartColor.Red )/(double)(Elements - 1);
+ dA = ((double)EndColor.Alpha - (double)StartColor.Alpha)/(double)(Elements - 1);
+ P = StartPos;
+ B = StartColor.Blue;
+ G = StartColor.Green;
+ R = StartColor.Red;
+ A = StartColor.Alpha;
+ for(i=0;i<Elements;i++,pC++,pP++){ /* hopefully the rounding errors are not a problem, used doubles to minimize that */
+ *pP = P;
+ P += dP;
+ *pC = (U_PMF_ARGB){B,G,R,A};
+ B += dB;
+ G += dG;
+ R += dR;
+ A += dA;
+ }
+ U_PSEUDO_OBJ *poColors = U_PMF_ARGBN_set(Elements, Colors);
+ U_PSEUDO_OBJ *po = U_PMF_BLENDCOLORS_set(Elements, Positions, poColors);
+ U_PO_free(&poColors);
+ free(Positions);
+ free(Colors);
+ return(po);
+}
+
+
+/**
+ \brief Create and set a U_PMF_BLENDFACTORS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements members in each array
+ \param Positions positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0.
+ \param Factors blending factors, 0.0->1.0 values, inclusive
+
+ EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object
+*/
+U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_FLOAT *Factors){
+ if(!Positions || !Factors)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Positions, 4, Elements, U_LE},
+ {Factors, 4, Elements, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BLENDFACTORS_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_BLENDFACTORS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements members in osition, inluding Start and End (0.0 - 1.0)
+ \param StartFactor Start Factor (0.0 - 1.0)
+ \param EndFactor End Factor (0.0 - 1.0)
+
+ EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object
+
+
+ Positions always start at 0.0 and always end at 1.0. It is not well documented but other
+ start and end values generally do not work.
+*/
+U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_linear_set(uint32_t Elements, U_FLOAT StartFactor, U_FLOAT EndFactor){
+ double dP,dF,P,F;
+ U_FLOAT StartPos = 0.0;
+ U_FLOAT EndPos = 1.0;
+ U_FLOAT *Positions;
+ U_FLOAT *Factors;
+ U_FLOAT *pP;
+ U_FLOAT *pF;
+ unsigned int i;
+ if(Elements <= 2 ){ return(NULL); }
+ pP = Positions = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT));
+ if(!Positions){ return(NULL); }
+ pF = Factors = (U_FLOAT *)malloc(Elements *sizeof(U_FLOAT));
+ if(!Factors){
+ free(Positions);
+ return(NULL);
+ }
+ dP = (EndPos - StartPos )/(float)(Elements - 1);
+ dF = (EndFactor - StartFactor)/(float)(Elements - 1);
+ P = StartPos;
+ F = StartFactor;
+ for(i=0;i<Elements;i++){ /* hopefully the rounding errors are not a problem, used doubles to minimize that */
+ *pP++ = P; P += dP;
+ *pF++ = F; F += dF;
+ }
+ U_PSEUDO_OBJ *po = U_PMF_BLENDFACTORS_set(Elements, Positions, Factors);
+ free(Positions);
+ free(Factors);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_BOUNDARYPATHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Path U_PSEUDO_OBJ containing U_PMF_PATH object
+
+ EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object
+*/
+U_PSEUDO_OBJ *U_PMF_BOUNDARYPATHDATA_set(const U_PSEUDO_OBJ *Path){
+ if(!Path || Path->Type != U_PMF_PATH_OID)return(NULL);
+ /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */
+ uint32_t Used = Path->Used;
+ const U_SERIAL_DESC List[] = {
+ {&Used, 4, 1, U_LE},
+ {Path->Data, Path->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BOUNDARYPATHDATA_OID, List);
+ return(po);
+}
+
+
+/**
+ \brief Create and set a U_PMF_BOUNDARYPOINTDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements members in each array
+ \param Points array of U_PMF_POINTF
+
+ EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object
+*/
+U_PSEUDO_OBJ *U_PMF_BOUNDARYPOINTDATA_set(uint32_t Elements, const U_PMF_POINTF *Points){
+ if(!Points)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Points, 4, 2*Elements,U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_BOUNDARYPOINTDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CHARACTERRANGE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param First First position in range
+ \param Length Range length
+
+ EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object
+*/
+U_PSEUDO_OBJ *U_PMF_CHARACTERRANGE_set(int32_t First, int32_t Length){
+ const U_SERIAL_DESC List[] = {
+ {&First, 4, 1, U_LE},
+ {&Length, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CHARACTERRANGE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_COMPOUNDLINEDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Members in Widths
+ \param Widths Array of U_FLOAT Line or gap widths (0.0 <-> 1.0, fraction of total line width )
+
+ EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object
+*/
+U_PSEUDO_OBJ *U_PMF_COMPOUNDLINEDATA_set(int32_t Elements, const char *Widths){
+ if(!Widths)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements ,4, 1, U_LE},
+ {Widths, 4, Elements,U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_COMPOUNDLINEDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_COMPRESSEDIMAGE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param cbImage Bytes in Image
+ \param Image Stored image in one of the supported formats (GIF, PNG, etc.).
+
+ EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object
+*/
+U_PSEUDO_OBJ *U_PMF_COMPRESSEDIMAGE_set(int32_t cbImage, const char *Image){
+ if(!cbImage || !Image)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {Image, cbImage, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_COMPRESSEDIMAGE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CUSTOMENDCAPDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Clc U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAP object
+
+ EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMENDCAPDATA_set(const U_PSEUDO_OBJ *Clc){
+ if(!Clc || Clc->Type != U_PMF_CUSTOMLINECAP_OID)return(NULL);
+ /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */
+ uint32_t Used = Clc->Used;
+ const U_SERIAL_DESC List[] = {
+ {&Used, 4, 1, U_LE},
+ {Clc->Data, Clc->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMENDCAPDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CUSTOMLINECAPARROWDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Width Arrow cap width (is multiplied by line width before draw)
+ \param Height Arrow cap length (is multiplied by line width before draw)
+ \param MiddleInset Pixels between outer edge and filled region
+ \param FillState If set, fill, otherwise, only border
+ \param StartCap LineCap enumeration (type of cap)
+ \param EndCap LineCap enumeration
+ \param Join LineJoin enumeration
+ \param MiterLimit Maximum (miter length / line width)
+ \param WidthScale Scale for U_PMF_CUSTOMLINECAP object
+
+ EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPARROWDATA_set(U_FLOAT Width, U_FLOAT Height,
+ U_FLOAT MiddleInset, uint32_t FillState, uint32_t StartCap, uint32_t EndCap, uint32_t Join,
+ U_FLOAT MiterLimit, U_FLOAT WidthScale
+ ){
+ const U_SERIAL_DESC List[] = {
+ {&Width, 4, 1, U_LE},
+ {&Height ,4, 1, U_LE},
+ {&MiddleInset, 4, 1, U_LE},
+ {&FillState, 4, 1, U_LE},
+ {&StartCap, 4, 1, U_LE},
+ {&EndCap, 4, 1, U_LE},
+ {&Join, 4, 1, U_LE},
+ {&MiterLimit, 4, 1, U_LE},
+ {&WidthScale, 4, 1, U_LE},
+ {NULL, 8, 2, U_LE}, /* FillHotSpots and LineHotSpots */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPARROWDATA_OID, List);
+ return(po);
+}
+
+
+/**
+ \brief Create and set a U_PMF_CUSTOMLINECAPDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags CustomLineCapData flags
+ \param Cap LineCap enumeration (type of cap)
+ \param Inset Distance line cap start -> line end
+ \param StartCap LineCap enumeration
+ \param EndCap LineCap enumeration
+ \param Join LineJoin enumeration
+ \param MiterLimit Maximum (miter length / line width)
+ \param WidthScale Scale for U_PMF_CUSTOMLINECAP object
+ \param Clcod U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAPOPTIONALDATA object
+
+ EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPDATA_set(uint32_t Flags, uint32_t Cap,
+ U_FLOAT Inset, uint32_t StartCap, uint32_t EndCap,
+ uint32_t Join, U_FLOAT MiterLimit, U_FLOAT WidthScale,
+ const U_PSEUDO_OBJ *Clcod
+ ){
+ if(!Clcod || Clcod->Type != U_PMF_CUSTOMLINECAPOPTIONALDATA_OID)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Flags, 4, 1, U_LE},
+ {&Cap, 4, 1, U_LE},
+ {&Inset, 4, 1, U_LE},
+ {&StartCap, 4, 1, U_LE},
+ {&EndCap, 4, 1, U_LE},
+ {&Join, 4, 1, U_LE},
+ {&MiterLimit, 4, 1, U_LE},
+ {&WidthScale, 4, 1, U_LE},
+ {NULL, 8, 2, U_LE}, /* FillHotSpots and LineHotSpots */
+ {Clcod->Data, Clcod->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CUSTOMLINECAPOPTIONALDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Fill U_PSEUDO_OBJ containing a U_PMF_FILLPATHOBJ object (optional)
+ \param Line U_PSEUDO_OBJ containing a U_PMF_LINEPATH object (optional)
+
+ EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPOPTIONALDATA_set(const U_PSEUDO_OBJ *Fill, const U_PSEUDO_OBJ *Line){
+ if(Fill && (Fill->Type != U_PMF_FILLPATHOBJ_OID))return(NULL);
+ if(Line && (Line->Type != U_PMF_LINEPATH_OID))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {(Fill ? Fill->Data : NULL), (Fill ? Fill->Used : 0), 1, U_XE},
+ {(Line ? Line->Data : NULL), (Line ? Line->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMLINECAPOPTIONALDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_CUSTOMSTARTCAPDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Clc U_PSEUDO_OBJ containing a U_PMF_CUSTOMLINECAPDATA object
+
+ EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object
+*/
+U_PSEUDO_OBJ *U_PMF_CUSTOMSTARTCAPDATA_set(const U_PSEUDO_OBJ *Clc){
+ if(!Clc || Clc->Type != U_PMF_CUSTOMLINECAP_OID)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {Clc->Data, Clc->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_CUSTOMSTARTCAPDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_DASHEDLINEDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Members in Lengths
+ \param Lengths Array of U_FLOAT holding lengths of dashes and spaces.
+
+ EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object
+*/
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set(int32_t Elements, const U_FLOAT *Lengths){
+ if(!Lengths)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Lengths, 4, Elements, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_DASHEDLINEDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from one of a predefined set of patterns
+ \return Pointer to PseudoObject, NULL on error
+ \param Unit Length of the repeat unit
+ \param StdPat Members in Lengths
+
+ EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object
+*/
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set2(U_FLOAT Unit, int StdPat){
+ uint32_t Elements;
+ uint8_t *p;
+ U_FLOAT SubUnit;
+ U_FLOAT Lengths[8]; /* This is the most dash/spaces that will be needed*/
+ int i;
+ /* Dot = 1, Dash = 2; Long = 3, 0 = terminate pattern */
+ uint8_t SB[U_DD_Types][5] =
+ {
+ {0,0,0,0,0}, // Solid
+ {2,0,0,0,0}, // Dash
+ {2,2,0,0,0}, // DashDash
+ {2,2,2,0,0}, // DashDashDash
+ {2,2,2,2,0}, // DashDashDashDash
+ {1,0,0,0,0}, // Dot
+ {1,1,0,0,0}, // DotDot
+ {1,1,1,0,0}, // DotDotDot
+ {1,1,1,1,0}, // DotDotDotDot
+ {2,1,0,0,0}, // DashDot
+ {2,2,1,0,0}, // DashDashDot
+ {2,2,1,1,0}, // DashDashDotDot
+ {2,2,2,1,0}, // DashDashDashDot
+ {2,1,1,0,0}, // DashDotDot
+ {2,1,1,1,0}, // DashDotDotDot
+ {2,1,2,1,0}, // DashDotDashDot
+ {3,0,0,0,0}, // Long
+ {3,3,0,0,0}, // LongLong
+ {3,3,3,0,0}, // LongLongLong
+ {3,3,3,3,0}, // LongLongLongLong
+ {3,1,0,0,0}, // LongDot
+ {3,3,1,0,0}, // LongLongDot
+ {3,3,1,1,0}, // LongLongDotDot
+ {3,3,3,1,0}, // LongLongLongDot
+ {3,1,1,0,0}, // LongDotDot
+ {3,1,1,1,0}, // LongDotDotDot
+ {3,1,3,1,0} // LongDotLongDot
+ };
+ if(Unit <= 0 ){ return(NULL); }
+ if((StdPat <= 0) || (StdPat > U_DD_LongDotLongDot)){ return(NULL); }
+ p = &(SB[StdPat][0]);
+ for(Elements = 0; *p; p++, Elements++){}
+ SubUnit = Unit/((U_FLOAT) Elements);
+ Elements *= 2;
+ p = &(SB[StdPat][0]);
+ for(i=0; *p; p++){
+ switch(*p){
+ case 0: break;
+ case 1: /* dot */
+ Lengths[i++] = SubUnit * 0.125;
+ Lengths[i++] = SubUnit * 0.875;
+ break;
+ case 2: /* dash */
+ Lengths[i++] = SubUnit * 0.5;
+ Lengths[i++] = SubUnit * 0.5;
+ break;
+ case 3: /* long */
+ Lengths[i++] = SubUnit * 0.75;
+ Lengths[i++] = SubUnit * 0.25;
+ break;
+ }
+ }
+
+ U_PSEUDO_OBJ *po = U_PMF_DASHEDLINEDATA_set(Elements, Lengths);
+ return(po);
+}
+
+/**
+ \brief Utility function to create and set a U_PMF_DASHEDLINEDATA PseudoObject from the bits that are set in a uint32_t
+ \return Pointer to PseudoObject, NULL on error
+ \param Unit Length of the repeat unit
+ \param BitPat uint32_t holding the bit pattern, the lowest order bit MUST be set and the highest order MUST be clear.
+
+ Make a line with a dot/dash pattern defined by the bits in the BitPat value. If a bit is set it is drawn,
+ if clear it is not. Every bit drawn has length Unit/32, and consecutive drawn bits are merged together.
+ The lowest order bit is the first bit that may be drawn, the highest the last.
+
+ Example: if the integer has value 0x13 the pattern produced will be:
+ 0 -> 2*unit/32 drawn
+ 2*unit/32 -> 5*unit/32 not drawn
+ 5*unit/32 -> 6*unit/32 drawn
+ 6*unit/32 -> unit not drawn
+
+ EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object
+*/
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set3(U_FLOAT Unit, uint32_t BitPat){
+ uint32_t Elements=0;
+ U_FLOAT SubUnit = Unit/32.0;
+ U_FLOAT Lengths[32]; /* This is the most dash/spaces that will be needed*/
+ if(!(0x00000001 & BitPat))return(NULL); /* Pattern must start with a drawn segment, this bit must be set */
+ if( 0x80000000 & BitPat )return(NULL); /* Pattern must end with an undrawn segment, this bit must be clear */
+ int i=0;
+ int k;
+ int lastType=1;
+ int newType=0;
+ uint32_t j=1;
+ Lengths[0]=0;
+ for(k=0; k<32; k++, j=j<<1){
+ if(j & BitPat){
+ if(!lastType){
+ newType=1;
+ }
+ }
+ else {
+ if(lastType){
+ newType=1;
+ }
+ }
+ if(newType){
+ i++;
+ Lengths[i]=0;
+ Elements++;
+ lastType = !lastType;
+ newType = 0;
+ }
+ Lengths[i] += SubUnit;
+ }
+ Elements = i+1;
+
+ U_PSEUDO_OBJ *po = U_PMF_DASHEDLINEDATA_set(Elements, Lengths);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_FILLPATHOBJ PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object
+
+ EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object
+*/
+U_PSEUDO_OBJ *U_PMF_FILLPATHOBJ_set(const U_PSEUDO_OBJ *Path){
+ if(!Path || (Path->Type != U_PMF_PATH_OID))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {Path->Data, Path->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FILLPATHOBJ_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_FOCUSSCALEDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ScaleX value 0.0 <-> 1.0
+ \param ScaleY value 0.0 <-> 1.0
+
+ EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object
+*/
+U_PSEUDO_OBJ *U_PMF_FOCUSSCALEDATA_set(U_FLOAT ScaleX, U_FLOAT ScaleY){
+ uint32_t tmp = 2;
+ const U_SERIAL_DESC List[] = {
+ {&tmp, 4, 1, U_LE},
+ {&ScaleX, 4, 1, U_LE},
+ {&ScaleY, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_FOCUSSCALEDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_GRAPHICSVERSION object (Signature always set to 0xDBC01)
+ \return Pointer to PseudoObject, NULL on error
+ \param GrfVersion GraphicsVersion enumeration
+
+ EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+*/
+U_PSEUDO_OBJ *U_PMF_GRAPHICSVERSION_set(int GrfVersion){
+ uint32_t tmp;
+ tmp = U_GFVR_PMF << 12; /* signature, can only have this value */
+ tmp |= (GrfVersion & U_GFVR_MASKLO);
+ const U_SERIAL_DESC List[] = {
+ {&tmp, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_GRAPHICSVERSION_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_GRAPHICSVERSION object Structure (Signature always set to 0xDBC01)
+ \return U_PMF_GRAPHICSVERSION
+ \param GrfVersion GraphicsVersion enumeration
+
+ EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+*/
+U_PMF_GRAPHICSVERSION U_PMF_GRAPHICSVERSIONOBJ_set(int GrfVersion){
+ uint32_t tmp;
+ tmp = U_GFVR_PMF << 12; /* signature, can only have this value */
+ tmp |= (GrfVersion & U_GFVR_MASKLO);
+ return(tmp);
+}
+
+
+/**
+ \brief Create and set a U_PMF_HATCHBRUSHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Style HatchStyle enumeration
+ \param Fg U_PSEUDO_OBJ containing a U_ARGB object, Foreground hatch pattern line color
+ \param Bg U_PSEUDO_OBJ containing a U_ARGB object, Background hatch pattern line color
+
+ EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object
+*/
+U_PSEUDO_OBJ *U_PMF_HATCHBRUSHDATA_set(uint32_t Style, const U_PSEUDO_OBJ *Fg, const U_PSEUDO_OBJ *Bg){
+ if(!Fg ||(Fg->Type != U_PMF_ARGB_OID))return(NULL);
+ if(!Bg ||(Bg->Type != U_PMF_ARGB_OID))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Style, 4, 1, U_LE},
+ {Fg->Data, Fg->Used, 1, U_XE},
+ {Bg->Data, Bg->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_HATCHBRUSHDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_INTEGER7 PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Value 7 bit signed integer (stored in an integer, range 63 <-> -64, inclusive)
+
+ EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object
+*/
+U_PSEUDO_OBJ *U_PMF_INTEGER7_set(int Value){
+ uint8_t utmp;
+ if(Value < -64 || Value > 63)return(NULL);
+ utmp = U_MASK_INT7 & *(unsigned int *)&Value;
+ U_PSEUDO_OBJ *po = U_PO_create((char *)&utmp, 1, 1, U_PMF_INTEGER7_OID); /* simple method is OK, no possibility of Endian issues */
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_INTEGER15 PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Value 15 bit signed integer (stored in an integer, range 32677 <-> -32678, inclusive)
+
+ EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object
+*/
+U_PSEUDO_OBJ *U_PMF_INTEGER15_set(int Value){
+ uint16_t utmp;
+ if(Value < -32678 || Value > 32677)return(NULL);
+ utmp = U_TEST_INT15 | (U_MASK_INT15 & *(unsigned int *)&Value);
+ const U_SERIAL_DESC List[] = {
+ {&utmp, 2, 1, U_BE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_INTEGER15_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_LANGUAGEIDENTIFIER value in 4 byte unsigned int, in NATIVE byte order
+ \return LID value in least significant two bytes and 0 in most significant two bytes.
+ \param SubLId Example: code for USA
+ \param PriLId Example: code for English
+
+ EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object
+*/
+U_PMF_LANGUAGEIDENTIFIER U_PMF_LANGUAGEIDENTIFIEROBJ_set(int SubLId, int PriLId){
+ U_PMF_LANGUAGEIDENTIFIER utmp32;
+ utmp32 = ((SubLId & U_FF_MASK_SUBLID) << U_FF_SHFT_SUBLID) | ((PriLId & U_FF_MASK_PRILID) << U_FF_SHFT_PRILID);
+ return(utmp32);
+}
+
+/**
+ \brief Create and set a U_PMF_LANGUAGEIDENTIFIER PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param LId Language Identifier as produced by U_PMF_LANGUAGEIDENTIFIEROBJ_set().
+
+ EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object
+*/
+U_PSEUDO_OBJ *U_PMF_LANGUAGEIDENTIFIER_set(U_PMF_LANGUAGEIDENTIFIER LId){
+ uint16_t utmp16;
+ utmp16 = (LId & U_FF_MASK_LID) << U_FF_SHFT_LID;
+ const U_SERIAL_DESC List[] = {
+ {&utmp16, 2, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LANGUAGEIDENTIFIER_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_LINEARGRADIENTBRUSHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Lgbd U_PMF_LINEARGRADIENTBRUSHDATA object (constant part)
+ \param Lgbod U_PSEUDO_OBJ containing a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object (variable part of a U_PMF_LINEARGRADIENTBRUSHDATA object)
+
+
+ EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object
+*/
+U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHDATA_set(const U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const U_PSEUDO_OBJ *Lgbod){
+ if(!Lgbd || !Lgbod || (Lgbod->Type != U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_OID))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {Lgbd, 4, 6, U_LE},
+ {&(Lgbd->StartColor), 4, 2, U_XE},
+ {&(Lgbd->StartColor), 4, 2, U_XE}, /* repeat the start/end colors. Supposedly reserved. */
+// {NULL, 4, 2, U_LE}, /* zero fill the two Reserved fields, no matter what is passed in */
+ {(Lgbod->Used ? Lgbod->Data : NULL), Lgbod->Used, 1, U_XE}, /* optional Data can exist and Used can be zero, SERIAL_set would throw an error on that */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEARGRADIENTBRUSHDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags Bits are set that indicate which of the following were included. The caller must clear before passing it in.
+ \param Tm (optional) U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object
+ \param Bc (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDCOLORS object or NULL
+ \param BfH (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDFACTORS (H) object or NULL
+ \param BfV (optional) U_PSEUDO_OBJ containing a U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.)
+
+
+ EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object
+
+
+ The rectangular gradients repeat in a tiled pattern. Tm can rotate and offset the gradient within each tile.
+ The gradient wraps when it is offset.
+
+*/
+U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_set(uint32_t *Flags, const U_PSEUDO_OBJ *Tm,
+ const U_PSEUDO_OBJ *Bc, const U_PSEUDO_OBJ *BfH, const U_PSEUDO_OBJ *BfV){
+ if(!Flags )return(NULL);
+ if(Tm && (Tm->Type != U_PMF_TRANSFORMMATRIX_OID))return(NULL);
+ if(Bc && (Bc->Type != U_PMF_BLENDCOLORS_OID) )return(NULL);
+ if(BfH && (BfH->Type != U_PMF_BLENDFACTORS_OID) )return(NULL);
+ if(BfV && (BfV->Type != U_PMF_BLENDFACTORS_OID) )return(NULL);
+ if(Bc && (BfH || BfV) )return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE},
+ {(Bc ? Bc->Data : NULL), (Bc ? Bc->Used : 0), 1, U_XE},
+ {(BfH ? BfH->Data : NULL), (BfH ? BfH->Used : 0), 1, U_XE},
+ {(BfV ? BfV->Data : NULL), (BfV ? BfV->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_OID, List);
+ if(Tm ){ *Flags |= U_BD_Transform; }
+ if(Bc ){ *Flags |= U_BD_PresetColors; }
+ if(BfH){ *Flags |= U_BD_BlendFactorsH; }
+ if(BfV){ *Flags |= U_BD_BlendFactorsV; }
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_LINEPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object
+
+
+ EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object
+*/
+U_PSEUDO_OBJ *U_PMF_LINEPATH_set(const U_PSEUDO_OBJ *Path){
+ if(!Path || (Path->Type != U_PMF_PATH_OID))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Path->Data, Path->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_LINEPATH_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_METAFILE object (NOT SUPPORTED!)
+ \return Null
+
+
+ EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object
+*/
+U_PSEUDO_OBJ *U_PMF_METAFILE_set(void){
+ return(NULL);
+}
+
+/**
+ \brief Create and set a U_PMF_PALETTE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags PaletteStyle flags
+ \param Elements Members in Lengths
+ \param Pd Array of U_PMF_ARGB holding colors of palettes. (Palette Data)
+
+ EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object
+*/
+U_PSEUDO_OBJ *U_PMF_PALETTE_set(uint32_t Flags, uint32_t Elements, const U_PMF_ARGB *Pd){
+ if(!Pd)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Flags, 4, 1, U_LE},
+ {&Elements, 4, 1, U_LE},
+ {Pd, 4, Elements, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PALETTE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PATHGRADIENTBRUSHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags PaletteStyle flags
+ \param WrapMode WrapMode enumeration
+ \param CenterColor U_PMF_ARGB Center color
+ \param Center Center coordinates
+ \param Gradient U_PSEUDO_OBJ containing an Array of U_PMF_ARGB holding colors of Gradient
+ \param Boundary U_PSEUDO_OBJ containing a U_PMF_BOUNDARYPATHDATA or U_PMF_BOUNDARYPOINTDATA object. (Boundary Data)
+ \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA, exact composition depends on Flags
+
+ EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHDATA_set(uint32_t Flags, int32_t WrapMode, U_PMF_ARGB CenterColor,
+ U_PMF_POINTF Center,
+ const U_PSEUDO_OBJ *Gradient, const U_PSEUDO_OBJ *Boundary, const U_PSEUDO_OBJ *Data){
+ if( (Flags & U_BD_Path) && (!Boundary || (Boundary->Type != U_PMF_BOUNDARYPATHDATA_OID)))return(NULL);
+ if(!(Flags & U_BD_Path) && (!Boundary || (Boundary->Type != U_PMF_BOUNDARYPOINTDATA_OID)))return(NULL);
+ if(!Gradient || (Gradient->Type != (U_PMF_ARGB_OID | U_PMF_ARRAY_OID)))return(NULL);
+ if(!(Flags & U_BD_Transform) &&
+ !(Flags & U_BD_PresetColors) &&
+ !(Flags & U_BD_BlendFactorsH) &&
+ !(Flags & U_BD_FocusScales) &&
+ (!Data || (Data->Type != U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_OID)))return(NULL);
+
+ const U_SERIAL_DESC List[] = {
+ {&Flags, 4, 1, U_LE},
+ {&WrapMode, 4, 1, U_LE},
+ {&CenterColor, 4, 1, U_XE},
+ {&Center.X, 4, 2, U_LE},
+ {Gradient->Data, Gradient->Used, 1, U_XE}, /* includes Elements */
+ {Boundary->Data, Boundary->Used, 1, U_XE},
+ {(Data ? Data->Data : NULL), (Data ? Data->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHGRADIENTBRUSHDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PATHGRADIENTBRUSHOPTIONALDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags PaletteStyle flags
+ \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix)
+ \param Pd U_PSEUDO_OBJ containing a U_PMF_BLENDCOLORS or U_PMF_BLENDFACTORS object. (Pattern Data)
+ \param Fsd U_PSEUDO_OBJ containing a U_PMF_FOCUSSSCALEDATA object. (Focus Scale Data)
+
+ EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_set(uint32_t Flags,
+ const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Pd, const U_PSEUDO_OBJ *Fsd){
+ if(Tm && (Tm->Type != U_PMF_TRANSFORMMATRIX_OID))return(NULL);
+ if(Pd && !(Flags & (U_BD_PresetColors | U_BD_BlendFactorsH)))return(NULL);
+ if( (Flags & U_BD_PresetColors) && ((Flags & U_BD_BlendFactorsH) || !Pd || (Pd->Type != U_PMF_BLENDCOLORS_OID) ))return(NULL);
+ if( (Flags & U_BD_BlendFactorsH) && ((Flags & U_BD_PresetColors) || !Pd || (Pd->Type != U_PMF_BLENDFACTORS_OID)))return(NULL);
+ if(Fsd && !(Flags & U_BD_FocusScales))return(NULL);
+ if( (Flags & U_BD_FocusScales) && (!Fsd || (Fsd->Type != U_PMF_BLENDCOLORS_OID) ))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE},
+ {(Pd ? Pd->Data : NULL), (Pd ? Pd->Used : 0), 1, U_XE},
+ {(Fsd ? Fsd->Data : NULL), (Fsd ? Fsd->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPE objects
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of entries in Flags and Enumerations
+ \param Ppt Array of unsigned bytes, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration.
+
+ EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set(uint32_t Elements, const uint8_t *Ppt){
+ if(!Elements || !Ppt)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Ppt, 1, Elements, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPE objects, with a preceding Elements count
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of elements to add. First is added once and Others Elements-1 times.
+ \param First Apply to first point, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration.
+ \param Others Apply to all other points, unsigned byte, lower 4 bits hold the PathPointType flag upper 4 bits hold the PathPointType enumeration.
+
+ EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set2(uint32_t Elements, uint8_t First, uint8_t Others){
+ if(!Elements)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_XE},
+ {&First, 1, 1, U_XE},
+ {&Others, 1, Elements-1, U_RP}, /* replicate the one value N-1 times */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PATHPOINTTYPE_OID | U_PMF_ARRAY_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_PATHPOINTTYPERLE objects
+ \return Pointer to PseudoObject containing first the number of elements, then an array of U_PMF_PATHPOINTTYPERLE, NULL on error
+ \param Elements Number of entries in the arrays
+ \param Bz Array of unsigned bytes, if not zero, element has Bezier bit set
+ \param RL Array of unsigned bytes, Run lengths.
+ \param Ppte Array of unsigned bytes, PathPointType enumerations.
+
+ EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object
+*/
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPERLE_set(uint32_t Elements, const uint8_t *Bz, const uint8_t *RL, const uint8_t *Ppte){
+ uint8_t utmp;
+ if(!Bz || !RL || !Ppte)return(NULL);
+ /* allocate space in the structure but put no data in */
+ U_PSEUDO_OBJ *po = U_PO_create(NULL, 4 + 2*Elements, 0, U_PMF_PATHPOINTTYPERLE_OID | U_PMF_ARRAY_OID);
+ U_PSEUDO_OBJ *holdpo = po;
+ if(po){
+ U_PSEUDO_OBJ *poi = U_PMF_4NUM_set(Elements);
+ if(!poi)goto end;
+ po = U_PO_append(po, poi->Data, poi->Used);
+ U_PO_free(&poi);
+ if(!po)goto end;
+
+ for( ;Elements; Elements--, Bz++, RL++, Ppte++){
+ po = U_PO_append(po, (char *)Ppte, 1);
+ if(!po)goto end;
+
+ if(*RL > 0x3F) goto end; /* run length too big for field */
+
+ utmp = (*Bz ? 1 : 0) | ((*RL & 0x3F)<<2); /* bit 1 is not used and is set to 0 */
+ po = U_PO_append(po, (char *)&utmp, 1);
+ if(!po)goto end;
+ }
+ }
+end:
+ if(!po)U_PO_free(&holdpo);
+ return(holdpo);
+}
+
+/**
+ \brief Create and set a U_PMF_PENDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Unit UnitType enumeration
+ \param Width Width in units set by Unit
+ \param Pod U_PSEUDO_OBJ containing first the PenData flags then a U_PMF_PENOPTIONALDATA object (the second part
+ may be an empty if Flags is 0)
+
+
+ EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object
+*/
+U_PSEUDO_OBJ *U_PMF_PENDATA_set(uint32_t Unit, U_FLOAT Width, const U_PSEUDO_OBJ *Pod){
+ if(Pod && ((Pod->Type != U_PMF_PENOPTIONALDATA_OID) || Pod->Used < 4))return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {(Pod ? Pod->Data : NULL), 4, 1, U_XE}, /* the Flags field, clear if no optional data */
+ {&Unit, 4, 1, U_LE},
+ {&Width, 4, 1, U_LE},
+ /* next is the (optional) U_PMF_PENOPTIONALDATA part or a terminator */
+ {(Pod ? Pod->Data + 4 : NULL), (Pod ? Pod->Used - 4 : 0), (Pod ? 1 : 0), (Pod ? U_XE : U_XX)},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PENDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_PENOPTIONALDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error. Returned PO contains first the Flags, then the PO proper.
+ \param Flags Determines which of the values are stored.
+ \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object (Transformation matrix)
+ \param StartCap LineCapType enumeration
+ \param EndCap LineCapType enumeration
+ \param Join LineJoinType enumeration
+ \param MiterLimit Maximum (miter length / line width)
+ \param Style LineStyle enumeration
+ \param DLCap DashedLineCapType enumeration
+ \param DLOffset Distance line start to first dash start
+ \param DLData U_PSEUDO_OBJ containing a U_PMF_DASHEDLINEDATA object Dash and space widths
+ \param PenAlignment PenAlignment enumeration
+ \param CmpndLineData U_PSEUDO_OBJ containing a U_PMF_COMPOUNDLINEDATA object Compount Line (parallel lines drawn instead of one)
+ \param CSCapData U_PSEUDO_OBJ containing a U_PMF_CUSTOMSTARTCAPDATA object Custom start cap
+ \param CECapData U_PSEUDO_OBJ containing a U_PMF_CUSTOMENDCAPDATA object Custom end cap
+
+
+ EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object
+*/
+U_PSEUDO_OBJ *U_PMF_PENOPTIONALDATA_set(uint32_t Flags, U_PSEUDO_OBJ *Tm, int32_t StartCap, int32_t EndCap, uint32_t Join,
+ U_FLOAT MiterLimit, int32_t Style, int32_t DLCap, U_FLOAT DLOffset,
+ U_PSEUDO_OBJ *DLData, int32_t PenAlignment, U_PSEUDO_OBJ *CmpndLineData, U_PSEUDO_OBJ *CSCapData,
+ U_PSEUDO_OBJ *CECapData
+ ){
+
+ if((Flags & U_PD_Transform) && (!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)) )return(NULL);
+ if((Flags & U_PD_DLData) && (!DLData || (DLData->Type != U_PMF_DASHEDLINEDATA_OID)) )return(NULL);
+ if((Flags & U_PD_CLData) && (!CmpndLineData || (CmpndLineData->Type != U_PMF_COMPOUNDLINEDATA_OID)) )return(NULL);
+ if((Flags & U_PD_CustomStartCap) && (!CSCapData || (CSCapData->Type != U_PMF_CUSTOMSTARTCAPDATA_OID)))return(NULL);
+ if((Flags & U_PD_CustomEndCap) && (!CECapData || (CECapData->Type != U_PMF_CUSTOMENDCAPDATA_OID)) )return(NULL);
+
+ /* prepend the Flags field to the PseudoObject proper */
+ const U_SERIAL_DESC List[] = {
+ {&Flags, 4, 1, U_LE},
+ {((Flags & U_PD_Transform) ? Tm->Data : NULL), ((Flags & U_PD_Transform) ? Tm->Used : 0), 1, U_XE},
+ {((Flags & U_PD_StartCap ) ? (char *)&StartCap : NULL), ((Flags & U_PD_StartCap ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_EndCap ) ? (char *)&EndCap : NULL), ((Flags & U_PD_EndCap ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_Join ) ? (char *)&Join : NULL), ((Flags & U_PD_Join ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_MiterLimit ) ? (char *)&MiterLimit : NULL), ((Flags & U_PD_MiterLimit ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_LineStyle ) ? (char *)&Style : NULL), ((Flags & U_PD_LineStyle ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_DLCap ) ? (char *)&DLCap : NULL), ((Flags & U_PD_DLCap ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_DLOffset ) ? (char *)&DLOffset : NULL), ((Flags & U_PD_DLOffset ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_DLData ) ? DLData->Data : NULL), ((Flags & U_PD_DLData ) ? DLData->Used : 0), 1, U_XE},
+ {((Flags & U_PD_NonCenter ) ? (char *)&PenAlignment : NULL), ((Flags & U_PD_NonCenter ) ? 4 : 0), 1, U_LE},
+ {((Flags & U_PD_CLData ) ? CmpndLineData->Data : NULL), ((Flags & U_PD_CLData ) ? CmpndLineData->Used : 0), 1, U_XE},
+ {((Flags & U_PD_CustomStartCap) ? CSCapData->Data : NULL), ((Flags & U_PD_CustomStartCap) ? CSCapData->Used : 0), 1, U_XE},
+ {((Flags & U_PD_CustomEndCap ) ? CECapData->Data : NULL), ((Flags & U_PD_CustomEndCap ) ? CECapData->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_PENOPTIONALDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_POINT objects
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of pairs of points in Coords
+ \param Coords Array of X,Y pairs.
+
+ EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object
+*/
+U_PSEUDO_OBJ *U_PMF_POINT_set(uint32_t Elements, const U_PMF_POINT *Coords){
+ if(!Elements || !Coords)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ { Coords, 2, 2*Elements, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_POINT_OID | U_PMF_ARRAY_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_POINTF objects, with a leading Elements value
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of pairs of points in Coords
+ \param Coords Array of X,Y pairs.
+
+ EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object
+*/
+U_PSEUDO_OBJ *U_PMF_POINTF_set(uint32_t Elements, const U_PMF_POINTF *Coords){
+ if(!Elements || !Coords)return(NULL);
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Coords, 4, 2*Elements, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_POINTF_OID | U_PMF_ARRAY_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an ARRAY of U_PMF_POINTR objects
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of pairs of points in Coords
+ \param Coords Array of X,Y pairs. These are absolute coordinates, they are converted to Relative here.
+
+ EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object
+*/
+U_PSEUDO_OBJ *U_PMF_POINTR_set(uint32_t Elements, const U_PMF_POINTF *Coords){
+ int X,Y;
+ U_FLOAT Xf,Yf;
+ U_PSEUDO_OBJ *poi;
+ /* Worst case scenario it is 4 bytes per coord, plus the count */
+ U_PSEUDO_OBJ *po = U_PO_create(NULL, 4 + 4*Elements, 0, U_PMF_POINTR_OID); /* not exactly an array, so no U_PMF_ARRAY_OID */
+ U_PSEUDO_OBJ *holdpo = po;
+ if(!po)goto end;
+
+ poi = U_PMF_4NUM_set(Elements);
+ po = U_PO_append(po, poi->Data, poi->Used);
+ U_PO_free(&poi);
+ if(!po)goto end;
+
+ for(Xf = Yf = 0.0 ;Elements; Elements--, Coords++){
+ Xf = U_ROUND(Coords->X) - Xf;
+ Yf = U_ROUND(Coords->Y) - Yf;
+ X = ( Xf >= UINT16_MAX ? UINT16_MAX : ( Xf <= INT16_MIN ? INT16_MIN : Xf));
+ Y = ( Yf >= UINT16_MAX ? UINT16_MAX : ( Yf <= INT16_MIN ? INT16_MIN : Yf));
+ Xf = U_ROUND(Coords->X);
+ Yf = U_ROUND(Coords->Y);
+
+ /* this is not a very efficient method, too much mucking around with memory */
+
+ poi = U_PMF_INTEGER7_set(X);
+ if(!poi)poi = U_PMF_INTEGER15_set(X); /* This one must work because of the range checking, above */
+ po = U_PO_append(po, poi->Data, poi->Used);
+ U_PO_free(&poi);
+ if(!po)goto end;
+
+ poi = U_PMF_INTEGER7_set(Y);
+ if(!poi)poi = U_PMF_INTEGER15_set(Y); /* This one must work because of the range checking, above */
+ po = U_PO_append(po, poi->Data, poi->Used);
+ U_PO_free(&poi);
+ if(!po)goto end;
+ }
+ /* Because the values stored were some unpredictable combination of 1 and 2 bytes, the last byte may not end
+ on a 4 byte boundary. Make it do so by padding with up to 3 zero bytes. */
+
+ int residual;
+ residual = 3 & po->Used;
+ if(residual){
+ po = U_PO_append(po, NULL, (4 - residual));
+ if(!po)goto end;
+ }
+
+end:
+ if(!po)U_PO_free(&holdpo);
+ return(holdpo);
+}
+
+/**
+ \brief Create and set a U_PMF_RECT object
+ \return Pointer to PseudoObject, NULL on error
+ \param X UL X value
+ \param Y UL Y value
+ \param Width Width
+ \param Height Height
+
+ EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECT4_set(int16_t X, int16_t Y, int16_t Width, int16_t Height){
+ const U_SERIAL_DESC List[] = {
+ {&X, 2, 1, U_LE},
+ {&Y, 2, 1, U_LE},
+ {&Width, 2, 1, U_LE},
+ {&Height, 2, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_RECT object
+ \return Pointer to PseudoObject, NULL on error
+ \param Rect U_PMF_RECT structures
+
+ EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECT_set(U_PMF_RECT *Rect){
+ const U_SERIAL_DESC List[] = {
+ {Rect, 2, 4, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an array of U_PMF_RECT objects in a PseudoObject
+ \return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECT objects.
+ \param Elements Number of elements in Rects
+ \param Rects Array of U_PMF_RECT structures
+
+ EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECTN_set(uint32_t Elements, U_PMF_RECT *Rects){
+ if(!Rects){ return(NULL); }
+ uint32_t count = Elements;
+ U_SERIAL_DESC *List = (U_SERIAL_DESC *) malloc((Elements + 2) * sizeof(U_SERIAL_DESC));
+ U_SERIAL_DESC *Lptr = List;
+ if(!List){ return(NULL); }
+ *Lptr++ = (U_SERIAL_DESC){&Elements, 4, 1, U_LE};
+ for(; count; count--, Lptr++, Rects++){
+ *Lptr = (U_SERIAL_DESC){Rects, 2, 4, U_LE};
+ }
+ *Lptr = (U_SERIAL_DESC){NULL,0,0,U_XX};
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECT_OID | U_PMF_ARRAY_OID, List);
+ free(List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_RECTF object in a PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param X UL X value
+ \param Y UL Y value
+ \param Width Width
+ \param Height Height
+
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECTF4_set(U_FLOAT X, U_FLOAT Y, U_FLOAT Width, U_FLOAT Height){
+ const U_SERIAL_DESC List[] = {
+ {&X, 4, 1, U_LE},
+ {&Y, 4, 1, U_LE},
+ {&Width, 4, 1, U_LE},
+ {&Height, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_RECTF object in a PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Rect U_PMF_RECTF structure
+
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECTF_set(U_PMF_RECTF *Rect){
+ const U_SERIAL_DESC List[] = {
+ {Rect, 4, 4, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set an array of U_PMF_RECTF objects in a PseudoObject
+ \return Pointer to PseudoObject, NULL on error. PseudoObject contains Elements followed by the array of U_PMF_RECTF objects.
+ \param Elements Number of elements in Rects
+ \param Rects Array of U_PMF_RECTF structures
+
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+U_PSEUDO_OBJ *U_PMF_RECTFN_set(uint32_t Elements, U_PMF_RECTF *Rects){
+ if(!Rects){ return(NULL); }
+ uint32_t count = Elements;
+ U_SERIAL_DESC *List = (U_SERIAL_DESC *) malloc((Elements + 2) * sizeof(U_SERIAL_DESC));
+ U_SERIAL_DESC *Lptr = List;
+ if(!List){ return(NULL); }
+ *Lptr++ = (U_SERIAL_DESC){&Elements, 4, 1, U_LE};
+ for(; count; count--, Lptr++, Rects++){
+ *Lptr = (U_SERIAL_DESC){Rects, 4, 4, U_LE};
+ }
+ *Lptr = (U_SERIAL_DESC){NULL,0,0,U_XX};
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_RECTF_OID | U_PMF_ARRAY_OID, List);
+ free(List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_REGIONNODE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Type RegionNodeDataType Enumeration
+ \param Rnd (optional) U_PSEUDO_OBJ containing a U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES object (Region Node Data)
+
+
+ EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object
+*/
+U_PSEUDO_OBJ *U_PMF_REGIONNODE_set(int32_t Type, const U_PSEUDO_OBJ *Rnd){
+ int32_t pType;
+ /* make sure that the type of Rnd agrees with Type */
+ if(Rnd){
+ pType = U_OID_To_RNDT(Rnd->Type);
+ if( pType < 0){ return(NULL); }
+ if((pType > 0) && (pType != Type)){ return(NULL); }
+ if((pType == 0) &&
+ (
+ (Type < U_RNDT_And) ||
+ (Type > U_RNDT_Complement)
+ )
+ ){ return(NULL); }
+ if((Type == U_RNDT_Rect) && (Rnd->Type != U_PMF_RECTF_OID)){ return(NULL); }
+ if((Type == U_RNDT_Path) && (Rnd->Type != U_PMF_REGIONNODEPATH_OID)){ return(NULL); }
+
+ }
+ else { /* only U_RNDT_Empty and U_RNDT_Infinite do not have data */
+ if((Type != U_RNDT_Empty) ||
+ (Type != U_RNDT_Infinite) ){ return(NULL); }
+ }
+
+
+ const U_SERIAL_DESC List[] = {
+ {&Type, 4, 1, U_LE},
+ {(Rnd ? Rnd->Data : NULL), (Rnd ? Rnd->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_REGIONNODECHILDNODES PseudoObject
+ \return Pointer to PseudoObject containing a U_PMF_REGIONNODECHILDNODES_OID object, NULL on error
+ \param Left U_PSEUDO_OBJ containing a U_PMF_REGIONNODE object
+ \param Right U_PSEUDO_OBJ containing a U_PMF_REGIONNODE object
+
+
+ EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object
+*/
+U_PSEUDO_OBJ *U_PMF_REGIONNODECHILDNODES_set(const U_PSEUDO_OBJ *Left, const U_PSEUDO_OBJ *Right){
+ if(!Left || (Left->Type != U_PMF_REGIONNODE_OID)){ return(NULL); }
+ if(!Right || (Right->Type != U_PMF_REGIONNODE_OID)){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {Left->Data, Left->Used, 1, U_XE},
+ {Right->Data, Right->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODECHILDNODES_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_REGIONNODEPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Path U_PSEUDO_OBJ containing a U_PMF_PATH object
+
+
+ EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object
+*/
+U_PSEUDO_OBJ *U_PMF_REGIONNODEPATH_set(const U_PSEUDO_OBJ *Path){
+ if(!Path || (Path->Type != U_PMF_PATH_OID)){ return(NULL); }
+ /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */
+ uint32_t Used = Path->Used;
+
+ const U_SERIAL_DESC List[] = {
+ {&Used, 4, 1, U_LE},
+ {Path->Data, Path->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_REGIONNODEPATH_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_SOLIDBRUSHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Color U_PSEUDO_OBJ containing a U_PMF_ARGB object
+
+
+ EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object
+*/
+U_PSEUDO_OBJ *U_PMF_SOLIDBRUSHDATA_set(const U_PSEUDO_OBJ *Color){
+ if(!Color || (Color->Type != U_PMF_ARGB_OID)){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {Color->Data, Color->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_SOLIDBRUSHDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_STRINGFORMATDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param TabStopCount Entries in TabStop array
+ \param TabStops (optional) Array of tabstop locations
+ \param Ranges (optional) U_PSEUDO_OBJ containing an array of U_PMF_CHARACTERRANGE objects
+
+
+ EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object
+*/
+U_PSEUDO_OBJ *U_PMF_STRINGFORMATDATA_set(uint32_t TabStopCount, U_FLOAT *TabStops, const U_PSEUDO_OBJ *Ranges){
+ if(Ranges && (Ranges->Type != (U_PMF_CHARACTERRANGE_OID | U_PMF_ARRAY_OID))){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {TabStops, TabStopCount*4, 1, U_LE},
+ {(Ranges ? Ranges->Data : NULL), (Ranges ? Ranges->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_STRINGFORMATDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_TEXTUREBRUSHDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Flags BrushData flags
+ \param WrapMode WrapMode enumeration
+ \param Tbod U_PSEUDO_OBJ containing an U_PMF_TEXTUREBRUSHOPTIONALDATA object
+
+
+ EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object
+*/
+U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHDATA_set(uint32_t Flags, uint32_t WrapMode, const U_PSEUDO_OBJ *Tbod){
+ if(Flags & ~U_BD_MASKB){ return(NULL); } /* a bit was set that is not supported for this record */
+ if(WrapMode > U_WM_Clamp){ return(NULL); }
+ if(!Tbod || (Tbod->Type != (U_PMF_TEXTUREBRUSHOPTIONALDATA_OID))){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {&Flags, 4, 1, U_LE},
+ {&WrapMode, 4, 1, U_LE},
+ {Tbod->Data, Tbod->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TEXTUREBRUSHDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_TEXTUREBRUSHOPTIONALDATA PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Tm (optional) U_PSEUDO_OBJ containing an U_PMF_TRANSFORMMATRIX object
+ \param Image (optional) U_PSEUDO_OBJ containing an U_PMF_IMAGE object
+
+
+ EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object
+*/
+U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHOPTIONALDATA_set(const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Image){
+ if(Tm && (Tm->Type != (U_PMF_TRANSFORMMATRIX_OID))){ return(NULL); }
+ if(Image && (Image->Type != (U_PMF_IMAGE_OID))){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {(Tm ? Tm->Data : NULL), (Tm ? Tm->Used : 0), 1, U_XE},
+ {(Image ? Image->Data : NULL), (Image ? Image->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TEXTUREBRUSHOPTIONALDATA_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_TRANSFORMMATRIX PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Tm U_PMF_TRANSFORMMATRIX_ object
+
+
+ EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object
+*/
+U_PSEUDO_OBJ *U_PMF_TRANSFORMMATRIX_set(U_PMF_TRANSFORMMATRIX *Tm){
+ if(!Tm){ return(NULL); }
+
+ const U_SERIAL_DESC List[] = {
+ {Tm, 4, 6, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_TRANSFORMMATRIX_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_BLUR PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Radius Blur radius in pixels
+ \param ExpandEdge 1: expand bitmap by Radius; 0: bitmap size unchanged
+
+
+ EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_BLUR_set(U_FLOAT Radius, uint32_t ExpandEdge){
+
+ const U_SERIAL_DESC List[] = {
+ {&Radius, 4, 1, U_LE},
+ {&ExpandEdge, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_BLUR_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_BRIGHTNESSCONTRAST PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Brightness -255 to 255, 0 is unchanged, positive increases, negative decreases
+ \param Contrast -100 to 100, 0 is unchanged, positive increases, negative decreases
+
+
+ EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_BRIGHTNESSCONTRAST_set(int32_t Brightness, int32_t Contrast){
+
+ const U_SERIAL_DESC List[] = {
+ {&Brightness, 4, 1, U_LE},
+ {&Contrast, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_BRIGHTNESSCONTRAST_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_COLORBALANCE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param CyanRed -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite
+ \param MagentaGreen -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite
+ \param YellowBlue -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite
+
+
+ EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_COLORBALANCE_set(int32_t CyanRed, int32_t MagentaGreen, int32_t YellowBlue){
+
+ const U_SERIAL_DESC List[] = {
+ {&CyanRed, 4, 1, U_LE},
+ {&MagentaGreen, 4, 1, U_LE},
+ {&YellowBlue, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORBALANCE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_COLORCURVE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Adjust CurveAdjustment enumeration
+ \param Channel CurveChannel enumeration
+ \param Intensity adjustment to apply. "Adjust" determines what field this is and range values.
+
+
+ EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_COLORCURVE_set(uint32_t Adjust, uint32_t Channel, int32_t Intensity){
+
+ const U_SERIAL_DESC List[] = {
+ {&Adjust, 4, 1, U_LE},
+ {&Channel, 4, 1, U_LE},
+ {&Intensity, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORCURVE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_COLORLOOKUPTABLE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param BLUT Blue color lookup table
+ \param GLUT Green color lookup table
+ \param RLUT Red color lookup table
+ \param ALUT Alpha color lookup table
+
+
+
+ EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object.
+ All tables have 256 entries.
+*/
+U_PSEUDO_OBJ *U_PMF_IE_COLORLOOKUPTABLE_set(const uint8_t *BLUT, const uint8_t *GLUT, const uint8_t *RLUT, const uint8_t *ALUT){
+ if(!BLUT || !GLUT || !RLUT || !ALUT)return(NULL);
+
+ const U_SERIAL_DESC List[] = {
+ {BLUT, 1, 256, U_XE},
+ {GLUT, 1, 256, U_XE},
+ {RLUT, 1, 256, U_XE},
+ {ALUT, 1, 256, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORLOOKUPTABLE_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_COLORMATRIX PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Matrix 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0]
+
+
+ EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_COLORMATRIX_set(const U_FLOAT *Matrix){
+ if(!Matrix)return(NULL);
+
+ const U_SERIAL_DESC List[] = {
+ {Matrix, 4, 25, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_COLORMATRIX_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_HUESATURATIONLIGHTNESS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Hue -180 to 180, 0 is unchanged
+ \param Saturation -100 to 100, 0 is unchanged
+ \param Lightness -100 to 100, 0 is unchanged
+
+
+ EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_HUESATURATIONLIGHTNESS_set(int32_t Hue, int32_t Saturation, int32_t Lightness){
+
+ const U_SERIAL_DESC List[] = {
+ {&Hue, 4, 1, U_LE},
+ {&Saturation, 4, 1, U_LE},
+ {&Lightness, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_HUESATURATIONLIGHTNESS_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_LEVELS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Highlight 0 to 100, 100 is unchanged
+ \param Midtone -100 to 0, 0 is unchanged
+ \param Shadow 0 to 100, 0 is unchanged
+
+
+ EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_LEVELS_set(int32_t Highlight, int32_t Midtone, int32_t Shadow){
+
+ const U_SERIAL_DESC List[] = {
+ {&Highlight, 4, 1, U_LE},
+ {&Midtone, 4, 1, U_LE},
+ {&Shadow, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_LEVELS_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_REDEYECORRECTION PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Elements Number of members in Rects
+ \param Rects Array of U_RECTL rectangular area(s) to apply red eye correction
+
+
+ EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_REDEYECORRECTION_set(uint32_t Elements, const U_RECTL *Rects){
+ if(!Elements || !Rects){return(NULL);}
+
+ const U_SERIAL_DESC List[] = {
+ {&Elements, 4, 1, U_LE},
+ {Rects, 4*4, Elements,U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_REDEYECORRECTION_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_SHARPEN PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Radius Sharpening radius in pixels
+ \param Sharpen 0 to 100, 0 is unchanged
+
+
+ EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_SHARPEN_set(U_FLOAT Radius, int32_t Sharpen){
+
+ const U_SERIAL_DESC List[] = {
+ {&Radius, 4, 1, U_LE},
+ {&Sharpen, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_SHARPEN_OID, List);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMF_IE_TINT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Hue -180 to 180, [positive==clockwise] rotation in degrees starting from blue
+ \param Amount -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis
+
+
+ EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object
+*/
+U_PSEUDO_OBJ *U_PMF_IE_TINT_set(const int32_t Hue, const int32_t Amount){
+
+ const U_SERIAL_DESC List[] = {
+ {&Hue, 4, 1, U_LE},
+ {&Amount, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMF_IE_TINT_OID, List);
+ return(po);
+}
+
+//! \cond
+/* internal routine, not part of the API.
+ Returns a PseudoObject containing a U_PMR_CMN_HDR_OID object.
+ The type is something like U_PMR_OFFSETCLIP (the record type, NOT the U_PMR_OFFSETCLIP_OID PseudoObject Type!).
+ The U_PMR_RECFLAG bit is added both in the data and in the Type of the PseudoObject.
+ If that bit is already set no harm, no foul.
+*/
+
+U_PSEUDO_OBJ *U_PMR_CMN_HDR_set(uint32_t Type, uint16_t Flags, uint32_t DataSize){
+
+ uint32_t Size = 12 + UP4(DataSize); /* The header itself is always 12, PMR records must be a multiple of 4 */
+ Type |= U_PMR_RECFLAG;
+ uint16_t utmp16 = Type;
+ const U_SERIAL_DESC List[] = {
+ {&utmp16, 2, 1, U_LE},
+ {&Flags, 2, 1, U_LE}, /* Microsoft EMF+ manual is BE, but this field in this implementation is LE */
+ {&Size, 4, 1, U_LE},
+ {&DataSize, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_CMN_HDR_OID, List);
+ return(po);
+}
+//! \endcond
+
+
+/**
+ \brief Create and set a U_PMR_STROKEFILLPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+
+
+ EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37
+
+ "This record closes any open figures in a path, strokes the outline of
+ the path by using the current pen, and fills its interior by using the current brush."
+
+*/
+U_PSEUDO_OBJ *U_PMR_STROKEFILLPATH_set(void){
+ int Size = 0;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_STROKEFILLPATH,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_STROKEFILLPATH_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_OFFSETCLIP PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param dX horizontal translation offset to apply to clipping region
+ \param dY vertical translation offset to apply to clipping region
+
+
+ EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35
+*/
+U_PSEUDO_OBJ *U_PMR_OFFSETCLIP_set(U_FLOAT dX, U_FLOAT dY){
+ int Size = 2*4;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_OFFSETCLIP,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&dX, 4, 1, U_LE},
+ {&dY, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_OFFSETCLIP_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_RESETCLIP PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+
+
+ EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31
+*/
+U_PSEUDO_OBJ *U_PMR_RESETCLIP_set(void){
+ int Size = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESETCLIP,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESETCLIP_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETCLIPPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param CMenum CombineMode enumeration..
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+
+
+ EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33
+*/
+U_PSEUDO_OBJ *U_PMR_SETCLIPPATH_set(uint32_t PathID, uint32_t CMenum){
+ if(PathID>63)return(NULL);
+ int Size=0;
+ uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPPATH,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPPATH_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETCLIPRECT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param CMenum CombineMode enumeration..
+ \param Rect U_PSEUDO_OBJ containing an U_PMF_RECTF object or an array of U_PMF_RECTF objects (the first is used)
+
+
+ EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32
+*/
+U_PSEUDO_OBJ *U_PMR_SETCLIPRECT_set(uint32_t CMenum, const U_PSEUDO_OBJ *Rect){
+ int Size=4*4;
+ const char *start;
+ uint16_t utmp16 = ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4);
+ if(Rect){
+ if( Rect->Type == U_PMF_RECTF_OID){
+ start = Rect->Data;
+ }
+ else if(Rect->Type == (U_PMF_RECTF_OID | U_PMF_ARRAY_OID)){
+ start = Rect->Data + 4;
+ }
+ else { return(0); }
+ }
+ else { return(0); }
+
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPRECT,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {start, 4, 4, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPRECT_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETCLIPREGION PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param CMenum CombineMode enumeration..
+
+
+ EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34
+*/
+U_PSEUDO_OBJ *U_PMR_SETCLIPREGION_set(uint32_t PathID, uint32_t CMenum){
+ if(PathID>63)return(NULL);
+ int Size=0;
+ uint16_t utmp16 = ((PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8) | ((CMenum & U_FF_MASK_CM4) << U_FF_SHFT_CM4);
+
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCLIPREGION,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCLIPREGION_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_COMMENT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param cbData Number of bytes in Data, must be a multiple of 4
+ \param Data Private data, may be anything. Stored in PseudoObject without adjusting byte order.
+
+
+ EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03
+*/
+U_PSEUDO_OBJ *U_PMR_COMMENT_set(size_t cbData, const void *Data){
+ if(UP4(cbData) != cbData){ return(NULL); }
+ if(cbData && !Data){ return(NULL); }
+ int Size=cbData;
+
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_COMMENT,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Data, cbData, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_COMMENT_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_ENDOFFILE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+
+
+ EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02
+*/
+U_PSEUDO_OBJ *U_PMR_ENDOFFILE_set(void){
+ int Size=0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ENDOFFILE,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ENDOFFILE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_GETDC PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+
+
+ EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04
+*/
+U_PSEUDO_OBJ *U_PMR_GETDC_set(void){
+ int Size=0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_GETDC,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_GETDC_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_HEADER PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param IsDual set = Dual-mode file, clear= EMF+ only file.
+ \param IsVideo set = video device, clear= printer. Ignore all other bits.
+ \param Version U_PSEUDO_OBJ containing a U_PMF_GRAPHICSVERSION object
+ \param LogicalDpiX Horizontal resolution reference device in DPI
+ \param LogicalDpiY Vertical resolution reference device in DPI
+
+
+ EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01
+*/
+U_PSEUDO_OBJ *U_PMR_HEADER_set(int IsDual, int IsVideo, const U_PSEUDO_OBJ *Version,
+ uint32_t LogicalDpiX, uint32_t LogicalDpiY){
+ if(!Version || (Version->Type != U_PMF_GRAPHICSVERSION_OID)){ return(NULL); }
+ int Size=Version->Used + 3*4;
+ uint16_t utmp16 = (IsDual ? U_PPF_DM : 0);
+ uint32_t Flags = (IsVideo ? U_PPF_VIDEO : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_HEADER,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Version->Data, Version->Used, 1, U_XE},
+ {&Flags, 4, 1, U_LE},
+ {&LogicalDpiX, 4, 1, U_LE},
+ {&LogicalDpiY, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_HEADER_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_CLEAR PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Color U_PSEUDO_OBJ containing a U_PMF_ARGB object.
+
+
+
+ EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09
+
+ Erase everything preceding, set background ARGB to Color.
+*/
+U_PSEUDO_OBJ *U_PMR_CLEAR_set(const U_PSEUDO_OBJ *Color){
+ if(!Color || (Color->Type != U_PMF_ARGB_OID)){ return(NULL); }
+ int Size=Color->Used;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_CLEAR,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Color->Data, Color->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_CLEAR_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWARC PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWARC_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect){
+ int ctype;
+ if(PenID>63)return(NULL);
+ if(!Rect){ return(NULL); }
+ else {
+ if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ int Size = 2*4 + Rect->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWARC,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Start, 4, 1, U_LE},
+ {&Sweep, 4, 1, U_LE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWARC_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWBEZIERS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Points U_PSEUDO_OBJ containing first Elements, then a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object
+
+
+ EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWBEZIERS_set(uint32_t PenID, const U_PSEUDO_OBJ *Points){
+ int ctype, RelAbs;
+ if(PenID>63)return(NULL);
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = Points->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWBEZIERS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Points->Data, Points->Used, 1, U_XE}, /* Includes Elements */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWBEZIERS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWCLOSEDCURVE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Points U_PSEUDO_OBJ containing a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object
+
+
+ EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17
+
+ Curve is a cardinal spline.
+
+ References sent by MS support:
+
+ http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+
+ http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+
+
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWCLOSEDCURVE_set(uint32_t PenID, U_FLOAT Tension, const U_PSEUDO_OBJ *Points){
+ int ctype, RelAbs;
+ if(PenID>63)return(NULL);
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = 4 + Points->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (RelAbs ? U_PPF_P : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWCLOSEDCURVE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Tension, 4, 1, U_LE},
+ {Points->Data, Points->Used, 1, U_XE}, /* includes Elements*/
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWCLOSEDCURVE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWCURVE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Offset The starting point in the list of points, 0 is first.
+ \param NSegs Number of segments to draw. Starting at Offset go NSegs straight lines, must not run out of points..
+ \param Points U_PSEUDO_OBJ containing an element count then a series of U_PMF_POINT or U_PMF_POINTF object
+
+
+ EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18
+
+ Curve is a cardinal spline, using doubled terminator points to generate curves for the terminal segments.
+
+ References sent by MS support:
+
+ http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+
+ http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension, uint32_t Offset, uint32_t NSegs, const U_PSEUDO_OBJ *Points){
+ int ctype;
+ if(PenID>63)return(NULL);
+ if(!Points){ return(NULL); }
+ if(!NSegs){ return(NULL); }
+ else {
+ if( Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ ctype = 0; }
+ else { return(NULL); }
+ }
+ uint32_t Elements = (Points->Used - 4)/(ctype ? 4 : 8); /* This way do not need to worry about byte order */
+ if(Offset + NSegs + 1 > Elements){ return(NULL); }
+ int Size = 3*4 + Points->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) |(PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWCURVE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Tension, 4, 1, U_LE},
+ {&Offset, 4, 1, U_LE},
+ {&NSegs, 4, 1, U_LE},
+ {Points->Data, Points->Used, 1, U_XE}, /* Elements, points */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWCURVE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWDRIVERSTRING PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param DSOFlags DriverStringOptions flags
+ \param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not.
+ \param GlyphCount The number of Elements in Glyphs, must agree with the number of elements in Points.
+ \param Glyphs If U_DSO_CmapLookup is set in DSOFlags this is an array of UTF16LE characters, otherwise, it is an array of indices into the U_PMF_FONT object indexed by Object_ID in flags.
+ \param Points U_PSEUDO_OBJ containing a U_PMF_POINTF object
+ \param Tm U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX object. Apply to Glyphs & Positions. Present if HasMatrix is 1
+
+
+ EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
+ uint32_t DSOFlags, uint32_t HasMatrix, uint32_t GlyphCount,
+ const uint16_t *Glyphs, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Tm){
+ int btype;
+ if(FontID>63){ return(NULL); }
+ if(!Glyphs){ return(NULL); }
+ if(!Points || (Points->Type != (U_PMF_POINTF_OID | U_PMF_ARRAY_OID))){ return(NULL); }
+ uint32_t Elements = (Points->Used -4)/4;
+ if(GlyphCount != Elements){ return(NULL); }
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = 4 + BrushID->Used + 3*4 + Elements*2 + (Points->Used - 4);
+ if(HasMatrix){
+ if(!Tm){ return(NULL); }
+ else if(Tm->Type != (U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); }
+ Size += Tm->Used;
+ }
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) |(FontID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWDRIVERSTRING,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data,ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {&DSOFlags, 4, 1, U_LE},
+ {&HasMatrix, 4, 1, U_LE},
+ {&Elements, 4, 1, U_LE},
+ {Glyphs, 2, Elements, U_LE},
+ {Points->Data + 4, Points->Used - 4, 1, U_XE}, /* omit Elements */
+ {(HasMatrix ? Tm->Data : NULL), (HasMatrix ? Tm->Used : 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWDRIVERSTRING_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWELLIPSE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWELLIPSE_set(uint32_t PenID, const U_PSEUDO_OBJ *Rect){
+ if(PenID>63)return(NULL);
+ int ctype;
+ if(!Rect){ return(NULL); }
+ else {
+ if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ int Size = Rect->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWELLIPSE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWELLIPSE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWIMAGE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive)
+ \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table
+ \param SrcUnit UnitType enumeration
+ \param SrcRect U_PSEUDO_OBJ containing a U_PMF_RECTF object, Source region of image
+ \param DstRect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWIMAGE_set(uint32_t ImgID,
+ int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect, const U_PSEUDO_OBJ *DstRect){
+ int ctype;
+ if(ImgID>63)return(NULL);
+ if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); }
+ if(!DstRect){ return(NULL); }
+ else {
+ if( DstRect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(DstRect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ int Size = 2*4 + SrcRect->Used + DstRect->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (ImgID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWIMAGE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&ImgAttrID, 4, 1, U_LE},
+ {&SrcUnit, 4, 1, U_LE},
+ {SrcRect->Data, SrcRect->Used, 1, U_XE},
+ {DstRect->Data, DstRect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWIMAGE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWIMAGEPOINTS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive)
+ \param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied
+ \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table
+ \param SrcUnit UnitType enumeration
+ \param SrcRect U_PSEUDO_OBJ containing a U_PMF_RECTF object, Source region of image
+ \param Points U_PSEUDO_OBJ containing an array of 3 (U_PMF_POINT, U_PMF_POINTF, or U_PMF_POINTF) objects. These points are the UL, UR, and LL vertices of a parallelogram.
+
+
+ EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B
+
+
+ WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
+ file is inserted as an image into PowerPoint.
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWIMAGEPOINTS_set(uint32_t ImgID, int etype,
+ int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect,
+ const U_PSEUDO_OBJ *Points){
+ int ctype, RelAbs;
+ if(ImgID>63){ return(NULL); }
+ if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); }
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = 2*4 + SrcRect->Used + Points->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (etype ? U_PPF_E : 0) | (RelAbs ? U_PPF_P : 0) | (ImgID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWIMAGEPOINTS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&ImgAttrID, 4, 1, U_LE},
+ {&SrcUnit, 4, 1, U_LE},
+ {SrcRect->Data, SrcRect->Used, 1, U_XE},
+ {Points->Data, Points->Used, 1, U_XE}, /* includes Elements*/
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWIMAGEPOINTS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWLINES PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param dtype Set: path must be closed, Clear: path is open
+ \param Points U_PSEUDO_OBJ containing an array of 3 U_PMF_POINT, U_PMF_POINTR, or U_PMF_POINTF objects
+
+
+ EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWLINES_set(uint32_t PenID, int dtype, const U_PSEUDO_OBJ *Points){
+ int ctype, RelAbs;
+ if(PenID>63){ return(NULL); }
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = Points->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (dtype ? U_PPF_D : 0) | (RelAbs ? U_PPF_P : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWLINES,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWLINES_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+
+
+ EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWPATH_set(uint32_t PathID, uint32_t PenID){
+ if(PathID>63)return(NULL);
+ if(PenID>63)return(NULL);
+ int Size = 4;
+ uint16_t utmp16 = (PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWPATH,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&PenID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWPATH_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWPIE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWPIE_set(uint32_t PenID,
+ U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect){
+ int ctype;
+ if(PenID>63)return(NULL);
+ if(!Rect){ return(NULL); }
+ else {
+ if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ int Size = 2*4 + Rect->Used;
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0) | (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWPIE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Start, 4, 1, U_LE},
+ {&Sweep, 4, 1, U_LE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWPIE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWRECTS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param Rects U_PSEUDO_OBJ containing 1 rect OR a count N follwed by N rects. Rects may be either U_PMF_RECT or U_PMF_RECTF
+
+
+ EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWRECTS_set(uint32_t PenID, const U_PSEUDO_OBJ *Rects){
+ int ctype;
+ int just1;
+ uint32_t Elements=1; /* only used when a single rect is passed in, not an array, not even an array with one member*/
+ if(PenID>63){ return(NULL); }
+ if(Rects){
+ if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECT_OID ){ ctype = 1; }
+ else if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ just1 = (Rects->Type & U_PMF_ARRAY_OID ? 0 : 1);
+ int Size = Rects->Used + (just1 ? 4 : 0); /* Elements in Rects for array, not for single */
+ uint16_t utmp16 = (ctype ? U_PPF_C : 0)| (PenID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWRECTS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {(just1 ? (char *)&Elements : NULL), (just1 ? 4: 0), 1, U_LE}, /* element count if a single Rect was passed in, empty otherwise */
+ {Rects->Data, Rects->Used, 1, U_XE}, /* Elements + Array, already stored in Rects, if an array was passed in, just rect if a single */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWRECTS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_DRAWSTRING PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param FormatID U_PMF_STRINGFORMAT object in EMF+ Object Table.
+ \param Length Number of characters in the string.
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECTF object, string's bounding box
+ \param Text Array of UFT-16LE unicode characters.
+
+
+ EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
+*/
+U_PSEUDO_OBJ *U_PMR_DRAWSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
+ uint32_t FormatID, uint32_t Length, const U_PSEUDO_OBJ *Rect, const uint16_t *Text){
+ int btype;
+ if(FontID>63){ return(NULL); }
+ if(!Length){ return(NULL); }
+ else if (!Text){ return(NULL); }
+ if(!Rect || Rect->Type != U_PMF_RECTF_OID){ return(NULL); }
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = BrushID->Used + 2*4 + Rect->Used +2*Length;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0)| (FontID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ uint32_t pad = (0x1 & Length ? 2 : 0);
+ Size+=pad;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWSTRING,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {&FormatID, 4, 1, U_LE},
+ {&Length, 4, 1, U_LE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {Text, 2*Length, 1, U_XE},
+ {NULL, pad, (pad ? 1 : 0), (pad ? U_XE : U_XX)}, /* Entire record must be a multiple of 4 */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_DRAWSTRING_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLCLOSEDCURVE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ftype If U_WINDING use winding fill, else use fill
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Points U_PSEUDO_OBJ containing a U_PMF_POINT, U_PMF_POINTR or U_PMF_POINTF object
+
+
+ EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16
+*/
+U_PSEUDO_OBJ *U_PMR_FILLCLOSEDCURVE_set(int ftype, U_FLOAT Tension, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points){
+ int btype, ctype, RelAbs;
+ int Size=0;
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ Size = BrushID->Used + 4 + Points->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0) |((ftype == U_WINDING) ? U_PPF_F : 0) |(RelAbs ? U_PPF_P : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLCLOSEDCURVE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {&Tension, 4, 1, U_LE},
+ {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLCLOSEDCURVE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLELLIPSE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E
+*/
+U_PSEUDO_OBJ *U_PMR_FILLELLIPSE_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect){
+ int btype, ctype;
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(Rect){
+ if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = BrushID->Used + Rect->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLELLIPSE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLELLIPSE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLPATH PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+
+
+ EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14
+*/
+U_PSEUDO_OBJ *U_PMR_FILLPATH_set(uint32_t PathID, const U_PSEUDO_OBJ *BrushID){
+ int btype;
+ int Size=0;
+ if(PathID>63)return(NULL);
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ Size = BrushID->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (PathID & U_FF_MASK_OID8) << U_FF_SHFT_OID8 ;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPATH,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPATH_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLPIE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param Rect U_PSEUDO_OBJ containing a U_PMF_RECT or U_PMF_RECTF object
+
+
+ EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10
+*/
+U_PSEUDO_OBJ *U_PMR_FILLPIE_set(U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect){
+ int btype, ctype;
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(!Rect){ return(NULL); }
+ else {
+ if( Rect->Type == U_PMF_RECT_OID ){ ctype = 1; }
+ else if(Rect->Type == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ int Size = BrushID->Used + 2*4 + Rect->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPIE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {&Start, 4, 1, U_LE},
+ {&Sweep, 4, 1, U_LE},
+ {Rect->Data, Rect->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPIE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLPOLYGON PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param Points U_PSEUDO_OBJ containing an array of 3 U_PMF_POINT, U_PMF_POINTR, or U_PMF_POINTF objects
+
+
+ EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C
+*/
+U_PSEUDO_OBJ *U_PMR_FILLPOLYGON_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points){
+ int btype, ctype, RelAbs;
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(Points){
+ if( Points->Type == U_PMF_POINTR_OID){ RelAbs = 1; ctype = 0; }
+ else if(Points->Type == (U_PMF_POINT_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 1; }
+ else if(Points->Type == (U_PMF_POINTF_OID | U_PMF_ARRAY_OID)){ RelAbs = 0; ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = BrushID->Used + Points->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (ctype ? U_PPF_C : 0) |(RelAbs ? U_PPF_P : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLPOLYGON,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {Points->Data, Points->Used, 1, U_XE}, /* includes Elements */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLPOLYGON_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLRECTS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+ \param Rects U_PSEUDO_OBJ containing 1 rect OR a count N followed by N rects. Rects may be either U_PMF_RECT or U_PMF_RECTF
+
+
+ EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A
+*/
+U_PSEUDO_OBJ *U_PMR_FILLRECTS_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rects){
+ int btype, ctype;
+ int just1;
+ uint32_t Elements=1; /* only used when a single rect is passed in, not an array, not even an array with one member*/
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ if(Rects){
+ if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECT_OID ){ ctype = 1; }
+ else if( (Rects->Type & U_PMF_MASK_OID) == U_PMF_RECTF_OID){ ctype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ just1 = (Rects->Type & U_PMF_ARRAY_OID ? 0 : 1);
+ int Size = BrushID->Used + Rects->Used + (just1 ? 4 : 0); /* Elements in Rects for array, not for single */
+ uint16_t utmp16 = (btype ? U_PPF_B : 0)|(ctype ? U_PPF_C : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLRECTS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {(just1 ? (char *)&Elements : NULL), (just1 ? 4: 0), 1, U_LE}, /* element count if a single Rect was passed in, empty otherwise */
+ {Rects->Data, Rects->Used, 1, U_XE}, /* Elements + Array, already stored in Rects, if an array was passed in, just rect if a single */
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLRECTS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_FILLREGION PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param RgnID U_PMF_REGION object in the EMF+ object table (0-63, inclusive)
+ \param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
+
+
+ EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13
+*/
+U_PSEUDO_OBJ *U_PMR_FILLREGION_set(uint32_t RgnID, const U_PSEUDO_OBJ *BrushID){
+ int btype;
+ if(BrushID){
+ if( BrushID->Used != 4){ return(NULL); }
+ else if( BrushID->Type == U_PMF_ARGB_OID){ btype = 1; }
+ else if( BrushID->Type == U_PMF_4NUM_OID){ btype = 0; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = BrushID->Used;
+ uint16_t utmp16 = (btype ? U_PPF_B : 0) | (RgnID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_FILLREGION,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {BrushID->Data, BrushID->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_FILLREGION_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_OBJECT PseudoObject from another PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ObjID Index for this object in the EMF+ object table (0-63, inclusive)
+ \param Po U_PSEUDO_OBJ containing an object type that may be stored in the EMF+ object table
+*/
+U_PSEUDO_OBJ *U_PMR_OBJECT_PO_set(uint32_t ObjID, U_PSEUDO_OBJ *Po){
+ if(!Po){ return(NULL); }
+ int otype = U_OID_To_OT(Po->Type); /* This will return 0 if the type is not valid for an object */
+ if(!otype){ return(NULL); }
+ U_PSEUDO_OBJ *po = U_PMR_OBJECT_set(ObjID, otype, 0, 0, Po->Used, Po->Data); /* 0,0 = rec. not continued, TSize value (ignored) */
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_OBJECT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param ObjID Index for this object in the EMF+ object table (0-63, inclusive)
+ \param otype ObjectType enumeration for this Object
+ \param ntype Set: object definition continues in next record; Clear: this is the sole object definition record
+ \param TSize If ntype is set the total number of data bytes split across multiple records. If ntype is clear, it is ignored.
+ \param cbData Object's data size, in bytes.
+ \param Data Object's data. Type from otype.
+
+
+ EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13
+
+ Normally this is only called by U_PMR_OBJECT_PO_set().
+
+ U_PMR_OBJECT records can only hold a maximum of 65020 bytes of data. If the object is larger than that
+ then multiple U_PMR_OBJECT records are created, one after the other. If this
+ happens each record has cbData following ph, and the ntype flag is set. If all of the data is less than 65020
+ then cbData is NOT entered following ph, and the ntype flag is clear.
+
+ Call initially in all cases with ntype clear and TSize = 0. If the record needs to be fragmented
+ the function will call itself recursively to do so.
+
+*/
+U_PSEUDO_OBJ *U_PMR_OBJECT_set(uint32_t ObjID, int otype, int ntype, uint32_t TSize, size_t cbData, const char *Data){
+ uint32_t CSize;
+ int Pad = UP4(TSize) - TSize;
+ if((otype < U_OT_Brush) || (otype > U_OT_CustomLineCap)){ return(NULL); }
+ if(ntype && (cbData > U_OBJRECLIM)){ return(NULL); }
+ if(!Data || !cbData){ return(NULL); }
+ U_PSEUDO_OBJ *po;
+
+ if(!ntype && !TSize && (cbData > U_OBJRECLIM)){
+ ntype = 1;
+ TSize = cbData;
+ po = U_PO_create(NULL, TSize + 16 * (1 + (TSize/cbData)), 0, U_PMR_OBJECT_OID);
+ if(po){
+ while(cbData){
+ CSize = (cbData > U_OBJRECLIM ? U_OBJRECLIM : cbData);
+ U_PSEUDO_OBJ *pot = U_PMR_OBJECT_set(ObjID, otype, ntype, TSize, CSize, Data);
+ if(!pot)break;
+ U_PSEUDO_OBJ *newpo = U_PO_po_append(po, pot, U_PMF_KEEP_ELEMENTS);
+ U_PO_free(&pot);
+ if(!newpo)break;
+ po = newpo;
+ Data += U_OBJRECLIM;
+ cbData -= CSize;
+ }
+ if(cbData){ /* some error */
+ U_PO_free(&po);
+ }
+ }
+ }
+ else {
+ /* Send in DataSize, U_PMR_CMN_HDR_set will adjust Header Size with 1-3 pad bytes if needed */
+ uint16_t utmp16 = otype << 8 | (ntype ? U_PPF_N : 0) | (ObjID & U_FF_MASK_OID8) << U_FF_SHFT_OID8;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_OBJECT,utmp16,cbData + (ntype ? 4 : 0));
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE },
+ {(ntype ? &TSize : NULL), (ntype ? 4 : 0), (ntype ? 1 : 0), U_LE },
+ {Data, cbData, 1, U_XE },
+ {NULL, (Pad ? Pad : 0), (Pad ? 1 : 0), (Pad ? U_XE : U_XX)}, /* Either 1-3 pad bytes or a terminator */
+ {NULL,0,0,U_XX} /* terminator, possibly a second in the list, which is harmless */
+ };
+ po = U_PMF_SERIAL_set(U_PMR_OBJECT_OID, List);
+ U_PO_free(&ph);
+ }
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SERIALIZABLEOBJECT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Siepb U_PSEUDO_OBJ containing a "Serialized image effects parameter block". One of the ImageEffects objects.
+
+ EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38
+
+
+ This sets an ImageEffect in the renderer, which will be applied to the next EmfPlusDrawImagePoints
+ record that is encountered. The image effect is "consumed" by that EmfPlusDrawImagePoints record, resetting
+ the renderer to its original state.\n
+
+ WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
+ file is inserted as an image into PowerPoint.
+
+*/
+U_PSEUDO_OBJ *U_PMR_SERIALIZABLEOBJECT_set(const U_PSEUDO_OBJ *Siepb){
+ if(!Siepb){ return(NULL); }
+ uint8_t *GUID = U_OID_To_GUID(Siepb->Type);
+ if(!GUID){ return(NULL); }
+ /* PO Used is size_t, might be 8 bytes, value in record must be 4 bytes */
+ uint32_t Used = Siepb->Used;
+ int Size = 16 + 4 + Siepb->Used;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SERIALIZABLEOBJECT,0,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {GUID, 16, 1, U_XE},
+ {&Used, 4, 1, U_LE},
+ {Siepb->Data, Siepb->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SERIALIZABLEOBJECT_OID, List);
+ U_PO_free(&ph);
+ free(GUID);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETANTIALIASMODE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param SMenum SmoothingMode enumeration
+ \param aatype Set: anti-aliasing on; Clear: anti-aliasing off
+
+
+ EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E
+*/
+U_PSEUDO_OBJ *U_PMR_SETANTIALIASMODE_set(int SMenum, int aatype){
+ int Size = 0;
+ uint16_t utmp16 = (aatype ? U_PPF_AA : 0) | (SMenum & U_FF_MASK_AA)<<U_FF_SHFT_AA;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETANTIALIASMODE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETANTIALIASMODE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETCOMPOSITINGMODE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param CMenum CompositingMode enumeration
+
+
+ EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23
+*/
+U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGMODE_set(int CMenum){
+ int Size = 0;
+ uint16_t utmp16 = (CMenum & U_FF_MASK_CM)<<U_FF_SHFT_CM;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCOMPOSITINGMODE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCOMPOSITINGMODE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETCOMPOSITINGQUALITY PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param CQenum CompositingQuality enumeration
+
+
+ EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24
+*/
+U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGQUALITY_set(int CQenum){
+ int Size = 0;
+ uint16_t utmp16 = (CQenum & U_FF_MASK_CQ)<<U_FF_SHFT_CQ;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETCOMPOSITINGQUALITY,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETCOMPOSITINGQUALITY_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETINTERPOLATIONMODE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param IMenum InterpolationMode enumeration
+
+
+ EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21
+*/
+U_PSEUDO_OBJ *U_PMR_SETINTERPOLATIONMODE_set(int IMenum){
+ int Size = 0;
+ uint16_t utmp16 = (IMenum & U_FF_MASK_IM)<<U_FF_SHFT_IM;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETINTERPOLATIONMODE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETINTERPOLATIONMODE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETPIXELOFFSETMODE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param POMenum PixelOffsetMode enumeration
+
+
+ EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22
+*/
+U_PSEUDO_OBJ *U_PMR_SETPIXELOFFSETMODE_set(int POMenum){
+ int Size = 0;
+ uint16_t utmp16 = (POMenum & U_FF_MASK_PxOffM) << U_FF_SHFT_PxOffM;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETPIXELOFFSETMODE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETPIXELOFFSETMODE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETRENDERINGORIGIN PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param X X coordinate of rendering origin.
+ \param Y Y coordinate of rendering origin.
+
+
+ EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D
+*/
+U_PSEUDO_OBJ *U_PMR_SETRENDERINGORIGIN_set(int32_t X, int32_t Y){
+ int Size = 2*4;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETRENDERINGORIGIN,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&X, 4, 1, U_LE},
+ {&Y, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETRENDERINGORIGIN_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETTEXTCONTRAST PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param TGC Text Gamma correction value (x 1000).
+
+
+ EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20
+*/
+U_PSEUDO_OBJ *U_PMR_SETTEXTCONTRAST_set(int TGC){
+ int Size = 0;
+ uint16_t utmp16 = (TGC & U_FF_MASK_TGC) << U_FF_SHFT_TGC;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTEXTCONTRAST,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTEXTCONTRAST_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETTEXTRENDERINGHINT PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param TRHenum TextRenderingHint enumeration
+
+
+ EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F
+*/
+U_PSEUDO_OBJ *U_PMR_SETTEXTRENDERINGHINT_set(int TRHenum){
+ int Size = 0;
+ uint16_t utmp16 = (TRHenum & U_FF_MASK_TRH) << U_FF_SHFT_TRH;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTEXTRENDERINGHINT,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTEXTRENDERINGHINT_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_BEGINCONTAINER PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param UTenum UnitType enumeration
+ \param DstRect a U_PSEUDO_OBJ containing a U_PMF_RECTF object. with SrcRect specifies a transformation
+ \param SrcRect a U_PSEUDO_OBJ containing a U_PMF_RECTF object. with DstRect specifies a transformation
+ \param StackID EMF+ Object Stack Index to use for this graphics container
+
+
+ EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27
+*/
+U_PSEUDO_OBJ *U_PMR_BEGINCONTAINER_set(int UTenum, U_PSEUDO_OBJ *DstRect, U_PSEUDO_OBJ *SrcRect, uint32_t StackID){
+ if(UTenum < U_UT_World || UTenum > U_UT_Millimeter){ return(NULL); }
+ if(!DstRect || (DstRect->Type != U_PMF_RECTF_OID)){ return(NULL); }
+ if(!SrcRect || (SrcRect->Type != U_PMF_RECTF_OID)){ return(NULL); }
+ int Size = DstRect->Used + SrcRect->Used + 4;
+ uint16_t utmp16 = (UTenum & U_FF_MASK_UT) << U_FF_SHFT_UT;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_BEGINCONTAINER,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {DstRect->Data, DstRect->Used, 1, U_XE},
+ {SrcRect->Data, SrcRect->Used, 1, U_XE},
+ {&StackID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_BEGINCONTAINER_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_BEGINCONTAINERNOPARAMS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param StackID EMF+ Object Stack Index to use for this graphics container
+
+
+ EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28
+*/
+U_PSEUDO_OBJ *U_PMR_BEGINCONTAINERNOPARAMS_set(int StackID){
+ int Size = 4;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_BEGINCONTAINERNOPARAMS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&StackID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_BEGINCONTAINERNOPARAMS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_ENDCONTAINER PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param StackID EMF+ Object Stack Index to use for this graphics container
+
+
+ EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29
+*/
+U_PSEUDO_OBJ *U_PMR_ENDCONTAINER_set(int StackID){
+ int Size = 4;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ENDCONTAINER,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&StackID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ENDCONTAINER_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_RESTORE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE.
+
+
+ EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26
+*/
+U_PSEUDO_OBJ *U_PMR_RESTORE_set(int StackID){
+ int Size = 4;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESTORE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&StackID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESTORE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SAVE PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param StackID EMF+ Graphics State Stack to restore from. Must have been put on the GSS with a U_PMR_SAVE.
+
+
+ EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25
+*/
+U_PSEUDO_OBJ *U_PMR_SAVE_set(int StackID){
+ int Size = 4;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SAVE,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&StackID, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SAVE_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETTSCLIP PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Rects a U_PSEUDO_OBJ containing an array of U_PMF_RECT or U_PMF_RECTF objects.
+
+
+ EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A
+*/
+U_PSEUDO_OBJ *U_PMR_SETTSCLIP_set(U_PSEUDO_OBJ *Rects){
+ int ctype;
+ uint32_t Elements;
+ if(Rects){
+ if( Rects->Type == (U_PMF_RECT_OID | U_PMF_ARRAY_OID)){ ctype = 1; Elements = (Rects->Used - 4)/8; }
+ else if(Rects->Type == (U_PMF_RECTF_OID | U_PMF_ARRAY_OID)){ ctype = 0; Elements = (Rects->Used - 4)/16; }
+ else { return(NULL); }
+ }
+ else { return(NULL); }
+ int Size = Rects->Used; /* Rects includes Elements */
+ uint16_t utmp16 = (ctype ? U_PPF_K : 0) | (Elements & U_FF_MASK_TSC) << U_FF_SHFT_TSC;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTSCLIP,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Rects->Data, Rects->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTSCLIP_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETTSGRAPHICS PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param vgatype Set: Palette is VGA basic colors; Clear: Palette is ???
+ \param Tsg A U_PMF_SETTSGRAPHICS object
+ \param Palette (optional) a U_PSEUDO_OBJ containing a U_PMF_PALETTE object.
+
+
+ EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39
+*/
+U_PSEUDO_OBJ *U_PMR_SETTSGRAPHICS_set(int vgatype, U_PMF_SETTSGRAPHICS *Tsg, U_PSEUDO_OBJ *Palette){
+ if(!Tsg){ return(NULL); }
+ int Size = sizeof(U_PMF_SETTSGRAPHICS) + (Palette ? Palette->Used : 0);
+ uint16_t utmp16 = (vgatype ? U_PPF_VGA : 0) | (Palette ? U_PPF_PP : 0) ;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETTSGRAPHICS,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&(Tsg->AntiAliasMode), 1, 1, U_XE},
+ {&(Tsg->TextRenderHint), 1, 1, U_XE},
+ {&(Tsg->CompositingMode), 1, 1, U_XE},
+ {&(Tsg->CompositingQuality), 1, 1, U_XE},
+ {&(Tsg->RenderOriginX), 2, 1, U_LE},
+ {&(Tsg->RenderOriginY), 2, 1, U_LE},
+ {&(Tsg->TextContrast), 2, 1, U_LE},
+ {&(Tsg->FilterType), 1, 1, U_XE},
+ {&(Tsg->PixelOffset), 1, 1, U_XE},
+ {&(Tsg->WorldToDevice), 4, 6, U_LE},
+ {(Palette ? Palette->Data : NULL), (Palette ? Palette->Used: 0), 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETTSGRAPHICS_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_MULTIPLYWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Tm a U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix)
+
+
+ EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C
+*/
+U_PSEUDO_OBJ *U_PMR_MULTIPLYWORLDTRANSFORM_set(int xmtype, U_PSEUDO_OBJ *Tm){
+ if(!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); }
+ int Size = Tm->Used;
+ uint16_t utmp16 = (xmtype ? U_PPF_XM : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_MULTIPLYWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Tm->Data, Tm->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_MULTIPLYWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_RESETWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+
+
+ EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B
+*/
+U_PSEUDO_OBJ *U_PMR_RESETWORLDTRANSFORM_set(void){
+ int Size = 0;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_RESETWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_RESETWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_ROTATEWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Angle Rotation angle, in degrees
+
+
+ EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F
+*/
+U_PSEUDO_OBJ *U_PMR_ROTATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Angle){
+ int Size = 4;
+ uint16_t utmp16 = (xmtype ? U_PPF_XM : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_ROTATEWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Angle, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_ROTATEWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SCALEWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param X Scale in X
+ \param Y Scale in Y
+
+ EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E
+*/
+U_PSEUDO_OBJ *U_PMR_SCALEWORLDTRANSFORM_set(int xmtype, U_FLOAT X, U_FLOAT Y){
+ int Size = 2*4;
+ uint16_t utmp16 = (xmtype ? U_PPF_XM : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SCALEWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&X, 4, 1, U_LE},
+ {&Y, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SCALEWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETPAGETRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param PUenum Page Unit, in UnitType enumeration
+ \param Scale Scale factor to convert page space to device space
+
+
+
+ EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30
+
+ Defines Page Space -> Device Space transformation
+*/
+U_PSEUDO_OBJ *U_PMR_SETPAGETRANSFORM_set(int PUenum, U_FLOAT Scale){
+ int Size = 4;
+ uint16_t utmp16 = (PUenum & U_FF_MASK_PU) << U_FF_SHFT_PU;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETPAGETRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Scale, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETPAGETRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_SETWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param Tm a U_PSEUDO_OBJ containing a U_PMF_TRANSFORMMATRIX. (Transformation matrix)
+
+
+
+ EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A
+
+ Defines World Space -> Page Space transformation
+*/
+U_PSEUDO_OBJ *U_PMR_SETWORLDTRANSFORM_set(U_PSEUDO_OBJ *Tm){
+ if(!Tm || (Tm->Type != U_PMF_TRANSFORMMATRIX_OID)){ return(NULL); }
+ int Size = Tm->Used;
+ uint16_t utmp16 = 0;
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_SETWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {Tm->Data, Tm->Used, 1, U_XE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_SETWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/**
+ \brief Create and set a U_PMR_TRANSLATEWORLDTRANSFORM PseudoObject
+ \return Pointer to PseudoObject, NULL on error
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Dx X offset
+ \param Dy Y offset
+
+
+ EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D
+*/
+U_PSEUDO_OBJ *U_PMR_TRANSLATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Dx, U_FLOAT Dy){
+ int Size = 2*4;
+ uint16_t utmp16 = (xmtype ? U_PPF_XM : 0);
+ U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_TRANSLATEWORLDTRANSFORM,utmp16,Size);
+ const U_SERIAL_DESC List[] = {
+ {ph->Data, ph->Used, 1, U_XE},
+ {&Dx, 4, 1, U_LE},
+ {&Dy, 4, 1, U_LE},
+ {NULL,0,0,U_XX}
+ };
+ U_PSEUDO_OBJ *po = U_PMF_SERIAL_set(U_PMR_TRANSLATEWORLDTRANSFORM_OID, List);
+ U_PO_free(&ph);
+ return(po);
+}
+
+/*
+
+ end of U_PMF_*_set() functions
+ =====================================================================================
+ start of U_PMF_*_get() functions
+
+ These functions all take a blimit value so that they can check if the data description in the fields
+ they process extend beyond the end of the record.
+
+*/
+
+
+//! \cond
+/* core _get functions, not accessed outside of this routine */
+
+/* get copies of up to 0-6 consecutive 4 byte values and a pointer to the rest */
+int U_PMF_CORE1_get(const char *contents, void *v1, void *v2, void *v3, void *v4, void *v5, void *v6, const char **vR){
+ if(v1){ U_PMF_MEMCPY_SRCSHIFT(v1, &contents, 4);
+ if(v2){ U_PMF_MEMCPY_SRCSHIFT(v2, &contents, 4);
+ if(v3){ U_PMF_MEMCPY_SRCSHIFT(v3, &contents, 4);
+ if(v4){ U_PMF_MEMCPY_SRCSHIFT(v4, &contents, 4);
+ if(v5){ U_PMF_MEMCPY_SRCSHIFT(v5, &contents, 4);
+ if(v6){ U_PMF_MEMCPY_SRCSHIFT(v6, &contents, 4); }}}}}}
+ if(vR){ *vR = contents; }
+ return(1);
+}
+//! \endcond
+
+
+/**
+ \brief Get data from a U_PMF_BRUSH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Type BrushType Enumeration
+ \param Data one of the 5 types of Brush data
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
+ if(!contents || !Version || !Type || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents,sizeof(U_PMF_BRUSH), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMLINECAP object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Type CustomLineCapData Enumeration
+ \param Data one of the 2 types of Linecap data
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
+ if(!contents || !Version || !Type || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAP), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_FONT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param EmSize em size in units of SizeUnit
+ \param SizeUnit UnitType enumeration
+ \param FSFlags FontStyle flags
+ \param Length Number of Unicode Characters in FamilyName
+ \param Data Unicode (UTF-16LE) name of font family
+
+ EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit,
+ int32_t *FSFlags, uint32_t *Length, const char **Data, const char *blimit){
+ if(!contents || !Version || !EmSize || !SizeUnit || !FSFlags || !Length || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FONT), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, EmSize, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, SizeUnit, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, FSFlags, 4, 1, U_LE);
+ contents += 4; /* Reserved field, which is ignored */
+ U_PMF_SERIAL_get(&contents, Length, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+
+/**
+ \brief Get data from a U_PMF_IMAGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Type ImageDataType Enumeration
+ \param Data one of the 2 types of image data
+
+ EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){
+ if(!contents || !Version || !Type || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IMAGEATTRIBUTES object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param WrapMode WrapMode object
+ \param ClampColor EmfPlusARGB object
+ \param ObjectClamp ObjectClamp Identifiers
+
+ EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object
+*/
+int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor,
+ uint32_t *ObjectClamp, const char *blimit){
+ if(!contents || !Version || !WrapMode || !ClampColor || !ObjectClamp || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGEATTRIBUTES), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ contents += 4; /* Skip Reserved 1*/
+ U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, ClampColor, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, ObjectClamp,4, 1, U_LE);
+ /* Skip Reserved 2*/
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PATH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Count Number of points and point types in this object
+ \param Flags PathPoint Flags
+ \param Points array of points type PMFPointR, PMFPoint, or PMFPointF
+ \param Types array of U_PMF_PATHPOINTTYPERLE and/or U_PMF_PATHPOINTTYPE
+
+ EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object
+
+ Caller must check Types for possible memory access violations if type can be U_PMF_PATHPOINTTYPERLE.
+*/
+int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags,
+ const char **Points, const char **Types, const char *blimit){
+ if(!contents || !Version || !Count || !Flags || !Points || !Types || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATH), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE);
+ contents+=2; /* reserved */
+ uint32_t sizeP, sizeT;
+ if(*Flags & U_PPF_P){
+ sizeP = U_PMF_LEN_REL715(contents,*Count); //DEBUG
+ printf("DEBUG U_PMF_PATH_get count:%d LENREL715:%d\n",*Count,sizeP);fflush(stdout);
+ }
+ else if(*Flags & U_PPF_C){ sizeP = *Count * sizeof(U_PMF_POINT); }
+ else { sizeP = *Count * sizeof(U_PMF_POINTF); }
+ if(IS_MEM_UNSAFE(contents, sizeP, blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Points, &contents, 0);
+ contents += sizeP;
+ /* this limit is correct if there are only U_PMF_PATHPOINTTYPE PointTypes, it is a lower bound if
+ there can also be U_PMF_PATHPOINTTYPERLE */
+ sizeT = *Count * sizeof(U_PMF_PATHPOINTTYPE);
+ if(IS_MEM_UNSAFE(contents, sizeT, blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Types, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PEN object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Type must be zero
+ \param PenData Pen description
+ \param Brush Brush Description
+
+ EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object
+
+ Caller must check Brush and PenData for possible memory access violations.
+*/
+int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit){
+ if(!contents || !Type || !PenData || !Brush || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PEN), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(PenData, &contents, 0);
+ *Brush = *PenData + U_PMF_LEN_PENDATA(*PenData);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_REGION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Version EmfPlusGraphicsVersion object
+ \param Count Number of CHILD nodes. This is one less than the total number of U_PMF_REGIONNODE objects in Nodes.
+ \param Nodes Nodes defining region
+
+ EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object
+*/
+int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit){
+ if(!contents || !Version || !Count || !Nodes || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGION), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Nodes, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_STRINGFORMAT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Sfs pointer to U_PMF_STRINGFORMAT structure, with no variable part
+ \param Data pointer to variable part
+
+ EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object
+*/
+int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit){
+ if(!contents || !Sfs || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_STRINGFORMAT), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Sfs, 4, 15, U_LE);
+ *Data = contents;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_ARGB object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Blue Blue color (0-255)
+ \param Green Green color (0-255)
+ \param Red Red color (0-255)
+ \param Alpha Alpha (0-255)
+
+ EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object
+*/
+int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit){
+ if(!contents || !Blue || !Green || !Red || !Alpha || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ARGB), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Blue, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, Green, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, Red, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, Alpha, 1, 1, U_XE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BITMAP object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Bs pointer to U_PMF_BITMAP structure, with no variable part
+ \param Data pointer to variable part
+
+ EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit){
+ if(!contents || !Bs || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BITMAP), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Bs, 4, 5, U_LE); // width, height, stride, pixelformat, type
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0); // bitmapdata
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BITMAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Ps pointer to U_PMF_PALETTE structure, with no variable part
+ \param Colors Color part of U_PMF_PALETTE object
+ \param Data An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration.
+
+ EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit){
+ if(!contents || !Ps || !Colors || !Data || !blimit){ return(0); }
+ /* this structure is entirely optional */
+ if(IS_MEM_UNSAFE(contents, 4*2, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Ps, 4, 2, U_LE);
+ U_PMF_PTRSAV_SHIFT(Colors, &contents, Ps->Elements * sizeof(U_PMF_ARGB));
+ /* difficult to know how big the actual bitmap will be, just return the pointer to it untested */
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BLENDCOLORS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements Number of members in Positions and Colors
+ \param Positions Caller must free. Pointer to memory holding positions along gradient line.
+ \param Colors Caller must NOT free memory, Pointer to memory holding colors at positions on gradient line.
+
+ EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object
+*/
+int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit){
+ if(!contents || !Positions || !Colors || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDCOLORS), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0);
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE,1)){ return(0); }
+ U_PMF_PTRSAV_SHIFT(Colors, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BLENDFACTORS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements members in each array
+ \param Positions Caller must free. Pointer to memory holding positions along gradient line.
+ \param Factors Caller must free. Pointer to memory holding blending factors, 0.0->1.0 values, inclusive along gradient line.
+
+ EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object
+*/
+int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit){
+ if(!contents || !Elements || !Positions || !Factors || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDFACTORS), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * 4 * 2, blimit))return(0);
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE, 1)){ return(0); }
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Factors, 4, *Elements, U_LE, 1)){
+ free(*Positions);
+ return(0);
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BOUNDARYPATHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size bytes in Data
+ \param Data boundary of the brush
+
+ EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPATHDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_BOUNDARYPOINTDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements Members in Points
+ \param Points Caller must free. Pointer to memory holding points along gradient line. Boundary of the brush.
+
+ EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object
+*/
+int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit){
+ if(!contents || !Elements || !Points || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPOINTDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0);
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements * 2, U_LE, 1)){ return(0); }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CHARACTERRANGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param First First position in range
+ \param Length Range length
+
+ EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object
+*/
+int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit){
+ if(!contents || !First || !Length || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CHARACTERRANGE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, First, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Length, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_COMPOUNDLINEDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements Members in the array
+ \param Widths Caller must free. Pointer to memory holding Line or gap widths (0.0 <-> 1.0, fraction of total line width ).
+
+ EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object
+*/
+int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit){
+ if(!contents || !Elements || !Widths || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_COMPOUNDLINEDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0);
+ *Widths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT));
+ if(!*Widths){ return(0); }
+ U_PMF_SERIAL_get(&contents, *Widths, 4, *Elements, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_COMPRESSEDIMAGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Data Stored image in one of the supported formats.
+
+ EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object
+
+
+ This function does not do anything useful, but it is included so that all objects have a corresponding _get().
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data, const char *blimit){
+ if(!contents || !Data || !blimit){ return(0); }
+ if(contents >= blimit)return(0);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMENDCAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size Bytes in Data
+ \param Data Description of linecap
+
+ EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMENDCAPDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMLINECAPARROWDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Ccad pointer to U_PMF_CUSTOMLINECAPARROWDATA structure
+
+ EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object
+*/
+int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit){
+ if(!contents || !Ccad || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPARROWDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Ccad, 4, 13, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMLINECAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Clcd pointer to U_PMF_CUSTOMLINECAPDATA structure, with no variable part
+ \param Data variable part of U_PMF_CUSTOMLINECAPDATA
+
+ EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit){
+ if(!contents || !Clcd || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Clcd, 4, 12, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMLINECAPOPTIONALDATA object
+ \return on success 3,5, or 7 (for varying combinations of data present) or 1 (no data is present), 0 on error
+ \param contents Record from which to extract data
+ \param Flags bits set to indicate the presence of FillData and/or LineData
+ \param FillData Path to fill (optional)
+ \param LineData Path to stroke (optional)
+
+ EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object
+
+ Caller must check LineData for possible memory access violations.
+*/
+int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit){
+ uint32_t length;
+ int status = 1;
+ if(!contents || !*FillData || !*LineData || !blimit){ return(0); }
+ /* this structure is entirely optional */
+ if(Flags & U_CLCD_FillPath){
+ if(!FillData){ return(0); }
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, length, blimit))return(0);
+ contents -= 4; /* undo the unneeded shift from preceding */
+ U_PMF_PTRSAV_SHIFT(FillData, &contents, 4 + length);
+ status += 2;
+ }
+ else { *FillData = NULL; }
+
+ if(Flags & U_CLCD_LinePath){
+ if(!LineData){ return(0); }
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, length, blimit))return(0);
+ contents -= 4; /* undo the unneeded shift from preceding */
+ U_PMF_PTRSAV_SHIFT(LineData, &contents, 0);
+ status += 4;
+ }
+ else { *LineData = NULL; }
+ return(status);
+}
+
+/**
+ \brief Get data from a U_PMF_CUSTOMSTARTCAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size Bytes in Data
+ \param Data Description of linecap
+
+ EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMSTARTCAPDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_DASHEDLINEDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements Members in the array
+ \param Lengths Caller must free. Pointer to memory holding lengths of dashes and spaces.
+
+ EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object
+*/
+int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit){
+ if(!contents || !Elements || !Lengths || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_DASHEDLINEDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0);
+ *Lengths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT));
+ if(!*Lengths){ return(0); }
+ U_PMF_SERIAL_get(&contents, *Lengths, 4, *Elements, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_FILLPATHOBJ object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size Bytes in Data
+ \param Data Path specification
+
+ EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FILLPATHO), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_FOCUSSCALEDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Count must be 2
+ \param ScaleX value 0.0 <-> 1.0
+ \param ScaleY value 0.0 <-> 1.0
+
+ EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object
+*/
+int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit){
+ if(!contents || !Count || !ScaleX || !ScaleY || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE);
+ if(*Count != 2){ return(0); }
+ U_PMF_SERIAL_get(&contents, ScaleX, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, ScaleY, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_GRAPHICSVERSION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Signature Must be U_GFVR_PMF (0xDBC01)
+ \param GrfVersion GraphicsVersion enumeration
+
+ EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+*/
+int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit){
+ uint32_t tmp;
+ if(!contents || !Signature || !GrfVersion || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_GRAPHICSVERSION), blimit))return(0);
+ memcpy(&tmp, contents, 4);
+ *Signature = tmp >> 12;
+ *GrfVersion = tmp & U_GFVR_MASKLO;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_HATCHBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Style HatchStyle enumeration
+ \param Foreground Hatch pattern line color
+ \param Background Hatch pattern bkground color
+
+ EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object
+*/
+int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit){
+ if(!contents || !Style || !Foreground || !Background || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_HATCHBRUSHDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Foreground, 4, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, Background, 4, 1, U_XE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_INTEGER7 object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Value 7 bit signed integer (stored in an integer)
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object
+*/
+int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value, const char *blimit){
+ uint8_t tmp;
+ if(!contents || !*contents || !Value || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(*contents, 1, blimit))return(0); /* past end of buffer */
+ if(**contents & U_TEST_INT7)return(0); /* this bit must be 0 in this object type */
+ U_PMF_SERIAL_get(contents, &tmp, 1, 1, U_XE);
+ if(tmp & U_SIGN_INT7){
+ tmp |= U_TEST_INT7; /* now it has the bit pattern of a signed int8_t */
+ *Value = *(int8_t *)&tmp;
+ }
+ else {
+ *Value = tmp;
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_INTEGER15 object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Value 15 bit signed integer (stored in an integer)
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object
+*/
+int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value, const char *blimit){
+ if(!contents || !*contents || !Value || !blimit){ return(0); }
+ uint16_t tmp;
+ if(IS_MEM_UNSAFE(*contents, 2, blimit))return(0); /* past end of buffer */
+ if(!(**contents & U_TEST_INT7))return(0); /* this bit must be 1 in this object type */
+ U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_BE);
+ tmp &= U_MASK_INT15; /* drop the 7/15 flag from the most significant bit */
+ if(tmp & U_SIGN_INT15){
+ tmp |= U_TEST_INT15; /* now it has the bit pattern of a signed int16_t */
+ *Value = *(int16_t *)&tmp;
+ }
+ else {
+ *Value = tmp;
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_LANGUAGEIDENTIFIER object
+ \return 1 on success, 0 on error
+ \param LId U_PMF_LANGUAGEIDENTIFIER from which to extract data
+ \param SubLId Example: code for USA
+ \param PriLId Example: code for English
+
+
+
+ EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object
+
+ This type is defined as 16 bits in the manual section, but it is only ever used as part of a 32 bit field!
+*/
+int U_PMF_LANGUAGEIDENTIFIER_get(U_PMF_LANGUAGEIDENTIFIER LId, int *SubLId, int *PriLId){
+ if(!SubLId || !PriLId){ return(0); }
+ *SubLId = (LId >> U_FF_SHFT_SUBLID ) & U_FF_MASK_SUBLID;
+ *PriLId = (LId >> U_FF_SHFT_PRILID ) & U_FF_MASK_PRILID;
+ /* 16 bits above that are not used */
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_LINEARGRADIENTBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Lgbd U_PMF_LINEARGRADIENTBRUSHDATA structure, with no variable part
+ \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit){
+ if(!contents || !Lgbd || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEARGRADIENTBRUSHDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Lgbd, 4, 6, U_LE); /* Flags, WrapMode, RectF*/
+ U_PMF_SERIAL_get(&contents, &(Lgbd->StartColor), 4, 4, U_XE); /* StartColor, EndColor, Reserved1 & 2 */
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags BrushData flags - indicates which of the following date fields are present.
+ \param Tm Transformation matrix
+ \param Bc U_PMF_BLENDCOLORS object or NULL
+ \param BfH U_PMF_BLENDFACTORS (H) object or NULL
+ \param BfV U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.)
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object
+
+*/
+int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm,
+ const char **Bc, const char **BfH, const char **BfV, const char *blimit){
+ uint32_t Elements;
+ if(!contents || !Tm|| !Bc || !BfH || !BfV || !blimit){ return(0); }
+ /* all of the fields are optional! */
+ *Bc = *BfH = *BfV = NULL;
+ if(Flags & U_BD_Transform){
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ROTMATRIX), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Tm, 4, 6, U_LE);
+ }
+ if(Flags & U_BD_PresetColors){
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/
+ if(IS_MEM_UNSAFE(contents, Elements * ( sizeof(U_FLOAT) + sizeof(U_PMF_ARGB)), blimit))return(0);
+ contents-=4; /* back up to the front of the count, as it is part of the data field */
+ U_PMF_PTRSAV_SHIFT(Bc, &contents, 0);
+ }
+ else if(Flags & U_BD_BlendFactorsH){
+ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/
+ if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0);
+ contents-=4; /* back up to the front of the count, as it is part of the data field */
+ U_PMF_PTRSAV_SHIFT(BfH, &contents, 4 + (Elements * 2 * sizeof(U_FLOAT))); /* 4 byte count + 2 * 4bytes * Elements */
+ if(Flags & U_BD_BlendFactorsV){
+ if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(BfV, &contents, 0);
+ }
+ }
+ else if(Flags & U_BD_BlendFactorsV){
+ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/
+ if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0);
+ contents-=4; /* back up to the front of the count, as it is part of the data field */
+ U_PMF_PTRSAV_SHIFT(BfV, &contents, 0);
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_LINEPATH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size Bytes in Data
+ \param Data Outline path
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEPATH), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_METAFILE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Type
+ \param Size Bytes in Data
+ \param Data Various types of data, like an EMF metafile, WMF metafile, another EMF+ metafile
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Type || !Size || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_METAFILE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &Type, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PALETTE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags PaletteStyle flags
+ \param Elements Members in the array
+ \param Colors Palette data (array of colors)
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object
+*/
+int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Colors, const char *blimit){
+ if(!contents || !Flags || !Elements || !Colors || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PALETTE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &Flags, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements*sizeof(U_RGBQUAD), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Colors, &contents, 0);
+ return(1);
+
+}
+
+/**
+ \brief Get data from a U_PMF_PATHGRADIENTBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Pgbd constant part of U_PMF_PATHGRADIENTBRUSHDATA object
+ \param Gradient variable part of U_PMF_LINEARGRADIENTBRUSHDATA, Color Gradient with Elements members
+ \param Boundary variable part of U_PMF_LINEARGRADIENTBRUSHDATA, U_PMF_BOUNDARYPATHDATA object if BrushDataPath bit set in Flag, else U_PMF_BOUNDARYPOINTDATA object
+ \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA, exact composition depends on Flags
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object
+
+ Caller must check Data for possible memory access violations.
+
+*/
+int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient,
+ const char **Boundary, const char **Data, const char *blimit){
+ if(!contents || !Pgbd || !Gradient || !Boundary || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATHGRADIENTBRUSHDATA), blimit))return(0);
+ uint32_t Size;
+ U_PMF_SERIAL_get(&contents, Pgbd, 4, 2, U_LE); /* Flags and WrapMode*/
+ U_PMF_SERIAL_get(&contents, &(Pgbd->CenterColor), 4, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, &(Pgbd->Center), 4, 3, U_LE); /* Center and Elements */
+ if(IS_MEM_UNSAFE(contents, Pgbd->Elements * sizeof(U_PMF_ARGB), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Gradient, &contents, Pgbd->Elements * sizeof(U_PMF_ARGB));
+ U_PMF_PTRSAV_SHIFT(Boundary, &contents, 0);
+ U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); /* The first 4 bytes of the Boundary are always a size */
+ if(Pgbd->Flags & U_BD_Path){ contents += Size; } // U_PMF_BOUNDARYPATHDATA
+ else { contents += Size*2*sizeof(U_FLOAT); } // U_PMF_BOUNDARYPOINTDATA
+ if(Pgbd->Flags & (U_BD_Transform |U_BD_PresetColors | U_BD_BlendFactorsH| U_BD_FocusScales)){ // optional data present
+ if(contents >= blimit)return(0); // the size is variable but this must still hold
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ }
+ else { *Data = NULL; } // no optional data present
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PATHGRADIENTBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags bits set to indicate the presence of FillData and/or LineData
+ \param Matrix Transformation matrix
+ \param Pattern Blend Pattern
+ \param Data Focus scales for the brush
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object
+*/
+int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix,
+ const char **Pattern, const char **Data, const char *blimit){
+ int varsize;
+ if(!contents || !Flags || !Matrix || !Pattern || !Data || !blimit){ return(0); }
+ /* this structure is entirely optional */
+ if(Flags & U_BD_Transform){
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ }
+ if(Flags & (U_BD_PresetColors | U_BD_BlendFactorsH)){
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ uint32_t Elements;
+ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE);
+ contents -= 4;
+ varsize=(Elements * 4 * (Flags & U_BD_BlendFactorsH ? 2 :1));
+ if(IS_MEM_UNSAFE(contents, varsize, blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Pattern, &contents, varsize);
+ }
+ else { *Pattern=NULL; }
+ if(Flags & U_BD_FocusScales){
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, sizeof(U_PMF_FOCUSSCALEDATA));
+ }
+ else { *Data=NULL; }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PATHPOINTTYPE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags PathPointType flags
+ \param Type PathPointType enumeration
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+
+ Note: order of 4bit fields appears to be shown in the LE column, not as
+ documented in the BE column.
+*/
+int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type, const char *blimit){
+ if(!contents || !Flags || !Type || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, 1, blimit))return(0);
+ uint8_t tmp;
+ memcpy(&tmp, contents, 1);
+ *Flags =(tmp & U_PTP_MASK) >> U_PTP_SHIFT;
+ *Type = (tmp & U_PPT_MASK);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PATHPOINTTYPERLE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Bezier Set: Bezier curve, Clear: straight line
+ \param RL Run Length
+ \param Ppt PathPointType enumeration
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object
+*/
+int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit){
+ if(!contents || !Bezier || !RL || !Ppt || !blimit){ return(0); }
+ uint16_t tmp;
+ if(IS_MEM_UNSAFE(contents, 2, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, &tmp, 2, 1, U_LE);
+ *Bezier = tmp & U_PPF_BZ;
+ *RL = (tmp >> U_FF_SHFT_RL) & U_FF_MASK_RL;
+ *Ppt = (tmp >> U_FF_SHFT_PPT) & U_FF_MASK_PPT;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PENDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags PenData flags
+ \param Unit UnitType enumeration
+ \param Width Width in units set by Unit
+ \param Data Optional pen data, exact composition depends on Flags
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object
+*/
+int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data, const char *blimit){
+ if(!contents || !Flags || !Unit || !Width || !Data || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, 3*4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Unit, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Width, 4, 1, U_LE);
+ if(contents >= blimit)return(0); // variable data will extend farther, but this much at least must be true
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_PENOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags; PenData Flags - indicated which of the many fields are present.
+ \param Matrix; Transformation matrix
+ \param StartCap LineCapType enumeration
+ \param EndCap LineCapType enumeration
+ \param Join LineJoinType enumeration
+ \param MiterLimit Maximum (miter length / line width)
+ \param Style LineStyle enumeration
+ \param DLCap DashedLineCapType enumeration
+ \param DLOffset Distance line start to first dash start
+ \param DLData Dash and space widths
+ \param Alignment PenAlignment enumeration
+ \param CmpndLineData Compount Line (parallel lines drawn instead of one)
+ \param CSCapData Custom start cap
+ \param CECapData Custom end cap
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object
+
+ This object consists of a large number of optional and or variable values, which
+ are returned, or not, depending on bits in Flags.
+*/
+int U_PMF_PENOPTIONALDATA_get(
+ const char *contents,
+ uint32_t Flags, // determines which fields are filled
+ U_PMF_TRANSFORMMATRIX *Matrix,
+ int32_t *StartCap,
+ int32_t *EndCap,
+ uint32_t *Join,
+ U_FLOAT *MiterLimit,
+ int32_t *Style,
+ int32_t *DLCap,
+ U_FLOAT *DLOffset,
+ const char **DLData,
+ int32_t *Alignment,
+ const char **CmpndLineData,
+ const char **CSCapData,
+ const char **CECapData,
+ const char *blimit){
+ if(!contents ||
+ !Flags || !Matrix || !StartCap || !EndCap ||
+ !Join || !MiterLimit || !Style || !DLCap ||
+ !DLOffset || !DLData || !Alignment || !CmpndLineData ||
+ !CSCapData || !CECapData || !blimit){ return(0); }
+
+ if(Flags & U_PD_Transform){ if(IS_MEM_UNSAFE(contents, 4*6, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ }
+ if(Flags & U_PD_StartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, StartCap, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_EndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, EndCap, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_Join){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Join, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_MiterLimit){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, MiterLimit, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_LineStyle){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_DLCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, DLCap, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_DLOffset){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, DLOffset, 4, 1, U_LE);
+ }
+ if(Flags & U_PD_DLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT( DLData, &contents, U_PMF_LEN_FLOATDATA(contents));
+ }
+ if(Flags & U_PD_NonCenter){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Alignment, 4, 1, U_LE); }
+ if(Flags & U_PD_CLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT( CmpndLineData, &contents, U_PMF_LEN_FLOATDATA(contents));
+ }
+ if(Flags & U_PD_CustomStartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT( CSCapData, &contents, U_PMF_LEN_BYTEDATA(contents));
+ }
+ if(Flags & U_PD_CustomEndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0);
+ U_PMF_PTRSAV_SHIFT( CECapData, &contents, U_PMF_LEN_BYTEDATA(contents));
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_POINT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINT).
+ \param X X coordinate
+ \param Y Y coordinate
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object
+*/
+int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){
+ if(!contents || !X || !Y || !blimit){ return(0); }
+ int16_t tmp;
+ if(IS_MEM_UNSAFE(*contents, 2*2, blimit))return(0);
+ U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *X = tmp;
+ U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *Y = tmp;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_POINTF object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINTF).
+ \param X X coordinate
+ \param Y Y coordinate
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object
+*/
+int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){
+ if(!contents || !X || !Y || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(*contents, 4*2, blimit))return(0);
+ U_PMF_SERIAL_get(contents, X, 4, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_POINTR object
+ \return size in bytes traversed on success, 0 on error
+ \param contents Record from which to extract data. On return position is offset by returned size.
+ \param X X coordinate
+ \param Y Y coordinate
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object
+*/
+int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){
+ if(!contents || !*contents | !X || !Y || !blimit){ return(0); }
+ int size=0;
+
+ if( U_PMF_INTEGER7_get( contents, X, blimit)){ size +=1; }
+ else if(U_PMF_INTEGER15_get(contents, X, blimit)){ size +=2; }
+ else { return(0); }
+
+ if( U_PMF_INTEGER7_get( contents, Y, blimit)){ size +=1; }
+ else if(U_PMF_INTEGER15_get(contents, Y, blimit)){ size +=2; }
+ else { return(0); }
+
+ return(size);
+}
+
+/**
+ \brief Get data from a variable POINTS object, which may be U_PMF_POINTS, U_PMF_POINTF, or U_PMF_POINTR.
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags Record flags (bits U_PPF_C and U_PPF_P are referenced)
+ \param Elements Number of points to retrieve.
+ \param Points Caller must free. Array of U_PMF_POINTF coordinates.
+ \param blimit one byte past the end of data
+
+ This function should never be called directly by end user code.
+*/
+int U_PMF_VARPOINTS_get(const char *contents, uint16_t Flags, int Elements, U_PMF_POINTF **Points, const char *blimit){
+ int status = 0;
+ if(!contents || !Points || !Elements || !blimit){ return(status); }
+ U_PMF_POINTF *pts = (U_PMF_POINTF *)malloc(Elements * sizeof(U_PMF_POINTF));
+ if(!pts){ return(status); }
+ *Points = pts;
+ U_FLOAT XF, YF;
+ U_FLOAT XFS, YFS;
+
+ if(Flags & U_PPF_P){
+ for(XFS = YFS = 0.0; Elements; Elements--, pts++){
+ if(!U_PMF_POINTR_get(&contents, &XF, &YF, blimit))return(0); /* this should never happen */
+ XFS += XF; /* position relative to previous point, first point is always 0,0 */
+ YFS += YF;
+ pts->X = XFS;
+ pts->Y = YFS;
+ }
+ }
+ else if(Flags & U_PPF_C){
+ for(XF = YF = 0.0; Elements; Elements--, pts++){
+ if(!U_PMF_POINT_get(&contents, &XF, &XF, blimit))break; /* this should never happen */
+ pts->X = XF;
+ pts->Y = YF;
+ }
+ }
+ else {
+ for(XF = YF = 0.0; Elements; Elements--, pts++){
+ (void) U_PMF_POINTF_get(&contents, &XF, &YF, blimit);
+ pts->X = XF;
+ pts->Y = YF;
+ }
+ }
+ if(Elements){ /* some error in the preceding */
+ free(*Points);
+ *Points = NULL;
+ }
+ else {
+ status = 1;
+ }
+ return(status);
+}
+
+/**
+ \brief Get data from a U_PMF_RECT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param X UL X value
+ \param Y UL Y value
+ \param Width Width
+ \param Height Height
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object
+*/
+int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit){
+ if(!contents || !X || !Y|| !Width || !Height){ return(0); }
+ if(IS_MEM_UNSAFE(*contents, 2*4, blimit))return(0);
+ U_PMF_SERIAL_get(contents, X, 2, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Y, 2, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Width, 2, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Height, 2, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_RECTF object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param X UL X value
+ \param Y UL Y value
+ \param Width Width
+ \param Height Height
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit){
+ if(!contents || !X || !Y|| !Width || !Height){ return(0); }
+ if(IS_MEM_UNSAFE(*contents, 4*4, blimit))return(0);
+ U_PMF_SERIAL_get(contents, X, 4, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Width, 4, 1, U_LE);
+ U_PMF_SERIAL_get(contents, Height, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a variable RECTS object, which may be U_PMF_RECT or U_PMF_RECTF
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags Record flags (bit U_PPF_C is referenced)
+ \param Elements Number of rects to retrieve.
+ \param Rects Caller must free. Array of U_PMF_RECTF coordinates.
+ \param blimit one byte past the end of data
+
+ Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always
+ returns U_PMF_RECTF
+*/
+int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_RECTF **Rects, const char *blimit){
+ int16_t X16, Y16, Width, Height;
+ if(!contents || !*contents || !Rects || !blimit){ return(0); }
+ U_PMF_RECTF *rts = (U_PMF_RECTF *)malloc(Elements * sizeof(U_PMF_RECTF));
+ if(!rts){
+ *Rects = NULL;
+ return(0);
+ }
+
+ *Rects = rts;
+ if(Flags & U_PPF_C){
+ if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){
+ free(rts);
+ return(0);
+ }
+ }
+ else {
+ if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){
+ free(rts);
+ return(0);
+ }
+ }
+ for(; Elements; Elements--, rts++){
+ if(Flags & U_PPF_C){
+ (void) U_PMF_RECT_get(contents, &X16, &Y16, &Width, &Height, blimit);
+ rts->X = X16;
+ rts->Y = Y16;
+ rts->Width = Width;
+ rts->Height = Height;
+ }
+ else {
+ (void) U_PMF_RECTF_get(contents, &(rts->X), &(rts->Y), &(rts->Width), &(rts->Height), blimit);
+ }
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_REGIONNODE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Type RegionNodeDataType
+ \param Data Depending on Type: U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit){
+ if(!contents || !Type || !Data || !blimit){ return(0); }
+ /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE);
+ if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true
+ U_PMF_PTRSAV_COND(Data, contents, !(*Type == U_RNDT_Empty || *Type == U_RNDT_Infinite ));
+ return(1);
+}
+
+/**
+ There is no U_PMF_REGIONNODECHILDNODES_get!
+
+ The Region object is recursive allowing U_PMF_REGIONNODECHILDNODES ->
+ U_PMF_REGIONNODE -> U_PMF_REGIONNODECHILDNODES etc.
+ So the data stored in each node must be handled as the tree is followed recursively.
+
+ See U_PMF_REGIONNODECHILDNODES_print() and U_PMF_REGIONNODE_print() for an example.
+
+
+ EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object
+*/
+
+/**
+ \brief Get data from a U_PMF_REGIONNODEPATH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Size Bytes in Data
+ \param Data Boundary of region node
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object
+*/
+int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){
+ if(!contents || !Size || !Data || !blimit){ return(0); }
+ /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODEPATH), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_SOLIDBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Color Color of brush
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object
+*/
+int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color, const char *blimit){
+ if(!contents || !Color || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_SOLIDBRUSHDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Color, 4, 1, U_XE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_STRINGFORMATDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param TabStopCount Entries in TabStop array
+ \param RangeCount Entries in CharRange array
+ \param TabStops Array of tabstop locations
+ \param CharRange Array of character ranges in the text
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object
+*/
+int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint32_t RangeCount,
+ const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange, const char *blimit){
+ if(!contents || !TabStops|| !CharRange || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, (TabStopCount + 2*RangeCount)*4, blimit))return(0);
+ *TabStops = NULL;
+ if(TabStopCount > 0){ U_PMF_SERIAL_get(&contents, TabStops, 4, TabStopCount, U_LE); }
+ *CharRange = NULL;
+ if(RangeCount > 0){ U_PMF_SERIAL_get(&contents, CharRange, 4, 2*RangeCount, U_LE); }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_TEXTUREBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Flags BrushData flags
+ \param WrapMode WrapMode enumeration
+ \param Data Optional texture data
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit){
+ if(!contents || !Flags || !WrapMode || !Data || !blimit){ return(0); }
+ /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TEXTUREBRUSHDATA), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE);
+ if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_TEXTUREBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param HasImage True if this object has an Image
+ \param Matrix Transformation matrix, NULL if Flag BrushDataTransform is not set.
+ \param Image Image that contains the texture.
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object
+
+ Caller must check Image for possible memory access violations.
+*/
+int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix,
+ const char **Image, const char *blimit){
+ if(!contents || !Image || !blimit){ return(0); }
+ if(Matrix){
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ }
+ if(HasImage){
+ if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true
+ U_PMF_PTRSAV_COND(Image, contents, HasImage);
+ }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_TRANSFORMMATRIX object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Matrix Transformation matrix, present if Flag BrushDataTransform is set.
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object
+*/
+int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit){
+ if(!contents || !Matrix || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_BLUR object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Radius Blur radius in pixels
+ \param ExpandEdge 1: expand bitmap by Radius; 0: bitmap size unchanged
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object
+*/
+int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit){
+ if(!contents || !Radius || !ExpandEdge || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BLUR), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, ExpandEdge, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_BRIGHTNESSCONTRAST object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Brightness -255 to 255, 0 is unchanged, positive increases, negative decreases
+ \param Contrast -100 to 100, 0 is unchanged, positive increases, negative decreases
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object
+*/
+int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit){
+ if(!contents || !Brightness || !Contrast || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BRIGHTNESSCONTRAST), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Brightness, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Contrast, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_COLORBALANCE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param CyanRed -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite
+ \param MagentaGreen -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite
+ \param YellowBlue -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object
+*/
+int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit){
+ if(!contents || !CyanRed || !MagentaGreen || !YellowBlue || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORBALANCE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, CyanRed, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, MagentaGreen, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, YellowBlue, 4, 1, U_LE);
+ return(1);
+}
+
+
+/**
+ \brief Get data from a U_PMF_IE_COLORCURVE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Adjust CurveAdjustment enumeration
+ \param Channel CurveChannel enumeration
+ \param Intensity adjustment to apply. "Adjust" determines what field this is and range values.
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object
+*/
+int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit){
+ if(!contents || !Adjust || !Channel || !Intensity || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORCURVE), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Adjust, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Channel, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Intensity, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_COLORLOOKUPTABLE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param BLUT Blue color lookup table
+ \param GLUT Green color lookup table
+ \param RLUT Red color lookup table
+ \param ALUT Alpha color lookup table
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object
+*/
+int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents,
+ const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit){
+ if(!contents || !BLUT || !GLUT || !RLUT || !ALUT || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORLOOKUPTABLE) + 4 * 256, blimit))return(0);
+ U_PMF_PTRSAV_SHIFT((const char **)BLUT, &contents, 256);
+ U_PMF_PTRSAV_SHIFT((const char **)GLUT, &contents, 256);
+ U_PMF_PTRSAV_SHIFT((const char **)RLUT, &contents, 256);
+ U_PMF_PTRSAV_SHIFT((const char **)ALUT, &contents, 256);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_COLORMATRIX object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Matrix 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0]
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object
+*/
+int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit){
+ if(!contents || !Matrix || !blimit){ return(0); }
+ /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORMATRIX), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 5*5, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_HUESATURATIONLIGHTNESS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Hue -180 to 180, 0 is unchanged
+ \param Saturation -100 to 100, 0 is unchanged
+ \param Lightness -100 to 100, 0 is unchanged
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object
+*/
+int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit){
+ if(!contents || !Hue || !Saturation || !Lightness || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_HUESATURATIONLIGHTNESS), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Saturation, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Lightness, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_LEVELS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Highlight 0 to 100, 100 is unchanged
+ \param Midtone -100 to 100, 0 is unchanged
+ \param Shadow 0 to 100, 0 is unchanged
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object
+*/
+int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit){
+ if(!contents || !Highlight || !Midtone || !Shadow || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_LEVELS), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Highlight, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Midtone, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Shadow, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_REDEYECORRECTION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Elements Number of members in Rects
+ \param Rects Caller must free. Pointer to memory holding an array of U_RECTL.
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object
+*/
+int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit){
+ if(!contents || !Elements || !Rects || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_REDEYECORRECTION), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0);
+ *Rects = (U_RECTL *) malloc(*Elements * sizeof(U_RECTL));
+ if(!*Rects){ return(0); }
+ U_PMF_SERIAL_get(&contents, *Rects, 4, *Elements * 4, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_SHARPEN object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Radius Sharpening radius in pixels
+ \param Sharpen 0 to 100, 0 is unchanged
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object
+*/
+int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit){
+ if(!contents || !Radius || !Sharpen || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_SHARPEN), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Sharpen, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMF_IE_TINT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Hue -180 to 180, [positive==clockwise] rotation in degrees starting from blue
+ \param Amount -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object
+*/
+int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount, const char *blimit){
+ if(!contents || !Hue || !Amount || !blimit){ return(0); }
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_TINT), blimit))return(0);
+ U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Amount, 4, 1, U_LE);
+ return(1);
+}
+
+/*
+
+ end of U_PMF_*_get() functions
+ =====================================================================================
+ start of U_PMR_*_get() functions
+
+ These functions all assume that the size field in the common EMF+ header has already
+ been checked, so that the extent the record claims exists in the data read in for the file.
+ Consequently none of them takes a blimit parameter. They generate a new one from the
+ header size field and contents if needed.
+
+*/
+
+int U_PMR_common_stack_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
+ if(!contents || !StackID){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_RESTORE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE);
+ return(1);
+}
+
+/* for records that have a type but no associated flag bits or data */
+int U_PMR_common_header_get(const char *contents, U_PMF_CMN_HDR *Header){
+ /* memory access safe, only uses the common header */
+ if(!contents){ return(0); }
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_OFFSETCLIP record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+ \param dX horizontal translation offset to apply to clipping region
+ \param dY vertical translation offset to apply to clipping region
+
+ EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35
+*/
+int U_PMR_OFFSETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header,
+ U_FLOAT *dX, U_FLOAT *dY){
+ if(!contents){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_OFFSETCLIP))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, dX, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, dY, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_RESETCLIP record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31
+*/
+int U_PMR_RESETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header){
+ if(!contents){ return(0); }
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETCLIPPATH record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param CMenum CombineMode enumeration..
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+
+ EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33
+*/
+int U_PMR_SETCLIPPATH_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PathID, int *CMenum){
+ if(!contents || !PathID || !CMenum){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETCLIPPATH))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4;
+ *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETCLIPRECT record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+ \param CMenum Combine mode enumeration.
+ \param Rect Rectangle used with CombineMode enumeration from Header.Flags
+
+ EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32
+*/
+int U_PMR_SETCLIPRECT_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *CMenum,
+ U_PMF_RECTF *Rect){
+ if(!contents || !CMenum || !Rect ){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETCLIPRECT))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4;
+ U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETCLIPREGION record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param CMenum CombineMode enumeration..
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+
+ EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34
+*/
+int U_PMR_SETCLIPREGION_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PathID, int *CMenum){
+ if(!contents || !PathID || !CMenum){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4;
+ *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_COMMENT record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+ \param Data Private data, may be anything
+
+ EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMR_COMMENT_get(const char *contents, U_PMF_CMN_HDR *Header,
+ const char **Data){
+ if(!contents || !Data){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_COMMENT))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_ENDOFFILE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02
+*/
+int U_PMR_ENDOFFILE_get(const char *contents, U_PMF_CMN_HDR *Header){
+ if(!contents){ return(0); }
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_GETDC record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04
+*/
+int U_PMR_GETDC_get(const char *contents, U_PMF_CMN_HDR *Header){
+ if(!contents){ return(0); }
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_HEADER record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+ \param Version EmfPlusGraphicsVersion object
+ \param IsDual set = Dual-mode file, clear= EMF+ only file.
+ \param IsVideo set = video device, clear= printer. Ignore all other bits.
+ \param LogicalDpiX Horizontal resolution reference device in DPI
+ \param LogicalDpiY Vertical resolution reference device in DPI
+
+ EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01
+*/
+int U_PMR_HEADER_get(const char *contents, U_PMF_CMN_HDR *Header,
+ U_PMF_GRAPHICSVERSION *Version, int *IsDual, int *IsVideo, uint32_t *LogicalDpiX, uint32_t *LogicalDpiY){
+ if(!contents || !Version || !IsDual || !IsVideo || !LogicalDpiX || !LogicalDpiY){ return(0); }
+ uint32_t tmp;
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_HEADER))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *IsDual = (lclHeader.Flags & U_PPF_DM ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, &tmp, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, LogicalDpiX, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, LogicalDpiY, 4, 1, U_LE);
+ *IsVideo = (tmp & U_PPF_VIDEO ? 1 : 0 );
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_CLEAR record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+ \param Color Erase everything preceding, set background ARGB color.
+
+ EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09
+*/
+int U_PMR_CLEAR_get(const char *contents, U_PMF_CMN_HDR *Header,
+ U_PMF_ARGB *Color){
+ if(!contents || !Color){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_CLEAR))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, Color, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWARC record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12
+*/
+int U_PMR_DRAWARC_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype,
+ U_FLOAT *Start, U_FLOAT *Sweep,
+ U_PMF_RECTF *Rect){
+ if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWARC))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE);
+ U_PMF_RECTF *Rects = NULL;
+ if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0);
+ memcpy(Rect,Rects,sizeof(U_PMF_RECTF));
+ free(Rects);
+ return(1);
+}
+
+
+/**
+ \brief Get data from a U_PMR_DRAWBEZIERS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
+ \param Elements Number of members in the Data array
+ \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19
+*/
+int U_PMR_DRAWBEZIERS_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype, int *RelAbs,
+ uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !PenID || !ctype || !RelAbs || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWBEZIERS))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ int status = U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit );
+ return(status);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWCLOSEDCURVE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Elements Number of members in the Data array
+ \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17
+*/
+int U_PMR_DRAWCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype, int *RelAbs,
+ U_FLOAT *Tension, uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !PenID || !ctype || !RelAbs || !Tension || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWCLOSEDCURVE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWCURVE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Offset Element in Points that is the spline's starting point
+ \param NSegs Number of segments
+ \param Elements Number of members in Data array
+ \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18
+*/
+int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype,
+ U_FLOAT *Tension, uint32_t *Offset, uint32_t *NSegs, uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !PenID || !ctype || !Tension || !Offset || !NSegs || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWCURVE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Offset, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, NSegs, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWDRIVERSTRING record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table.
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depends on Flags bit0
+ \param DSOFlags DriverStringOptions flags
+ \param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not.
+ \param Elements Number of members in Glyphs and Positions array
+ \param Glyphs Caller must free. If U_DSO_CmapLookup is set in DSOFlags this is an array of UTF16LE characters, otherwise, it is an array of indices into the U_PMF_FONT object indexed by Object_ID in flags.
+ \param Points Caller must free. Coordinates of each member of Glyphs. U_DSO_RealizedAdvance set in DSOFlags Relative then positions are calculated relative to the first glyph which is stored in Positions, otherwise, all glyph positions are stored in Positions.
+ \param Matrix Caller must free. Transformation to apply to Glyphs & Positions. Present if HasMatrix is 1
+
+ EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36
+*/
+int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *FontID, int *btype,
+ uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements,
+ uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix){
+ if(!contents || !FontID || !btype || !BrushID ||
+ !DSOFlags || !HasMatrix || !Elements || !Glyphs || !Points || !Matrix){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWDRIVERSTRING))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, DSOFlags, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, HasMatrix, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements*2 + *Elements*2*4 + 24, blimit))return(0);
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Glyphs, 2, *Elements, U_LE, (*DSOFlags & U_DSO_CmapLookup))){ return(0); }
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements *2, U_LE, (*DSOFlags & U_DSO_RealizedAdvance))){ return(0); }
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Matrix, 4, 6, U_LE, (*HasMatrix))){ return(0); }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWELLIPSE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F
+*/
+int U_PMR_DRAWELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype,
+ U_PMF_RECTF *Rect){
+ if(!contents || !PenID || !ctype || !Rect){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWELLIPSE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWIMAGE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param ImgAttrID index of a U_PMF_IMAGEATTRIBUTES object in the object table
+ \param SrcUnit UnitType enumeration
+ \param SrcRect Region of image
+ \param DstRect Destination rectangle for image. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A
+*/
+int U_PMR_DRAWIMAGE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *ImgID, int *ctype,
+ uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect,
+ U_PMF_RECTF *DstRect){
+ if(!contents || !ImgID || !ctype || !ImgAttrID || !SrcUnit || !SrcRect || !DstRect){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE);
+ U_PMF_SERIAL_get(&contents, DstRect, 4, 4, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWIMAGEPOINTS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param ImgID U_PMF_IMAGE object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param etype Set: effect from previous U_PMR_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied
+ \param RelAbs Set: Data is relative, Clear: if it is absolute
+ \param ImgAttrID EmfPlusImageAttributes object
+ \param SrcUnit UnitType enumeration
+ \param SrcRect Region of image
+ \param Elements Number of members in Points, must be 3
+ \param Points Caller must free. 3 points of a parallelogram.. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B
+*/
+int U_PMR_DRAWIMAGEPOINTS_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *ImgID, int *ctype, int *etype, int *RelAbs,
+ uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !ImgID || !ctype || !etype || !RelAbs || !ImgAttrID || !SrcUnit || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGEPOINTS))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *etype = (lclHeader.Flags & U_PPF_E ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 );
+ *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWLINES record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param dtype Set: path must be closed, Clear: path is open
+ \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
+ \param Elements Number of members in Points
+ \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D
+*/
+int U_PMR_DRAWLINES_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype, int *dtype, int *RelAbs,
+ uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !PenID || !ctype || !dtype || !RelAbs || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *dtype = (lclHeader.Flags & U_PPF_D ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWPATH record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+
+ EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15
+*/
+int U_PMR_DRAWPATH_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PathID, uint32_t *PenID){
+ if(!contents || !PathID || !PenID){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWPATH))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, PenID, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWPIE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rect Caller must free. Bounding rectangle. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D
+*/
+int U_PMR_DRAWPIE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype,
+ U_FLOAT *Start, U_FLOAT *Sweep,
+ U_PMF_RECTF *Rect){
+ if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE);
+ U_PMF_RECTF *Rects = NULL;
+ if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0);
+ memcpy(Rect,Rects,sizeof(U_PMF_RECTF));
+ free(Rects);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWRECTS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PenID U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Elements Number of members in Rects
+ \param Rects Caller must free. Array of U_PMF_RECTF rectangles to draw.
+
+ EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B
+
+ Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always
+ returns U_PMF_RECTF
+*/
+int U_PMR_DRAWRECTS_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PenID, int *ctype,
+ uint32_t *Elements,
+ U_PMF_RECTF **Rects){
+ if(!contents || !PenID || !Elements || !Rects){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_DRAWSTRING record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table.
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param FormatID U_PMF_STRINGFORMAT object in EMF+ Object Table.
+ \param Elements Number of characters in the string.
+ \param Rect String's bounding box.
+ \param String Caller must free. Array of UFT-16LE unicode characters.
+
+ EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
+*/
+int U_PMR_DRAWSTRING_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *FontID, int *btype,
+ uint32_t *BrushID, uint32_t *FormatID, uint32_t *Elements, U_PMF_RECTF *Rect,
+ uint16_t **String){
+ if(!contents || !FontID || !btype || !BrushID || !FormatID || !Elements || !String){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, FormatID, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE);
+ if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0);
+ if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)String, 2, *Elements, U_XE, 1)){ return(0); }
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLCLOSEDCURVE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param ftype Set: winding fill; Clear: alternate fill
+ \param RelAbs Set: Coordinates are relative; Clear: Coordinates are absolute and their type is set by ctype
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param Tension Controls splines, 0 is straight line, >0 is curved
+ \param Elements Number of members in Points
+ \param Points Caller must free. Array of U_POINT_F = Sequence of points to connect. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16
+*/
+int U_PMR_FILLCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *btype, int *ctype, int *ftype, int *RelAbs,
+ uint32_t *BrushID, U_FLOAT *Tension, uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !btype || !ctype || !ftype || !RelAbs || !BrushID || !Tension || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *ftype = (lclHeader.Flags & U_PPF_F ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLELLIPSE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param Rect Caller must free. Bounding box for elliptical pie segment being drawn. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E
+*/
+int U_PMR_FILLELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *btype, int *ctype,
+ uint32_t *BrushID,
+ U_PMF_RECTF *Rect){
+ if(!contents || !btype || !ctype || !BrushID || !Rect){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_FILLELLIPSE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLPATH record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param PathID U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+
+ EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14
+
+ Note: U_PMF_FILLPATHOBJ is the object, U_PMF_FILLPATH is the file record
+*/
+int U_PMR_FILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *PathID, int *btype,
+ uint32_t *BrushID){
+ if(!contents || !PathID || !btype || !BrushID){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_FILLPATH))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLPIE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param Start Start angle, >=0.0, degrees clockwise from 3:00
+ \param Sweep Sweep angle, -360<= angle <=360, degrees clockwise from Start
+ \param Rect Bounding box for elliptical pie segment being filled. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10
+*/
+int U_PMR_FILLPIE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *btype, int *ctype,
+ uint32_t *BrushID, U_FLOAT *Start, U_FLOAT *Sweep,
+ U_PMF_RECTF *Rect){
+ if(!contents || !btype || !ctype || !BrushID || !Start || !Sweep || !Rect){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_FILLPIE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE);
+ U_PMF_RECTF *Rects = NULL;
+ if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0);
+ memcpy(Rect,Rects,sizeof(U_PMF_RECTF));
+ free(Rects);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLPOLYGON record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param RelAbs Set: U_PMF_PathPointTypeRLE and/or U_PMF_PathPointType objects; Clear: only U_PMF_PathPointType
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param Elements Number of members in Data.
+ \param Points Sequence of points to connect with line segments. Coordinate type set by ctype and RelAbs.
+
+ EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C
+*/
+int U_PMR_FILLPOLYGON_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *btype, int *ctype, int *RelAbs,
+ uint32_t *BrushID, uint32_t *Elements,
+ U_PMF_POINTF **Points){
+ if(!contents || !btype || !ctype || !RelAbs || !BrushID || !Elements || !Points){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *RelAbs = (lclHeader.Flags & U_PPF_R ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_FILLRECTS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+ \param Elements Number of members in Data.
+ \param Rects Caller must free. Array of U_PMF_RECTF rectangles to draw.
+
+ EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A
+
+ EMF+ files have been encountered where BrushID must be a color, because it has a value like FFFF0000 but
+ the flags are set wrong, so that U_PPF_B is not set. Detect these by BrushID >63 for btype=0 and correct.
+ If the opposite problem occurs it cannot be reliably detected, so it cannot be corrected.
+
+ Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always
+ returns U_PMF_RECTF
+*/
+int U_PMR_FILLRECTS_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *btype, int *ctype,
+ uint32_t *BrushID, uint32_t *Elements,
+ U_PMF_RECTF **Rects){
+ if(!contents || !btype || !ctype || !BrushID || !Elements || !Rects){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_FILLRECTS))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE);
+ U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit);
+ /* correct btype, if necessary, for invalid EMF+ input */
+ if((*BrushID > 63) & !*btype)*btype=1;
+ return(1);
+}
+
+
+/**
+ \brief Get data from a U_PMR_FILLREGION record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param RgnID U_PMF_REGION object in the EMF+ object table (0-63, inclusive)
+ \param btype Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depending on btype.
+
+ EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13
+*/
+int U_PMR_FILLREGION_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *RgnID, int *btype, int *ctype,
+ uint32_t *BrushID){
+ if(!contents || !RgnID || !btype || !ctype || !BrushID){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_FILLREGION))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
+ *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 );
+ *RgnID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_OBJECT record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param ObjID Index for this object in the EMF+ object table (0-63, inclusive)
+ \param otype ObjectType enumeration
+ \param ntype Set: object definition continue bit is set
+ \param TSize If ntype is set, holds the total number of data bytes split across multiple records. If ntype is clear, has no meaning.
+ \param Data Object's data. Type from otype.
+
+ EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13
+
+ Caller must check Data for possible memory access violations.
+
+ OTHER NOTES:
+ All objects are to be stored in the same table and retrieved by index.
+ Documentation indicates that this table contains only 64 slots, although the index
+ field which references it can code for values 0-127.
+ If a new object has the same index as an existing object the old one is deleted and
+ the new one goes into its storage slot.
+ The continuation bit (U_PPF_N) is documented as indicating that the object is continued into
+ the next record. Examination of emf+ records in emf files produced by PowerPoint 2003
+ show that changing the ObjID also serves as a continued record terminator, and that it apparently
+ overrides the value for the continue bit. That is, even though the preceding records said
+ that it was continued, the change of ObjID terminates that preceding record without adding
+ any more data to it. In one example the sequential emf+ records were:
+ ObjID type size continue
+ 0 5 65008 Y
+ 0 5 65008 Y
+ 0 5 63104 Y
+ 1 8 24 N
+ A DrawImagePoints record followed that referenced ObjID 0.
+ Examination of the records with continue set showed that data in each
+ was preceded by a uint32_t size value equivalent to the size of the
+ data that had been split across multiple records, in this case
+ 0x0002F254 = 193108. It is not clear at present if this size value
+ will also be present at the end of a continued series that terminates
+ by not using the continue bit, rather than changing the ObjID.
+*/
+int U_PMR_OBJECT_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint32_t *ObjID, int *otype, int *ntype, uint32_t *TSize,
+ const char **Data){
+ if(!contents || !ObjID || !otype || !ntype || !Data){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_OBJECT))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *ntype = (lclHeader.Flags & U_PPF_N ? 1 : 0 );
+ *ObjID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
+ *otype = (lclHeader.Flags >> U_FF_SHFT_OT) & U_FF_MASK_OT;
+ if(*ntype){ U_PMF_SERIAL_get(&contents, TSize, 4, 1, U_LE); }
+ else { *TSize = 0; }
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SERIALIZABLEOBJECT record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param GUID ImageEffects identifier.
+ \param Size Bytes in Data.
+ \param Data "Serialized image effects parameter block". One of the ImageEffects objects.
+
+ EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMR_SERIALIZABLEOBJECT_get(const char *contents, U_PMF_CMN_HDR *Header,
+ uint8_t *GUID, uint32_t *Size,
+ const char **Data){
+ if(!contents || !GUID || !Size || !Data){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SERIALIZABLEOBJECT))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, GUID, 1, 16, U_XE);
+ U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE);
+ U_PMF_PTRSAV_SHIFT(Data, &contents, 0);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETANTIALIASMODE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param SMenum SmoothingMode enumeration
+ \param aatype Set: anti-aliasing on; Clear: anti-aliasing off
+
+ EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E
+*/
+int U_PMR_SETANTIALIASMODE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *SMenum, int *aatype){
+ if(!contents || !SMenum || !aatype){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETANTIALIASMODE))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *aatype = (lclHeader.Flags & U_PPF_AA ? 1 : 0 );
+ *SMenum = (lclHeader.Flags >> U_FF_SHFT_AA) & U_FF_MASK_AA;
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETCOMPOSITINGMODE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param CMenum CompositingMode enumeration
+
+ EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23
+*/
+int U_PMR_SETCOMPOSITINGMODE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *CMenum){
+ /* memory access safe, only uses the common header */
+ if(!contents || !CMenum){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *CMenum = (Flags >> U_FF_SHFT_CM) & U_FF_MASK_CM;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETCOMPOSITINGQUALITY record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param CQenum CompositingQuality enumeration
+
+ EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24
+*/
+int U_PMR_SETCOMPOSITINGQUALITY_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *CQenum){
+ /* memory access safe, only uses the common header */
+ if(!contents || !CQenum){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *CQenum = (Flags >> U_FF_SHFT_CQ) & U_FF_MASK_CQ;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETINTERPOLATIONMODE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param IMenum InterpolationMode enumeration
+
+ EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21
+*/
+int U_PMR_SETINTERPOLATIONMODE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *IMenum){
+ /* memory access safe, only uses the common header */
+ if(!contents || !IMenum){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *IMenum = (Flags >> U_FF_SHFT_IM) & U_FF_MASK_IM;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETPIXELOFFSETMODE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param POMenum PixelOffsetMode enumeration.
+
+ EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22
+*/
+int U_PMR_SETPIXELOFFSETMODE_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *POMenum){
+ /* memory access safe, only uses the common header */
+ if(!contents || !POMenum){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *POMenum = (Flags >> U_FF_SHFT_PxOffM) & U_FF_MASK_PxOffM;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETRENDERINGORIGIN record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header.
+ \param X X coordinate of rendering origin.
+ \param Y Y coordinate of rendering origin.
+
+ EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D
+*/
+int U_PMR_SETRENDERINGORIGIN_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int32_t *X, int32_t *Y){
+ if(!contents || !X || !Y){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ if(!U_PMF_CMN_HDR_get(&contents, &lclHeader))return(0);
+ if(lclHeader.Size < sizeof(U_PMF_SETRENDERINGORIGIN))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, X, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Y, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETTEXTCONTRAST record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header.
+ \param TGC Text Gamma correction value (x 1000).
+
+ EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20
+*/
+int U_PMR_SETTEXTCONTRAST_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *TGC){
+ /* memory access safe, only uses the common header */
+ if(!contents || !TGC){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *TGC = (Flags >> U_FF_SHFT_TGC) & U_FF_MASK_TGC;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETTEXTRENDERINGHINT record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header.
+ \param TRHenum TextRenderingHint enumeration
+
+ EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F
+*/
+int U_PMR_SETTEXTRENDERINGHINT_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *TRHenum){
+ /* memory access safe, only uses the common header */
+ if(!contents || !TRHenum){ return(0); }
+ uint16_t Flags = U_PMF_HEADERFLAGS_get(contents);
+ *TRHenum = (Flags >> U_FF_SHFT_TRH) & U_FF_MASK_TRH;
+ U_PMF_CMN_HDR_get(&contents, Header);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_BEGINCONTAINER record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param UTenum UnitType enumeration
+ \param DstRect with SrcRect specifies a transformation
+ \param SrcRect with DstRect specifies a transformation
+ \param StackID EMF+ Object Stack Index to use for this graphics container
+
+ EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27
+*/
+int U_PMR_BEGINCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *UTenum,
+ U_PMF_RECTF *DstRect, U_PMF_RECTF *SrcRect, uint32_t *StackID){
+ if(!contents || !UTenum || !DstRect || !SrcRect || !StackID){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *UTenum = (lclHeader.Flags >> U_FF_SHFT_UT) & U_FF_MASK_UT;
+ U_PMF_SERIAL_get(&contents, DstRect, 4, 4, U_LE);
+ U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE);
+ U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_BEGINCONTAINERNOPARAMS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param StackID EMF+ Object Stack Index to use for this graphics container
+
+ EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28
+*/
+int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
+ return(U_PMR_common_stack_get(contents, Header, StackID));
+}
+
+/**
+ \brief Get data from a U_PMR_ENDCONTAINER record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param StackID EMF+ Object Stack Index of this graphics container
+
+ EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29
+*/
+int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
+ return(U_PMR_common_stack_get(contents, Header, StackID));
+}
+
+/**
+ \brief Get data from a U_PMR_RESTORE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param StackID State (level) to restore from the EMF+ Graphics Stack. Must have been put on the GS with a U_PMR_SAVE.
+
+ EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26
+*/
+int U_PMR_RESTORE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
+ return(U_PMR_common_stack_get(contents, Header, StackID));
+}
+
+/**
+ \brief Get data from a U_PMR_SAVE record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param StackID State (level) to save.on the EMF+ Graphics Stack
+
+ EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25
+*/
+int U_PMR_SAVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){
+ return(U_PMR_common_stack_get(contents, Header, StackID));
+}
+
+/**
+ \brief Get data from a U_PMR_SETTSCLIP record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param ctype Set: int16_t coordinates; Clear: U_FLOAT coordinates
+ \param Elements Number of members in Data.
+ \param Rects Caller must free. Array of rectangles to draw. Coordinate type set by ctype.
+
+ EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A
+*/
+int U_PMR_SETTSCLIP_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *ctype, uint32_t *Elements,
+ U_PMF_RECTF **Rects){
+ if(!contents || !ctype || !Elements || !Rects){ return(0); }
+
+ const char *blimit = contents;
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETTSCLIP))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+ blimit += lclHeader.Size;
+
+ *ctype = (lclHeader.Flags & U_PPF_K ? 1 : 0 );
+ *Elements = (lclHeader.Flags >> U_FF_SHFT_TSC) & U_FF_MASK_TSC;
+ U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETTSGRAPHICS record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param vgatype Set: Palette is VGA basic colors; Clear: Palette is ???
+ \param pptype Set: Palette is present; Clear: Palette is absent.
+ \param AntiAliasMode SmoothingMode enumeration
+ \param TextRenderHint TextRenderingHint enumeration
+ \param CompositingMode CompositingMode enumeration
+ \param CompositingQuality CompositingQuality enumeration
+ \param RenderOriginX Origin X for halftoning and dithering
+ \param RenderOriginY Origin Y for halftoning and dithering
+ \param TextContrast Gamma correction, range 0 to 12
+ \param FilterType FilterType enumeraton
+ \param PixelOffset PixelOffsetMode enumeration
+ \param WorldToDevice world to device transform
+ \param Data Palette (optional)
+
+ EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39
+
+ Caller must check Data for possible memory access violations.
+*/
+int U_PMR_SETTSGRAPHICS_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *vgatype, int *pptype,
+ uint8_t *AntiAliasMode, uint8_t *TextRenderHint, uint8_t *CompositingMode, uint8_t *CompositingQuality,
+ int16_t *RenderOriginX, int16_t *RenderOriginY, uint16_t *TextContrast, uint8_t *FilterType,
+ uint8_t *PixelOffset, U_PMF_TRANSFORMMATRIX *WorldToDevice,
+ const char **Data){
+ if(!contents || !vgatype || !pptype ||
+ !AntiAliasMode || !TextRenderHint || !CompositingMode || !CompositingQuality ||
+ !RenderOriginX || !RenderOriginY || !TextContrast || !FilterType ||
+ !PixelOffset || !WorldToDevice || !Data){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETTSGRAPHICS))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *vgatype = (lclHeader.Flags & U_PPF_VGA ? 1 : 0 );
+ *pptype = (lclHeader.Flags & U_PPF_PP ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, AntiAliasMode, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, TextRenderHint, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, CompositingMode, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, CompositingQuality, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, RenderOriginX, 2, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, RenderOriginY, 2, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, TextContrast, 2, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, FilterType, 1, 1, U_XE);
+ U_PMF_SERIAL_get(&contents, WorldToDevice, 4, 6, U_LE);
+ U_PMF_PTRSAV_COND(Data, contents, *pptype);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_MULTIPLYWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Matrix Transformation matrix
+
+ EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C
+*/
+int U_PMR_MULTIPLYWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *xmtype,
+ U_PMF_TRANSFORMMATRIX *Matrix){
+ if(!contents || !xmtype || !Matrix){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_MULTIPLYWORLDTRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_RESETWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+
+ EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B
+*/
+int U_PMR_RESETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header){
+ return( U_PMR_common_header_get(contents,Header));
+}
+
+/**
+ \brief Get data from a U_PMR_ROTATEWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Angle Rotation angle, in degrees
+
+ EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F
+*/
+int U_PMR_ROTATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *xmtype,
+ U_FLOAT *Angle){
+ if(!contents || !xmtype || !Angle){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_ROTATEWORLDTRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Angle, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SCALEWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param xmtype Set: Post multiply; Clear: Pre multiply.
+ \param Sx X scale factor.
+ \param Sy Y scale factor.
+
+ EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E
+*/
+int U_PMR_SCALEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *xmtype,
+ U_FLOAT *Sx, U_FLOAT *Sy){
+ if(!contents || !xmtype || !Sx || !Sy){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SCALEWORLDTRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Sx, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Sy, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETPAGETRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param PUenum Page Unit, UnitType enumeration
+ \param Scale Scale factor to convert page space to device space
+
+ EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30
+*/
+int U_PMR_SETPAGETRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *PUenum,
+ U_FLOAT *Scale){
+ if(!contents || !PUenum || !Scale){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETPAGETRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *PUenum = (lclHeader.Flags >> U_FF_SHFT_PU) & U_FF_MASK_PU;
+ U_PMF_SERIAL_get(&contents, Scale, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_SETWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param Matrix Transformation matrix
+
+ EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A
+*/
+int U_PMR_SETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ U_PMF_TRANSFORMMATRIX *Matrix){
+ if(!contents || !Matrix){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_SETWORLDTRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_TRANSLATEWORLDTRANSFORM record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header
+ \param xmtype Set: Post multiply; Clear: Pre multiply
+ \param Dx X offset
+ \param Dy Y offset
+
+ EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D
+*/
+int U_PMR_TRANSLATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header,
+ int *xmtype,
+ U_FLOAT *Dx, U_FLOAT *Dy){
+ if(!contents || !xmtype || !Dx || !Dy){ return(0); }
+
+ U_PMF_CMN_HDR lclHeader;
+ U_PMF_CMN_HDR_get(&contents, &lclHeader);
+ if(lclHeader.Size < sizeof(U_PMF_TRANSLATEWORLDTRANSFORM))return(0);
+ if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); }
+
+ *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 );
+ U_PMF_SERIAL_get(&contents, Dx, 4, 1, U_LE);
+ U_PMF_SERIAL_get(&contents, Dy, 4, 1, U_LE);
+ return(1);
+}
+
+/**
+ \brief Get data from a U_PMR_STROKEFILLPATH record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+
+ EMF+ manual mentioned in 2.1.1.1, not otherwise documented, Microsoft name: EmfPlusStrokeFillPath Record, Index 0x37
+
+ "This record closes any open figures in a path, strokes the outline of
+ the path by using the current pen, and fills its interior by using the current brush."
+*/
+int U_PMR_STROKEFILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header){
+ return( U_PMR_common_header_get(contents,Header));
+}
+
+/**
+ \brief Get data from a U_PMR_MULTIFORMATSTART record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatStart Record, Index 0x05
+*/
+int U_PMR_MULTIFORMATSTART_get(const char *contents, U_PMF_CMN_HDR *Header){
+ return( U_PMR_common_header_get(contents,Header));
+}
+
+/**
+ \brief Get data from a U_PMR_MULTIFORMATSECTION record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatSection Record, Index 0x06
+*/
+int U_PMR_MULTIFORMATSECTION_get(const char *contents, U_PMF_CMN_HDR *Header){
+ return( U_PMR_common_header_get(contents,Header));
+}
+
+/**
+ \brief Get data from a U_PMR_MULTIFORMATEND record
+ \return 1 on success, 0 on error
+ \param contents Record from which to extract data
+ \param Header Common header (ignore flags)
+
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatEnd Record, Index 0x06
+*/
+int U_PMR_MULTIFORMATEND_get(const char *contents, U_PMF_CMN_HDR *Header){
+ return( U_PMR_common_header_get(contents,Header));
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/upmf.h b/src/3rdparty/libuemf/upmf.h
new file mode 100644
index 000000000..4fb7ad492
--- /dev/null
+++ b/src/3rdparty/libuemf/upmf.h
@@ -0,0 +1,3178 @@
+/**
+ @file upmf.h
+
+ @brief Structures, definitions, and function prototypes for EMF+ files.
+
+ EMF+ file Record structure derived from Microsoft's EMF+ Information pdf, releade date July 5,2012, link from
+ here:
+
+ http://msdn.microsoft.com/en-us/library/cc230724.aspx
+
+ If the direct link fails the document may be found
+ by searching for: "[MS-EMFPLUS]: Enhanced Metafile Format Plus Extensions "
+
+ EMR records and structures are EMF or common with EMF+
+ PMR records and structures are specific to EMF+
+
+ Using PMF instead of EMF+ because "+" is a problem in symbol names.
+
+ *****************************************************************************************
+ * WARNING: Microsoft's EMF+ documentation is little-endian for everything EXCEPT *
+ * bitfields, which are big-endian. See section 1.3.2 *
+ * That documentation also uses 0 as the MOST significant bit, N-1 as the least. *
+ * This code is little-endian throughout, and 0 is the LEAST significant bit *
+ *****************************************************************************************
+
+*/
+
+/*
+File: upmf.h
+Version: 0.0.5
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UPMF_
+#define _UPMF_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "uemf.h"
+
+
+/** \defgroup U_PMF_PMF_Misc PMF Miscellaneous defines
+ @{
+*/
+#define U_PMF_DROP_ELEMENTS 1 //!< Remove leading Elements value from data.
+#define U_PMF_KEEP_ELEMENTS 0 //!< Retain leading Elements value from data.
+
+#define U_SEG_NEW 1 //!< start a new segment in the path
+#define U_SEG_OLD 0 //!< continue the old (current) segment in the path
+
+#define U_FILTER_APPLY 1 //!< With U_PMR_DRAWIMAGEPOINTS_set, use whatever filter has been set up up.
+#define U_FILTER_IGNORE 0 //!< With U_PMR_DRAWIMAGEPOINTS_set, ignore whatever filter has been set up up.
+#define U_OBJRECLIM 65020 //!< Longest U_PMR_OBJECT that GDI+ will process
+ // used 9728 to test fragmenting of emitted object records
+
+/** @} */
+
+/** \defgroup U_PMF_DD_ PMF "standard" custom Dash Dot patterns for lines.
+
+ U_DD_DASH, U_DD_DOT, U_DD_DASHDOT, and U_DD_DASHDOTDOT are the only ones with corresponding
+ standard EMF and EMF+ dash/dot patterns.
+
+ These values are used to tell U_PMF_DASHEDLINEDATA_set2() to create one of 27 custom line patterns.
+ Other custom line patterns may be created using U_PMF_DASHEDLINEDATA_set(), but this provides an easier
+ way to get the same result if one of these patterns is acceptable.
+
+ The length is divided by 2X the number of elements, so dashdash has twice as many
+ dashes of half the length as just dash.
+
+ Dot is 1/8 of (sub)unit length
+ Dash is 1/2 of (sub)unit length
+ Long is 3/4 of (sub)unit length
+ Example: DotDot has (sub)unit length 1/2, so each dot will be 1/16 of unit length.
+
+ @{
+*/
+#define U_DD_Solid 0 //!< Solid line.
+#define U_DD_Dash 1 //!< Dash line.
+#define U_DD_DashDash 2 //!< Dash Dash line.
+#define U_DD_DashDashDash 3 //!< Dash Dash Dash line.
+#define U_DD_DashDashDashDash 4 //!< Dash Dash Dash Dash line.
+#define U_DD_Dot 5 //!< Dot line.
+#define U_DD_DotDot 6 //!< Dot Dot line.
+#define U_DD_DotDotDot 7 //!< Dot Dot Dot line.
+#define U_DD_DotDotDotDot 8 //!< Dot Dot Dot Dot line.
+#define U_DD_DashDot 9 //!< Dash Dot line.
+#define U_DD_DashDashDot 10 //!< Dash Dash Dot line.
+#define U_DD_DashDashDotDot 11 //!< Dash Dash Dot Dot line.
+#define U_DD_DashDashDashDot 12 //!< Dash Dash Das hDot line.
+#define U_DD_DashDotDot 13 //!< Dash Dot Dot line.
+#define U_DD_DashDotDotDot 14 //!< Dash Dot Dot Dot line.
+#define U_DD_DashDotDashDot 15 //!< Dash Dot Dash Dot line.
+#define U_DD_Long 16 //!< Long line.
+#define U_DD_LongLong 17 //!< Long Long line.
+#define U_DD_LongLongLong 18 //!< Long Long Long line.
+#define U_DD_LongLongLongLong 19 //!< Long Long Long Long line.
+#define U_DD_LongDot 20 //!< Long Dot line.
+#define U_DD_LongLongDot 21 //!< Long Long Dot line.
+#define U_DD_LongLongDotDot 22 //!< Long Long Dot Dot line.
+#define U_DD_LongLongLongDot 23 //!< Long Long Long Dot line.
+#define U_DD_LongDotDot 24 //!< Long Dot Dot line.
+#define U_DD_LongDotDotDot 25 //!< Long Dot Dot Dot line.
+#define U_DD_LongDotLongDot 26 //!< Long Dot Long Dot line.
+#define U_DD_Types 27 //!< Types
+
+/** @} */
+
+
+/** \defgroup U_PMF_PMR_Qualifiers PMF RecordType Enumeration
+ EMF+ manual 2.1.1.1, Microsoft name: RecordType Enumeration
+ @{
+*/
+#define U_PMR_HEADER 0x0001 //!< U_PMRHeader record
+#define U_PMR_ENDOFFILE 0x0002 //!< U_PMREndOfFile record
+#define U_PMR_COMMENT 0x0003 //!< U_PMRComment record
+#define U_PMR_GETDC 0x0004 //!< U_PMRGetDC record
+#define U_PMR_MULTIFORMATSTART 0x0005 //!< U_PMRMultiFormatStart record
+#define U_PMR_MULTIFORMATSECTION 0x0006 //!< U_PMRMultiFormatSection record
+#define U_PMR_MULTIFORMATEND 0x0007 //!< U_PMRMultiFormatEnd record
+#define U_PMR_OBJECT 0x0008 //!< U_PMRObject record
+#define U_PMR_CLEAR 0x0009 //!< U_PMRClear record
+#define U_PMR_FILLRECTS 0x000A //!< U_PMRFillRects record
+#define U_PMR_DRAWRECTS 0x000B //!< U_PMRDrawRects record
+#define U_PMR_FILLPOLYGON 0x000C //!< U_PMRFillPolygon record
+#define U_PMR_DRAWLINES 0x000D //!< U_PMRDrawLines record
+#define U_PMR_FILLELLIPSE 0x000E //!< U_PMRFillEllipse record
+#define U_PMR_DRAWELLIPSE 0x000F //!< U_PMRDrawEllipse record
+#define U_PMR_FILLPIE 0x0010 //!< U_PMRFillPie record
+#define U_PMR_DRAWPIE 0x0011 //!< U_PMRDrawPie record
+#define U_PMR_DRAWARC 0x0012 //!< U_PMRDrawArc record
+#define U_PMR_FILLREGION 0x0013 //!< U_PMRFillRegion record
+#define U_PMR_FILLPATH 0x0014 //!< U_PMRFillPath record
+#define U_PMR_DRAWPATH 0x0015 //!< U_PMRDrawPath record
+#define U_PMR_FILLCLOSEDCURVE 0x0016 //!< U_PMRFillClosedCurve record
+#define U_PMR_DRAWCLOSEDCURVE 0x0017 //!< U_PMRDrawClosedCurve record
+#define U_PMR_DRAWCURVE 0x0018 //!< U_PMRDrawCurve record
+#define U_PMR_DRAWBEZIERS 0x0019 //!< U_PMRDrawBeziers record
+#define U_PMR_DRAWIMAGE 0x001A //!< U_PMRDrawImage record
+#define U_PMR_DRAWIMAGEPOINTS 0x001B //!< U_PMRDrawImagePoints record
+#define U_PMR_DRAWSTRING 0x001C //!< U_PMRDrawString record
+#define U_PMR_SETRENDERINGORIGIN 0x001D //!< U_PMRSetRenderingOrigin record
+#define U_PMR_SETANTIALIASMODE 0x001E //!< U_PMRSetAntiAliasMode record
+#define U_PMR_SETTEXTRENDERINGHINT 0x001F //!< U_PMRSetTextRenderingHint record
+#define U_PMR_SETTEXTCONTRAST 0x0020 //!< U_PMRSetTextContrast record
+#define U_PMR_SETINTERPOLATIONMODE 0x0021 //!< U_PMRSetInterpolationMode record
+#define U_PMR_SETPIXELOFFSETMODE 0x0022 //!< U_PMRSetPixelOffsetMode record
+#define U_PMR_SETCOMPOSITINGMODE 0x0023 //!< U_PMRSetCompositingMode record
+#define U_PMR_SETCOMPOSITINGQUALITY 0x0024 //!< U_PMRSetCompositingQuality record
+#define U_PMR_SAVE 0x0025 //!< U_PMRSave record
+#define U_PMR_RESTORE 0x0026 //!< U_PMRRestore record
+#define U_PMR_BEGINCONTAINER 0x0027 //!< U_PMRBeginContainer record
+#define U_PMR_BEGINCONTAINERNOPARAMS 0x0028 //!< U_PMRBeginContainerNoParams record
+#define U_PMR_ENDCONTAINER 0x0029 //!< U_PMREndContainer record
+#define U_PMR_SETWORLDTRANSFORM 0x002A //!< U_PMRSetWorldTransform record
+#define U_PMR_RESETWORLDTRANSFORM 0x002B //!< U_PMRResetWorldTransform record
+#define U_PMR_MULTIPLYWORLDTRANSFORM 0x002C //!< U_PMRMultiplyWorldTransform record
+#define U_PMR_TRANSLATEWORLDTRANSFORM 0x002D //!< U_PMRTranslateWorldTransform record
+#define U_PMR_SCALEWORLDTRANSFORM 0x002E //!< U_PMRScaleWorldTransform record
+#define U_PMR_ROTATEWORLDTRANSFORM 0x002F //!< U_PMRRotateWorldTransform record
+#define U_PMR_SETPAGETRANSFORM 0x0030 //!< U_PMRSetPageTransform record
+#define U_PMR_RESETCLIP 0x0031 //!< U_PMRResetClip record
+#define U_PMR_SETCLIPRECT 0x0032 //!< U_PMRSetClipRect record
+#define U_PMR_SETCLIPPATH 0x0033 //!< U_PMRSetClipPath record
+#define U_PMR_SETCLIPREGION 0x0034 //!< U_PMRSetClipRegion record
+#define U_PMR_OFFSETCLIP 0x0035 //!< U_PMROffsetClip record
+#define U_PMR_DRAWDRIVERSTRING 0x0036 //!< U_PMRDrawDriverstring record
+#define U_PMR_STROKEFILLPATH 0x0037 //!< U_PMRStrokeFillPath record
+#define U_PMR_SERIALIZABLEOBJECT 0x0038 //!< U_PMRSerializableObject record
+#define U_PMR_SETTSGRAPHICS 0x0039 //!< U_PMRSetTSGraphics record
+#define U_PMR_SETTSCLIP 0x003A //!< U_PMRSetTSClip record
+#define U_PMR_RECFLAG 0x4000 //!< In EMF+ files the type is one of the above + this flag
+#define U_PMR_TYPE_MASK 0x003F //!< mask for EMF+ types
+#define U_PMR_MIN 1 //!< Minimum U_PMR_ value.
+#define U_PMR_MAX 58 //!< Maximum U_PMR_ value.
+
+/** @} */
+
+/** \defgroup U_PMF_PID_Values PMF Identifiers for PseudoObjects
+ These are used by the *_set routines to identify types of PseudoObject.
+ Note that records are U_PMR_*_OID and other objects are U_PMF_*_OID
+ The numbers are derived from the EMF+ manual sections, as in 2.2.1.3 become
+ 02020103. Numbers 40000000 and up are not derived from manual setions.
+ @{
+*/
+#define U_UNDEFINED_OID 0x00000000 //!< Undefined PseudoObject
+#define U_PMF_BRUSH_OID 0x02020101 //!< PMF_BRUSH PseudoObject type.
+#define U_PMF_CUSTOMLINECAP_OID 0x02020102 //!< PMF_CUSTOMLINECAP PseudoObject type.
+#define U_PMF_FONT_OID 0x02020103 //!< PMF_FONT PseudoObject type.
+#define U_PMF_IMAGE_OID 0x02020104 //!< PMF_IMAGE PseudoObject type.
+#define U_PMF_IMAGEATTRIBUTES_OID 0x02020105 //!< PMF_IMAGEATTRIBUTES PseudoObject type.
+#define U_PMF_PATH_OID 0x02020106 //!< PMF_PATH PseudoObject type.
+#define U_PMF_PEN_OID 0x02020107 //!< PMF_PEN PseudoObject type.
+#define U_PMF_REGION_OID 0x02020108 //!< PMF_REGION PseudoObject type.
+#define U_PMF_STRINGFORMAT_OID 0x02020109 //!< PMF_STRINGFORMAT PseudoObject type.
+#define U_PMF_ARGB_OID 0x02020201 //!< PMF_ARGB PseudoObject type.
+#define U_PMF_BITMAP_OID 0x02020202 //!< PMF_BITMAP PseudoObject type.
+#define U_PMF_BITMAPDATA_OID 0x02020203 //!< PMF_BITMAPDATA PseudoObject type.
+#define U_PMF_BLENDCOLORS_OID 0x02020204 //!< PMF_BLENDCOLORS PseudoObject type.
+#define U_PMF_BLENDFACTORS_OID 0x02020205 //!< PMF_BLENDFACTORS PseudoObject type.
+#define U_PMF_BOUNDARYPATHDATA_OID 0x02020206 //!< PMF_BOUNDARYPATHDATA PseudoObject type.
+#define U_PMF_BOUNDARYPOINTDATA_OID 0x02020207 //!< PMF_BOUNDARYPOINTDATA PseudoObject type.
+#define U_PMF_CHARACTERRANGE_OID 0x02020208 //!< PMF_CHARACTERRANGE PseudoObject type.
+#define U_PMF_COMPOUNDLINEDATA_OID 0x02020209 //!< PMF_COMPOUNDLINEDATA PseudoObject type.
+#define U_PMF_COMPRESSEDIMAGE_OID 0x02020210 //!< PMF_COMPRESSEDIMAGE PseudoObject type.
+#define U_PMF_CUSTOMENDCAPDATA_OID 0x02020211 //!< PMF_CUSTOMENDCAPDATA PseudoObject type.
+#define U_PMF_CUSTOMLINECAPARROWDATA_OID 0x02020212 //!< PMF_CUSTOMLINECAPARROWDATA PseudoObject type.
+#define U_PMF_CUSTOMLINECAPDATA_OID 0x02020213 //!< PMF_CUSTOMLINECAPDATA PseudoObject type.
+#define U_PMF_CUSTOMLINECAPOPTIONALDATA_OID 0x02020214 //!< PMF_CUSTOMLINECAPOPTIONALDATA PseudoObject type.
+#define U_PMF_CUSTOMSTARTCAPDATA_OID 0x02020215 //!< PMF_CUSTOMSTARTCAPDATA PseudoObject type.
+#define U_PMF_DASHEDLINEDATA_OID 0x02020216 //!< PMF_DASHEDLINEDATA PseudoObject type.
+#define U_PMF_FILLPATHOBJ_OID 0x02020217 //!< PMF_FILLPATHOBJ PseudoObject type.
+#define U_PMF_FOCUSSCALEDATA_OID 0x02020218 //!< PMF_FOCUSSCALEDATA PseudoObject type.
+#define U_PMF_GRAPHICSVERSION_OID 0x02020219 //!< PMF_GRAPHICSVERSION PseudoObject type.
+#define U_PMF_HATCHBRUSHDATA_OID 0x02020220 //!< PMF_HATCHBRUSHDATA PseudoObject type.
+#define U_PMF_INTEGER7_OID 0x02020221 //!< PMF_INTEGER7 PseudoObject type.
+#define U_PMF_INTEGER15_OID 0x02020222 //!< PMF_INTEGER15 PseudoObject type.
+#define U_PMF_LANGUAGEIDENTIFIER_OID 0x02020223 //!< PMF_LANGUAGEIDENTIFIER PseudoObject type.
+#define U_PMF_LINEARGRADIENTBRUSHDATA_OID 0x02020224 //!< PMF_LINEARGRADIENTBRUSHDATA PseudoObject type.
+#define U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_OID 0x02020225 //!< PMF_LINEARGRADIENTBRUSHOPTIONALDATA PseudoObject type.
+#define U_PMF_LINEPATH_OID 0x02020226 //!< PMF_LINEPATH PseudoObject type.
+#define U_PMF_METAFILE_OID 0x02020227 //!< PMF_METAFILE PseudoObject type.
+#define U_PMF_PALETTE_OID 0x02020228 //!< PMF_PALETTE PseudoObject type.
+#define U_PMF_PATHGRADIENTBRUSHDATA_OID 0x02020229 //!< PMF_PATHGRADIENTBRUSHDATA PseudoObject type.
+#define U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_OID 0x02020230 //!< PMF_PATHGRADIENTBRUSHOPTIONALDATA PseudoObject type.
+#define U_PMF_PATHPOINTTYPE_OID 0x02020231 //!< PMF_PATHPOINTTYPE PseudoObject type.
+#define U_PMF_PATHPOINTTYPERLE_OID 0x02020232 //!< PMF_PATHPOINTTYPERLE PseudoObject type.
+#define U_PMF_PENDATA_OID 0x02020233 //!< PMF_PENDATA PseudoObject type.
+#define U_PMF_PENOPTIONALDATA_OID 0x02020234 //!< PMF_PENOPTIONALDATA PseudoObject type.
+#define U_PMF_POINT_OID 0x02020235 //!< PMF_POINT PseudoObject type.
+#define U_PMF_POINTF_OID 0x02020236 //!< PMF_POINTF PseudoObject type.
+#define U_PMF_POINTR_OID 0x02020237 //!< PMF_POINTR PseudoObject type.
+#define U_PMF_RECT_OID 0x02020238 //!< PMF_RECT PseudoObject type.
+#define U_PMF_RECTF_OID 0x02020239 //!< PMF_RECTF PseudoObject type.
+#define U_PMF_REGIONNODE_OID 0x02020240 //!< PMF_REGIONNODE PseudoObject type.
+#define U_PMF_REGIONNODECHILDNODES_OID 0x02020241 //!< PMF_REGIONNODECHILDNODES PseudoObject type.
+#define U_PMF_REGIONNODEPATH_OID 0x02020242 //!< PMF_REGIONNODEPATH PseudoObject type.
+#define U_PMF_SOLIDBRUSHDATA_OID 0x02020243 //!< PMF_SOLIDBRUSHDATA PseudoObject type.
+#define U_PMF_STRINGFORMATDATA_OID 0x02020244 //!< PMF_STRINGFORMATDATA PseudoObject type.
+#define U_PMF_TEXTUREBRUSHDATA_OID 0x02020245 //!< PMF_TEXTUREBRUSHDATA PseudoObject type.
+#define U_PMF_TEXTUREBRUSHOPTIONALDATA_OID 0x02020246 //!< PMF_TEXTUREBRUSHOPTIONALDATA PseudoObject type.
+#define U_PMF_TRANSFORMMATRIX_OID 0x02020247 //!< PMF_TRANSFORMMATRIX PseudoObject type.
+#define U_PMF_IE_BLUR_OID 0x02020301 //!< PMF_IE_BLUR PseudoObject type.
+#define U_PMF_IE_BRIGHTNESSCONTRAST_OID 0x02020302 //!< PMF_IE_BRIGHTNESSCONTRAST PseudoObject type.
+#define U_PMF_IE_COLORBALANCE_OID 0x02020303 //!< PMF_IE_COLORBALANCE PseudoObject type.
+#define U_PMF_IE_COLORCURVE_OID 0x02020304 //!< PMF_IE_COLORCURVE PseudoObject type.
+#define U_PMF_IE_COLORLOOKUPTABLE_OID 0x02020305 //!< PMF_IE_COLORLOOKUPTABLE PseudoObject type.
+#define U_PMF_IE_COLORMATRIX_OID 0x02020306 //!< PMF_IE_COLORMATRIX PseudoObject type.
+#define U_PMF_IE_HUESATURATIONLIGHTNESS_OID 0x02020307 //!< PMF_IE_HUESATURATIONLIGHTNESS PseudoObject type.
+#define U_PMF_IE_LEVELS_OID 0x02020308 //!< PMF_IE_LEVELS PseudoObject type.
+#define U_PMF_IE_REDEYECORRECTION_OID 0x02020309 //!< PMF_IE_REDEYECORRECTION PseudoObject type.
+#define U_PMF_IE_SHARPEN_OID 0x02020310 //!< PMF_IE_SHARPEN PseudoObject type.
+#define U_PMF_IE_TINT_OID 0x02020311 //!< PMF_IE_TINT PseudoObject type.
+#define U_PMR_STROKEFILLPATH_OID 0x02010101 //!< PMR_STROKEFILLPATH PseudoObject type. (Mentioned in passing here).
+#define U_PMR_OFFSETCLIP_OID 0x02030101 //!< PMR_OFFSETCLIP PseudoObject type.
+#define U_PMR_RESETCLIP_OID 0x02030102 //!< PMR_RESETCLIP PseudoObject type.
+#define U_PMR_SETCLIPPATH_OID 0x02030103 //!< PMR_SETCLIPPATH PseudoObject type.
+#define U_PMR_SETCLIPRECT_OID 0x02030104 //!< PMR_SETCLIPRECT PseudoObject type.
+#define U_PMR_SETCLIPREGION_OID 0x02030105 //!< PMR_SETCLIPREGION PseudoObject type.
+#define U_PMR_COMMENT_OID 0x02030201 //!< PMR_COMMENT PseudoObject type.
+#define U_PMR_ENDOFFILE_OID 0x02030301 //!< PMR_ENDOFFILE PseudoObject type.
+#define U_PMR_GETDC_OID 0x02030302 //!< PMR_GETDC PseudoObject type.
+#define U_PMR_HEADER_OID 0x02030303 //!< PMR_HEADER PseudoObject type.
+#define U_PMR_CLEAR_OID 0x02030401 //!< PMR_CLEAR PseudoObject type.
+#define U_PMR_DRAWARC_OID 0x02030402 //!< PMR_DRAWARC PseudoObject type.
+#define U_PMR_DRAWBEZIERS_OID 0x02030403 //!< PMR_DRAWBEZIERS PseudoObject type.
+#define U_PMR_DRAWCLOSEDCURVE_OID 0x02030404 //!< PMR_DRAWCLOSEDCURVE PseudoObject type.
+#define U_PMR_DRAWCURVE_OID 0x02030405 //!< PMR_DRAWCURVE PseudoObject type.
+#define U_PMR_DRAWDRIVERSTRING_OID 0x02030406 //!< PMR_DRAWDRIVERSTRING PseudoObject type.
+#define U_PMR_DRAWELLIPSE_OID 0x02030407 //!< PMR_DRAWELLIPSE PseudoObject type.
+#define U_PMR_DRAWIMAGE_OID 0x02030408 //!< PMR_DRAWIMAGE PseudoObject type.
+#define U_PMR_DRAWIMAGEPOINTS_OID 0x02030409 //!< PMR_DRAWIMAGEPOINTS PseudoObject type.
+#define U_PMR_DRAWLINES_OID 0x02030410 //!< PMR_DRAWLINES PseudoObject type.
+#define U_PMR_DRAWPATH_OID 0x02030411 //!< PMR_DRAWPATH PseudoObject type.
+#define U_PMR_DRAWPIE_OID 0x02030412 //!< PMR_DRAWPIE PseudoObject type.
+#define U_PMR_DRAWRECTS_OID 0x02030413 //!< PMR_DRAWRECTS PseudoObject type.
+#define U_PMR_DRAWSTRING_OID 0x02030414 //!< PMR_DRAWSTRING PseudoObject type.
+#define U_PMR_FILLCLOSEDCURVE_OID 0x02030415 //!< PMR_FILLCLOSEDCURVE PseudoObject type.
+#define U_PMR_FILLELLIPSE_OID 0x02030416 //!< PMR_FILLELLIPSE PseudoObject type.
+#define U_PMR_FILLPATH_OID 0x02030417 //!< PMR_FILLPATH PseudoObject type.
+#define U_PMR_FILLPIE_OID 0x02030418 //!< PMR_FILLPIE PseudoObject type.
+#define U_PMR_FILLPOLYGON_OID 0x02030419 //!< PMR_FILLPOLYGON PseudoObject type.
+#define U_PMR_FILLRECTS_OID 0x02030420 //!< PMR_FILLRECTS PseudoObject type.
+#define U_PMR_FILLREGION_OID 0x02030421 //!< PMR_FILLREGION PseudoObject type.
+#define U_PMR_OBJECT_OID 0x02030501 //!< PMR_OBJECT PseudoObject type.
+#define U_PMR_SERIALIZABLEOBJECT_OID 0x02030502 //!< PMR_SERIALIZABLEOBJECT PseudoObject type.
+#define U_PMR_SETANTIALIASMODE_OID 0x02030601 //!< PMR_SETANTIALIASMODE PseudoObject type.
+#define U_PMR_SETCOMPOSITINGMODE_OID 0x02030602 //!< PMR_SETCOMPOSITINGMODE PseudoObject type.
+#define U_PMR_SETCOMPOSITINGQUALITY_OID 0x02030603 //!< PMR_SETCOMPOSITINGQUALITY PseudoObject type.
+#define U_PMR_SETINTERPOLATIONMODE_OID 0x02030604 //!< PMR_SETINTERPOLATIONMODE PseudoObject type.
+#define U_PMR_SETPIXELOFFSETMODE_OID 0x02030605 //!< PMR_SETPIXELOFFSETMODE PseudoObject type.
+#define U_PMR_SETRENDERINGORIGIN_OID 0x02030606 //!< PMR_SETRENDERINGORIGIN PseudoObject type.
+#define U_PMR_SETTEXTCONTRAST_OID 0x02030607 //!< PMR_SETTEXTCONTRAST PseudoObject type.
+#define U_PMR_SETTEXTRENDERINGHINT_OID 0x02030608 //!< PMR_SETTEXTRENDERINGHINT PseudoObject type.
+#define U_PMR_BEGINCONTAINER_OID 0x02030701 //!< PMR_BEGINCONTAINER PseudoObject type.
+#define U_PMR_BEGINCONTAINERNOPARAMS_OID 0x02030702 //!< PMR_BEGINCONTAINERNOPARAMS PseudoObject type.
+#define U_PMR_ENDCONTAINER_OID 0x02030703 //!< PMR_ENDCONTAINER PseudoObject type.
+#define U_PMR_RESTORE_OID 0x02030704 //!< PMR_RESTORE PseudoObject type.
+#define U_PMR_SAVE_OID 0x02030705 //!< PMR_SAVE PseudoObject type.
+#define U_PMR_SETTSCLIP_OID 0x02030801 //!< PMR_SETTSCLIP PseudoObject type.
+#define U_PMR_SETTSGRAPHICS_OID 0x02030802 //!< PMR_SETTSGRAPHICS PseudoObject type.
+#define U_PMR_MULTIPLYWORLDTRANSFORM_OID 0x02030901 //!< PMR_MULTIPLYWORLDTRANSFORM PseudoObject type.
+#define U_PMR_RESETWORLDTRANSFORM_OID 0x02030902 //!< PMR_RESETWORLDTRANSFORM PseudoObject type.
+#define U_PMR_ROTATEWORLDTRANSFORM_OID 0x02030903 //!< PMR_ROTATEWORLDTRANSFORM PseudoObject type.
+#define U_PMR_SCALEWORLDTRANSFORM_OID 0x02030904 //!< PMR_SCALEWORLDTRANSFORM PseudoObject type.
+#define U_PMR_SETPAGETRANSFORM_OID 0x02030905 //!< PMR_SETPAGETRANSFORM PseudoObject type.
+#define U_PMR_SETWORLDTRANSFORM_OID 0x02030906 //!< PMR_SETWORLDTRANSFORM PseudoObject type.
+#define U_PMR_TRANSLATEWORLDTRANSFORM_OID 0x02030907 //!< PMR_TRANSLATEWORLDTRANSFORM PseudoObject type.
+#define U_PMR_TRANSLATEWORLDTRANSFORM_OID 0x02030907 //!< PMR_TRANSLATEWORLDTRANSFORM PseudoObject type.
+#define U_PMR_CMN_HDR_OID 0x40000000 //!< PMR_CMN_HDR PseudoObject type.
+#define U_PMF_4NUM_OID 0x40000001 //!< PMF_4NUM PseudoObject type. PseudoObject contains a 4 unsigned int in EMF+ file byte order, used in some contexts to indicate an object index number..
+#define U_PMF_RAW_OID 0x40000002 //!< PMF_RAW PseudoObject type. Raw data: no preceding elements, data has native endianness.
+#define U_PMF_ARRAY_OID 0x80000000 //!< PMF_ARRAY PseudoObject type modifier. PseudoObject contains an array of the data type revealed when this bit is cleared.
+#define U_PMF_MASK_OID 0x7FFFFFFF //!< PMF_MASK. Select PseudoObject data type without regard to PMF_ARRAY.
+
+/** @} */
+
+
+/** \defgroup U_PMF_BDT_ PMF BitmapDataType Enumeration
+ For
+ EMF+ manual 2.1.1.2, Microsoft name: BitmapDataType Enumeration (U_BDT_*)
+ @{
+*/
+#define U_BDT_Pixel 0x00 //!< Data is a bitmap.
+#define U_BDT_Compressed 0x01 //!< Data is a compressed bitmap (like a PNG).
+/** @} */
+
+/** \defgroup U_PMF_BT_ PMF BrushType Enumeration
+ For
+ EMF+ manual 2.1.1.3, Microsoft name: BrushType Enumeration (U_BT_*)
+ @{
+*/
+#define U_BT_SolidColor 0x00 //!< Solid Color brush.
+#define U_BT_HatchFill 0x01 //!< Hatch Fill brush.
+#define U_BT_TextureFill 0x02 //!< Texture Fill brush.
+#define U_BT_PathGradient 0x03 //!< Path Gradient brush.
+#define U_BT_LinearGradient 0x04 //!< Linear Gradient brush.
+/** @} */
+
+/** \defgroup U_PMF_CM_ PMF CombineMode Enumeration
+ For
+ EMF+ manual 2.1.1.4, Microsoft name: CombineMode Enumeration (U_CM_*)
+ @{
+*/
+#define U_CM_Replace 0x00 //!< Region becomes new region.
+#define U_CM_Intersect 0x01 //!< Region becomes intersection of existing region and new region.
+#define U_CM_Union 0x02 //!< Region becomes union of existing and new regions.
+#define U_CM_XOR 0x03 //!< Region becomes XOR of existing and new regions.
+#define U_CM_Exclude 0x04 //!< Region becomes part of existing region not in new region.
+#define U_CM_Complement 0x05 //!< Region becomes part of new region not in existing region.
+/** @} */
+
+/** \defgroup U_PMF_CMS_ PMF CompositingMode Enumeration
+ For
+ EMF+ manual 2.1.1.5, Microsoft name: CompositingMode Enumeration (U_CMS_* [S==Source])
+ @{
+*/
+#define U_CMS_Over 0x00 //!< Source is alpha blends with destination.
+#define U_CMS_Copy 0x01 //!< Source over writes destination.
+/** @} */
+
+/** \defgroup U_PMF_CQ_ PMF CompositingQuality Enumeration
+ For
+ EMF+ manual 2.1.1.6, Microsoft name: CompositingQuality Enumeration (U_CQ_*)
+ @{
+*/
+#define U_CQ_Default 0x01 //!< Default compositing quality
+#define U_CQ_HighSpeed 0x02 //!< High Speed compositing quality
+#define U_CQ_HighQuality 0x03 //!< High Quality compositing quality
+#define U_CQ_GammaCorrected 0x04 //!< Gamma Corrected compositing quality
+#define U_CQ_AssumeLinear 0x05 //!< Assume Linear compositing quality
+/** @} */
+
+/** \defgroup U_PMF_CA_ PMF CurveAdjustments Enumeration
+ For
+ EMF+ manual 2.1.1.7, Microsoft name: CurveAdjustments Enumeration (U_CA_*)
+ @{
+*/
+#define U_CA_Exposure 0x00 //!< Exposure color curve adjustment
+#define U_CA_Density 0x01 //!< Density color curve adjustment
+#define U_CA_Contrast 0x02 //!< Contrast color curve adjustment
+#define U_CA_Highlight 0x03 //!< Highlight color curve adjustment
+#define U_CA_Shadow 0x04 //!< Shadow color curve adjustment
+#define U_CA_Midtone 0x05 //!< Midtone color curve adjustment
+#define U_CA_WhiteSaturation 0x06 //!< White Saturation color curve adjustment
+#define U_CA_BlackSaturation 0x07 //!< Black Saturation color curve adjustment
+/** @} */
+
+/** \defgroup U_PMF_CC_ PMF CurveChannel Enumeration
+ For
+ EMF+ manual 2.1.1.8, Microsoft name: CurveChannel Enumeration (U_CC_*)
+ @{
+*/
+#define U_CC_All 0x00 //!< All color channels
+#define U_CC_Red 0x01 //!< Red color channel
+#define U_CC_Green 0x02 //!< Green color channel
+#define U_CC_Blue 0x03 //!< Blue color channel
+/** @} */
+
+/** \defgroup U_PMF_CLCDT_ PMF CustomLineCapDataType Enumeration
+ For
+ EMF+ manual 2.1.1.9, Microsoft name: CustomLineCapDataType Enumeration (U_CLCDT_*)
+ @{
+*/
+#define U_CLCDT_Default 0x00 //!< Default custom line cap
+#define U_CLCDT_AdjustableArrow 0x01 //!< Adjustable Arrow custom line cap
+/** @} */
+
+/** \defgroup U_PMF_DLCT_ PMF DashedLineCapType Enumeration
+ For
+ EMF+ manual 2.1.1.10, Microsoft name: DashedLineCapType Enumeration (U_DLCT_*)
+ @{
+*/
+#define U_DLCT_Flat 0x00 //!< Flat dashed line cap
+#define U_DLCT_Round 0x02 //!< Round dashed line cap
+#define U_DLCT_Triangle 0x03 //!< Triangle dashed line cap
+/** @} */
+
+/** \defgroup U_PMF_FT_ PMF FilterType Enumeration
+ For
+ EMF+ manual 2.1.1.11, Microsoft name: FilterType Enumeration (U_FT_*)
+ @{
+*/
+#define U_FT_None 0x00 //!< No filtering
+#define U_FT_Point 0x01 //!< Point filtering
+#define U_FT_Linear 0x02 //!< Linear filtering
+#define U_FT_Triangle 0x03 //!< Triangle filtering
+#define U_FT_Box 0x04 //!< Box filtering
+#define U_FT_PyramidalQuad 0x06 //!< Pyramidal Quad filtering
+#define U_FT_GaussianQuad 0x07 //!< Gaussian Quad filtering
+/** @} */
+
+/** \defgroup U_PMF_GV_ PMF GraphicsVersion Enumeration
+ For
+ EMF+ manual 2.1.1.12, Microsoft name: GraphicsVersion Enumeration (U_GV_*)
+ @{
+*/
+#define U_GV_1 0x01 //!< 1 graphics version
+#define U_GV_1_1 0x02 //!< 1.1 graphics version
+/** @} */
+
+/** \defgroup U_PMF_HSP_ PMF HatchStyle Enumeration
+ For
+ EMF+ manual 2.1.1.13, Microsoft name: HatchStyle Enumeration (U_HSP_* [U_HS_ already used for EMF])
+ @{
+*/
+#define U_HSP_Horizontal 0x00000000 //!< Horizontal
+#define U_HSP_Vertical 0x00000001 //!< Vertical
+#define U_HSP_ForwardDiagonal 0x00000002 //!< Forward Diagonal
+#define U_HSP_BackwardDiagonal 0x00000003 //!< Backward Diagonal
+#define U_HSP_LargeGrid 0x00000004 //!< Large Grid
+#define U_HSP_DiagonalCross 0x00000005 //!< Diagonal Cross
+#define U_HSP_05Percent 0x00000006 //!< 05 Percent
+#define U_HSP_10Percent 0x00000007 //!< 10 Percent
+#define U_HSP_20Percent 0x00000008 //!< 20 Percent
+#define U_HSP_25Percent 0x00000009 //!< 25 Percent
+#define U_HSP_30Percent 0x0000000A //!< 30 Percent
+#define U_HSP_40Percent 0x0000000B //!< 40 Percent
+#define U_HSP_50Percent 0x0000000C //!< 50 Percent
+#define U_HSP_60Percent 0x0000000D //!< 60 Percent
+#define U_HSP_70Percent 0x0000000E //!< 70 Percent
+#define U_HSP_75Percent 0x0000000F //!< 75 Percent
+#define U_HSP_80Percent 0x00000010 //!< 80 Percent
+#define U_HSP_90Percent 0x00000011 //!< 90 Percent
+#define U_HSP_LightDownwardDiagonal 0x00000012 //!< Light Downward Diagonal
+#define U_HSP_LightUpwardDiagonal 0x00000013 //!< Light Upward Diagonal
+#define U_HSP_DarkDownwardDiagonal 0x00000014 //!< Dark Downward Diagonal
+#define U_HSP_DarkUpwardDiagonal 0x00000015 //!< Dark Upward Diagonal
+#define U_HSP_WideDownwardDiagonal 0x00000016 //!< Wide Downward Diagonal
+#define U_HSP_WideUpwardDiagonal 0x00000017 //!< Wide Upward Diagonal
+#define U_HSP_LightVertical 0x00000018 //!< Light Vertical
+#define U_HSP_LightHorizontal 0x00000019 //!< Light Horizontal
+#define U_HSP_NarrowVertical 0x0000001A //!< Narrow Vertical
+#define U_HSP_NarrowHorizontal 0x0000001B //!< Narrow Horizontal
+#define U_HSP_DarkVertical 0x0000001C //!< Dark Vertical
+#define U_HSP_DarkHorizontal 0x0000001D //!< Dark Horizontal
+#define U_HSP_DashedDownwardDiagonal 0x0000001E //!< Dashed Downward Diagonal
+#define U_HSP_DashedUpwardDiagonal 0x0000001F //!< Dashed Upward Diagonal
+#define U_HSP_DashedHorizontal 0x00000020 //!< Dashed Horizontal
+#define U_HSP_DashedVertical 0x00000021 //!< Dashed Vertical
+#define U_HSP_SmallConfetti 0x00000022 //!< Small Confetti
+#define U_HSP_LargeConfetti 0x00000023 //!< LargeC onfetti
+#define U_HSP_ZigZag 0x00000024 //!< Zig Zag
+#define U_HSP_Wave 0x00000025 //!< Wave
+#define U_HSP_DiagonalBrick 0x00000026 //!< Diagonal Brick
+#define U_HSP_HorizontalBrick 0x00000027 //!< Horizontal Brick
+#define U_HSP_Weave 0x00000028 //!< Weave
+#define U_HSP_Plaid 0x00000029 //!< Plaid
+#define U_HSP_Divot 0x0000002A //!< Divot
+#define U_HSP_DottedGrid 0x0000002B //!< DottedGrid
+#define U_HSP_DottedDiamond 0x0000002C //!< DottedDiamond
+#define U_HSP_Shingle 0x0000002D //!< Shingle
+#define U_HSP_Trellis 0x0000002E //!< Trellis
+#define U_HSP_Sphere 0x0000002F //!< Sphere
+#define U_HSP_SmallGrid 0x00000030 //!< Small Grid
+#define U_HSP_SmallCheckerBoard 0x00000031 //!< Small Checker Board
+#define U_HSP_LargeCheckerBoard 0x00000032 //!< Large Checker Board
+#define U_HSP_OutlinedDiamond 0x00000033 //!< Outlined Diamond
+#define U_HSP_SolidDiamond 0x00000034 //!< Solid Diamond
+/** @} */
+
+/** \defgroup U_PMF_HKP_ PMF HotkeyPrefix Enumeration
+ For
+ EMF+ manual 2.1.1.14, Microsoft name: HotkeyPrefix Enumeration (U_HKP_*)
+ @{
+*/
+#define U_HKP_None 0x00 //!< No hot key prefix
+#define U_HKP_Show 0x01 //!< Show hot key prefix
+#define U_HKP_Hide 0x02 //!< Hide hot key prefix
+/** @} */
+
+/** \defgroup U_PMF_IDT_ PMF ImageDataType Enumeration
+ For
+ EMF+ manual 2.1.1.15, Microsoft name: ImageDataType Enumeration (U_IDT_*)
+ @{
+*/
+#define U_IDT_Unknown 0x00 //!< Unknown image data type
+#define U_IDT_Bitmap 0x01 //!< Bitmap image data type
+#define U_IDT_Metafile 0x02 //!< Metafile image data type
+/** @} */
+
+/** \defgroup U_PMF_IM_ PMF InterpolationMode Enumeration
+ For
+ EMF+ manual 2.1.1.16, Microsoft name: InterpolationMode Enumeration (U_IM_*)
+ @{
+*/
+#define U_IM_Default 0x00 //!< Default interpolation mode
+#define U_IM_LowQuality 0x01 //!< Low Quality interpolation mode
+#define U_IM_HighQuality 0x02 //!< High Quality interpolation mode
+#define U_IM_Bilinear 0x03 //!< Bilinear interpolation mode
+#define U_IM_Bicubic 0x04 //!< Bicubic interpolation mode
+#define U_IM_NearestNeighbor 0x05 //!< Nearest Neighbor interpolation mode
+#define U_IM_HighQualityBilinear 0x06 //!< High Quality Bilinear interpolation mode
+#define U_IM_HighQualityBicubic 0x07 //!< High Quality Bicubic interpolation mode
+/** @} */
+
+/** \defgroup U_PMF_LID_ PMF LanguageIdentifier Enumeration
+ For
+ EMF+ manual 2.1.1.17, Microsoft name: LanguageIdentifier Enumeration (U_LID_*)
+ @{
+*/
+#define U_LID_LANG_NEUTRAL 0x0000 //!< LANG_NEUTRAL
+#define U_LID_zh_CHS 0x0004 //!< zh_CHS
+#define U_LID_LANG_INVARIANT 0x007F //!< LANG_INVARIANT
+#define U_LID_LANG_NEUTRAL_USER_DEFAULT 0x0400 //!< LANG_NEUTRAL_USER_DEFAULT
+#define U_LID_ar_SA 0x0401 //!< ar_SA
+#define U_LID_bg_BG 0x0402 //!< bg_BG
+#define U_LID_ca_ES 0x0403 //!< ca_ES
+#define U_LID_zh_CHT 0x0404 //!< zh_CHT
+#define U_LID_cs_CZ 0x0405 //!< cs_CZ
+#define U_LID_da_DK 0x0406 //!< da_DK
+#define U_LID_de_DE 0x0407 //!< de_DE
+#define U_LID_el_GR 0x0408 //!< el_GR
+#define U_LID_en_US 0x0409 //!< en_US
+#define U_LID_es_Tradnl_ES 0x040A //!< es_Tradnl_ES
+#define U_LID_fi_FI 0x040B //!< fi_FI
+#define U_LID_fr_FR 0x040C //!< fr_FR
+#define U_LID_he_IL 0x040D //!< he_IL
+#define U_LID_hu_HU 0x040E //!< hu_HU
+#define U_LID_is_IS 0x040F //!< is_IS
+#define U_LID_it_IT 0x0410 //!< it_IT
+#define U_LID_ja_JA 0x0411 //!< ja_JA
+#define U_LID_ko_KR 0x0412 //!< ko_KR
+#define U_LID_nl_NL 0x0413 //!< nl_NL
+#define U_LID_nb_NO 0x0414 //!< nb_NO
+#define U_LID_pl_PL 0x0415 //!< pl_PL
+#define U_LID_pt_BR 0x0416 //!< pt_BR
+#define U_LID_rm_CH 0x0417 //!< rm_CH
+#define U_LID_ro_RO 0x0418 //!< ro_RO
+#define U_LID_ru_RU 0x0419 //!< ru_RU
+#define U_LID_hr_HR 0x041A //!< hr_HR
+#define U_LID_sk_SK 0x041B //!< sk_SK
+#define U_LID_sq_AL 0x041C //!< sq_AL
+#define U_LID_sv_SE 0x041D //!< sv_SE
+#define U_LID_th_TH 0x041E //!< th_TH
+#define U_LID_tr_TR 0x041F //!< tr_TR
+#define U_LID_ur_PK 0x0420 //!< ur_PK
+#define U_LID_id_ID 0x0421 //!< id_ID
+#define U_LID_uk_UA 0x0422 //!< uk_UA
+#define U_LID_be_BY 0x0423 //!< be_BY
+#define U_LID_sl_SI 0x0424 //!< sl_SI
+#define U_LID_et_EE 0x0425 //!< et_EE
+#define U_LID_lv_LV 0x0426 //!< lv_LV
+#define U_LID_lt_LT 0x0427 //!< lt_LT
+#define U_LID_tg_TJ 0x0428 //!< tg_TJ
+#define U_LID_fa_IR 0x0429 //!< fa_IR
+#define U_LID_vi_VN 0x042A //!< vi_VN
+#define U_LID_hy_AM 0x042B //!< hy_AM
+#define U_LID_az_Latn_AZ 0x042C //!< az_Latn_AZ
+#define U_LID_eu_ES 0x042D //!< eu_ES
+#define U_LID_wen_DE 0x042E //!< wen_DE
+#define U_LID_mk_MK 0x042F //!< mk_MK
+#define U_LID_st_ZA 0x0430 //!< st_ZA
+#define U_LID_tn_ZA 0x0432 //!< tn_ZA
+#define U_LID_xh_ZA 0x0434 //!< xh_ZA
+#define U_LID_zu_ZA 0x0435 //!< zu_ZA
+#define U_LID_af_ZA 0x0436 //!< af_ZA
+#define U_LID_ka_GE 0x0437 //!< ka_GE
+#define U_LID_fa_FA 0x0438 //!< fa_FA
+#define U_LID_hi_IN 0x0439 //!< hi_IN
+#define U_LID_mt_MT 0x043A //!< mt_MT
+#define U_LID_se_NO 0x043B //!< se_NO
+#define U_LID_ga_GB 0x043C //!< ga_GB
+#define U_LID_ms_MY 0x043E //!< ms_MY
+#define U_LID_kk_KZ 0x043F //!< kk_KZ
+#define U_LID_ky_KG 0x0440 //!< ky_KG
+#define U_LID_sw_KE 0x0441 //!< sw_KE
+#define U_LID_tk_TM 0x0442 //!< tk_TM
+#define U_LID_uz_Latn_UZ 0x0443 //!< uz_Latn_UZ
+#define U_LID_tt_Ru 0x0444 //!< tt_Ru
+#define U_LID_bn_IN 0x0445 //!< bn_IN
+#define U_LID_pa_IN 0x0446 //!< pa_IN
+#define U_LID_gu_IN 0x0447 //!< gu_IN
+#define U_LID_or_IN 0x0448 //!< or_IN
+#define U_LID_ta_IN 0x0449 //!< ta_IN
+#define U_LID_te_IN 0x044A //!< te_IN
+#define U_LID_kn_IN 0x044B //!< kn_IN
+#define U_LID_ml_IN 0x044C //!< ml_IN
+#define U_LID_as_IN 0x044D //!< as_IN
+#define U_LID_mr_IN 0x044E //!< mr_IN
+#define U_LID_sa_IN 0x044F //!< sa_IN
+#define U_LID_mn_MN 0x0450 //!< mn_MN
+#define U_LID_bo_CN 0x0451 //!< bo_CN
+#define U_LID_cy_GB 0x0452 //!< cy_GB
+#define U_LID_km_KH 0x0453 //!< km_KH
+#define U_LID_lo_LA 0x0454 //!< lo_LA
+#define U_LID_gl_ES 0x0456 //!< gl_ES
+#define U_LID_kok_IN 0x0457 //!< kok_IN
+#define U_LID_sd_IN 0x0459 //!< sd_IN
+#define U_LID_syr_SY 0x045A //!< syr_SY
+#define U_LID_si_LK 0x045B //!< si_LK
+#define U_LID_iu_Cans_CA 0x045D //!< iu_Cans_CA
+#define U_LID_am_ET 0x045E //!< am_ET
+#define U_LID_ne_NP 0x0461 //!< ne_NP
+#define U_LID_fy_NL 0x0462 //!< fy_NL
+#define U_LID_ps_AF 0x0463 //!< ps_AF
+#define U_LID_fil_PH 0x0464 //!< fil_PH
+#define U_LID_div_MV 0x0465 //!< div_MV
+#define U_LID_ha_Latn_NG 0x0468 //!< ha_Latn_NG
+#define U_LID_yo_NG 0x046A //!< yo_NG
+#define U_LID_quz_BO 0x046B //!< quz_BO
+#define U_LID_nzo_ZA 0x046C //!< nzo_ZA
+#define U_LID_ba_RU 0x046D //!< ba_RU
+#define U_LID_lb_LU 0x046E //!< lb_LU
+#define U_LID_kl_GL 0x046F //!< kl_GL
+#define U_LID_ig_NG 0x0470 //!< ig_NG
+#define U_LID_so_SO 0x0477 //!< so_SO
+#define U_LID_ii_CN 0x0478 //!< ii_CN
+#define U_LID_arn_CL 0x047A //!< arn_CL
+#define U_LID_moh_CA 0x047C //!< moh_CA
+#define U_LID_br_FR 0x047E //!< br_FR
+#define U_LID_ug_CN 0x0480 //!< ug_CN
+#define U_LID_ mi_NZ 0x0481 //!< mi_NZ
+#define U_LID_oc_FR 0x0482 //!< oc_FR
+#define U_LID_co_FR 0x0483 //!< co_FR
+#define U_LID_gsw_FR 0x0484 //!< gsw_FR
+#define U_LID_sah_RU 0x0485 //!< sah_RU
+#define U_LID_qut_GT 0x0486 //!< qut_GT
+#define U_LID_rw_RW 0x0487 //!< rw_RW
+#define U_LID_wo_SN 0x0488 //!< wo_SN
+#define U_LID_gbz_AF 0x048C //!< gbz_AF
+#define U_LID_LANG_NEUTRAL_SYS_DEFAULT 0x0800 //!< LANG_NEUTRAL_SYS_DEFAULT
+#define U_LID_ar_IQ 0x0801 //!< ar_IQ
+#define U_LID_zh_CN 0x0804 //!< zh_CN
+#define U_LID_de_CH 0x0807 //!< de_CH
+#define U_LID_en_GB 0x0809 //!< en_GB
+#define U_LID_es_MX 0x080A //!< es_MX
+#define U_LID_fr_BE 0x080C //!< fr_BE
+#define U_LID_it_CH 0x0810 //!< it_CH
+#define U_LID_ko_Johab_KR 0x0812 //!< ko_Johab_KR
+#define U_LID_nl_BE 0x0813 //!< nl_BE
+#define U_LID_nn_NO 0x0814 //!< nn_NO
+#define U_LID_pt_PT 0x0816 //!< pt_PT
+#define U_LID_sr_Latn_SP 0x081A //!< sr_Latn_SP
+#define U_LID_sv_FI 0x081D //!< sv_FI
+#define U_LID_ur_IN 0x0820 //!< ur_IN
+#define U_LID_lt_C_LT 0x0827 //!< lt_C_LT
+#define U_LID_az_Cyrl_AZ 0x082C //!< az_Cyrl_AZ
+#define U_LID_wee_DE 0x082E //!< wee_DE
+#define U_LID_se_SE 0x083B //!< se_SE
+#define U_LID_ga_IE 0x083C //!< ga_IE
+#define U_LID_ms_BN 0x083E //!< ms_BN
+#define U_LID_uz_Cyrl_UZ 0x0843 //!< uz_Cyrl_UZ
+#define U_LID_bn_BD 0x0845 //!< bn_BD
+#define U_LID_mn_Mong_CN 0x0850 //!< mn_Mong_CN
+#define U_LID_sd_PK 0x0859 //!< sd_PK
+#define U_LID_iu_Latn_CA 0x085D //!< iu_Latn_CA
+#define U_LID_tzm_Latn_DZ 0x085F //!< tzm_Latn_DZ
+#define U_LID_quz_EC 0x086B //!< quz_EC
+#define U_LID_LANG_NEUTRAL_CUSTOM_DEFAULT 0x0C00 //!< LANG_NEUTRAL_CUSTOM_DEFAULT
+#define U_LID_ar_EG 0x0C01 //!< ar_EG
+#define U_LID_zh_HK 0x0C04 //!< zh_HK
+#define U_LID_de_AT 0x0C07 //!< de_AT
+#define U_LID_en_AU 0x0C09 //!< en_AU
+#define U_LID_es_ES 0x0C0A //!< es_ES
+#define U_LID_fr_CA 0x0C0C //!< fr_CA
+#define U_LID_sr_Cyrl_CS 0x0C1A //!< sr_Cyrl_CS
+#define U_LID_se_FI 0x0C3B //!< se_FI
+#define U_LID_quz_PE 0x0C6B //!< quz_PE
+#define U_LID_LANG_NEUTRAL_CUSTOM 0x1000 //!< LANG_NEUTRAL_CUSTOM
+#define U_LID_ar_LY 0x1001 //!< ar_LY
+#define U_LID_zh_SG 0x1004 //!< zh_SG
+#define U_LID_de_LU 0x1007 //!< de_LU
+#define U_LID_en_CA 0x1009 //!< en_CA
+#define U_LID_es_GT 0x100A //!< es_GT
+#define U_LID_fr_CH 0x100C //!< fr_CH
+#define U_LID_hr_BA 0x101A //!< hr_BA
+#define U_LID_smj_NO 0x103B //!< smj_NO
+#define U_LID_LANG_NEUTRAL_CUSTOM_DEFAULT_MUI 0x1400 //!< LANG_NEUTRAL_CUSTOM_DEFAULT_MUI
+#define U_LID_ar_DZ 0x1401 //!< ar_DZ
+#define U_LID_zh_MO 0x1404 //!< zh_MO
+#define U_LID_de_LI 0x1407 //!< de_LI
+#define U_LID_en_NZ 0x1409 //!< en_NZ
+#define U_LID_es_CR 0x140A //!< es_CR
+#define U_LID_fr_LU 0x140C //!< fr_LU
+#define U_LID_bs_Latn_BA 0x141A //!< bs_Latn_BA
+#define U_LID_smj_SE 0x143B //!< smj_SE
+#define U_LID_ar_MA 0x1801 //!< ar_MA
+#define U_LID_en_IE 0x1809 //!< en_IE
+#define U_LID_es_PA 0x180A //!< es_PA
+#define U_LID_ar_MC 0x180C //!< ar_MC
+#define U_LID_sr_Latn_BA 0x181A //!< sr_Latn_BA
+#define U_LID_sma_NO 0x183B //!< sma_NO
+#define U_LID_ar_TN 0x1C01 //!< ar_TN
+#define U_LID_en_ZA 0x1C09 //!< en_ZA
+#define U_LID_es_DO 0x1C0A //!< es_DO
+#define U_LID_sr_Cyrl_BA 0x1C1A //!< sr_Cyrl_BA
+#define U_LID_sma_SE 0x1C3B //!< sma_SE
+#define U_LID_ar_OM 0x2001 //!< ar_OM
+#define U_LID_el_2_GR 0x2008 //!< el_2_GR
+#define U_LID_en_JM 0x2009 //!< en_JM
+#define U_LID_es_VE 0x200A //!< es_VE
+#define U_LID_bs_Cyrl_BA 0x201A //!< bs_Cyrl_BA
+#define U_LID_sms_FI 0x203B //!< sms_FI
+#define U_LID_ar_YE 0x2401 //!< ar_YE
+#define U_LID_ar_029 0x2409 //!< ar_029
+#define U_LID_es_CO 0x240A //!< es_CO
+#define U_LID_smn_FI 0x243B //!< smn_FI
+#define U_LID_ar_SY 0x2801 //!< ar_SY
+#define U_LID_en_BZ 0x2809 //!< en_BZ
+#define U_LID_es_PE 0x280A //!< es_PE
+#define U_LID_ar_JO 0x2C01 //!< ar_JO
+#define U_LID_en_TT 0x2C09 //!< en_TT
+#define U_LID_es_AR 0x2C0A //!< es_AR
+#define U_LID_ar_LB 0x3001 //!< ar_LB
+#define U_LID_en_ZW 0x3009 //!< en_ZW
+#define U_LID_es_EC 0x300A //!< es_EC
+#define U_LID_ar_KW 0x3401 //!< ar_KW
+#define U_LID_en_PH 0x3409 //!< en_PH
+#define U_LID_es_CL 0x340A //!< es_CL
+#define U_LID_ar_AE 0x3801 //!< ar_AE
+#define U_LID_es_UY 0x380A //!< es_UY
+#define U_LID_ar_BH 0x3C01 //!< ar_BH
+#define U_LID_es_PY 0x3C0A //!< es_PY
+#define U_LID_ar_QA 0x4001 //!< ar_QA
+#define U_LID_en_IN 0x4009 //!< en_IN
+#define U_LID_es_BO 0x400A //!< es_BO
+#define U_LID_en_MY 0x4409 //!< en_MY
+#define U_LID_es_SV 0x440A //!< es_SV
+#define U_LID_en_SG 0x4809 //!< en_SG
+#define U_LID_es_HN 0x480A //!< es_HN
+#define U_LID_es_NI 0x4C0A //!< es_NI
+#define U_LID_es_PR 0x500A //!< es_PR
+#define U_LID_es_US 0x540A //!< es_US
+#define U_LID_zh_Hant 0x7C04 //!< zh_Hant
+#define U_LID_SEC_MASK 0xFB00 //!< Mask for region part of LID
+#define U_LID_PRI_MASK 0x03FF //!< MASK for languagepart of LID
+/** @} */
+
+/** \defgroup U_PMF_LCT_ PMF LineCapType Enumeration
+ For
+ EMF+ manual 2.1.1.18, Microsoft name: LineCapType Enumeration (U_LCT_*)
+ @{
+*/
+#define U_LCT_Flat 0x00 //!< Flat line cap
+#define U_LCT_Square 0x01 //!< Square line cap
+#define U_LCT_Round 0x02 //!< Round line cap
+#define U_LCT_Triangle 0x03 //!< Triangle line cap
+#define U_LCT_NoAnchor 0x10 //!< No Anchor line cap
+#define U_LCT_SquareAnchor 0x11 //!< Square Anchor line cap
+#define U_LCT_RoundAnchor 0x12 //!< Round Anchor line cap
+#define U_LCT_DiamondAnchor 0x13 //!< Diamond Anchor line cap
+#define U_LCT_ArrowAnchor 0x14 //!< Arrow Anchor line cap
+#define U_LCT_AnchorMask 0xF0 //!< Ancho rMask line cap
+#define U_LCT_Custom 0xFF //!< Custom line cap
+/** @} */
+
+/** \defgroup U_PMF_LJT_ PMF LineJoinType Enumeration
+ For
+ EMF+ manual 2.1.1.19, Microsoft name: LineJoinType Enumeration (U_LJT_*)
+ @{
+*/
+#define U_LJT_Miter 0x00 //!< Miter line join
+#define U_LJT_Bevel 0x01 //!< Bevel line join
+#define U_LJT_Round 0x02 //!< Round line join
+#define U_LJT_MiterClipped 0x03 //!< Miter Clipped line join
+/** @} */
+
+/** \defgroup U_PMF_LS_ PMF LineStyle Enumeration
+ For
+ EMF+ manual 2.1.1.20, Microsoft name: LineStyle Enumeration (U_LS_*)
+ @{
+*/
+#define U_LS_Solid 0x00 //!< Solid line
+#define U_LS_Dash 0x01 //!< Dashed line
+#define U_LS_Dot 0x02 //!< Dotted line
+#define U_LS_DashDot 0x03 //!< Dash Dot line
+#define U_LS_DashDotDot 0x04 //!< Dash Dot Dot line
+#define U_LS_Custom 0x05 //!< Custom line
+/** @} */
+
+/** \defgroup U_PMF_MDT_ PMF MetafileDataType Enumeration
+ For
+ EMF+ manual 2.1.1.21, Microsoft name: MetafileDataType Enumeration (U_MDT_*)
+ @{
+*/
+#define U_MDT_Wmf 0x01 //!< WMF metafile
+#define U_MDT_WmfPlaceable 0x02 //!< WMF placeable metafile
+#define U_MDT_Emf 0x03 //!< EMF metafile
+#define U_MDT_EmfPlusOnly 0x04 //!< EMF+ single mode metafile
+#define U_MDT_EmfPlusDual 0x05 //!< EMF+ dual mode metafile
+/** @} */
+
+/** \defgroup U_PMF_OT_ PMF ObjectType Enumeration
+ For
+ EMF+ manual 2.1.1.22, Microsoft name: ObjectType Enumeration (U_OT_*)
+ @{
+*/
+#define U_OT_Invalid 0x00 //!< Invalid object
+#define U_OT_Brush 0x01 //!< Brush object
+#define U_OT_Pen 0x02 //!< Pen object
+#define U_OT_Path 0x03 //!< Path object
+#define U_OT_Region 0x04 //!< Region object
+#define U_OT_Image 0x05 //!< Image object
+#define U_OT_Font 0x06 //!< Font object
+#define U_OT_StringFormat 0x07 //!< StringFormat object
+#define U_OT_ImageAttributes 0x08 //!< ImageAttributes object
+#define U_OT_CustomLineCap 0x09 //!< CustomLineCap object
+/** @} */
+
+/** \defgroup U_PMF_PPT_ PMF PathPointType Enumeration
+ For
+ EMF+ manual 2.1.1.23, Microsoft name: PathPointType Enumeration (U_PPT_*)
+ @{
+*/
+#define U_PPT_Start 0x00 //!< Start of path
+#define U_PPT_Line 0x01 //!< Line path
+#define U_PPT_Bezier 0x03 //!< Bezier path
+#define U_PPT_MASK 0x0F //!< MASK for bits in flag
+/** @} */
+
+/** \defgroup U_PMF_PA_ PMF PenAlignment Enumeration
+ For
+ EMF+ manual 2.1.1.24, Microsoft name: PenAlignment Enumeration (U_PA_*)
+ @{
+*/
+#define U_PA_Center 0x00 //!< Center pen alignment
+#define U_PA_Inset 0x01 //!< Inset pen alignment
+#define U_PA_Left 0x02 //!< Left pen alignment
+#define U_PA_Outset 0x03 //!< Outset pen alignment
+#define U_PA_Right 0x04 //!< Right pen alignment
+/** @} */
+
+/** \defgroup U_PMF_PF_ PMF PixelFormat Enumeration
+ For U_PMF_BITMAP PxFormat field
+ EMF+ manual 2.1.1.25, Microsoft name: PixelFormat Enumeration (U_PF_*)
+
+ Bitmap for this 32 bit value is:
+ 0-9 ignored
+ 10 Set: 32 bit ARGB; Clear: !32 bit ARGB
+ 11 Set: 16 bits/channel; Clear: !16 bits
+ 12 Set: colors premultiplied by alpha; Clear: !premultiplied
+ 13 Set: has Alpha; Clear: !has Alpha
+ 14 Set: Windows GDI supports; Clear: !Windows GDI supports
+ 15 Set: uses LUT; Clear !uses LUT
+ 16-23 = total number of BITS per pixel
+ 24-31 = pixel format enumeration index (0->15)
+ @{
+*/
+#define U_PF_Undefined 0x00000000 //!< undefined Pixel Format
+#define U_PF_1bppIndexed 0x00030101 //!< monochrome with LUT
+#define U_PF_4bppIndexed 0x00030402 //!< 4 bit with LUT
+#define U_PF_8bppIndexed 0x00030803 //!< 8 bit with LUT
+#define U_PF_16bppGrayScale 0x00101004 //!< 16 bits grey values
+#define U_PF_16bppRGB555 0x00021005 //!< 16 bit RGB values (5,5,5,(1 ignored))
+#define U_PF_16bppRGB565 0x00021006 //!< 16 bit RGB values (5,6,5)
+#define U_PF_16bppARGB1555 0x00061007 //!< 16 bit ARGB values (1 alpha, 5,5,5 colors)
+#define U_PF_24bppRGB 0x00021808 //!< 24 bit RGB values (8,8.8)
+#define U_PF_32bppRGB 0x00022009 //!< 32 bit RGB value (8,8,8,(8 ignored))
+#define U_PF_32bppARGB 0x0026200A //!< 32 bit ARGB values (8 alpha,8,8,8)
+#define U_PF_32bppPARGB 0x000E200B //!< 32 bit PARGB values (8,8,8,8, but RGB already multiplied by A)
+#define U_PF_48bppRGB 0x0010300C //!< 48 bit RGB (16,16,16)
+#define U_PF_64bppARGB 0x0034400D //!< 64 bit ARGB (16 alpha, 16,16,16)
+#define U_PF_64bppPARGB 0x001A400E //!< 64 bit PARGB (16,16,16,16, but RGB already multiplied by A)
+/** @} */
+
+/** \defgroup U_PMF_POM_ PMF PixelOffsetMode Enumeration
+ For
+ EMF+ manual 2.1.1.26, Microsoft name: PixelOffsetMode Enumeration (U_POM_*)
+ @{
+*/
+#define U_POM_Default 0x00 //!< center at {0.0,0.0}
+#define U_POM_HighSpeed 0x01 //!< center at {0.0,0.0}
+#define U_POM_HighQuality 0x02 //!< center at {0.5,0.5}
+#define U_POM_None 0x03 //!< center at {0.0,0.0}
+#define U_POM_Half 0x04 //!< center at {0.5,0.5}
+/** @} */
+
+/** \defgroup U_PMF_RNDT_ PMF RegionNodeDataType Enumeration
+ For
+ EMF+ manual 2.1.1.27, Microsoft name: RegionNodeDataType Enumeration (U_RNDT_*)
+ @{
+*/
+#define U_RNDT_Kids 0x00000000 //!< One of the next 5 is to be applied
+#define U_RNDT_And 0x00000001 //!< AND the child nodes
+#define U_RNDT_Or 0x00000002 //!< OR the child nodes
+#define U_RNDT_Xor 0x00000003 //!< XOR the child nodes
+#define U_RNDT_Exclude 0x00000004 //!< Part of 1st child node not in 2nd child node
+#define U_RNDT_Complement 0x00000005 //!< Part of 2nd child node not in 1st child node
+#define U_RNDT_Rect 0x10000000 //!< Child node is a rectangle
+#define U_RNDT_Path 0x10000001 //!< Child node is a path
+#define U_RNDT_Empty 0x10000002 //!< Child node is empty
+#define U_RNDT_Infinite 0x10000003 //!< Child node has infinite extent (?)
+/** @} */
+
+/** \defgroup U_PMF_SM_ PMF SmoothingMode Enumeration
+ For
+ EMF+ manual 2.1.1.28, Microsoft name: SmoothingMode Enumeration (U_SM_*)
+ @{
+*/
+#define U_SM_Default 0x00 //!< Default smoothing
+#define U_SM_HighSpeed 0x01 //!< High Speed smoothing
+#define U_SM_HighQuality 0x02 //!< High Quality smoothing
+#define U_SM_None 0x03 //!< No smoothing
+#define U_SM_AntiAlias8x4 0x04 //!< Anti Alias 8x4 smoothing
+#define U_SM_AntiAlias8x8 0x05 //!< Anti Alias 8x8 smoothing
+/** @} */
+
+/** \defgroup U_PMF_SA_ PMF StringAlignment Enumeration
+ For
+ EMF+ manual 2.1.1.29, Microsoft name: StringAlignment Enumeration (U_SA_*)
+
+ Note, that unlike EMF these are with respect to the bounding rectangle, not to a single point. So
+ to draw centered text, for instance, U_SA_Center must be used, and the bounding rectangle must also be
+ centered.
+
+ For horizontal positioning of L->R text Near is all the way left in the box, Far is all the way right,
+ and Center puts the center of the text in the center of the box.
+
+ For vertical positioning things are a little strange. Near is a certain distance down from the top, Far is a
+ certain distance up from the bottom, and center puts the center of the text in the center of the box. The
+ "certain distance" is not specified in the EMF+ documentation. See the function U_PMR_drawstring() for an
+ implementation that places text on the baseline.
+ @{
+*/
+#define U_SA_Near 0x00 //!< Position near
+#define U_SA_Center 0x01 //!< Position center
+#define U_SA_Far 0x02 //!< Position far
+/** @} */
+
+/** \defgroup U_PMF_SDS_ PMF StringDigitSubstitution Enumeration
+ For
+ EMF+ manual 2.1.1.30, Microsoft name: StringDigitSubstitution Enumeration (U_SDS_*)
+ @{
+*/
+#define U_SDS_User 0x00 //!< Digit substitution is set by implementation
+#define U_SDS_None 0x01 //!< No Digit substitution
+#define U_SDS_National 0x02 //!< Digit substitution by official locale
+#define U_SDS_Traditional 0x03 //!< Digit substitution by traditional locale
+/** @} */
+
+/** \defgroup U_PMF_ST_ PMF StringTrimming Enumeration
+ For
+ EMF+ manual 2.1.1.31, Microsoft name: StringTrimming Enumeration (U_ST_*)
+ @{
+*/
+#define U_ST_None 0x00 //!< no string trimming
+#define U_ST_Character 0x01 //!< Trim at Character
+#define U_ST_Word 0x02 //!< Trim at Word
+#define U_ST_EllipsisCharacter 0x03 //!< Trim at Ellipsis Character
+#define U_ST_EllipsisWord 0x04 //!< Trim at Ellipsis Word
+#define U_ST_EllipsisPath 0x05 //!< Trim at Ellipsis Path
+/** @} */
+
+/** \defgroup U_PMF_TRH_ PMF TextRenderingHint Enumeration
+ For
+ EMF+ manual 2.1.1.32, Microsoft name: TextRenderingHint Enumeration (U_TRH_*)
+ @{
+*/
+#define U_TRH_SystemDefault 0x00 //!< System Default
+#define U_TRH_SingleBitPerPixelGridFit 0x01 //!< Single Bit Per Pixel Grid Fit
+#define U_TRH_SingleBitPerPixel 0x02 //!< Single Bit Per Pixel
+#define U_TRH_AntialiasGridFit 0x03 //!< Antialias Grid Fit
+#define U_TRH_Antialias 0x04 //!< Antialias
+#define U_TRH_ClearTypeGridFit 0x05 //!< ClearType Grid Fit
+/** @} */
+
+/** \defgroup U_PMF_UT_ PMF UnitType Enumeration
+ For
+ EMF+ manual 2.1.1.33, Microsoft name: UnitType Enumeration (U_UT_*)
+ @{
+*/
+#define U_UT_World 0x00 //!< World units
+#define U_UT_Display 0x01 //!< Display units
+#define U_UT_Pixel 0x02 //!< Pixel units
+#define U_UT_Point 0x03 //!< Point units
+#define U_UT_Inch 0x04 //!< Inch units
+#define U_UT_Document 0x05 //!< Document units
+#define U_UT_Millimeter 0x06 //!< Millimeter units
+/** @} */
+
+/** \defgroup U_PMF_WM_ PMF WrapMode Enumeration
+ For
+ EMF+ manual 2.1.1.34, Microsoft name: WrapMode Enumeration (U_WM_*)
+ @{
+*/
+#define U_WM_Tile 0x00000000 //!< Tile
+#define U_WM_TileFlipX 0x00000001 //!< Reverse horizontally then tile
+#define U_WM_TileFlipY 0x00000002 //!< Reverse vertically then tile
+#define U_WM_TileFlipXY 0x00000003 //!< Reverse horizontally and vertically then tile
+#define U_WM_Clamp 0x00000004 //!< Clamp pattern to the object boundary
+/** @} */
+
+/** \defgroup U_PMF_BD_ PMF BrushData Flags
+ For
+ EMF+ manual 2.1.2.1, Microsoft name: BrushData Flags (U_BD_*)
+
+ Bit flags allowed in brush object types. Each bit indicates a type of object which is included.
+ There are 5 brush types abbreviated A through E, and each uses a subset of the
+ BrushData Flags, as summarized in the following table:
+
+ Bits Brush____Type EMF+ Manual
+ used Abbrev. Name
+ 5 A U_PMF_LINEARGRADIENTBRUSHDATA 2.2.2.24
+ 6 B U_PMF_PATHGRADIENTBRUSHDATA 2.2.2.29
+ 3 C U_PMF_TEXTUREBRUSHDATA 2.2.2.45
+ 0 D U_PMF_HATCHBRUSHDATA 2.2.2.20
+ 0 E U_PMF_SOLIDBRUSHDATA 2.2.2.45
+ @{
+*/
+#define U_BD_None 0x0000 //!< no bits set
+#define U_BD_Path 0x0001 //!< Path, in {B}
+#define U_BD_Transform 0x0002 //!< Transform in {ABC}
+#define U_BD_PresetColors 0x0004 //!< PresetColors in {AB}
+#define U_BD_BlendFactorsH 0x0008 //!< BlendFactorsH in {AB}
+#define U_BD_BlendFactorsV 0x0010 //!< BlendFactorsV in {A} - Note, not actually implemented in GDI+.
+#define U_BD_NoBit 0x0020 //!< unused bit
+#define U_BD_FocusScales 0x0040 //!< Focus Scales in {B}
+#define U_BD_IsGammaCorrected 0x0080 //!< GammaCorrected in {ABC}
+#define U_BD_DoNotTransform 0x0100 //!< Ignore world to device transform in {C}
+#define U_BD_MASKA 0x009E //!< all bits that MAY be set in A
+#define U_BD_MASKB 0x00CF //!< all bits that MAY be set in B
+#define U_BD_MASKC 0x0182 //!< all bits that MAY be set in C
+/** @} */
+
+/** \defgroup U_PMF_CLCD_ PMF CustomLineCapData Flags
+ For
+ EMF+ manual 2.1.2.2, Microsoft name: CustomLineCapData Flags (U_CLCD_*)
+ @{
+*/
+#define U_CLCD_None 0x00 //!< no bits set
+#define U_CLCD_FillPath 0x01 //!< Fill Path
+#define U_CLCD_LinePath 0x02 //!< Line Path
+/** @} */
+
+/** \defgroup U_PMF_DSO_ PMF DriverStringOptions Flags
+ For
+ EMF+ manual 2.1.2.3, Microsoft name: DriverStringOptions Flags (U_DSO_*)
+ @{
+*/
+#define U_DSO_None 0x00 //!< no bits set
+#define U_DSO_CmapLookup 0x01 //!< Set: value is a Unicode character; Clear: value is an index into Glyph table in a font
+#define U_DSO_Vertical 0x02 //!< Set: draw string verically; Clear: draw horizontally
+#define U_DSO_RealizedAdvance 0x04 /**< Set: U_PMF_DRAWDRIVERSTRING Positions field specifies only position of first of Glyphs field,
+ with the rest calculated from font information; Clear: Positions specifies coordinates for each Glyphs member.*/
+#define U_DSO_LimitSubpixel 0x08 //!< Set: use less memory to cache anti-aliased glyphs; Clear: use more
+/** @} */
+
+/** \defgroup U_PMF_FS_ PMF FontStyle Flags
+ For
+ EMF+ manual 2.1.2.4, Microsoft name: FontStyle Flags (U_FS_*)
+# @{
+*/
+#define U_FS_None 0x00 //!< no bits set
+#define U_FS_Bold 0x01 //!< Bold
+#define U_FS_Italic 0x02 //!< Italic
+#define U_FS_Underline 0x04 //!< Underline
+#define U_FS_Strikeout 0x08 //!< Strikeout
+/** @} */
+
+/** \defgroup U_PMF_PLTS_ PMF PaletteStyle Flags
+ For
+ EMF+ manual 2.1.2.5, Microsoft name: PaletteStyle Flags (U_PLTS_*)
+ @{
+*/
+#define U_PLTS_None 0x00 //!< no bits set
+#define U_PLTS_HasAlpha 0x01 //!< Has Alpha
+#define U_PLTS_GrayScale 0x02 //!< Gray Scale
+#define U_PLTS_Halftone 0x04 //!< Halftone
+/** @} */
+
+/** \defgroup U_PMF_PTP_ PMF PathPointType Flags
+ For
+ EMF+ manual 2.1.2.6, Microsoft name: PathPointType Flags (U_PTP_*)
+ @{
+*/
+#define U_PTP_None 0x00 //!< no bits set
+#define U_PTP_DashMode 0x10 //!< Dash Mode
+#define U_PTP_PathMarker 0x20 //!< Path Marker
+#define U_PTP_NoBit 0x40 //!< unused bit
+#define U_PTP_CloseSubpath 0x80 //!< CloseSubpath
+#define U_PTP_NotClose 0x70 //!< Everything but close
+#define U_PTP_MASK 0xF0 //!< Everything
+#define U_PTP_SHIFT 4 //!< offset to this bitfield
+/** @} */
+
+/** \defgroup U_PMF_PD_ PMF PenData Flags
+ For
+ EMF+ manual 2.1.2.7, Microsoft name: PenData Flags (U_PD_*)
+
+If bit is set the corresponding object must be specfied in the OptionalData field
+
+ @{
+*/
+#define U_PD_None 0x0000 //!< no bits set
+#define U_PD_Transform 0x0001 //!< Transform
+#define U_PD_StartCap 0x0002 //!< Start Cap
+#define U_PD_EndCap 0x0004 //!< End Cap
+#define U_PD_Join 0x0008 //!< Join
+#define U_PD_MiterLimit 0x0010 //!< Miter Limit
+#define U_PD_LineStyle 0x0020 //!< Line Style
+#define U_PD_DLCap 0x0040 //!< Dashed Line Cap
+#define U_PD_DLOffset 0x0080 //!< Dashed Line Offset
+#define U_PD_DLData 0x0100 //!< Dashed Line Data
+#define U_PD_NonCenter 0x0200 //!< Alignment must be specified with optinal data
+#define U_PD_CLData 0x0400 //!< Compound Line Data
+#define U_PD_CustomStartCap 0x0800 //!< Custom Start Cap
+#define U_PD_CustomEndCap 0x1000 //!< Custom End Cap
+/** @} */
+
+/** \defgroup U_PMF_SF_ PMF StringFormat Flags
+ For EmfPlusStringFormat
+ EMF+ manual 2.1.2.8, Microsoft name: StringFormat Flags (U_SF_*)
+ @{
+*/
+#define U_SF_None 0x00000000 //!< no bits set
+#define U_SF_DirectionRightToLeft 0x00000001 //!< text Right to Left
+#define U_SF_DirectionVertical 0x00000002 //!< text Left to Right
+#define U_SF_NoFitBlackBox 0x00000004 //!< text not restricted to layout bbox
+#define U_SF_NoBit4 0x00000008 //!< unused bit
+#define U_SF_NoBit5 0x00000010 //!< unused bit
+#define U_SF_DisplayFormatControl 0x00000020 //!< control codes display as "representative" glyphs
+#define U_SF_NoBit7 0x00000040 //!< unused bit
+#define U_SF_NoBit8 0x00000080 //!< unused bit
+#define U_SF_NoBit9 0x00000100 //!< unused bit
+#define U_SF_NoBit10 0x00000200 //!< unused bit
+#define U_SF_NoFontFallback 0x00000400 //!< show as missing glyph if not in font
+#define U_SF_MeasureTrailingSpaces 0x00000800 //!< trailing spaces included in line length
+#define U_SF_NoWrap 0x00001000 //!< text does not wrap
+#define U_SF_LineLimit 0x00002000 //!< emit whole lines if not clipped
+#define U_SF_NoClip 0x00004000 //!< text is not clipped
+#define U_SF_BypassGDI 0x80000000 //!< use implementation specific text rendering instead of GDI
+/** @} */
+
+/** \defgroup U_PMF_IE_ PMF ImageEffects Identifiers
+ For
+ EMF+ manual 2.1.3.1, Microsoft name: ImageEffects Identifiers (U_IE_*)
+ @{
+*/
+#define U_IE_BlurEffectGuid "{633C80A4-1843-482B-9EF2-BE2834C5FDD4}" //!< Blur Effect
+#define U_IE_BrightnessContrastEffectGuid "{D3A1DBE1-8EC4-4C17-9F4C-EA97AD1C343D}" //!< Brightness Contrast Effect
+#define U_IE_ColorBalanceEffectGuid "{537E597D-251E-48DA-9664-29CA496B70F8}" //!< Color Balance Effect
+#define U_IE_ColorCurveEffectGuid "{DD6A0022-58E4-4A67-9D9B-D48EB881A53D}" //!< Color Curve Effect
+#define U_IE_ColorLookupTableEffectGuid "{A7CE72A9-0F7F-40D7-B3CC-D0C02D5C3212}" //!< Color Lookup Table Effect
+#define U_IE_ColorMatrixEffectGuid "{718F2615-7933-40E3-A511-5F68FE14DD74}" //!< Color Matrix Effect
+#define U_IE_HueSaturationLightnessEffectGuid "{8B2DD6C3-EB07-4D87-A5F0-7108E26A9C5F}" //!< Hue Saturation Lightness Effect
+#define U_IE_LevelsEffectGuid "{99C354EC-2A31-4F3A-8C34-17A803B33A25}" //!< Levels Effect
+#define U_IE_RedEyeCorrectionEffectGuid "{74D29D05-69A4-4266-9549-3CC52836B632}" //!< Red Eye Correction Effect
+#define U_IE_SharpenEffectGuid "{63CBF3EE-C526-402C-8F71-62C540BF5142}" //!< Sharpen Effect
+#define U_IE_TintEffectGuid "{1077AF00-2848-4441-9489-44AD4C2D7A2C}" //!< Tint Effect
+/** @} */
+
+/** \defgroup U_PMF_IEE_ PMF ImageEffects Enumerators
+ based on U_IE_
+ These may be used by a parser to set up for a switch() statement.
+ @{
+*/
+#define U_IEE_Unknown 0 //!< none of the following
+#define U_IEE_BlurEffectGuid 1 //!< Blur Effect
+#define U_IEE_BrightnessContrastEffectGuid 2 //!< Brightness Contrast Effect
+#define U_IEE_ColorBalanceEffectGuid 3 //!< Color Balance Effect
+#define U_IEE_ColorCurveEffectGuid 4 //!< Color Curve Effect
+#define U_IEE_ColorLookupTableEffectGuid 5 //!< Color Lookup Table Effect
+#define U_IEE_ColorMatrixEffectGuid 6 //!< Color Matrix Effect
+#define U_IEE_HueSaturationLightnessEffectGuid 7 //!< Hue Saturation Lightness Effect
+#define U_IEE_LevelsEffectGuid 8 //!< Levels Effect
+#define U_IEE_RedEyeCorrectionEffectGuid 9 //!< Red Eye Correction Effect
+#define U_IEE_SharpenEffectGuid 10 //!< Sharpen Effect
+#define U_IEE_TintEffectGuid 11 //!< Tint Effect
+/** @} */
+
+/** \defgroup U_PMF_OC_ PMF ObjectClamp Identifiers
+ For U_PMF_IMAGEATTRIBUTES ObjectClamp field
+ EMF+ manual 2.2.1.5, Microsoft name: ImageEffects Identifiers (U_OC_*)
+ @{
+*/
+#define U_OC_Rect 0x00 //!< Clamp object to rectangle.
+#define U_OC_Bitmap 0x01 //!< Clamp object to bitmap.
+/** @} */
+
+/** \defgroup U_PMF_PPF_ PMF PathPoint Flags
+ For U_PMF_PATH Flags field
+ For U_PMF_CMN_HDR Flags field
+ EMF+ manual 2.2.1.6, Microsoft name: PathPoint Flags (U_PPF_*)
+ For U_PMF_CMN_HDR Flags the bits are scattered all over the EMF+ manual.
+ NOTE: bitfields in manual are BIG endian and MSB 0.
+ This code reads the 16 bit flag field as LITTLE endian and uses LSB 0.
+ The values shown are AFTER the data has been read into a uint16_t and the byte order set
+ appropriately.
+ All of these come out of a 16 bit field.
+ @{
+*/
+#define U_PPF_B 0x8000 //!< 15 Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+#define U_PPF_BZ 0x8000 //!< 15 Set: Points are on a Bezier curve; Clear: Points are on a line
+#define U_PPF_N 0x8000 //!< 15 Set: object definition continues in next record; Clear: this is the final object definition record
+#define U_PPF_K 0x8000 //!< 15 Set: int16_t coordinates; Clear: use U_FLOAT coordinates
+#define U_PPF_C 0x4000 //!< 14 Set: int16_t coordinates; Clear: use U_FLOAT coordinates
+#define U_PPF_XM 0x2000 //!< 13 Set: Post multiply matrix; Clear: Pre multiply matrix
+#define U_PPF_F 0x2000 //!< 13 Set: winding fill; Clear: alternate fill
+#define U_PPF_E 0x2000 //!< 13 Set: effect from previous U_PMF_SERIALIZABLEOBJECT record will be applied,; Clear: no effect applied
+#define U_PPF_R 0x1000 //!< 12 Set: U_PMF_PathPointTypeRLE and/or U_PMF_PathPointType objects; Clear: only U_PMF_PathPointType
+#define U_PPF_P 0x0800 //!< 11 Set: relative coordinates; Clear absolute coordinates
+#define U_PPF_D 0x0400 //!< 10 Set: draw path closed; Clear: draw path open
+#define U_PPF_VGA 0x0002 //!< 1 Set: Palette is VGA basic colors; Clear: Palette is ???
+#define U_PPF_PP 0x0001 //!< 0 Set: Palette field is present; Clear: Palette field is absent
+#define U_PPF_DM 0x0001 //!< 0 Set: Dual-mode file; Clear: EMF+ only file
+#define U_PPF_AA 0x0001 //!< 0 Set: anti-aliasing on; Clear: anti-aliasing off
+#define U_PPF_VIDEO 0x0001 //!< 0 Set: reference device is video display; Clear: reference devis is printer
+/** @} */
+
+/** \defgroup U_PMF_FF_ PMF Masks and offsets for 16 bit flag fields
+ Documenting the OBSERVED positions of fields in 16 bit flag integers
+ after they have been read in Little Ended from files.
+
+ Note, some of these are used in more than one record type, only a single reference is provided
+ @{
+*/
+
+#define U_FF_MASK_SUBLID 0x003F //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_SHFT_SUBLID 0x000A //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_MASK_PRILID 0x03FF //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_SHFT_PRILID 0x0000 //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_MASK_LID 0xFFFF //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_SHFT_LID 0x0000 //!< EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier
+#define U_FF_MASK_RL 0x003F //!< EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE
+#define U_FF_SHFT_RL 0x0008 //!< EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE
+#define U_FF_MASK_PPT 0x00FF //!< EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE
+#define U_FF_SHFT_PPT 0x0000 //!< EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE
+/* the next one is used most places an object ID is specified */
+#define U_FF_MASK_OID8 0x00FF //!< EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath
+#define U_FF_SHFT_OID8 0x0000 //!< EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath
+#define U_FF_MASK_CM4 0x000F //!< EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath
+#define U_FF_SHFT_CM4 0x0008 //!< EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath
+#define U_FF_MASK_OT 0x003F //!< EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject
+#define U_FF_SHFT_OT 0x0008 //!< EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject
+#define U_FF_MASK_AA 0x007F //!< EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode
+#define U_FF_SHFT_AA 0x0001 //!< EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode
+#define U_FF_MASK_CM 0x00FF //!< EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode
+#define U_FF_SHFT_CM 0x0000 //!< EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode
+#define U_FF_MASK_CQ 0x00FF //!< EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality
+#define U_FF_SHFT_CQ 0x0000 //!< EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality
+#define U_FF_MASK_IM 0x00FF //!< EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode
+#define U_FF_SHFT_IM 0x0000 //!< EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode
+#define U_FF_MASK_PxOffM 0x00FF //!< EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode
+#define U_FF_SHFT_PxOffM 0x0000 //!< EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode
+#define U_FF_MASK_TGC 0x0FFF //!< EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast
+#define U_FF_SHFT_TGC 0x0000 //!< EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast
+#define U_FF_MASK_TRH 0x00FF //!< EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint
+#define U_FF_SHFT_TRH 0x0000 //!< EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint
+#define U_FF_MASK_UT 0x00FF //!< EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer
+#define U_FF_SHFT_UT 0x0008 //!< EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer
+#define U_FF_MASK_TSC 0x7FFF //!< EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip
+#define U_FF_SHFT_TSC 0x0000 //!< EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip
+#define U_FF_MASK_PU 0x00FF //!< EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform
+#define U_FF_SHFT_PU 0x0000 //!< EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform
+/** @} */
+
+
+/** \defgroup U_PMF_GFVR_ PMF MetafileSignature
+ For U_PMF_GRAPHICSVERSION Signature field
+ EMF+ manual 2.2.2.19, Microsoft name: (none) (U_GFVR_*)
+ @{
+*/
+#define U_GFVR_PMF 0x000DBC01 //!< indicates an EMF+ metafile
+#define U_GFVR_MASKHI 0xFFFFF000 //!< mask for the signature bit field (20 bits)
+#define U_GFVR_MASKLO 0x00000FFF //!< mask for the version bit field (12 bits)
+/** @} */
+
+/** \defgroup U_PMF_XM_ PMF Matrix Multiplication Enumerator
+ For U_PMF_RotateWorldTransform and others
+ EMF+ manual 2.3.9.3, Microsoft name: (none) (U_XM_*)
+ @{
+*/
+#define U_XM_PostX 1 //!< Post Multiply change to current Transformation Matrix
+#define U_XM_PreX 0 //!< Pre Multiply change to current Transformation Matrix
+/** @} */
+
+
+/* Utility objects, not defined in EMF+ spec */
+
+/** @brief Used to accumulate data for objects continued over multiple records.
+ see EMF+ manual 2.3.5.1
+*/
+typedef struct {
+ char *accum; /**< data accumulates here */
+ uint32_t space; /**< bytes allocated */
+ uint32_t used; /**< bytes in use */
+ int Type; /**< ObjectType enumeration */
+ int Id; /**< Object ID */
+} U_OBJ_ACCUM;
+
+/** @brief Holds EMF+ objects and records in EMF+ file format byte order.
+*/
+typedef struct {
+ char *Data; /**< Buffer that hold's the PseudoObject's data */
+ size_t Size; /**< Number of bytes allocated in Data (may be >Used if padding is present) */
+ size_t Used; /**< Number of data bytes that are stored in Data */
+ uint32_t Type; /**< Type numbers are from manual section: 1.2.3.4 -> 10203040 */
+} U_PSEUDO_OBJ;
+
+/** @brief DoublePseudoObject holds pairs of PseudoObjects. Used for constructing paths along with their types.
+ The data stored in the PsuedoObjects maintains LittleEndian-ness, as expected in the final file.
+ The type is U_RAW_OID, and there is no elements count at the beginning of Data
+*/
+typedef struct {
+ uint32_t Elements; /**< Element count, applies to both PseudoObjects */
+ U_PSEUDO_OBJ *poPoints; /**< Points in path */
+ U_PSEUDO_OBJ *poTypes; /**< Types of points in path */
+} U_DPSEUDO_OBJ;
+
+/** @brief Serializer description records.
+
+An array of these are passed to U_PMF_SERIAL_set() to construct EMF+ objects from their component parts.
+The U_PMF_SERIAL_set() function should not ever be called directly by end user code.
+*/
+typedef struct {
+ const void *Ptr; /**< Pointer to the first byte of the data field.
+ Each data field is an array of a basic type of Units
+ bytes repeated Reps times */
+ size_t Units; /**< Number of bytes in each unit of each data field. */
+ size_t Reps; /**< MNumber of repeats of Units in eah data field. */
+ int TE; /**< (Target Endian). Only relevant for Units of 2 or 4*/
+} U_SERIAL_DESC;
+
+/** @brief FontInfoParams hold font information that is needed by U_PMR_drawstring so that it can
+ place text on the baseline. This must be extracted from the font file using
+ an appropriate utility. (See testbed_pmf.c for a table of these values for some
+ common fonts.)
+*/
+typedef struct {
+ char *name; /**< Font name (like "Arial") */
+ int Ascent; /**< in Font units (positive) */
+ int Descent; /**< in Font units (negative) */
+ int LineGap; /**< in Font units (positive) */
+ int EmSize; /**< Y extent of Em square, usually 2048 */
+ int yMax; /**< in Font units (positive) */
+ int yMin; /**< in Font units (negative) */
+} U_FontInfoParams;
+
+
+
+/* EMF+ objects */
+
+/** @brief EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object
+
+variable part of object follows structure:
+ uint32_t Data[]; // one of the 5 types of Brush data (2.2.2 20, 24, 29, 43, or 45)
+*/
+typedef struct {
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Type; //!< BrushType Enumeration
+} U_PMF_BRUSH;
+
+/** @brief EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object */
+typedef struct {
+/*@{*/
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Type; //!< BrushType Enumeration
+/* variable part of object, not part of structure
+ uint32_t Data[]; //!< one of the 2 types of Linecap data (2.2.2 12, 13)
+*/
+/*@}*/
+} U_PMF_CUSTOMLINECAP;
+
+/** @brief EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object */
+typedef struct {
+/*@{*/
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ U_FLOAT EmSize; //!< em size in units of SizeUnit
+ uint32_t SizeUnit; //!< UnitType enumeration
+ int32_t FSFlags; //!< FontStyle flags
+ uint32_t Reserved; //!< ignored
+ uint32_t Length; //!< Number of Unicode Characters in FamilyName
+/* variable part of object, not part of structure
+ uint16_t FamilyName[]; //!< Unicode (UTF-16LE) name of font family
+*/
+/*@}*/
+} U_PMF_FONT;
+
+/** @brief EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object */
+typedef struct {
+/*@{*/
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Type; //!< ImageDataType Enumeration
+/* variable part of object, not part of structure
+ uint32_t Data[]; //!< one of the 2 types of image data (2.2.2 2 or 27)
+*/
+/*@}*/
+} U_PMF_IMAGE;
+
+/** @brief EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object, out of order, needed for 2.2.1.5 */
+typedef struct {
+/*@{*/
+ uint8_t Blue; //!< Blue color (0-255)
+ uint8_t Green; //!< Green color (0-255)
+ uint8_t Red; //!< Red color (0-255)
+ uint8_t Alpha; //!< Alpha (0-255)
+/*@}*/
+} U_PMF_ARGB;
+
+/** @brief EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object */
+typedef struct {
+ /*@{*/
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Reserved1; //!< ignored
+ uint32_t WrapMode; //!< WrapMode object
+ U_PMF_ARGB ClampColor; //!< EmfPlusARGB object
+ int32_t ObjectClamp; //!< ObjectClamp Identifiers
+ uint32_t Reserved2; //!< ignored
+/*@}*/
+} U_PMF_IMAGEATTRIBUTES;
+
+/** @brief EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object */
+typedef struct {
+/*@{*/
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Count; //!< points and point types in this object
+ uint16_t Flags; //!< PathPoint Flags
+/* variable part of object, not part of structure
+ points array of points like:
+ U_PPF_P U_PPF_C Type
+ 1 x U_PMF_POINTR
+ 0 1 U_PMF_POINT
+ 0 0 U_PMF_POINTF
+ types array of:.
+ U_PPF_R Type
+ 1 U_PMF_PATHPOINTTYPERLE and/or U_PMF_PATHPOINTTYPE
+ 0 U_PMF_PathPointType (only)
+ alignment padding up to 3 bytes
+*/
+/*@}*/
+} U_PMF_PATH;
+
+/** @brief EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object */
+
+typedef struct {
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t type; //!< must be zero
+/* variable part of object, not part of structure
+ U_PMF_PENDATA pen
+ U_PMF_BRUSH brush
+*/
+} U_PMF_PEN;
+
+/** @brief EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object, out of order, needed for 2.2.1.8 */
+typedef struct {
+ uint32_t Type; //!< RegionNodeDataType
+/* variable part of object, not part of structure, will be absent in object for some types
+ data data is a tree made up of some combination of these objects
+ U_PMF_REGIONNODEPATH 2.2.2.42 terminal node
+ U_PMF_RECTF 2.2.2.39 terminal node
+ U_PMF_REGIONNODECHILDNODES 2.2.2.41 non-terminal node
+*/
+} U_PMF_REGIONNODE;
+
+/** @brief EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object */
+typedef struct {
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Elements; //!< Number of members in Nodes array
+/* variable part of object, not part of structure, will be absent in object for some types
+ U_PMF_REGIONNODE Nodes[1]; //!< Nodes defining region
+*/
+} U_PMF_REGION;
+
+/** @brief EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object, out of order, needed for 2.2.1.9
+
+Bit fields are not used in structs in this implementation, these are serialized/deserialized in
+the corresponding routines. Bitfields in the FILE (LITTLE endian here, manual uses BIG endian) are:
+ int SubLId : 6; Example: code for USA
+ int PriLId : 10; Example: code for English
+
+This type is defined as 16 bits in the manual section, but it is only ever used as part of a 32 bit field!
+*/
+typedef uint32_t U_PMF_LANGUAGEIDENTIFIER;
+
+/** @brief EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object */
+typedef struct {
+ uint32_t Version; //!< EmfPlusGraphicsVersion object
+ uint32_t Flags; //!< StringFormat flags
+ U_PMF_LANGUAGEIDENTIFIER
+ Language; //!< String's Language
+ uint32_t StringAlignment; //!< StringAlignment enumeration.
+ uint32_t LineAlign; //!< StringAlignment enumeration.
+ uint32_t DigitSubstitution; //!< StringDigitSubstitution enumeration
+ U_PMF_LANGUAGEIDENTIFIER
+ DigitLanguage; //!< Digit's Language (overrides Language, above)
+ U_FLOAT FirstTabOffset; //!< the number of spaces to the first tab stop.
+ int32_t HotkeyPrefix; //!< HotkeyPrefix enumeration
+ U_FLOAT LeadingMargin; //!< space before starting position (text) of a string
+ U_FLOAT TrailingMargin; //!< space after last position (text) of a string
+ U_FLOAT Tracking; //!< horizontal space alotted per character/font specification per character
+ uint32_t Trimming; //!< StringTrimming enumeration
+ uint32_t TabStopCount; //!< Number of tab stops in data field.
+ uint32_t RangeCount; //!< Number of U_PMF_CHARACTERRANGE objects in data field.
+/* variable part of object, not part of structure.
+ U_PMF_STRINGFORMATDATA data
+
+ Note that U_PMF_STRINGFORMATDATA has no struct as it is entirely variable
+ and the size of the two fields in it are specified by the two preceding fields in this object type.
+*/
+} U_PMF_STRINGFORMAT;
+
+/** U_PMF_ARGB EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object, defined above, before 2.2.1.6*/
+
+/** @brief EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object */
+typedef struct {
+ int32_t Width; //!< Width in pixels
+ int32_t Height; //!< Height in pixels
+ int32_t Stride; //!< length in bytes of 1 scan line (multiple of 4)
+ uint32_t PxFormat; //!< PixelFormat enumeration
+ uint32_t Type; //!< BitmapDataType enumeration (section 2.1.1.2).
+/* variable part of object, not part of structure.
+ (various types) BitmapData //!< is either an U_PMF_BITMAPDATA or U_PMF_COMPRESSEDIMAGE object
+*/
+} U_PMF_BITMAP;
+
+/** U_PMF_BITMAPDATA EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object
+U_PMF_BITMAPDATA is an entirely variable object, there is no corresponding struct. It consists of
+
+ Colors U_PMF_PALETTE object
+ PixelData An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration.
+
+*/
+
+/** @brief EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object
+ For Pattern field of U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA
+*/
+typedef struct {
+ uint32_t Elements; //!< members in each array
+/* variable part of object, not part of structure.
+ U_FLOAT Positions //!< positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0.
+ U_PMF_ARGB Colors //!< colors at positions on gradient line
+*/
+} U_PMF_BLENDCOLORS;
+
+/** @brief EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object */
+typedef struct {
+ uint32_t Elements; //!< Members in each array
+/* variable part of object, not part of structure.
+ U_FLOAT Positions //!< positions along gradient line. The first position MUST be 0.0 and the last MUST be 1.0.
+ U_FLOAT Factors //!< blending factors, 0.0->1.0 values, inclusive
+*/
+} U_PMF_BLENDFACTORS;
+
+/** @brief EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object */
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_PATH Data //!< Boundary of the brush
+*/
+} U_PMF_BOUNDARYPATHDATA;
+
+/** @brief EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object */
+typedef struct {
+ int32_t Elements; //!< Members in the array
+/* variable part of object, not part of structure.
+ U_PMF_POINTF Points //!< Boundary of the brush
+*/
+} U_PMF_BOUNDARYPOINTDATA;
+
+/** @brief EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object */
+typedef struct {
+ int32_t First; //!< First position in range
+ int32_t Length; //!< Range length
+} U_PMF_CHARACTERRANGE;
+
+/** @brief EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object
+Compound lines are pens that draw several parallel lines at once. The data here
+alternates (sub)line width (as fraction of total width and gaps (also as fraction
+of total width).
+*/
+typedef struct {
+ int32_t Elements; //!< Members in the array
+/* variable part of object, not part of structure.
+ U_FLOAT Data //!< Line or gap width (0.0 <-> 1.0, fraction of total line width )
+*/
+} U_PMF_COMPOUNDLINEDATA;
+
+/** @brief EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object
+Holds an EXIF, GIF, JFIF, PNG, or TIFF image.
+ For U_PMF_BITMAP BitmapData field
+
+ object has no assocated struct!
+ U_PMF_COMPRESSEDIMAGE
+*/
+
+/** @brief EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object */
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_CUSTOMLINECAP Data //!< Description of linecap
+*/
+} U_PMF_CUSTOMENDCAPDATA;
+
+/** @brief EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object */
+typedef struct {
+ U_FLOAT Width; //!< Arrow cap width (is multiplied by line width before draw)
+ U_FLOAT Height; //!< Arrow cap length (is multiplied by line width before draw)
+ U_FLOAT MiddleInset; //!< Pixels between outer edge and filled region
+ uint32_t FillState; //!< If set, fill, otherwise, only border
+ uint32_t StartCap; //!< LineCap enumeration (type of cap)
+ uint32_t EndCap; //!< LineCap enumeration
+ uint32_t Join; //!< LineJoin enumeration
+ U_FLOAT MiterLimit; //!< Maximum (miter length / line width)
+ U_FLOAT WidthScale; //!< Scale for U_PMF_CUSTOMLINECAP object
+ U_FLOAT FillHotSpot[2]; //!< must be 0.0, 0.0
+ U_FLOAT LineHotSpot[2]; //!< must be 0.0, 0.0
+} U_PMF_CUSTOMLINECAPARROWDATA;
+
+/** @brief EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object */
+typedef struct {
+ uint32_t Flags; //!< CustomLineCapData flags
+ uint32_t Cap; //!< LineCap enumeration (type of cap)
+ U_FLOAT Inset; //!< Distance line cap start -> line end
+ uint32_t StartCap; //!< LineCap enumeration
+ uint32_t EndCap; //!< LineCap enumeration
+ uint32_t Join; //!< LineJoin enumeration
+ U_FLOAT MiterLimit; //!< Maximum (miter length / line width)
+ U_FLOAT WidthScale; //!< Scale for U_PMF_CUSTOMLINECAP object
+ U_FLOAT FillHotSpot[2]; //!< must be 0.0, 0.0
+ U_FLOAT LineHotSpot[2]; //!< must be 0.0, 0.0
+/* variable part of object, not part of structure.
+ U_PMF_CUSTOMLINECAPOPTIONALDATA Data //!< meaning determined by Flags
+*/
+} U_PMF_CUSTOMLINECAPDATA;
+
+/** U_PMF_CUSTOMLINECAPOPTIONALDATA EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object
+
+ object has no assocated struct!
+
+ U_PMF_FILLPATHO FillData; //!< path to fill (optional)
+ U_PMF_LINEPATH LineData; //!< path to stroke (optional)
+*/
+
+/** @brief EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object */
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_CUSTOMLINECAP Data //!< Description of linecap
+*/
+} U_PMF_CUSTOMSTARTCAPDATA;
+
+/** @brief EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object */
+typedef struct {
+ int32_t Elements; //!< Elements in Data
+/* variable part of object, not part of structure.
+ U_FLOAT Data; //!< Array of lengths of dashes and spaces
+*/
+} U_PMF_DASHEDLINEDATA;
+
+/** @brief EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object
+Note: U_PMF_FILLPATHOBJ is the object, U_PMF_FILLPATH is the file record
+*/
+
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_PATH Data; //!< Path specification
+*/
+} U_PMF_FILLPATHO;
+
+/** @brief EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object
+ for U_PMF_PATHGRADIENTBRUSHOPTIONALDATA data field
+
+Used with path gradient brushes. May be used to expand the center color
+of a gradient, which would otherwise only be found at the center point.
+The expanded area is the width, height X scale factor, but in no case
+less than 1 pixel.
+
+*/
+typedef struct {
+ uint32_t Count; //!< must be 2
+ U_FLOAT ScaleX; //!< value 0.0 <-> 1.0
+ U_FLOAT ScaleY; //!< value 0.0 <-> 1.0
+} U_PMF_FOCUSSCALEDATA;
+
+/** @brief EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+
+Bit fields are not used in structs in this implementation, these are serialized/deserialized in
+the corresponding routines. Bitfields in the FILE (LITTLE endian here, manual uses BIG endian) are:
+ unsigned int GrfVersion : 12; GraphicsVersion enumeration
+ unsigned int Signature : 20; Must be U_GFVR_PMF (0xDBC01)
+ @{
+*/
+typedef uint32_t U_PMF_GRAPHICSVERSION; //!< EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+/** @} */
+
+/** @brief EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object */
+typedef struct {
+ uint32_t Style; //!< HatchStyle enumeration
+ U_PMF_ARGB Foreground; //!< Hatch pattern line color
+ U_PMF_ARGB Background; //!< Hatch pattern bkground color
+} U_PMF_HATCHBRUSHDATA;
+
+/** \defgroup U_PMF_Int7 PMF 7 bit signed integer
+ @brief EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object
+
+ bit 7 U_INT7 Clear in Integer7 objects
+ bits 0-6 7 bit signed integer value
+ @{
+*/
+#define U_TEST_INT7 0x80 //!< This bit is clear in Integer7 objects.
+#define U_SIGN_INT7 0x40 //!< Sign bit on an Integer7 object.
+#define U_MASK_INT7 0x7F //!< xMask to retrieve integer7 bits.
+/** @} */
+
+/** \defgroup U_PMF_Int15 PMF 15 bit signed integer
+ @brief EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object
+
+ bit 15 U_INT15 Set in Integer15 objects
+ bits 0-15 15 bit signed integer value
+
+ This is the one data type that really does seem to be stored into the file in Big Endian order.
+ It has to be this way because the bit that determines if data is int7 or int15 must be in the first byte
+ the parser sees, and that byte is the high order byte.
+ @{
+*/
+#define U_TEST_INT15 0x8000 //!< This bit is set in Integer15 objects.
+#define U_SIGN_INT15 0x4000 //!< Sign bit on an Integer15 object.
+#define U_MASK_INT15 0x7FFF //!< Mask to retrieve integer15 bits.
+/** @} */
+
+/* EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object, defined above, before 2.2.1.9 */
+
+/** @brief EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object, out of order, needed for 2.2.2.24 */
+typedef struct {
+ U_FLOAT X; //!< UL X value
+ U_FLOAT Y; //!< UL Y value
+ U_FLOAT Width; //!< Width
+ U_FLOAT Height; //!< Height
+} U_PMF_RECTF;
+
+/** @brief EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object
+Manual says that Reserved1 and Reserved2 must be ignored. In practice if Reserved1 is not set to StartColor
+and Reserved2 is not set to EndColor, then XP Preview will not display the gradient.
+*/
+typedef struct {
+ uint32_t Flags; //!< BrushData flags
+ int32_t WrapMode; //!< WrapMode enumeration
+ U_PMF_RECTF RectF; //!< UL=start, LR=end of gradient
+ U_PMF_ARGB StartColor; //!< Gradient start color
+ U_PMF_ARGB EndColor; //!< Gradient end color
+ uint32_t Reserved1; //!< ignore
+ uint32_t Reserved2; //!< ignore
+/* variable part of object, not part of structure.
+ U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA data; //!< presence and meaning depend on Flags field
+*/
+} U_PMF_LINEARGRADIENTBRUSHDATA;
+
+/** @brief EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object, out of order, needed for 2.2.2.25 */
+typedef struct {
+ U_FLOAT m11; //!< Rotation matrix m11 element
+ U_FLOAT m12; //!< Rotation matrix m12 element
+ U_FLOAT m21; //!< Rotation matrix m21 element
+ U_FLOAT m22; //!< Rotation matrix m22 element
+ U_FLOAT dX; //!< Translation in X
+ U_FLOAT dY; //!< Translation in Y
+} U_PMF_TRANSFORMMATRIX;
+
+/** NOT DOCUMENTED. Encountered in actual EmfPlusLinearGradientBrushOptionalData Object made by PowerPoint 2003. This
+ structure is needed for the next. */
+typedef struct {
+ U_FLOAT m11; //!< Rotation matrix m11 element
+ U_FLOAT m12; //!< Rotation matrix m12 element
+ U_FLOAT m21; //!< Rotation matrix m21 element
+ U_FLOAT m22; //!< Rotation matrix m22 element
+} U_PMF_ROTMATRIX;
+
+/** @brief EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object
+ For U_PMF_LINEARGRADIENTBRUSHDATA data field
+*/
+/* Entire object is variable and not part of a structure! U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA
+ U_PMF_ROTMATRIX Matrix; //!< Rotation matrix, Manuals says that this should be Transformation matrix, but last two values are missing
+ (various) pattern; //!< Presence and meaning depend on Flags field, see below
+
+ Flag values
+ U_BD_PresetColors U_BD_BlendFactorsH U_BD_BlendFactorsV pattern(s) present?
+ 0 0 0 none
+ 1 0 0 U_PMF_BLENDCOLORS
+ 0 1 0 U_PMF_BLENDFACTORS
+ 0 0 1 U_PMF_BLENDFACTORS
+ 0 1 1 U_PMF_BLENDFACTORS, U_PMF_BLENDFACTORS
+*/
+
+/** @brief EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object */
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_PATH Data; //!< Outline path
+*/
+} U_PMF_LINEPATH;
+
+/** @brief EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object */
+typedef struct {
+ uint32_t Type; //!< MetaFileDatatype enumeration
+ uint32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_IMAGE Data; //!< Various types of data, like an EMF metafile, WMF metafile, another EMF+ metafile
+*/
+} U_PMF_METAFILE;
+
+/** @brief EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object */
+typedef struct {
+ uint32_t Flags; //!< PaletteStyle flags
+ uint32_t Elements; //!< elements in Data
+/* variable part of object, not part of structure.
+ U_PMF_ARGB Data; //!< Palette data (array of colors)
+*/
+} U_PMF_PALETTE;
+
+/** @brief EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object, out of order, needed for 2.2.2.29 */
+typedef struct {
+ U_FLOAT X; //!< UL X value
+ U_FLOAT Y; //!< UL Y value
+} U_PMF_POINTF;
+
+/** @brief EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object */
+typedef struct {
+ uint32_t Flags; //!< BrushData flags
+ int32_t WrapMode; //!< WrapMode enumeration
+ U_PMF_ARGB CenterColor; //!< Gradient center color
+ U_PMF_POINTF Center; //!< Center coordinates
+ uint32_t Elements; //!< Number of elements in gradient (not counting center)
+/* variable part of object, not part of structure.
+ U_PMF_ARGB Gradient; //!< Color Gradient with Elements members
+ (varies) Boundary; //!< U_PMF_BOUNDARYPATHDATA object if BrushDataPath bit set in Flag, else U_PMF_BOUNDARYPOINTDATA object
+ U_PMF_GRADIENTBRUSHOPTIONALDATA data; //!< exact composition depends on Flags
+*/
+} U_PMF_PATHGRADIENTBRUSHDATA;
+
+/** EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object
+ for U_PMF_PATHGRADIENTNBRUSHDATA data field
+*/
+/* Entire thing is variable or optional.
+typedef struct {
+ U_PMF_TRANSFORMMATRIX Matrix; //!< Optional Transformation matrix
+ U_PMF_BLENDCOLORS Pattern; //!< presence and meaning depend on Flags field
+ Flag values
+ U_BD_PresetColors U_BD_BlendFactorsH pattern?
+ 0 0 none
+ 1 0 U_PMF_BLENDCOLORS
+ 0 1 U_PMF_BLENDFACTORS
+ U_PMF_FOCUSSSCALEDATA data //!< Present if U_BD_FocusScales bit set in Flags in U_PMF_PATHGRADIENTNBRUSHDATA object
+} U_PMF_PATHGRADIENTBRUSHOPTIONALDATA;
+*/
+
+/** \defgroup U_PMF_PPTYPE PMF Path Point Types
+ @brief EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+
+Bitfields in the FILE (LITTLE endian here, manual uses BIG endian) are:
+ bits 4-7 PathPointType flags
+ bits 0-3 PathPointType enumeration
+ @{
+*/
+typedef uint8_t U_PMF_PATHPOINTTYPE; //!< EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+/** @} */
+
+/** \defgroup U_PMF_PPTYPERLE PMF Run Length Encoded Path Point Types
+ @brief EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object
+
+U_PMF_PATHPOINTTYPERLE fields specify point types in a path where the path is Run Length Encoded.
+Bit fields are not used in structs in this implementation, these are serialized/deserialized in
+the corresponding routines. Bitfields in the FILE (LITTLE endian here, manual uses BIG endian) are:
+ bit 15 Set: Bezier curve; Clear: straight line
+ bit 14 ignored
+ bits 8-13 Run count
+ bits 0-7 PathPointType enumeration
+ @{
+*/
+typedef uint16_t U_PMF_PATHPOINTTYPERLE; //!< EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object
+/** @} */
+
+/** @brief EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object
+
+Variable part of object follows structure:
+ U_PMF_PENOPTIONALDATA data; Optional pen data, exact composition depends on Flags
+*/
+typedef struct {
+ uint32_t Flags; //!< PenData flags
+ uint32_t Unit; //!< UnitType enumeration
+ U_FLOAT Width; //!< Width in units set by Unit
+} U_PMF_PENDATA;
+
+/** @brief EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object
+
+Every part of this object is variable or optional, there is no corresponding struct
+
+ Present if Flag What is it
+ U_PMF_TRANSFORMMATRIX Matrix //!< U_PD_Transform Transformation matrix
+ int32_t StartCap //!< U_PD_StartCap LineCapType enumeration
+ int32_t EndCap //!< U_PD_EndCap LineCapType enumeration
+ uint32_t Join //!< U_PD_Join LineJoinType enumeration
+ U_FLOAT MiterLimit //!< U_PD_MiterLimit Maximum (miter length / line width)
+ int32_t Style //!< U_PD_LineStyle LineStyle enumeration
+ int32_t DLCap //!< U_PD_DLCap DashedLineCapType enumeration
+ U_FLOAT DLOffset //!< U_PD_DLOffset Distance line start to first dash start
+ U_PMF_DASHEDLINEDATA DLData //!< U_PD_DLData Dash and space widths
+ int32_t PenAlignment //!< U_PD_NonCenter PenAlignment enumeration
+ U_PMF_COMPOUNDLINEDATA CLData //!< U_PD_CompoundLineData Compount Line (parallel lines drawn instead of one)
+ U_PMF_CUSTOMSTARTCAPDATA CSCapData //!< U_PD_CustomStartCap Custom start cap
+ U_PMF_CUSTOMENDCAPDATA CECapData //!< U_PD_CustomEndCap Custom end cap
+ */
+
+/** @brief EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object */
+typedef struct {
+ int16_t X; //!< X coordinate
+ int16_t Y; //!< Y coordinate
+} U_PMF_POINT;
+
+/** U_PMF_POINTF EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object, defined above, before 2.2.2.29 */
+
+/** U_PMF_POINTR EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object
+ For U_PMF_DRAWBEZIERS data field (optionally).
+ Both parts of this object are variable, there is no corresponding struct.
+ Any combination of the two allowed types of integer is valid.
+
+ (varies) X; //!< U_PMF_INTEGER7 or U_PMF_INTEGER15
+ (varies) Y; //!< U_PMF_INTEGER7 or U_PMF_INTEGER15
+
+*/
+
+/** @brief EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object */
+typedef struct {
+ int16_t X; //!< UL X value
+ int16_t Y; //!< UL Y value
+ int16_t Width; //!< Width
+ int16_t Height; //!< Height
+} U_PMF_RECT;
+
+/** U_PMF_RECTF EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object, defined above, before 2.2.2.24 */
+
+/** U_PMF_REGIONNODE EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object, defined above, before 2.2.1.8 */
+
+/** U_PMF_REGIONNODECHILDNODES EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object
+ For U_PMF_REGIONNODE data field (optionally).
+ Both parts of this object are variable, there is no corresponding struct.
+ U_PMF_REGIONNODE Left; //!< Left child
+ U_PMF_REGIONNODE Right; //!< Right child
+*/
+
+/** @brief EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object */
+typedef struct {
+ int32_t Size; //!< Bytes in Data
+/* variable part of object, not part of structure.
+ U_PMF_PATH Data; //!< Boundary of region node
+*/
+} U_PMF_REGIONNODEPATH;
+
+/** @brief EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object
+ For U_PMF_BRUSH data field (one type of brush)
+*/
+typedef struct {
+ U_PMF_ARGB Color; //!< Color of brush
+} U_PMF_SOLIDBRUSHDATA;
+
+/** U_PMF_STRINGFORMATDATA EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object
+ Both parts of this object are variable and optional, there is no corresponding struct
+ U_FLOAT TabStops[]; //!< Array of tabstop locations
+ U_PMF_CHARACTERRANGE CharRange[]; //!< Array of character ranges in the text
+*/
+
+/** @brief EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object */
+typedef struct {
+ uint32_t Flags; //!< BrushData flags
+ int32_t WrapMode; //!< WrapMode enumeration
+/* variable part of object, not part of structure.
+ U_PMF_TEXTUREBRUSHOPTIONALDATA data; //!< Optional texture data
+*/
+} U_PMF_TEXTUREBRUSHDATA;
+
+/** U_PMF_TEXTUREBRUSHOPTIONALDATA EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object
+
+Every part of this object is variable or optional, there is no corresponding struct
+
+ U_PMF_TRANSFORMMATRIX Matrix; Transformation matrix, present if Flag BrushDataTransform is set.
+ U_PMF_IMAGE Image Image that contains the texture. Present if the PMR record that includes this object still has space
+ for an U_PMF_IMAGE after all the other variable and optional data
+ within it has been accounted for.
+*/
+
+/** U_PMF_TRANSFORMMATRIX EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object, defined above, before 2.2.2.25 */
+
+/** common structure present at the beginning of all(*) EMF+ records */
+typedef struct {
+ uint16_t Type; //!< Recordtype enumeration (what this record is)
+ uint16_t Flags; //!< Flags (meaning varies by record type)
+ uint32_t Size; //!< Bytes in record, including this struct (will be a multiple of 4)
+ uint32_t DataSize; //!< Bytes of data that follow, may not be a multiple of 4.
+} U_PMF_CMN_HDR;
+
+/** These are the Image Effect Objects 2.2.3.* They specify parameters for "filters" that may be applied to bitmaps. */
+
+/** @brief EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object */
+typedef struct {
+ U_FLOAT Radius; //!< Blur radius in pixels
+ uint32_t ExpandEdge; //!< 1: expand bitmap by Radius; 0: bitmap size unchanged
+} U_PMF_IE_BLUR;
+
+
+/** @brief EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object */
+typedef struct {
+ int32_t Brightness; //!< -255 to 255, 0 is unchanged, positive increases, negative decreases
+ int32_t Contrast; //!< -100 to 100, 0 is unchanged, positive increases, negative decreases
+} U_PMF_IE_BRIGHTNESSCONTRAST;
+
+/** @brief EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object */
+typedef struct {
+ int32_t CyanRed; //!< -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite
+ int32_t MagentaGreen; //!< -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite
+ int32_t YellowBlue; //!< -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite
+} U_PMF_IE_COLORBALANCE;
+
+/** @brief EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object
+ Adjust Range
+ Exposure -255 to 255, 0 is unchanged
+ Density -255 to 255, 0 is unchanged
+ Contrast -100 to 100, 0 is unchanged
+ Highlight -100 to 100, 0 is unchanged
+ Shadow -100 to 100, 0 is unchanged
+ WhiteSaturation 0 to 255
+ BlackSaturation 0 to 255
+*/
+typedef struct {
+ uint32_t Adjust; //!< CurveAdjustment enumeration
+ uint32_t Channel; //!< CurveChannel enumeration
+ int32_t Intensity; //!< adjustment to apply. "Adjust" determines what field this is and range values.
+} U_PMF_IE_COLORCURVE;
+
+/** @brief EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object */
+typedef struct {
+ uint8_t BLUT[256]; //!< Blue color lookup table
+ uint8_t GLUT[256]; //!< Green color lookup table
+ uint8_t RLUT[256]; //!< Red color lookup table
+ uint8_t ALUT[256]; //!< Alpha color lookup table
+} U_PMF_IE_COLORLOOKUPTABLE;
+
+/** @brief EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object */
+typedef struct {
+ U_FLOAT M[5][5]; //!< 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0]
+} U_PMF_IE_COLORMATRIX;
+
+/** @brief EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object */
+typedef struct {
+ int32_t Hue; //!< -180 to 180, 0 is unchanged
+ int32_t Saturation; //!< -100 to 100, 0 is unchanged
+ int32_t Lightness; //!< -100 to 100, 0 is unchanged
+} U_PMF_IE_HUESATURATIONLIGHTNESS;
+
+/** @brief EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object */
+typedef struct {
+ int32_t Highlight; //!< 0 to 100, 100 is unchanged
+ int32_t Midtone; //!< -100 to 100, 0 is unchanged
+ int32_t Shadow; //!< 0 to 100, 0 is unchanged
+} U_PMF_IE_LEVELS;
+
+/** @brief EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object */
+typedef struct {
+ int32_t Elements; //!< Number of members in Rects
+/* variable part of object, not included in structure
+ U_RECTL Rects[]; //!< Array of rectangular area(s) to apply red eye correction
+*/
+} U_PMF_IE_REDEYECORRECTION;
+
+/** @brief EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object */
+typedef struct {
+ U_FLOAT Radius; //!< Sharpening radius in pixels
+ int32_t Sharpen; //!< 0 to 100, 0 is unchanged
+} U_PMF_IE_SHARPEN;
+
+/** @brief EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object */
+typedef struct {
+ int32_t Hue; //!< -180 to 180, [positive==clockwise] rotation in degrees starting from blue
+ int32_t Amount; //!< -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis
+} U_PMF_IE_TINT;
+
+/* ************************** EMF+ Records ******************************** */
+
+/** @brief EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags)
+ U_FLOAT dX; //!< horizontal translation offset to apply to clipping region
+ U_FLOAT dY; //!< vertical translation offset to apply to clipping region
+} U_PMF_OFFSETCLIP;
+
+/** @brief U_PMF_RESETCLIP EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags)
+} U_PMF_RESETCLIP;
+
+/** @brief EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33
+
+flags (LITTLE endian here, manual uses BIG endian)
+ bits 8-11 CombineMode enumeration
+ bits 0-7 Index of an U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETCLIPPATH;
+
+/** @brief EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32
+
+flags (LITTLE endian here, manual uses BIG endian)
+ bits 8-11 CombineMode enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_PMF_RECTF Rect; //!< Rectangle used with CombineMode enumeration from Header.Flags
+} U_PMF_SETCLIPRECT;
+
+/** @brief EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 12-15 CombineMode enumeration
+ bits 0-7 Index of an U_PMF_REGION object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETCLIPREGION;
+
+/** @brief EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03
+
+ variable part of record, not included in structure
+ char data[]; //!< Private data, may be anything
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+} U_PMF_COMMENT;
+
+/** @brief EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+} U_PMF_ENDOFFILE;
+
+/** @brief EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+} U_PMF_GETDC;
+
+/** @brief EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 0 Set indicates "dual mode" EMF+
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ U_PMF_GRAPHICSVERSION Version; //!< EmfPlusGraphicsVersion object
+ uint32_t EmfPlusFlags; //!< Reference device 0 bit: set = video device, clear= printer. Ignore all other bits.
+ uint32_t LogicalDpiX; //!< Horizontal resolution reference device in DPI
+ uint32_t LogicalDpiY; //!< Vertical resolution reference device in DPI
+} U_PMF_HEADER;
+
+/** @brief EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ U_PMF_ARGB Color; //!< Erase everything preceding, set background ARGB color.
+} U_PMF_CLEAR;
+
+/** @brief EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+ bits 0-7 Index of an U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Start; //!< Start angle, >=0.0, degrees clockwise from 3:00
+ U_FLOAT Sweep; //!< Sweep angle, -360<= angle <=360, degrees clockwise from Start
+/* variable part of record, not included in structure
+ U_RECT or U_RECTF Rect; //!< Bounding box for elliptical arc being drawn.
+*/
+} U_PMF_DRAWARC;
+
+/** @brief EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: int16_t coordinates; Clear: U_FLOAT coordinates (IGNORE if bit 4 is set)
+ bit 12 U_PPF_P Set: Coordinates are relative; Clear: they are absolute
+ bits 0-7 Index of an U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t Elements; //!< Number of members in the Points array
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Points, for type see table above
+*/
+} U_PMF_DRAWBEZIERS;
+
+/** @brief EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: int16_t coordinates; Clear: U_FLOAT coordinates (IGNORE if bit 4 is set)
+ bit 12 U_PPF_P Set: Coordinates are relative; Clear: they are absolute
+ bits 0-7 Index of an U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+
+Curve is a cardinal spline.
+References sent by MS support:
+
+http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Tension; //!< Controls splines, 0 is straight line, >0 is curved
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Points, for type see table above
+*/
+} U_PMF_DRAWCLOSEDCURVE;
+
+/** @brief EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: int16_t coordinates; Clear: U_FLOAT coordinates (IGNORE if bit 4 is set)
+ bits 0-7 Index of an U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+
+ bit1 Type of Data
+ 1 U_EMF_POINT
+ 0 U_EMF_POINTF
+
+Curve is a cardinal spline, using doubled terminator points to generate curves for the terminal segments.
+References sent by MS support:
+
+http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Tension; //!< Controls splines, 0 is straight line, >0 is curved
+ uint32_t Offset; //!< Element in Points that is the spline's starting point
+ uint32_t NSegs; //!< Number of segments
+ uint32_t Elements; //!< Number of members in Points array
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Points, for type see table above
+*/
+} U_PMF_DRAWCURVE;
+
+/** @brief EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36
+
+ flags (LITTLE endian here, manual uses BIG endian)
+. bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table
+ bits 0-7 Index of an U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Flags bit0
+ uint32_t DSOFlags; //!< DriverStringOptions flags
+ uint32_t HasMatrix; //!< If 1 record contains a TransformMatrix field, if 0 it does not.
+ uint32_t Elements; //!< Number of members in Glyphs and Positions array
+/*
+ variable part of record, not included in structure
+ uint16_t Glyphs; //!< If U_DSO_CmapLookup is set in DSOFlags this is an array
+ of UTF16LE characters, otherwise, it is an array of indices into the U_PMF_FONT
+ object indexed by Object_ID in flags.
+ U_PMF_POINTF Positions; //!< Coordinates of each member of Glyphs. U_DSO_RealizedAdvance set in DSOFlags
+ Relative then positions are calculated relative to the first glyph which is stored
+ in Positions, otherwise, all glyph positions are stored in Positions.
+ U_PMF_TRANSFORMMATRIX Matrix; //!< Transformation to apply to Glyphs & Positions. Present if HasMatrix is 1
+*/
+} U_PMF_DRAWDRIVERSTRING;
+
+/** @brief EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+ bits 0-7 Index of an U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+/*
+ variable part of record, not included in structure
+ (varies) Rect; //!< Bounding rectangle, data type set by bit1 of Header.Flags
+*/
+} U_PMF_DRAWELLIPSE;
+
+/** @brief EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: DstRect is U_PMF_RECT; Clear: DstRect is U_PMF_RECTF
+ bits 0-7 Index of an U_PMF_Image object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t ImgAttrID; //!< EmfPlusImageAttributes object
+ int32_t SrcUnit; //!< UnitType enumeration
+ U_PMF_RECTF SrcRect; //!< Region of image
+/*
+ variable part of record, not included in structure
+ (varies) DstRect; //!< Destination rectangle for image. Type controlled by bit1 of Header.Flags
+*/
+} U_PMF_DRAWIMAGE;
+
+/** @brief EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 14 U_PPF_C Set: Points is U_PMF_POINT; Clear: Points is U_PMF_POINTF
+ bit 13 U_PPF_E Set: effect from previous U_PMF_SERIALIZABLEOBJECT record will be applied; Clear: no effect applied
+ bit 11 U_PPF_P Set: Points has relative coordinates; Clear: Points has absolute coordinates
+ bits 0-7 Index of an U_PMF_Image object in the EMF+ object table (0-63, inclusive)
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+
+ WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
+ file is inserted as an image into PowerPoint.
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t ImgAttrID; //!< EmfPlusImageAttributes object
+ int32_t SrcUnit; //!< UnitType enumeration
+ U_PMF_RECTF SrcRect; //!< Region of image
+ uint32_t Elements; //!< Number of members in Points, must be 3
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< 3 points of a parallelogram. Type from bit1 and bit4 of Header.Flags, see table above
+*/
+} U_PMF_DRAWIMAGEPOINTS;
+
+/** @brief EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: Points is U_PMF_POINT; Clear: Points is U_PMF_POINTF
+ bit 10 U_PPF_D Set: close shape by connecting last point to first; Clear: leave path open
+ bit 12 U_PPF_P Set: Points has relative coordinates; Clear: Points has absolute coordinates
+ bits 0-7 Index of an U_PMF_Image object in the EMF+ object table (0-63, inclusive)
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t Elements; //!< Number of members in Points
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Sequence of points to connect with line segments. Type from bit1 and bit4 of Header.Flags, see table above
+*/
+} U_PMF_DRAWLINES;
+
+/** @brief EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 Index of an U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t PenID; //!< U_PMF_PEN object in the EMF+ object table (0-63, inclusive)
+} U_PMF_DRAWPATH;
+
+/** @brief EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+ bits 0-7 Index of an U_PMF_Pen object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Start; //!< Start angle, >=0.0, degrees clockwise from 3:00
+ U_FLOAT Sweep; //!< Sweep angle, -360<= angle <=360, degrees clockwise from Start
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rect; //!< Bounding box for elliptical pie segment being drawn. Type from bit1 of Header.Flags, see above
+*/
+} U_PMF_DRAWPIE;
+
+/** @brief EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+ bits 0-7 Index of an U_PMF_Pen object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t Elements; //!< Number of members in Rects
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rects; //!< Array of rectangles to draw. Type from bit1 of Header.Flags, see above
+*/
+} U_PMF_DRAWRECTS;
+
+/** @brief EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bits 0-7 Index of an U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Flags bit0
+ uint32_t FormatID; //!< U_PMF_STRINGFORMAT object in EMF+ Object Table.
+ uint32_t Length; //!< Number of characters in the string.
+ U_PMF_RECTF Rect; //!< String's bounding box.
+/*
+ variable part of record, not included in structure
+ uint16_t String; //!< Array of UFT-16LE unicode characters.
+*/
+} U_PMF_DRAWSTRING;
+
+/** @brief EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bit 9 U_PPF_C Set: Points is U_PMF_POINT; Clear: Points is U_PMF_POINTF
+ bit 10 U_PPF_F Set: winding fill; Clear: alternate fill
+ bit 12 U_PPF_P Set: Points has relative coordinates; Clear: Points has absolute coordinates
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+ U_FLOAT Tension; //!< Controls splines, 0 is straight line, >0 is curved
+ uint32_t Elements; //!< Number of members in Points
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Sequence of points to connect. Type from bit1 and bit4 of Header.Flags, see table above
+*/
+} U_PMF_FILLCLOSEDCURVE;
+
+/** @brief EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rect; //!< Bounding box for elliptical pie segment being drawn. Type from bit1 of Header.Flags, see above
+*/
+} U_PMF_FILLELLIPSE;
+
+/** @brief EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14
+Note: U_PMF_FILLPATHOBJ is the object, U_PMF_FILLPATH is the file record
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bits 0-7 Index of an U_PMF_PATH object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+} U_PMF_FILLPATH;
+
+/** @brief EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+ U_FLOAT Start; //!< Start angle, >=0.0, degrees clockwise from 3:00
+ U_FLOAT Sweep; //!< Sweep angle, -360<= angle <=360, degrees clockwise from Start
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rect; //!< Bounding box for elliptical pie segment being filled. Type from bit1 of Header.Flags, see above
+*/
+} U_PMF_FILLPIE;
+
+/** @brief EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bit 9 U_PPF_C Set: Points is U_PMF_POINT; Clear: Points is U_PMF_POINTF
+ bit 12 U_PPF_P Set: Points has relative coordinates; Clear: Points has absolute coordinates
+
+ bit1 bit4 Type of Data
+ 1 0 U_EMF_POINT
+ 0 0 U_EMF_POINTF
+ 0 1 U_EMF_POINTR
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+ uint32_t Elements; //!< Number of members in Points
+/*
+ variable part of record, not included in structure
+ (varies) Points; //!< Sequence of points to connect with line segments. Type from bit1 and bit4 of Header.Flags, see table above
+*/
+} U_PMF_FILLPOLYGON;
+
+/** @brief EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bit 9 U_PPF_C Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+ uint32_t Elements; //!< Number of members in Rects
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rects; //!< Array of rectangles to draw. Type from bit1 of Header.Flags, see above
+*/
+} U_PMF_FILLRECTS;
+
+/** @brief EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_B Set: BrushID is an U_PFM_ARGB; Clear: is index of U_PMF_BRUSH object in EMF+ object table.
+ bits 0-7 Index of an U_PMF_REGION object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint32_t BrushID; //!< Color or index to Brush object, depends on Header.Flags bit0
+} U_PMF_FILLREGION;
+
+/** @brief EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_N Set: object definition continues in next record; Clear: this is the final object definition record
+ bits 8-14 Type of object being created, ObjectType enumeration
+ bits 0-7 Index of an U_PMF_REGION object in the EMF+ object table (0-63, inclusive)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+/*
+ variable part of record, not included in structure
+ uint8_t Data; //!< Object's data. Type from bits1-7 and bits8-15 of Header.Flags, see above
+*/
+} U_PMF_OBJECT;
+
+/** @brief EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38
+
+ WARNING! Windows XP Preview does not show filter effects, whether or not U_PPF_E is set. They are visible if the EMF+
+ file is inserted as an image into PowerPoint.
+
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ uint8_t GUID[16]; //!< ImageEffects identifier. Composed of Data1[4]-Data2[2]-Data3[2]-Data4[8]
+ //!< Data1-Data3 are stored as little endian integers. Data4 is stored big endian (like a string)
+ uint32_t Size; //!< Bytes in Data.
+/*
+ variable part of record, not included in structure
+ uint8_t Data; //!< "Serialized image effects parameter block". One of the ImageEffects objects.
+*/
+} U_PMF_SERIALIZABLEOBJECT;
+
+/** @brief EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 7-1 SmoothingMode enumeration
+ bit 0 U_PPF_AA Set: anti-aliasing on; Clear: anti-aliasing off
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETANTIALIASMODE;
+
+/** @brief EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 CompositingMode enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETCOMPOSITINGMODE;
+
+/** @brief EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 CompositingQuality enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETCOMPOSITINGQUALITY;
+
+/** @brief EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 InterpolationMode enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETINTERPOLATIONMODE;
+
+/** @brief EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 PixelOffsetMode enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETPIXELOFFSETMODE;
+
+/** @brief EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ int32_t X; //!< X coordinate of rendering origin
+ int32_t Y; //!< Y coordinate of rendering origin
+} U_PMF_SETRENDERINGORIGIN;
+
+/** @brief EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 12-0 1000 x Gamma correction value. Range 1000-2200 = gamma 1.0-2.2
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETTEXTCONTRAST;
+
+/** @brief EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 TextRenderingHint enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+} U_PMF_SETTEXTRENDERINGHINT;
+
+/** @brief EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 8-15 UnitType enumeration
+ bits 0-7 (all zero)
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_PMF_RECTF DstRect; //!< with SrcRect specifies a transformation
+ U_PMF_RECTF SrcRect; //!< with DstRect specifies a transformation
+ uint32_t Index; //!< Index to apply to this graphics container
+} U_PMF_BEGINCONTAINER;
+
+/** @brief EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ uint32_t Index; //!< Index to apply to this graphics container
+} U_PMF_BEGINCONTAINERNOPARAMS;
+
+/** @brief EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ uint32_t Index; //!< Index of container being closed, from U_PMF_BEGINCONTAINERNOPARAMS or U_PMF_BEGINCONTAINER
+} U_PMF_ENDCONTAINER;
+
+/** @brief EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ uint32_t Index; //!< Index of Graphics State being restored, from U_PMF_SAVE
+} U_PMF_RESTORE;
+
+/** @brief EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25 */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ uint32_t Index; //!< Index of Graphics State being saved
+} U_PMF_SAVE;
+
+/** @brief EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 15 U_PPF_K Set: Rect is U_PMF_RECT; Clear: Rect is U_PMF_RECTF
+ bits 14-0 Number of rectangles in Rects field
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+/*
+ variable part of record, not included in structure
+ U_RECT or U_RECTF Rects; //!< Array of rectangles to draw. Type from bit0 of Header.Flags, see above
+*/
+} U_PMF_SETTSCLIP;
+
+/** @brief EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 1 U_PPF_VGA Set: Palette is VGA basic colors; Clear: Palette is a U_PMF_PALETTE object.
+ bit 0 U_PPF_PP Set: Palette field is present; Clear: Palette field is absent
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ uint8_t AntiAliasMode; //!< SmoothingMode enumeration
+ uint8_t TextRenderHint; //!< TextRenderingHint enumeration
+ uint8_t CompositingMode; //!< CompositingMode enumeration
+ uint8_t CompositingQuality; //!< CompositingQuality enumeration
+ int16_t RenderOriginX; //!< Origin X for halftoning and dithering
+ int16_t RenderOriginY; //!< Origin Y for halftoning and dithering
+ uint16_t TextContrast; //!< Gamma correction, range 0 to 12
+ uint8_t FilterType; //!< FilterType enumeraton
+ uint8_t PixelOffset; //!< PixelOffsetMode enumeration
+ U_PMF_TRANSFORMMATRIX WorldToDevice; //!< world to device transform
+/*
+ optional part of record, not included in structure
+ U_PMF_PALETTE Palette; //!< Present if bit15 of Header.Flags is set
+*/
+} U_PMF_SETTSGRAPHICS;
+
+/** @brief EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 13 U_PPF_XM Set: Post multiply; Clear: Pre multiply
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_PMF_TRANSFORMMATRIX Matrix; //!< Transformation matrix
+} U_PMF_MULTIPLYWORLDTRANSFORM;
+
+/** @brief EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B
+Sets transformation matrix to identity matrix.
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+} U_PMF_RESETWORLDTRANSFORM;
+
+/** @brief EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F
+ Construct transformation matrix from Angle:
+ sin(Angle) cos(Angle) 0
+ cos(Angle) -sin(Angle) 0
+ Multiply this against current world space transform, result becomes new world space transform.
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 13 U_PPF_XM Set: Post multiply; Clear: Pre multiply
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Angle; //!< Rotation angle, in degrees
+} U_PMF_ROTATEWORLDTRANSFORM;
+
+/** @brief EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E
+ Construct transformation matrix:
+ Sx 0 0
+ 0 Sy 0
+ Multiply this against current world space transform, result becomes new world space transform.
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 13 U_PPF_XM Set: Post multiply; Clear: Pre multiply
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Sx; //!< X scale factor
+ U_FLOAT Sy; //!< Y scale factor
+} U_PMF_SCALEWORLDTRANSFORM;
+
+/** @brief EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30
+ flags (LITTLE endian here, manual uses BIG endian)
+ bits 0-7 UnitType enumeration
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Scale; //!< Scale factor to convert page space to device space
+} U_PMF_SETPAGETRANSFORM;
+
+
+/** @brief EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A */
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header (ignore flags and set to zero)
+ U_PMF_TRANSFORMMATRIX Matrix; //!< Transformation matrix
+} U_PMF_SETWORLDTRANSFORM;
+
+/** @brief EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D
+ Construct transformation matrix:
+ 1 0 Dx
+ 0 1 Dy
+ Multiply this against current world space transform, result becomes new world space transform.
+
+ flags (LITTLE endian here, manual uses BIG endian)
+ bit 13 U_PPF_XM Set: Post multiply; Clear: Pre multiply
+*/
+typedef struct {
+ U_PMF_CMN_HDR Header; //!< Common header
+ U_FLOAT Dx; //!< X offset
+ U_FLOAT Dy; //!< Y offset
+} U_PMF_TRANSLATEWORLDTRANSFORM;
+
+//! \cond
+
+/* EMF+ prototypes (helper functions) */
+int U_PMR_write(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *sum, EMFTRACK *et);
+int U_PMR_drawline(uint32_t PenID, uint32_t PathID, U_PMF_POINTF Start, U_PMF_POINTF End, int Dashed, U_PSEUDO_OBJ *sum, EMFTRACK *et);
+int U_PMR_drawstring( const char *string, int Vpos, uint32_t FontID, const U_PSEUDO_OBJ *BrushID, uint32_t FormatID,
+ U_PMF_STRINGFORMAT Sfs, const char *FontName, U_FLOAT Height, U_FontInfoParams *fip, uint32_t FontFlags,
+ U_FLOAT x, U_FLOAT y, U_PSEUDO_OBJ *sum, EMFTRACK *et);
+U_PMF_POINT *POINTF_To_POINT16_LE(U_PMF_POINTF *points, int count);
+int U_PMF_LEN_REL715(const char *contents, int Elements);
+int U_PMF_LEN_FLOATDATA(const char *contents);
+int U_PMF_LEN_BYTEDATA(const char *contents);
+int U_PMF_LEN_PENDATA(const char *PenData);
+int U_PMF_LEN_OPTPENDATA(const char *PenData, uint32_t Flags);
+char *U_PMF_CURLYGUID_set(uint8_t *GUID);
+int U_PMF_KNOWNCURLYGUID_set(const char *string);
+void U_PMF_MEMCPY_SRCSHIFT(void *Dst, const char **Src, size_t Size);
+void U_PMF_MEMCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size);
+void U_PMF_REPCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size, size_t Reps);
+void U_PMF_PTRSAV_SHIFT(const char **Dst, const char **Src, size_t Size);
+uint16_t U_PMF_HEADERFLAGS_get(const char *contents);
+int U_PMF_RECORD_SIZE_get(const char *contents);
+int U_PMF_CMN_HDR_get(const char **contents, U_PMF_CMN_HDR *Header);
+int U_OID_To_OT(uint32_t OID);
+int U_OID_To_BT(uint32_t OID);
+int U_OID_To_CLCDT(uint32_t OID);
+int U_OID_To_IDT(uint32_t OID);
+int U_OID_To_RNDT(uint32_t OID);
+uint8_t *U_OID_To_GUID(uint32_t OID);
+int U_OA_append(U_OBJ_ACCUM *oa, const char *data, int size, int Type, int Id);
+int U_OA_clear(U_OBJ_ACCUM *oa);
+int U_OA_release(U_OBJ_ACCUM *oa);
+U_PSEUDO_OBJ *U_PO_create(char *Data, size_t Size, size_t Use, uint32_t Type);
+U_PSEUDO_OBJ *U_PO_append(U_PSEUDO_OBJ *po, const char *Data, size_t Size);
+U_PSEUDO_OBJ *U_PO_po_append(U_PSEUDO_OBJ *po, U_PSEUDO_OBJ *src, int StripE);
+int U_PO_free(U_PSEUDO_OBJ **po);
+U_DPSEUDO_OBJ *U_PATH_create(int Elements, const U_PMF_POINTF *Points, uint8_t First, uint8_t Others);
+int U_DPO_free(U_DPSEUDO_OBJ **dpo);
+int U_DPO_clear(U_DPSEUDO_OBJ *dpo);
+int U_PATH_moveto(U_DPSEUDO_OBJ *path, U_PMF_POINTF Point, uint8_t Flags);
+int U_PATH_lineto(U_DPSEUDO_OBJ *path, U_PMF_POINTF Point, uint8_t Flags);
+int U_PATH_closepath(U_DPSEUDO_OBJ *path);
+int U_PATH_polylineto(U_DPSEUDO_OBJ *path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg);
+int U_PATH_polybezierto(U_DPSEUDO_OBJ *path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags, uint8_t StartSeg);
+int U_PATH_polygon(U_DPSEUDO_OBJ *Path, uint32_t Elements, const U_PMF_POINTF *Points, uint8_t Flags);
+int U_PATH_arcto(U_DPSEUDO_OBJ *Path, U_FLOAT Start, U_FLOAT Sweep, U_FLOAT Rot, U_PMF_RECTF *Rect, uint8_t Flags, int StartSeg);
+U_PMF_POINTF *pointfs_transform(U_PMF_POINTF *points, int count, U_XFORM xform);
+U_PMF_RECTF *rectfs_transform(U_PMF_RECTF *rects, int count, U_XFORM xform);
+U_PMF_TRANSFORMMATRIX tm_for_gradrect(U_FLOAT Angle, U_FLOAT w, U_FLOAT h, U_FLOAT x, U_FLOAT y, U_FLOAT Periods);
+U_PSEUDO_OBJ *U_PMR_drawfill(uint32_t PathID, uint32_t PenID, const U_PSEUDO_OBJ *BrushID);
+
+
+char *U_pmr_names(unsigned int idx);
+
+/* EMF+ prototypes (objects_set) */
+
+U_PSEUDO_OBJ *U_PMF_BRUSH_set(uint32_t Version, const U_PSEUDO_OBJ *po);
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAP_set(uint32_t Version, const U_PSEUDO_OBJ *po);
+U_PSEUDO_OBJ *U_PMF_FONT_set(uint32_t Version, U_FLOAT EmSize, uint32_t SizeUnit,
+ int32_t FSFlags, uint32_t Length, const uint16_t *Font);
+U_PSEUDO_OBJ *U_PMF_IMAGE_set(uint32_t Version, const U_PSEUDO_OBJ *po);
+U_PSEUDO_OBJ *U_PMF_IMAGEATTRIBUTES_set(uint32_t Version, uint32_t WrapMode, uint32_t ClampColor, uint32_t ObjectClamp);
+U_PSEUDO_OBJ *U_PMF_PATH_set(uint32_t Version, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Types);
+U_PSEUDO_OBJ *U_PMF_PATH_set2(uint32_t Version, const U_DPSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_PATH_set3(uint32_t Version, const U_DPSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_PEN_set(uint32_t Version, const U_PSEUDO_OBJ *PenData, const U_PSEUDO_OBJ *Brush);
+U_PSEUDO_OBJ *U_PMF_REGION_set(uint32_t Version, uint32_t Count, const U_PSEUDO_OBJ *Nodes);
+U_PSEUDO_OBJ *U_PMF_STRINGFORMAT_set(U_PMF_STRINGFORMAT *Sfs, const U_PSEUDO_OBJ *Sfd);
+U_PSEUDO_OBJ *U_PMF_4NUM_set(uint32_t BrushID);
+U_PSEUDO_OBJ *U_PMF_ARGB_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue);
+U_PSEUDO_OBJ *U_PMF_ARGBN_set(uint32_t Count, U_PMF_ARGB *Colors);
+U_PMF_ARGB U_PMF_ARGBOBJ_set(uint8_t Alpha, uint8_t Red, uint8_t Green, uint8_t Blue);
+U_PSEUDO_OBJ *U_PMF_BITMAP_set(const U_PMF_BITMAP *Bs, const U_PSEUDO_OBJ *Bm);
+U_PSEUDO_OBJ *U_PMF_BITMAPDATA_set( const U_PSEUDO_OBJ *Ps, int cbBm, const char *Bm);
+U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_PSEUDO_OBJ *Colors);
+U_PSEUDO_OBJ *U_PMF_BLENDCOLORS_linear_set(uint32_t Elements,U_PMF_ARGB StartColor, U_PMF_ARGB EndColor);
+U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_set(uint32_t Elements, const U_FLOAT *Positions, const U_FLOAT *Factors);
+U_PSEUDO_OBJ *U_PMF_BLENDFACTORS_linear_set(uint32_t Elements, U_FLOAT StartFactor, U_FLOAT EndFactor);
+U_PSEUDO_OBJ *U_PMF_BOUNDARYPATHDATA_set(const U_PSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_BOUNDARYPOINTDATA_set(uint32_t Elements, const U_PMF_POINTF *Points);
+U_PSEUDO_OBJ *U_PMF_CHARACTERRANGE_set(int32_t First, int32_t Length);
+U_PSEUDO_OBJ *U_PMF_COMPOUNDLINEDATA_set(int32_t Elements, const char *Widths);
+U_PSEUDO_OBJ *U_PMF_COMPRESSEDIMAGE_set(int32_t cbImage, const char *Image);
+U_PSEUDO_OBJ *U_PMF_CUSTOMENDCAPDATA_set(const U_PSEUDO_OBJ *Clc);
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPARROWDATA_set(U_FLOAT Width, U_FLOAT Height,
+ U_FLOAT MiddleInset, uint32_t FillState, uint32_t StartCap, uint32_t EndCap, uint32_t Join,
+ U_FLOAT MiterLimit, U_FLOAT WidthScale);
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPDATA_set(uint32_t Flags, uint32_t Cap,
+ U_FLOAT Inset, uint32_t StartCap, uint32_t EndCap,
+ uint32_t Join, U_FLOAT MiterLimit, U_FLOAT WidthScale,
+ const U_PSEUDO_OBJ *Clcod);
+U_PSEUDO_OBJ *U_PMF_CUSTOMLINECAPOPTIONALDATA_set(const U_PSEUDO_OBJ *Fill, const U_PSEUDO_OBJ *Line);
+U_PSEUDO_OBJ *U_PMF_CUSTOMSTARTCAPDATA_set(const U_PSEUDO_OBJ *Clc);
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set(int32_t Elements, const U_FLOAT *Lengths);
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set2(U_FLOAT Unit, int StdPat);
+U_PSEUDO_OBJ *U_PMF_DASHEDLINEDATA_set3(U_FLOAT Unit, uint32_t BitPat);
+U_PSEUDO_OBJ *U_PMF_FILLPATHOBJ_set(const U_PSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_FOCUSSCALEDATA_set(U_FLOAT ScaleX, U_FLOAT ScaleY);
+U_PSEUDO_OBJ *U_PMF_GRAPHICSVERSION_set(int GrfVersion);
+U_PMF_GRAPHICSVERSION U_PMF_GRAPHICSVERSIONOBJ_set(int GrfVersion);
+U_PSEUDO_OBJ *U_PMF_HATCHBRUSHDATA_set(uint32_t Style, const U_PSEUDO_OBJ *Fg, const U_PSEUDO_OBJ *Bg);
+U_PSEUDO_OBJ *U_PMF_INTEGER7_set(int value);
+U_PSEUDO_OBJ *U_PMF_INTEGER15_set(int value);
+U_PMF_LANGUAGEIDENTIFIER U_PMF_LANGUAGEIDENTIFIEROBJ_set(int SubLId, int PriLId);
+U_PSEUDO_OBJ *U_PMF_LANGUAGEIDENTIFIER_set(U_PMF_LANGUAGEIDENTIFIER LId);
+U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHDATA_set(const U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const U_PSEUDO_OBJ *Lgbod);
+U_PSEUDO_OBJ *U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_set(uint32_t *Flags, const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Bc, const U_PSEUDO_OBJ *BfH, const U_PSEUDO_OBJ *BfV);
+U_PSEUDO_OBJ *U_PMF_LINEPATH_set(const U_PSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_METAFILE_set(void);
+U_PSEUDO_OBJ *U_PMF_PALETTE_set(uint32_t Flags, uint32_t Elements, const U_PMF_ARGB *Pd);
+U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHDATA_set(uint32_t Flags, int32_t WrapMode, U_PMF_ARGB CenterColor,
+ U_PMF_POINTF Center, const U_PSEUDO_OBJ *Gradient, const U_PSEUDO_OBJ *Boundary, const U_PSEUDO_OBJ *Data);
+U_PSEUDO_OBJ *U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_set(uint32_t Flags,
+ const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Pd, const U_PSEUDO_OBJ *Fsd);
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set(uint32_t Elements, const uint8_t *Ppt);
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPE_set2(uint32_t Elements, uint8_t Start, uint8_t Others);
+U_PSEUDO_OBJ *U_PMF_PATHPOINTTYPERLE_set(uint32_t Elements, const uint8_t *Bz, const uint8_t *RL, const uint8_t *Ppte);
+U_PSEUDO_OBJ *U_PMF_PENDATA_set(uint32_t Unit, U_FLOAT Width, const U_PSEUDO_OBJ *Pod);
+U_PSEUDO_OBJ *U_PMF_PENOPTIONALDATA_set(uint32_t Flags, U_PSEUDO_OBJ *Tm, int32_t StartCap, int32_t EndCap, uint32_t Join,
+ U_FLOAT MiterLimit, int32_t Style, int32_t DLCap, U_FLOAT DLOffset,
+ U_PSEUDO_OBJ *DLData, int32_t PenAlignment, U_PSEUDO_OBJ *CmpndLineData, U_PSEUDO_OBJ *CSCapData,
+ U_PSEUDO_OBJ *CECapData);
+U_PSEUDO_OBJ *U_PMF_POINT_set(uint32_t Elements, const U_PMF_POINT *Coords);
+U_PSEUDO_OBJ *U_PMF_POINTF_set(uint32_t Elements, const U_PMF_POINTF *Coords);
+U_PSEUDO_OBJ *U_PMF_POINTR_set(uint32_t Elements, const U_PMF_POINTF *Coords);
+U_PSEUDO_OBJ *U_PMF_RECT4_set(int16_t X, int16_t Y, int16_t Width, int16_t Height);
+U_PSEUDO_OBJ *U_PMF_RECT_set(U_PMF_RECT *Rect);
+U_PSEUDO_OBJ *U_PMF_RECTN_set(uint32_t Elements, U_PMF_RECT *Rects);
+U_PSEUDO_OBJ *U_PMF_RECTF4_set(U_FLOAT X, U_FLOAT Y, U_FLOAT Width, U_FLOAT Height);
+U_PSEUDO_OBJ *U_PMF_RECTF_set(U_PMF_RECTF *Rect);
+U_PSEUDO_OBJ *U_PMF_RECTFN_set(uint32_t Elements, U_PMF_RECTF *Rects);
+U_PSEUDO_OBJ *U_PMF_REGIONNODE_set(int32_t Type, const U_PSEUDO_OBJ *Rnd);
+U_PSEUDO_OBJ *U_PMF_REGIONNODECHILDNODES_set(const U_PSEUDO_OBJ *Left, const U_PSEUDO_OBJ *Right);
+U_PSEUDO_OBJ *U_PMF_REGIONNODEPATH_set(const U_PSEUDO_OBJ *Path);
+U_PSEUDO_OBJ *U_PMF_SOLIDBRUSHDATA_set(const U_PSEUDO_OBJ *Color);
+U_PSEUDO_OBJ *U_PMF_STRINGFORMATDATA_set(uint32_t TabStopCount, U_FLOAT *TabStops, const U_PSEUDO_OBJ *Ranges);
+U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHDATA_set(uint32_t Flags, uint32_t WrapMode, const U_PSEUDO_OBJ *Tbod);
+U_PSEUDO_OBJ *U_PMF_TEXTUREBRUSHOPTIONALDATA_set(const U_PSEUDO_OBJ *Tm, const U_PSEUDO_OBJ *Image);
+U_PSEUDO_OBJ *U_PMF_TRANSFORMMATRIX_set(U_PMF_TRANSFORMMATRIX *Tm);
+U_PSEUDO_OBJ *U_PMF_IE_BLUR_set(U_FLOAT Radius, uint32_t ExpandEdge);
+U_PSEUDO_OBJ *U_PMF_IE_BRIGHTNESSCONTRAST_set(int32_t Brightness, int32_t Contrast);
+U_PSEUDO_OBJ *U_PMF_IE_COLORBALANCE_set(int32_t CyanRed, int32_t MagentaGreen, int32_t YellowBlue);
+U_PSEUDO_OBJ *U_PMF_IE_COLORCURVE_set(uint32_t Adjust, uint32_t Channel, int32_t Intensity);
+U_PSEUDO_OBJ *U_PMF_IE_COLORLOOKUPTABLE_set(const uint8_t *BLUT, const uint8_t *GLUT, const uint8_t *RLUT, const uint8_t *ALUT);
+U_PSEUDO_OBJ *U_PMF_IE_COLORMATRIX_set(const U_FLOAT *Matrix);
+U_PSEUDO_OBJ *U_PMF_IE_HUESATURATIONLIGHTNESS_set(int32_t Hue, int32_t Saturation, int32_t Lightness);
+U_PSEUDO_OBJ *U_PMF_IE_LEVELS_set(int32_t Highlight, int32_t Midtone, int32_t Shadow);
+U_PSEUDO_OBJ *U_PMF_IE_REDEYECORRECTION_set(uint32_t Elements, const U_RECTL *rects);
+U_PSEUDO_OBJ *U_PMF_IE_SHARPEN_set(U_FLOAT Radius, int32_t Sharpen);
+U_PSEUDO_OBJ *U_PMF_IE_TINT_set(int32_t Hue, int32_t Amount);
+U_PSEUDO_OBJ *U_PMR_SERIALIZABLEOBJECT_set(const U_PSEUDO_OBJ *Siepb);
+
+/* EMF+ prototypes (records_set) */
+
+U_PSEUDO_OBJ *U_PMR_OFFSETCLIP_set(U_FLOAT dX, U_FLOAT dY);
+U_PSEUDO_OBJ *U_PMR_RESETCLIP_set(void);
+U_PSEUDO_OBJ *U_PMR_SETCLIPPATH_set(uint32_t PathID, uint32_t CMenum);
+U_PSEUDO_OBJ *U_PMR_SETCLIPRECT_set(uint32_t CMenum, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_SETCLIPREGION_set(uint32_t PathID, uint32_t CMenum);
+U_PSEUDO_OBJ *U_PMR_COMMENT_set(size_t cbData, const void *Data);
+U_PSEUDO_OBJ *U_PMR_ENDOFFILE_set(void);
+U_PSEUDO_OBJ *U_PMR_GETDC_set(void);
+U_PSEUDO_OBJ *U_PMR_HEADER_set(int IsDual, int IsVideo, const U_PSEUDO_OBJ *Version,
+ uint32_t LogicalDpiX, uint32_t LogicalDpiY);
+U_PSEUDO_OBJ *U_PMR_CLEAR_set(const U_PSEUDO_OBJ *Color);
+U_PSEUDO_OBJ *U_PMR_DRAWARC_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_DRAWBEZIERS_set(uint32_t PenID, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_DRAWCLOSEDCURVE_set(uint32_t PenID, U_FLOAT Tension, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension,uint32_t Offset, uint32_t NSegs, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
+ uint32_t DSOFlags, uint32_t HasMatrix, uint32_t GlyphCount,
+ const uint16_t *Glyphs, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Tm);
+U_PSEUDO_OBJ *U_PMR_DRAWELLIPSE_set(uint32_t PenID, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_DRAWIMAGE_set(uint32_t ImgID, int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect, const U_PSEUDO_OBJ *DstRect);
+U_PSEUDO_OBJ *U_PMR_DRAWIMAGEPOINTS_set(uint32_t ImgID, int etype, int32_t ImgAttrID, int32_t SrcUnit, const U_PSEUDO_OBJ *SrcRect, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_DRAWLINES_set(uint32_t PenID, int dtype, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_DRAWPATH_set(uint32_t PathID, uint32_t PenID);
+U_PSEUDO_OBJ *U_PMR_DRAWPIE_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_DRAWRECTS_set(uint32_t PenID, const U_PSEUDO_OBJ *Rects);
+U_PSEUDO_OBJ *U_PMR_DRAWSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
+ uint32_t FormatID, uint32_t Length, const U_PSEUDO_OBJ *Rect, const uint16_t *Text);
+U_PSEUDO_OBJ *U_PMR_FILLCLOSEDCURVE_set(int ftype, U_FLOAT Tension, const U_PSEUDO_OBJ * BrushID, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_FILLELLIPSE_set(const U_PSEUDO_OBJ * BrushID, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_FILLPATH_set(uint32_t PathID, const U_PSEUDO_OBJ * BrushID);
+U_PSEUDO_OBJ *U_PMR_FILLPIE_set(U_FLOAT Start, U_FLOAT Sweep, const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rect);
+U_PSEUDO_OBJ *U_PMR_FILLPOLYGON_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Points);
+U_PSEUDO_OBJ *U_PMR_FILLRECTS_set(const U_PSEUDO_OBJ *BrushID, const U_PSEUDO_OBJ *Rects);
+U_PSEUDO_OBJ *U_PMR_FILLREGION_set(uint32_t RgnID, const U_PSEUDO_OBJ *BrushID);
+U_PSEUDO_OBJ *U_PMR_OBJECT_PO_set(uint32_t ObjID, U_PSEUDO_OBJ *Po);
+U_PSEUDO_OBJ *U_PMR_OBJECT_set(uint32_t ObjID, int otype, int ntype, uint32_t TSize, size_t cbData, const char *Data);
+U_PSEUDO_OBJ *U_PMR_SETANTIALIASMODE_set(int SMenum, int aatype);
+U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGMODE_set(int CMenum);
+U_PSEUDO_OBJ *U_PMR_SETCOMPOSITINGQUALITY_set(int CQenum);
+U_PSEUDO_OBJ *U_PMR_SETINTERPOLATIONMODE_set(int IMenum);
+U_PSEUDO_OBJ *U_PMR_SETPIXELOFFSETMODE_set(int POMenum);
+U_PSEUDO_OBJ *U_PMR_SETRENDERINGORIGIN_set(int32_t X, int32_t Y);
+U_PSEUDO_OBJ *U_PMR_SETTEXTCONTRAST_set(int GC);
+U_PSEUDO_OBJ *U_PMR_SETTEXTRENDERINGHINT_set(int TRHenum);
+U_PSEUDO_OBJ *U_PMR_BEGINCONTAINER_set(int UTenum, U_PSEUDO_OBJ *DstRect, U_PSEUDO_OBJ *SrcRect, uint32_t StackID);
+U_PSEUDO_OBJ *U_PMR_BEGINCONTAINERNOPARAMS_set(int StackID);
+U_PSEUDO_OBJ *U_PMR_ENDCONTAINER_set(int StackID);
+U_PSEUDO_OBJ *U_PMR_RESTORE_set(int StackID);
+U_PSEUDO_OBJ *U_PMR_SAVE_set(int StackID);
+U_PSEUDO_OBJ *U_PMR_SETTSCLIP_set(U_PSEUDO_OBJ *Rects);
+U_PSEUDO_OBJ *U_PMR_SETTSGRAPHICS_set(int vgatype, U_PMF_SETTSGRAPHICS *Tsg, U_PSEUDO_OBJ *Palette);
+U_PSEUDO_OBJ *U_PMR_MULTIPLYWORLDTRANSFORM_set(int xmtype, U_PSEUDO_OBJ *Tm);
+U_PSEUDO_OBJ *U_PMR_RESETWORLDTRANSFORM_set(void);
+U_PSEUDO_OBJ *U_PMR_ROTATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Angle);
+U_PSEUDO_OBJ *U_PMR_SCALEWORLDTRANSFORM_set(int xmtype, U_FLOAT X, U_FLOAT Y);
+U_PSEUDO_OBJ *U_PMR_SETPAGETRANSFORM_set(int PUenum, U_FLOAT Sale);
+U_PSEUDO_OBJ *U_PMR_SETWORLDTRANSFORM_set(U_PSEUDO_OBJ *Tm);
+U_PSEUDO_OBJ *U_PMR_TRANSLATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Dx, U_FLOAT Dy);
+U_PSEUDO_OBJ *U_PMR_STROKEFILLPATH_set(void);
+
+
+
+
+/* EMF+ prototypes (objects_get) */
+
+int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit);
+int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit);
+int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit, int32_t *FSFlags, uint32_t *Length, const char **Data, const char *blimit);
+int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit);
+int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, uint32_t *ObjectClamp, const char *blimit);
+int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, const char **Points, const char **Types, const char *blimit);
+int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit);
+int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit);
+int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit);
+int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit);
+int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit);
+int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit);
+int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit);
+int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit);
+int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit);
+int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit);
+int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit);
+int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data, const char *blimit);
+int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit);
+int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit);
+int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit);
+int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit);
+int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit);
+int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit);
+int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit);
+int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value, const char *blimit);
+int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value, const char *blimit);
+int U_PMF_LANGUAGEIDENTIFIER_get(U_PMF_LANGUAGEIDENTIFIER LId, int *SubLId, int *PriLId);
+int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit);
+int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm, const char **Bc, const char **BfH, const char **BfV, const char *blimit);
+int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit);
+int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Data, const char *blimit);
+int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, const char **Boundary, const char **Data, const char *blimit);
+int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, const char **Pattern, const char **Data, const char *blimit);
+int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type, const char *blimit);
+int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit);
+int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data, const char *blimit);
+int U_PMF_PENOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix,
+ int32_t *StartCap, int32_t *EndCap, uint32_t *Join, U_FLOAT *MiterLimit, int32_t *Style, int32_t *DLCap, U_FLOAT *DLOffset,
+ const char **DLData, int32_t *Alignment, const char **CmpndLineData, const char **CSCapData, const char **CECapData, const char *blimit);
+int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit);
+int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit);
+int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit);
+int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit);
+int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit);
+int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit);
+/* There is no U_PMF_REGIONNODECHILDNODES_get, see the note in upmf.c */
+int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit);
+int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color, const char *blimit);
+int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint32_t RangeCount,
+ const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange, const char *blimit);
+int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit);
+int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, const char **Image, const char *blimit);
+int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit);
+int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit);
+int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit);
+int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit);
+int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit);
+int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents,
+ const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit);
+int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit);
+int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit);
+int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit);
+int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit);
+int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit);
+int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount, const char *blimit);
+
+/* EMF+ prototypes (records_get) */
+
+int U_PMR_OFFSETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *dX, U_FLOAT *dY);
+int U_PMR_RESETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_SETCLIPPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *CMenum);
+int U_PMR_SETCLIPRECT_get(const char *contents, U_PMF_CMN_HDR *Header, int *CMenum, U_PMF_RECTF *Rect);
+int U_PMR_SETCLIPREGION_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *CMenum);
+int U_PMR_COMMENT_get(const char *contents, U_PMF_CMN_HDR *Header, const char **Data);
+int U_PMR_ENDOFFILE_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_GETDC_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_HEADER_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_GRAPHICSVERSION *Version, int *IsDual, int *IsVideo, uint32_t *LogicalDpiX, uint32_t *LogicalDpiY);
+int U_PMR_CLEAR_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_ARGB *Color);
+int U_PMR_DRAWARC_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect);
+int U_PMR_DRAWBEZIERS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, int *RelAbs, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_DRAWCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, int *RelAbs, U_FLOAT *Tension, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_FLOAT *Tension, uint32_t *Offset, uint32_t *NSegs, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *FontID, int *btype, uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements, uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix);
+int U_PMR_DRAWELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_PMF_RECTF *Rect);
+int U_PMR_DRAWIMAGE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgID, int *ctype, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, U_PMF_RECTF *DstRect);
+int U_PMR_DRAWIMAGEPOINTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgID, int *ctype, int *etype, int *RelAbs, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_DRAWLINES_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, int *dtype, int *RelAbs, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_DRAWPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, uint32_t *PenID);
+int U_PMR_DRAWPIE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect);
+int U_PMR_DRAWRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, uint32_t *Elements, U_PMF_RECTF **Rects);
+int U_PMR_DRAWSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *FontID, int *btype, uint32_t *BrushID, uint32_t *FormatID, uint32_t *Elements, U_PMF_RECTF *Rect, uint16_t **String);
+int U_PMR_FILLCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, int *btype, int *ctype, int *ftype, int *RelAbs, uint32_t *BrushID, U_FLOAT *Tension, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_FILLELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, int *btype, int *ctype, uint32_t *BrushID, U_PMF_RECTF *Rect);
+int U_PMR_FILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *btype, uint32_t *BrushID);
+int U_PMR_FILLPIE_get(const char *contents, U_PMF_CMN_HDR *Header, int *btype, int *ctype, uint32_t *BrushID, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect);
+int U_PMR_FILLPOLYGON_get(const char *contents, U_PMF_CMN_HDR *Header, int *btype, int *ctype, int *RelAbs, uint32_t *BrushID, uint32_t *Elements, U_PMF_POINTF **Points);
+int U_PMR_FILLRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, int *btype, int *ctype, uint32_t *BrushID, uint32_t *Elements, U_PMF_RECTF **Rects);
+int U_PMR_FILLREGION_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *RgnID, int *btype, int *ctype, uint32_t *BrushID);
+int U_PMR_OBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ObjID, int *otype, int *ntype, uint32_t *TSize, const char **Data);
+int U_PMR_SERIALIZABLEOBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, uint8_t *GUID, uint32_t *Size, const char **Data);
+int U_PMR_SETANTIALIASMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *SMenum, int *aatype);
+int U_PMR_SETCOMPOSITINGMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *CMenum);
+int U_PMR_SETCOMPOSITINGQUALITY_get(const char *contents, U_PMF_CMN_HDR *Header, int *CQenum);
+int U_PMR_SETINTERPOLATIONMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *IMenum);
+int U_PMR_SETPIXELOFFSETMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *POMenum);
+int U_PMR_SETRENDERINGORIGIN_get(const char *contents, U_PMF_CMN_HDR *Header, int32_t *X, int32_t *Y);
+int U_PMR_SETTEXTCONTRAST_get(const char *contents, U_PMF_CMN_HDR *Header, int *TGC);
+int U_PMR_SETTEXTRENDERINGHINT_get(const char *contents, U_PMF_CMN_HDR *Header, int *TRHenum);
+int U_PMR_BEGINCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, int *UTenum, U_PMF_RECTF *DstRect, U_PMF_RECTF *SrcRect, uint32_t *StackID);
+int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID);
+int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID);
+int U_PMR_RESTORE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID);
+int U_PMR_SAVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID);
+int U_PMR_SETTSCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, int *ctype, uint32_t *Elements, U_PMF_RECTF **Rects);
+int U_PMR_SETTSGRAPHICS_get(const char *contents, U_PMF_CMN_HDR *Header, int *vgatype, int *pptype, uint8_t *AntiAliasMode, uint8_t *TextRenderHint, uint8_t *CompositingMode, uint8_t *CompositingQuality, int16_t *RenderOriginX, int16_t *RenderOriginY, uint16_t *TextContrast, uint8_t *FilterType, uint8_t *PixelOffset, U_PMF_TRANSFORMMATRIX *WorldToDevice, const char **Data);
+int U_PMR_MULTIPLYWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_PMF_TRANSFORMMATRIX *Matrix);
+int U_PMR_RESETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_ROTATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_FLOAT *Angle);
+int U_PMR_SCALEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_FLOAT *Sx, U_FLOAT *Sy);
+int U_PMR_SETPAGETRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *PUenum, U_FLOAT *Scale);
+int U_PMR_SETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_TRANSFORMMATRIX *Matrix);
+int U_PMR_TRANSLATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_FLOAT *Dx, U_FLOAT *Dy);
+int U_PMR_STROKEFILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_MULTIFORMATSTART_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_MULTIFORMATSECTION_get(const char *contents, U_PMF_CMN_HDR *Header);
+int U_PMR_MULTIFORMATEND_get(const char *contents, U_PMF_CMN_HDR *Header);
+//! \endcond
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UPMF_ */
diff --git a/src/3rdparty/libuemf/upmf_print.c b/src/3rdparty/libuemf/upmf_print.c
new file mode 100644
index 000000000..69fad3691
--- /dev/null
+++ b/src/3rdparty/libuemf/upmf_print.c
@@ -0,0 +1,3400 @@
+/**
+ @file upmf_print.c
+
+ @brief Functions for printing EMF records
+*/
+
+/*
+File: upmf_print.c
+Version: 0.0.8
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+/* compiler options:
+
+-DNOBRUSH causes brush objects to be treated as pen objects. PowerPoint 2003 and 2010 define pen objects
+as brush objects, and this is one way to see their structure even though they are misidentified.
+This option should only be used for tiny test files, consisting of just line objects.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h> /* for offsetof() macro */
+#include <string.h>
+#include "upmf_print.h"
+#include "uemf_print.h"
+#include "uemf_safe.h"
+
+
+//! \cond
+
+#define UNUSED(x) (void)(x) //! Please ignore - Doxygen simply insisted on including this
+
+/*
+ this function is not visible in the API. Print "data" for one of the many records that has none.
+*/
+int U_PMR_NODATAREC_print(const char *contents){
+ U_PMF_CMN_HDR Header;
+ int status = U_PMR_RESETCLIP_get(contents,&Header); /* One of many possibilities */
+ if(status)status = Header.Size;
+ return(status);
+}
+
+/*
+ this function is not visible in the API. Common routine used by many functions that draw points.
+*/
+void U_PMF_VARPOINTS_print(const char **contents, int Flags, uint32_t Elements, const char *blimit){
+ unsigned int i;
+ U_FLOAT Xpos, Ypos;
+
+ if( Flags & U_PPF_P){ printf(" + Points(Relative):"); }
+ else if(Flags & U_PPF_C){ printf(" + Points(Int16):"); }
+ else { printf(" + Points(Float):"); }
+ for(Xpos = Ypos = i = 0; i<Elements; i++){
+ printf(" %d:",i);
+ if( Flags & U_PPF_P){ (void) U_PMF_POINTR_print(contents, &Xpos, &Ypos, blimit); }
+ else if(Flags & U_PPF_C){ (void) U_PMF_POINT_print(contents, blimit); }
+ else { (void) U_PMF_POINTF_print(contents, blimit); }
+ }
+#if 0
+int residual;
+uintptr_t holdptr = (uintptr_t) *contents;
+ residual = holdptr & 0x3;
+ if(residual){ *contents += (4-residual); }
+printf("DEBUG U_PMF_VARPOINTS_print residual:%d *contents:%p\n",residual,*contents);fflush(stdout);
+#endif
+ printf("\n");
+}
+
+/*
+ this function is not visible in the API. Common routine used by many functions that draw points.
+*/
+void U_PMF_VARPOINTF_S_print(U_PMF_POINTF *Points, uint32_t Elements){
+ unsigned int i;
+ printf(" + Points:");
+ for(i=0; i<Elements; i++, Points++){
+ printf(" %d:",i);
+ (void) U_PMF_POINTF_S_print(Points);
+ }
+ printf("\n");
+}
+
+/*
+ this function is not visible in the API. Common routine used by many functions that draw rectangles.
+*/
+int U_PMF_VARRECTF_S_print(U_PMF_RECTF *Rects, uint32_t Elements){
+ if(!Elements)return(0);
+ if(Elements == 1){ printf(" Rect(Float):"); }
+ else { printf(" Rects(Float):"); }
+ while(1){
+ U_PMF_RECTF_S_print(Rects++);
+ Elements--;
+ if(!Elements)break;
+ printf(" ");
+ }
+ return(1);
+}
+
+/*
+ this function is not visible in the API. Common routine used by many functions.
+*/
+int U_PMF_VARBRUSHID_print(int btype, uint32_t BrushID){
+ if(btype){
+ printf(" Color:");
+ (void) U_PMF_ARGB_print((char *)&(BrushID));
+ }
+ else {
+ printf(" BrushID:%u",BrushID);
+ }
+ return(1);
+}
+//! \endcond
+
+/**
+ \brief Print any EMF+ record
+ \returns record length for a normal record, 0 for EMREOF or , -1 for a bad record
+ \param contents pointer to a buffer holding this EMF+ record
+ \param blimit one byte after this EMF+ record
+ \param recnum EMF number of this record in contents
+ \param off Offset from the beginning of the EMF+ file to the start of this record.
+*/
+int U_pmf_onerec_print(const char *contents, const char *blimit, int recnum, int off){
+ int status;
+ int rstatus;
+ static U_OBJ_ACCUM ObjCont={NULL,0,0,0,0}; /* for keeping track of object continuation. These may
+ be split across multiple EMF Comment records */
+ U_PMF_CMN_HDR Header;
+ const char *contemp = contents;
+
+ /* Check that COMMON header data in record can be touched without an access violation. If it cannot be
+ this is either a corrupt EMF or one engineered to cause a buffer overflow. Pointer math
+ could wrap so check both sides of the range.
+ */
+ if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CMN_HDR), blimit))return(-1);
+ if(!U_PMF_CMN_HDR_get(&contemp, &Header)){return(-1);}
+
+ int type = Header.Type & U_PMR_TYPE_MASK; /* strip the U_PMR_RECFLAG bit, leaving the indexable part */
+ if(type < U_PMR_MIN || type > U_PMR_MAX)return(-1); /* unknown EMF+ record type */
+ status = U_PMF_CMN_HDR_print(contents, Header, recnum, off); /* EMF+ part */
+
+ /* Buggy EMF+ can set the continue bit and then do something else. In that case, force out the pending
+ Object. Side effect - clears the pending object. */
+ if((type != U_PMR_OBJECT) && (ObjCont.used > 0)){
+ U_PMR_OBJECT_print(contents, blimit, &ObjCont, 1);
+ }
+
+ /* Check that the record size is OK, abort if not. */
+ if(Header.Size < sizeof(U_PMF_CMN_HDR) ||
+ IS_MEM_UNSAFE(contents, Header.Size, blimit))return(-1);
+
+ switch(type){
+ case (U_PMR_HEADER): rstatus = U_PMR_HEADER_print(contents); break;
+ case (U_PMR_ENDOFFILE): rstatus = U_PMR_ENDOFFILE_print(contents);
+ U_OA_release(&ObjCont); break;
+ case (U_PMR_COMMENT): rstatus = U_PMR_COMMENT_print(contents); break;
+ case (U_PMR_GETDC): rstatus = U_PMR_GETDC_print(contents); break;
+ case (U_PMR_MULTIFORMATSTART): rstatus = U_PMR_MULTIFORMATSTART_print(contents); break;
+ case (U_PMR_MULTIFORMATSECTION): rstatus = U_PMR_MULTIFORMATSECTION_print(contents); break;
+ case (U_PMR_MULTIFORMATEND): rstatus = U_PMR_MULTIFORMATEND_print(contents); break;
+ case (U_PMR_OBJECT): rstatus = U_PMR_OBJECT_print(contents,blimit,&ObjCont,0); break;
+ case (U_PMR_CLEAR): rstatus = U_PMR_CLEAR_print(contents); break;
+ case (U_PMR_FILLRECTS): rstatus = U_PMR_FILLRECTS_print(contents); break;
+ case (U_PMR_DRAWRECTS): rstatus = U_PMR_DRAWRECTS_print(contents); break;
+ case (U_PMR_FILLPOLYGON): rstatus = U_PMR_FILLPOLYGON_print(contents); break;
+ case (U_PMR_DRAWLINES): rstatus = U_PMR_DRAWLINES_print(contents); break;
+ case (U_PMR_FILLELLIPSE): rstatus = U_PMR_FILLELLIPSE_print(contents); break;
+ case (U_PMR_DRAWELLIPSE): rstatus = U_PMR_DRAWELLIPSE_print(contents); break;
+ case (U_PMR_FILLPIE): rstatus = U_PMR_FILLPIE_print(contents); break;
+ case (U_PMR_DRAWPIE): rstatus = U_PMR_DRAWPIE_print(contents); break;
+ case (U_PMR_DRAWARC): rstatus = U_PMR_DRAWARC_print(contents); break;
+ case (U_PMR_FILLREGION): rstatus = U_PMR_FILLREGION_print(contents); break;
+ case (U_PMR_FILLPATH): rstatus = U_PMR_FILLPATH_print(contents); break;
+ case (U_PMR_DRAWPATH): rstatus = U_PMR_DRAWPATH_print(contents); break;
+ case (U_PMR_FILLCLOSEDCURVE): rstatus = U_PMR_FILLCLOSEDCURVE_print(contents); break;
+ case (U_PMR_DRAWCLOSEDCURVE): rstatus = U_PMR_DRAWCLOSEDCURVE_print(contents); break;
+ case (U_PMR_DRAWCURVE): rstatus = U_PMR_DRAWCURVE_print(contents); break;
+ case (U_PMR_DRAWBEZIERS): rstatus = U_PMR_DRAWBEZIERS_print(contents); break;
+ case (U_PMR_DRAWIMAGE): rstatus = U_PMR_DRAWIMAGE_print(contents); break;
+ case (U_PMR_DRAWIMAGEPOINTS): rstatus = U_PMR_DRAWIMAGEPOINTS_print(contents); break;
+ case (U_PMR_DRAWSTRING): rstatus = U_PMR_DRAWSTRING_print(contents); break;
+ case (U_PMR_SETRENDERINGORIGIN): rstatus = U_PMR_SETRENDERINGORIGIN_print(contents); break;
+ case (U_PMR_SETANTIALIASMODE): rstatus = U_PMR_SETANTIALIASMODE_print(contents); break;
+ case (U_PMR_SETTEXTRENDERINGHINT): rstatus = U_PMR_SETTEXTRENDERINGHINT_print(contents); break;
+ case (U_PMR_SETTEXTCONTRAST): rstatus = U_PMR_SETTEXTCONTRAST_print(contents); break;
+ case (U_PMR_SETINTERPOLATIONMODE): rstatus = U_PMR_SETINTERPOLATIONMODE_print(contents); break;
+ case (U_PMR_SETPIXELOFFSETMODE): rstatus = U_PMR_SETPIXELOFFSETMODE_print(contents); break;
+ case (U_PMR_SETCOMPOSITINGMODE): rstatus = U_PMR_SETCOMPOSITINGMODE_print(contents); break;
+ case (U_PMR_SETCOMPOSITINGQUALITY): rstatus = U_PMR_SETCOMPOSITINGQUALITY_print(contents); break;
+ case (U_PMR_SAVE): rstatus = U_PMR_SAVE_print(contents); break;
+ case (U_PMR_RESTORE): rstatus = U_PMR_RESTORE_print(contents); break;
+ case (U_PMR_BEGINCONTAINER): rstatus = U_PMR_BEGINCONTAINER_print(contents); break;
+ case (U_PMR_BEGINCONTAINERNOPARAMS): rstatus = U_PMR_BEGINCONTAINERNOPARAMS_print(contents); break;
+ case (U_PMR_ENDCONTAINER): rstatus = U_PMR_ENDCONTAINER_print(contents); break;
+ case (U_PMR_SETWORLDTRANSFORM): rstatus = U_PMR_SETWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_RESETWORLDTRANSFORM): rstatus = U_PMR_RESETWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_MULTIPLYWORLDTRANSFORM): rstatus = U_PMR_MULTIPLYWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_TRANSLATEWORLDTRANSFORM): rstatus = U_PMR_TRANSLATEWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_SCALEWORLDTRANSFORM): rstatus = U_PMR_SCALEWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_ROTATEWORLDTRANSFORM): rstatus = U_PMR_ROTATEWORLDTRANSFORM_print(contents); break;
+ case (U_PMR_SETPAGETRANSFORM): rstatus = U_PMR_SETPAGETRANSFORM_print(contents); break;
+ case (U_PMR_RESETCLIP): rstatus = U_PMR_RESETCLIP_print(contents); break;
+ case (U_PMR_SETCLIPRECT): rstatus = U_PMR_SETCLIPRECT_print(contents); break;
+ case (U_PMR_SETCLIPPATH): rstatus = U_PMR_SETCLIPPATH_print(contents); break;
+ case (U_PMR_SETCLIPREGION): rstatus = U_PMR_SETCLIPREGION_print(contents); break;
+ case (U_PMR_OFFSETCLIP): rstatus = U_PMR_OFFSETCLIP_print(contents); break;
+ case (U_PMR_DRAWDRIVERSTRING): rstatus = U_PMR_DRAWDRIVERSTRING_print(contents); break;
+ case (U_PMR_STROKEFILLPATH): rstatus = U_PMR_STROKEFILLPATH_print(contents); break;
+ case (U_PMR_SERIALIZABLEOBJECT): rstatus = U_PMR_SERIALIZABLEOBJECT_print(contents); break;
+ case (U_PMR_SETTSGRAPHICS): rstatus = U_PMR_SETTSGRAPHICS_print(contents); break;
+ case (U_PMR_SETTSCLIP): rstatus = U_PMR_SETTSCLIP_print(contents); break;
+ }
+ if(!rstatus)status=-1;
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CMN_HDR object
+ \return number of bytes in record, 0 on error
+ \param contents pointer to a buffer holding this EMF+ record
+ \param Header Header of the record
+ \param precnum EMF+ record number in file.
+ \param off Offset in file to the start of this EMF+ record.
+ common structure present at the beginning of all(*) EMF+ records
+*/
+int U_PMF_CMN_HDR_print(const char *contents, U_PMF_CMN_HDR Header, int precnum, int off){
+ printf(" %-29srec+:%5d type:%X offset:%8d rsize:%8u dsize:%8u flags:%4.4X crc32:%8.8X\n",
+ U_pmr_names(Header.Type &U_PMR_TYPE_MASK),precnum, Header.Type,off,Header.Size,Header.DataSize,Header.Flags,
+ lu_crc32(contents,Header.Size));
+ return((int) Header.Size);
+}
+
+/**
+ \brief Print data from a an array of uint8_t values
+ \return 1
+ \param Start Text to lead array data
+ \param Array uint8_t array of data passed as char *
+ \param Elements Number of elements in Array
+ \param End Text to follow array data
+*/
+int U_PMF_UINT8_ARRAY_print(const char *Start, const uint8_t *Array, int Elements, char *End){
+ if(Start)printf("%s",Start);
+ for(; Elements--; Array++){ printf(" %u", *Array); }
+ if(End)printf("%s",End);
+ return(1);
+}
+
+/**
+ \brief Print value of an BrushType Enumeration
+ \returns record 1 on sucess, 0 on error
+ \param otype Value to print.
+ EMF+ manual 2.1.1.3, Microsoft name: BrushType Enumeration
+*/
+int U_PMF_BRUSHTYPEENUMERATION_print(int otype){
+ int status=1;
+ switch(otype){
+ case U_BT_SolidColor: printf("SolidColor"); break;
+ case U_BT_HatchFill: printf("HatchFill"); break;
+ case U_BT_TextureFill: printf("TextureFill"); break;
+ case U_BT_PathGradient: printf("PathGradient"); break;
+ case U_BT_LinearGradient: printf("LinearGradient"); break;
+ default: status=0; printf("INVALID(%d)",otype); break;
+ }
+ return(status);
+}
+
+/**
+ \brief Print value of an BrushType Enumeration
+ \returns record 1 on sucess, 0 on error
+ \param otype Value to print.
+ EMF+ manual 2.1.1.4, Microsoft name: BrushType Enumeration
+*/
+int U_PMF_COMBINEMODEENUMERATION_print(int otype){
+ int status=1;
+ switch(otype){
+ case U_CM_Replace: printf("Replace" ); break;
+ case U_CM_Intersect: printf("Intersect" ); break;
+ case U_CM_Union: printf("Union" ); break;
+ case U_CM_XOR: printf("XOR" ); break;
+ case U_CM_Exclude: printf("Exclude" ); break;
+ case U_CM_Complement: printf("Complement"); break;
+ default: status=0; printf("INVALID(%d)",otype); break;
+ }
+ return(status);
+}
+
+/**
+ \brief Print value of a HatchStyle Enumeration
+ \returns record 1 on sucess, 0 on error
+ \param hstype Value to print.
+ EMF+ manual 2.1.1.13, Microsoft name: HatchStyle Enumeration
+*/
+int U_PMF_HATCHSTYLEENUMERATION_print(int hstype){
+ int status=1;
+ switch(hstype){
+ case U_HSP_Horizontal: printf("Horizontal"); break;
+ case U_HSP_Vertical: printf("Vertical"); break;
+ case U_HSP_ForwardDiagonal: printf("ForwardDiagonal"); break;
+ case U_HSP_BackwardDiagonal: printf("BackwardDiagonal"); break;
+ case U_HSP_LargeGrid: printf("LargeGrid"); break;
+ case U_HSP_DiagonalCross: printf("DiagonalCross"); break;
+ case U_HSP_05Percent: printf("05Percent"); break;
+ case U_HSP_10Percent: printf("10Percent"); break;
+ case U_HSP_20Percent: printf("20Percent"); break;
+ case U_HSP_25Percent: printf("25Percent"); break;
+ case U_HSP_30Percent: printf("30Percent"); break;
+ case U_HSP_40Percent: printf("40Percent"); break;
+ case U_HSP_50Percent: printf("50Percent"); break;
+ case U_HSP_60Percent: printf("60Percent"); break;
+ case U_HSP_70Percent: printf("70Percent"); break;
+ case U_HSP_75Percent: printf("75Percent"); break;
+ case U_HSP_80Percent: printf("80Percent"); break;
+ case U_HSP_90Percent: printf("90Percent"); break;
+ case U_HSP_LightDownwardDiagonal: printf("LightDownwardDiagonal"); break;
+ case U_HSP_LightUpwardDiagonal: printf("LightUpwardDiagonal"); break;
+ case U_HSP_DarkDownwardDiagonal: printf("DarkDownwardDiagonal"); break;
+ case U_HSP_DarkUpwardDiagonal: printf("DarkUpwardDiagonal"); break;
+ case U_HSP_WideDownwardDiagonal: printf("WideDownwardDiagonal"); break;
+ case U_HSP_WideUpwardDiagonal: printf("WideUpwardDiagonal"); break;
+ case U_HSP_LightVertical: printf("LightVertical"); break;
+ case U_HSP_LightHorizontal: printf("LightHorizontal"); break;
+ case U_HSP_NarrowVertical: printf("NarrowVertical"); break;
+ case U_HSP_NarrowHorizontal: printf("NarrowHorizontal"); break;
+ case U_HSP_DarkVertical: printf("DarkVertical"); break;
+ case U_HSP_DarkHorizontal: printf("DarkHorizontal"); break;
+ case U_HSP_DashedDownwardDiagonal: printf("DashedDownwardDiagonal"); break;
+ case U_HSP_DashedUpwardDiagonal: printf("DashedUpwardDiagonal"); break;
+ case U_HSP_DashedHorizontal: printf("DashedHorizontal"); break;
+ case U_HSP_DashedVertical: printf("DashedVertical"); break;
+ case U_HSP_SmallConfetti: printf("SmallConfetti"); break;
+ case U_HSP_LargeConfetti: printf("LargeConfetti"); break;
+ case U_HSP_ZigZag: printf("ZigZag"); break;
+ case U_HSP_Wave: printf("Wave"); break;
+ case U_HSP_DiagonalBrick: printf("DiagonalBrick"); break;
+ case U_HSP_HorizontalBrick: printf("HorizontalBrick"); break;
+ case U_HSP_Weave: printf("Weave"); break;
+ case U_HSP_Plaid: printf("Plaid"); break;
+ case U_HSP_Divot: printf("Divot"); break;
+ case U_HSP_DottedGrid: printf("DottedGrid"); break;
+ case U_HSP_DottedDiamond: printf("DottedDiamond"); break;
+ case U_HSP_Shingle: printf("Shingle"); break;
+ case U_HSP_Trellis: printf("Trellis"); break;
+ case U_HSP_Sphere: printf("Sphere"); break;
+ case U_HSP_SmallGrid: printf("SmallGrid"); break;
+ case U_HSP_SmallCheckerBoard: printf("SmallCheckerBoard"); break;
+ case U_HSP_LargeCheckerBoard: printf("LargeCheckerBoard"); break;
+ case U_HSP_OutlinedDiamond: printf("OutlinedDiamond"); break;
+ case U_HSP_SolidDiamond: printf("SolidDiamond"); break;
+ default: status=0; printf("INVALID(%d)",hstype); break;
+ }
+ return(status);
+}
+
+/**
+ \brief Print value of an ObjectType Enumeration
+ \returns record 1 on sucess, 0 on error
+ \param otype Value to print.
+ EMF+ manual 2.1.1.22, Microsoft name: ObjectType Enumeration
+*/
+int U_PMF_OBJECTTYPEENUMERATION_print(int otype){
+ int status=1;
+ switch(otype){
+ case U_OT_Invalid: printf("Invalid"); break;
+ case U_OT_Brush: printf("Brush"); break;
+ case U_OT_Pen: printf("Pen"); break;
+ case U_OT_Path: printf("Path"); break;
+ case U_OT_Region: printf("Region"); break;
+ case U_OT_Image: printf("Image"); break;
+ case U_OT_Font: printf("Font"); break;
+ case U_OT_StringFormat: printf("StringFormat"); break;
+ case U_OT_ImageAttributes: printf("ImageAttributes"); break;
+ case U_OT_CustomLineCap: printf("CustomLineCap"); break;
+ default:
+ status=0; printf("INVALID(%d)",otype); break;
+ }
+ return(status);
+}
+
+/**
+ \brief Print value of a U_PMF_PATHPOINTTYPE_ENUM object
+ \return 1
+ \param Type Value to print
+ EMF+ manual 2.1.1.23, Microsoft name: PathPointType Enumeration
+*/
+int U_PMF_PATHPOINTTYPE_ENUM_print(int Type){
+ switch(Type & U_PPT_MASK){
+ case U_PPT_Start : printf("Start"); break;
+ case U_PPT_Line : printf("Line"); break;
+ case U_PPT_Bezier: printf("Bezier"); break;
+ default: printf("INVALID(%d)",Type); break;
+ }
+ return(1);
+}
+
+/**
+ \brief Print data from a PixelFormat Enumeration value
+ \return 1 always
+ \param pfe A PixelFormat Enumeration value
+ EMF+ manual 2.1.1.25, Microsoft name: PixelFormat Enumeration (U_PF_*)
+*/
+int U_PMF_PX_FMT_ENUM_print(int pfe){
+ uint8_t idx;
+ printf(" + PxFmtEnum: ");
+ printf(" 32Bit:%c", (pfe & 1<< 9 ? 'Y' : 'N'));
+ printf(" 16Bit:%c", (pfe & 1<<10 ? 'Y' : 'N'));
+ printf(" PreAlpha:%c", (pfe & 1<<11 ? 'Y' : 'N'));
+ printf(" Alpha:%c", (pfe & 1<<12 ? 'Y' : 'N'));
+ printf(" GDI:%c", (pfe & 1<<13 ? 'Y' : 'N'));
+ printf(" LUT:%c", (pfe & 1<<14 ? 'Y' : 'N'));
+ printf(" BitsPerPx:%u", (pfe >> 16) & 0xFF);
+ idx = pfe >> 24;
+ printf(" Type:%u(",idx);
+ switch(idx){
+ case 0: printf("undefined"); break;
+ case 1: printf("monochrome with LUT"); break;
+ case 2: printf("4 bit with LUT"); break;
+ case 3: printf("8 bit with LUT"); break;
+ case 4: printf("16 bits grey values"); break;
+ case 5: printf("16 bit RGB values (5,5,5,(1 ignored))"); break;
+ case 6: printf("16 bit RGB values (5,6,5)"); break;
+ case 7: printf("16 bit ARGB values (1 alpha, 5,5,5 colors)"); break;
+ case 8: printf("24 bit RGB values (8,8.8)"); break;
+ case 9: printf("32 bit RGB value (8,8,8,(8 ignored))"); break;
+ case 10: printf("32 bit ARGB values (8 alpha,8,8,8)"); break;
+ case 11: printf("32 bit PARGB values (8,8,8,8, but RGB already multiplied by A)"); break;
+ case 12: printf("48 bit RGB (16,16,16)"); break;
+ case 13: printf("64 bit ARGB (16 alpha, 16,16,16)"); break;
+ case 14: printf("64 bit PARGB (16,16,16,16, but RGB already multiplied by A)"); break;
+ default: printf("INVALID(%d)",idx); break;
+ }
+ printf(")");
+ return(1);
+}
+
+/**
+ \brief Print as text a RegionNodeDataType Enumeration
+ \return 1
+ \param Type RegionNodeDataType Enumeration
+ EMF+ manual 2.1.1.27, Microsoft name: RegionNodeDataType Enumeration (U_RNDT_*)
+*/
+int U_PMF_NODETYPE_print(int Type){
+ if( Type == U_RNDT_And ){ printf("And" ); }
+ else if(Type == U_RNDT_Or ){ printf("Or" ); }
+ else if(Type == U_RNDT_Xor ){ printf("Xor" ); }
+ else if(Type == U_RNDT_Exclude ){ printf("Exclude" ); }
+ else if(Type == U_RNDT_Complement){ printf("Complement"); }
+ else if(Type == U_RNDT_Rect ){ printf("Rect" ); }
+ else if(Type == U_RNDT_Path ){ printf("Path" ); }
+ else if(Type == U_RNDT_Empty ){ printf("Empty" ); }
+ else if(Type == U_RNDT_Infinite ){ printf("Infinite" ); }
+ else { printf("Undefined" ); return(0); }
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_BRUSH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object
+*/
+int U_PMF_BRUSH_print(const char *contents, const char *blimit){
+ uint32_t Version, Type;
+ const char *Data;
+ int status = U_PMF_BRUSH_get(contents, &Version, &Type, &Data, blimit);
+ if(status){
+ printf(" + Brush:");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" Type:%X(",Type);
+ (void) U_PMF_BRUSHTYPEENUMERATION_print(Type);
+ printf(")");
+ switch(Type){
+ case U_BT_SolidColor:
+ status = U_PMF_ARGB_print(Data);
+ break;
+ case U_BT_HatchFill:
+ printf("\n");
+ status = U_PMF_HATCHBRUSHDATA_print(Data, blimit);
+ break;
+ case U_BT_TextureFill:
+ printf("\n");
+ status = U_PMF_TEXTUREBRUSHDATA_print(Data, blimit);
+ break;
+ case U_BT_PathGradient:
+ printf("\n");
+ status = U_PMF_PATHGRADIENTBRUSHDATA_print(Data, blimit);
+ break;
+ case U_BT_LinearGradient:
+ printf("\n");
+ status = U_PMF_LINEARGRADIENTBRUSHDATA_print(Data, blimit);
+ break;
+ default:
+ status = 0;
+ }
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CUSTOMLINECAP object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param Which A string which is either "Start" or "End".
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object
+*/
+int U_PMF_CUSTOMLINECAP_print(const char *contents, const char *Which, const char *blimit){
+ uint32_t Version, Type;
+ const char *Data;
+ int status = U_PMF_CUSTOMLINECAP_get(contents, &Version, &Type, &Data, blimit);
+
+ if(status){
+ printf(" + %sLineCap:",Which);
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(", Type %X\n",Type);
+ switch(Type){
+ case U_CLCDT_Default:
+ status = U_PMF_CUSTOMLINECAPDATA_print(Data, blimit);
+ break;
+ case U_CLCDT_AdjustableArrow:
+ status = U_PMF_CUSTOMLINECAPARROWDATA_print(Data, blimit);
+ break;
+ default:
+ status = 0;
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_FONT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object
+*/
+int U_PMF_FONT_print(const char *contents, const char *blimit){
+ uint32_t Version, SizeUnit, Length;
+ U_FLOAT EmSize;
+ int32_t FSFlags;
+ const char *Data;
+ char *string;
+ int status = U_PMF_FONT_get(contents, &Version, &EmSize, &SizeUnit, &FSFlags, &Length, &Data, blimit);
+ if(status){
+ printf(" + Font:");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" EmSize:%f ", EmSize );
+ printf(" SizeUnit:%d ",SizeUnit);
+ printf(" FSFlags:%d ", FSFlags );
+ printf(" Length:%d", Length );
+ string = U_Utf16leToUtf8((uint16_t *)Data, Length, NULL);
+ if(string){
+ printf(" Family:<%s>\n",string);
+ free(string);
+ }
+ else {
+ printf(" Family:<>\n");
+ }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_IMAGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object
+*/
+int U_PMF_IMAGE_print(const char *contents, const char *blimit){
+ uint32_t Version, Type;
+ const char *Data;
+ int status = U_PMF_IMAGE_get(contents, &Version, &Type, &Data, blimit);
+ if(status){
+ printf(" + Image:");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" Type:%X\n",Type);
+ switch(Type){
+ case U_IDT_Unknown:
+ printf(" + Unknown Image Type\n");
+ break;
+ case U_IDT_Bitmap:
+ status = U_PMF_BITMAP_print(Data, blimit);
+ break;
+ case U_IDT_Metafile:
+ status = U_PMF_METAFILE_print(Data, blimit);
+ break;
+ default:
+ status = 0;
+ }
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_IMAGEATTRIBUTES object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object
+*/
+int U_PMF_IMAGEATTRIBUTES_print(const char *contents, const char *blimit){
+ uint32_t Version, WrapMode, ClampColor, ObjectClamp;
+ int status = U_PMF_IMAGEATTRIBUTES_get(contents, &Version, &WrapMode, &ClampColor, &ObjectClamp, blimit);
+
+ if(status){
+ printf(" + Image Attributes: ");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" WrapMode:%X", WrapMode);
+ printf(" ClampColor:%X", ClampColor);
+ printf(" ObjectClamp:%X\n", ObjectClamp);
+ }
+ return(status);
+}
+
+
+
+/**
+ \brief Print data from a U_PMF_PATH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object
+*/
+int U_PMF_PATH_print(const char *contents, const char *blimit){
+ unsigned int i, pos;
+ uint32_t Version, Count;
+ uint16_t Flags;
+ const char *Points;
+ const char *Types;
+ int status = U_PMF_PATH_get(contents, &Version, &Count, &Flags, &Points, &Types, blimit);
+ if(status){
+ printf(" + Path: Version:%X Count:%d Flags:%X\n",Version, Count, Flags);
+
+ /* Points part */
+ U_PMF_VARPOINTS_print(&Points, Flags, Count, blimit);
+
+ /* Types part */
+ printf(" + Types:");
+ pos = 0;
+ for(i=0; i<Count; i++){
+ /* EMF+ manual says that the first of these two cases can actually contain either type
+ of PATHPOINT, but it does not say how the program is supposed to figure out which record
+ is which type. */
+ if(Flags & U_PPF_R){
+ printf(" %u:",pos);
+ pos += U_PMF_PATHPOINTTYPERLE_print(Types, blimit);
+ Types+=2;
+ }
+ else {
+ printf(" %d:",i);
+ (void) U_PMF_PATHPOINTTYPE_print(Types, blimit);
+ Types++;
+ }
+ }
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PEN object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object
+*/
+int U_PMF_PEN_print(const char *contents, const char *blimit){
+ uint32_t Version, Type;
+ const char *PenData;
+ const char *Brush;
+ int status = U_PMF_PEN_get(contents, &Version, &Type, &PenData, &Brush, blimit);
+ if(status){
+ printf(" + Pen: Version:%X Type:%d\n",Version,Type);
+ (void) U_PMF_PENDATA_print(PenData, blimit);
+ (void) U_PMF_BRUSH_print(Brush, blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_REGION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object
+*/
+int U_PMF_REGION_print(const char *contents, const char *blimit){
+ uint32_t Version, Count;
+ const char *Nodes;
+ int status = U_PMF_REGION_get(contents, &Version, &Count, &Nodes, blimit);
+ if(status){
+ printf(" + ");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" ChildNodes:%d",Count);
+ (void) U_PMF_REGIONNODE_print(Nodes, 1, blimit); /* 1 == top level*/
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_STRINGFORMAT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object
+*/
+int U_PMF_STRINGFORMAT_print(const char *contents, const char *blimit){
+ U_PMF_STRINGFORMAT Sfs;
+ const char *Data;
+ int status = U_PMF_STRINGFORMAT_get(contents, &Sfs, &Data, blimit);
+ if(status){
+ printf(" + StringFormat: ");
+ printf(" Version:%X", Sfs.Version );
+ printf(" Flags:%X", Sfs.Flags );
+ printf(" Language"); (void) U_PMF_LANGUAGEIDENTIFIER_print(Sfs.Language);
+ printf(" StringAlignment:%X", Sfs.StringAlignment );
+ printf(" LineAlign:%X", Sfs.LineAlign );
+ printf(" DigitSubstitution:%X",Sfs.DigitSubstitution);
+ printf(" DigitLanguage"); (void) U_PMF_LANGUAGEIDENTIFIER_print(Sfs.DigitLanguage);
+ printf(" FirstTabOffset:%f", Sfs.FirstTabOffset );
+ printf(" HotkeyPrefix:%d", Sfs.HotkeyPrefix );
+ printf(" LeadingMargin:%f", Sfs.LeadingMargin );
+ printf(" TrailingMargin:%f", Sfs.TrailingMargin );
+ printf(" Tracking:%f", Sfs.Tracking );
+ printf(" Trimming:%X", Sfs.Trimming );
+ printf(" TabStopCount:%u", Sfs.TabStopCount );
+ printf(" RangeCount:%u", Sfs.RangeCount );
+ (void) U_PMF_STRINGFORMATDATA_print(Data, Sfs.TabStopCount, Sfs.RangeCount, blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_ARGB object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+
+ Does not accept a blimit value.
+ EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object
+*/
+int U_PMF_ARGB_print(const char *contents){
+ uint8_t Blue, Green, Red, Alpha;
+ int status = U_PMF_ARGB_get(contents, &Blue, &Green, &Red, &Alpha, contents + sizeof(U_RGBQUAD));
+ if(status){
+ printf(" RGBA{%2.2X,%2.2X,%2.2X,%2.2X}", Red, Green, Blue, Alpha);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_BITMAP object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object
+*/
+int U_PMF_BITMAP_print(const char *contents, const char *blimit){
+ U_PMF_BITMAP Bs;
+ const char *Data;
+ int status = U_PMF_BITMAP_get(contents, &Bs, &Data, blimit);
+ if(status){
+ printf(" + Bitmap: Width:%d Height:%d Stride:%d\n",Bs.Width, Bs.Height, Bs.Stride);
+ U_PMF_PX_FMT_ENUM_print(Bs.PxFormat);
+ switch(Bs.Type){
+ case 0: printf(" Type:MSBitmap\n"); break;
+ case 1: printf(" Type:(PNG|JPG|GIF|EXIF|TIFF)\n"); break;
+ default: printf(" Type:INVALID(%d)\n",Bs.Type); break;
+ }
+ /* Pixel data is never shown - it could easily swamp the output for even a smallish picture */
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_BITMAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object
+*/
+int U_PMF_BITMAPDATA_print(const char *contents, const char *blimit){
+ unsigned int i;
+ U_PMF_PALETTE Ps;
+ const char *Colors;
+ const char *Data;
+ int status = U_PMF_BITMAPDATA_get(contents, &Ps, &Colors, &Data, blimit);
+ if(status){
+ status = 0;
+ printf(" BMData: Flags:%X, Elements:%u Colors:", Ps.Flags, Ps.Elements);
+ for(i=0; i<Ps.Elements; i++, Colors+=sizeof(U_PMF_ARGB)){
+ (void) U_PMF_ARGB_print(Colors);
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_BLENDCOLORS object
+ \return size in bytes on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object
+*/
+int U_PMF_BLENDCOLORS_print(const char *contents, const char *blimit){
+ unsigned int i;
+ uint32_t Elements;
+ U_FLOAT *Positions;
+ const char *Colors;
+ int status = U_PMF_BLENDCOLORS_get(contents, &Elements, &Positions, &Colors, blimit);
+ if(status){
+ printf(" + BlendColors: Entries:%d (entry,pos,color): ", Elements);
+ for(i=0; i<Elements; i++){
+ printf(" (%d,%f,", i, Positions[i]);
+ (void) U_PMF_ARGB_print(Colors);
+ Colors += sizeof(U_PMF_ARGB);
+ printf(")");
+ }
+ status = sizeof(uint32_t) + Elements*sizeof(U_FLOAT) + Elements*sizeof(U_PMF_ARGB);
+ free(Positions);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_BLENDFACTORS object
+ \return size on success, 0 on error
+ \param type Type of BlendFactors, usually H or V
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object
+*/
+int U_PMF_BLENDFACTORS_print(const char *contents, const char *type, const char *blimit){
+ unsigned int i;
+ uint32_t Elements;
+ U_FLOAT *Positions;
+ U_FLOAT *Factors;
+ int status = U_PMF_BLENDFACTORS_get(contents, &Elements, &Positions, &Factors, blimit);
+ if(status){
+ printf(" + BlendFactors%s: Entries:%d (entry,pos,factor): ",type, Elements);
+ for(i=0; i<Elements; i++){
+ printf(" (%d,%f,%f)", i, Positions[i],Factors[i]);
+ }
+ status = sizeof(uint32_t) + Elements*2*sizeof(U_FLOAT);
+ free(Positions);
+ free(Factors);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_BOUNDARYPATHDATA object
+ \return size on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object
+*/
+int U_PMF_BOUNDARYPATHDATA_print(const char *contents, const char * blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_BOUNDARYPATHDATA_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" + BoundaryPathData: Size:%d\n",Size);
+ (void) U_PMF_PATH_print(Data, blimit);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_BOUNDARYPOINTDATA object
+ \return size on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object
+*/
+int U_PMF_BOUNDARYPOINTDATA_print(const char *contents, const char *blimit){
+ int32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMF_BOUNDARYPOINTDATA_get(contents, &Elements, &Points, blimit);
+ if(status){
+ printf(" + BoundaryPointData: Elements:%u\n",Elements);
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CHARACTERRANGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object
+*/
+int U_PMF_CHARACTERRANGE_print(const char *contents, const char *blimit){
+ int32_t First, Length;
+ int status = U_PMF_CHARACTERRANGE_get(contents, &First, &Length, blimit);
+ if(status){
+ printf(" {%d,%d}",First,Length);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_DASHEDLINEDATA object
+ \return 1 on success, 0 on error
+ \param blimit one byte past the end of data
+ \param contents Record from which to print data
+ EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object
+*/
+int U_PMF_COMPOUNDLINEDATA_print(const char *contents, const char *blimit){
+ int32_t Elements;
+ U_FLOAT *Widths;
+ U_FLOAT *hold;
+ int status = U_PMF_COMPOUNDLINEDATA_get(contents, &Elements, &Widths, blimit);
+ if(status){
+ printf(" + CompoundLineData: Elements:%u {",Elements);
+ Elements--;
+ for(hold=Widths; Elements; Elements--,Widths++){ printf("%f, ",*Widths); }
+ printf("%f}",*Widths);
+ free(hold);
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_COMPRESSEDIMAGE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.10, Microsoft name: EmfPlusCompressedImage Object
+
+ This function does not do anything useful, but it is included so that all objects have a corresponding _get().
+*/
+int U_PMF_COMPRESSEDIMAGE_print(const char *contents, const char *blimit){
+ const char *Data;
+ int status = U_PMF_COMPRESSEDIMAGE_get(contents, &Data, blimit);
+ if(status){
+ printf("CompressedImage:\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CUSTOMENDCAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object
+*/
+int U_PMF_CUSTOMENDCAPDATA_print(const char *contents, const char *blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_CUSTOMENDCAPDATA_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" + CustomEndCap: Size:%d\n",Size);
+ (void) U_PMF_CUSTOMLINECAP_print(Data, "End", blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CUSTOMLINECAPARROWDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object
+*/
+int U_PMF_CUSTOMLINECAPARROWDATA_print(const char *contents, const char *blimit){
+ U_PMF_CUSTOMLINECAPARROWDATA Ccad;
+ int status = U_PMF_CUSTOMLINECAPARROWDATA_get(contents, &Ccad, blimit);
+ if(status){
+ printf("CustomLineCapArrowData: ");
+ printf(" Width:%f", Ccad.Width );
+ printf(" Height:%f", Ccad.Height );
+ printf(" MiddleInset:%f", Ccad.MiddleInset );
+ printf(" FillState:%u", Ccad.FillState );
+ printf(" StartCap:%X", Ccad.StartCap );
+ printf(" EndCap:%X", Ccad.EndCap );
+ printf(" Join:%X", Ccad.Join );
+ printf(" MiterLimit:%f", Ccad.MiterLimit );
+ printf(" WidthScale:%f", Ccad.WidthScale );
+ printf(" FillHotSpot:{%f,%f}",Ccad.FillHotSpot[0],Ccad.FillHotSpot[1]);
+ printf(" LineHotSpot:{%f,%f}",Ccad.LineHotSpot[0],Ccad.LineHotSpot[1]);
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CUSTOMLINECAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object
+*/
+int U_PMF_CUSTOMLINECAPDATA_print(const char *contents, const char *blimit){
+ U_PMF_CUSTOMLINECAPDATA Clcd;
+ const char *Data;
+ int status = U_PMF_CUSTOMLINECAPDATA_get(contents, &Clcd, &Data, blimit);
+ if(status){
+ printf(" + CustomLineCapData: ");
+ printf(" Flags:%X", Clcd.Flags );
+ printf(" Cap:%X", Clcd.Cap );
+ printf(" Inset:%f", Clcd.Inset );
+ printf(" StartCap:%X", Clcd.StartCap );
+ printf(" EndCap:%X", Clcd.EndCap );
+ printf(" Join:%X", Clcd.Join );
+ printf(" MiterLimit:%f", Clcd.MiterLimit );
+ printf(" WidthScale:%f", Clcd.WidthScale );
+ printf(" FillHotSpot:{%f,%f}",Clcd.FillHotSpot[0],Clcd.FillHotSpot[1]);
+ printf(" LineHotSpot:{%f,%f}\n",Clcd.LineHotSpot[0],Clcd.LineHotSpot[1]);
+ (void) U_PMF_CUSTOMLINECAPOPTIONALDATA_print(Data, Clcd.Flags, blimit);
+ /* preceding line always emits an EOL */
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_CUSTOMLINECAPOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param Flags CustomLineCapData Flags
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object
+*/
+int U_PMF_CUSTOMLINECAPOPTIONALDATA_print(const char *contents, uint32_t Flags, const char *blimit){
+ const char *FillData;
+ const char *LineData;
+ int status = U_PMF_CUSTOMLINECAPOPTIONALDATA_get(contents, Flags, &FillData, &LineData, blimit);
+ if(status){ /* True even if there is nothing in it! */
+ printf(" + CustomLineCapOptionalData:");
+ if(FillData || LineData){
+ if(FillData){ (void) U_PMF_FILLPATHOBJ_print(FillData, blimit); }
+ if(LineData){ (void) U_PMF_LINEPATH_print(LineData, blimit); }
+ }
+ else {
+ printf("None");
+ }
+ }
+ if(status<=1){ printf("\n"); }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_CUSTOMSTARTCAPDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object
+*/
+int U_PMF_CUSTOMSTARTCAPDATA_print(const char *contents, const char *blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_CUSTOMSTARTCAPDATA_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" + CustomStartCap: Size:%d ",Size);
+ (void) U_PMF_CUSTOMLINECAP_print(Data, "Start", blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_DASHEDLINEDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object
+*/
+int U_PMF_DASHEDLINEDATA_print(const char *contents, const char *blimit){
+ int32_t Elements;
+ U_FLOAT *Lengths;
+ U_FLOAT *hold;
+ int status = U_PMF_DASHEDLINEDATA_get(contents, &Elements, &Lengths, blimit);
+ if(status){
+ printf(" DashedLineData: Elements:%u {",Elements);
+ Elements--;
+ for(hold=Lengths; Elements; Elements--, Lengths++){ printf("%f, ", *Lengths); }
+ printf("%f}", *Lengths);
+ free(hold);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_FILLPATHOBJ object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object
+*/
+int U_PMF_FILLPATHOBJ_print(const char *contents, const char * blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_FILLPATHOBJ_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" FillPathObj: Size:%d\n",Size);
+ if(Size){ (void) U_PMF_PATH_print(Data, blimit); }
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_FOCUSSCALEDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object
+*/
+int U_PMF_FOCUSSCALEDATA_print(const char *contents, const char *blimit){
+ uint32_t Count;
+ U_FLOAT ScaleX, ScaleY;
+ int status = U_PMF_FOCUSSCALEDATA_get(contents, &Count, &ScaleX, &ScaleY, blimit);
+ if(status){
+ printf(" FocusScaleData: Count:%d ScaleX:%f ScaleY:%f ",Count,ScaleX,ScaleY);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_GRAPHICSVERSION object already known to be memory safe
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+
+ In this module the only time a U_PMF_GRAPHICSVERSION is printed is after it
+ has already been copied into a safe memory structure. This routine fakes up
+ a blimit for the general routine.
+
+*/
+int U_PMF_GRAPHICSVERSION_memsafe_print(const char *contents){
+ const char *blimit = contents + sizeof(U_PMF_GRAPHICSVERSION);
+ return(U_PMF_GRAPHICSVERSION_print(contents, blimit));
+}
+
+/**
+ \brief Print data from a U_PMF_GRAPHICSVERSION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object
+*/
+int U_PMF_GRAPHICSVERSION_print(const char *contents, const char *blimit){
+ int Signature,GrfVersion;
+ int status = U_PMF_GRAPHICSVERSION_get(contents, &Signature, &GrfVersion, blimit);
+ if(status){
+ printf(" MetaFileSig:%X",Signature );
+ printf(" GraphicsVersion:%X", GrfVersion);
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_HATCHBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit One byte past the last record in memory.
+ EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object
+*/
+int U_PMF_HATCHBRUSHDATA_print(const char *contents, const char *blimit){
+ uint32_t Style;
+ U_PMF_ARGB Foreground, Background;
+ int status = U_PMF_HATCHBRUSHDATA_get(contents, &Style, &Foreground, &Background, blimit);
+ if(status){
+ printf(" + HBdata: Style:%u(",Style);
+ U_PMF_HATCHSTYLEENUMERATION_print(Style);
+ printf(") FG:{");
+ (void) U_PMF_ARGB_print((char *)&Foreground);
+ printf("} BG:{");
+ (void) U_PMF_ARGB_print((char *)&Background);
+ printf("}");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_LANGUAGEIDENTIFIER object
+ \return 1 on success, 0 on error
+ \param LId Record from which to print data
+ EMF+ manual 2.2.2.23, Microsoft name: EmfPlusLanguageIdentifier Object
+*/
+int U_PMF_LANGUAGEIDENTIFIER_print(U_PMF_LANGUAGEIDENTIFIER LId){
+ int SubLId, PriLId;
+ int status = U_PMF_LANGUAGEIDENTIFIER_get(LId, &SubLId, &PriLId);
+ if(status){ /* do it the hard way just to verify that the preceding call works, OK to just print LId directly */
+ printf("{%4.4X}",U_PMF_LANGUAGEIDENTIFIEROBJ_set(SubLId, PriLId));
+ }
+ return(status);
+}
+
+
+
+/**
+ \brief Print data from a U_PMF_LINEARGRADIENTBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit One byte past the last record in memory.
+ EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object
+*/
+int U_PMF_LINEARGRADIENTBRUSHDATA_print(const char *contents, const char *blimit){
+ U_PMF_LINEARGRADIENTBRUSHDATA Lgbd;
+ const char *Data;
+ int status = U_PMF_LINEARGRADIENTBRUSHDATA_get(contents, &Lgbd, &Data, blimit);
+ if(status){
+ printf(" + LinearGradientBrushData: Flags:%X WrapMode:%d Rect:",Lgbd.Flags, Lgbd.WrapMode);
+ (void) U_PMF_RECTF_S_print(&(Lgbd.RectF));
+ printf(" StartColor:");
+ (void) U_PMF_ARGB_print((char *)&(Lgbd.StartColor));
+ printf(" EndColor:");
+ (void) U_PMF_ARGB_print((char *)&(Lgbd.EndColor));
+ /* Technically these are to be ignored, in practice they must be colors with the same value as the preceding 2*/
+ printf(" Reserved1:");
+ (void) U_PMF_ARGB_print((char *)&(Lgbd.Reserved1));
+ printf(" Reserved2:");
+ (void) U_PMF_ARGB_print((char *)&(Lgbd.Reserved2));
+ printf("\n");
+ (void) U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_print(Data, Lgbd.Flags, blimit);
+ }
+ return(status);
+}
+
+
+
+/**
+ \brief Print data from a U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param BDFlag Describes optional values in contents
+ \param blimit One byte past the last record in memory.
+ EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object
+*/
+int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit){
+ U_PMF_TRANSFORMMATRIX Tm;
+ const char *Bc;
+ const char *BfH;
+ const char *BfV;
+ int None=1;
+ printf(" + LinearGradientBrushOptionalData: ");
+ int status = U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(contents, BDFlag, &Tm, &Bc, &BfH, &BfV, blimit);
+ if(status){
+ if(BDFlag & U_BD_Transform){
+ U_PMF_TRANSFORMMATRIX2_print(&Tm);
+ None=0;
+ }
+ if(Bc){
+ printf("\n");
+ (void) U_PMF_BLENDCOLORS_print(Bc, blimit);
+ None=0;
+ }
+ if(BfH){
+ printf("\n");
+ (void) U_PMF_BLENDFACTORS_print(BfH,"H", blimit);
+ None=0;
+ }
+ if(BfV){
+ printf("\n");
+ (void) U_PMF_BLENDFACTORS_print(BfV,"V", blimit);
+ None=0;
+ }
+ if(None){
+ printf("(none)");
+ }
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_LINEPATH object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object
+*/
+int U_PMF_LINEPATH_print(const char *contents, const char * blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_LINEPATH_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" LinePath: Size:%d\n", Size);
+ (void) U_PMF_PATH_print(Data, blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_METAFILE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object
+*/
+int U_PMF_METAFILE_print(const char *contents, const char * blimit){
+ uint32_t Type;
+ uint32_t Size;
+ const char *Data;
+ int status = U_PMF_METAFILE_get(contents, &Type, &Size, &Data, blimit);
+ if(status){
+ printf(" MetaFile: Type:%X Size:%d",Type, Size);
+ /* embedded metafiles are not handled beyond this*/
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PALETTE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object
+*/
+int U_PMF_PALETTE_print(const char *contents, const char *blimit){
+ unsigned int i;
+ uint32_t Flags;
+ uint32_t Elements;
+ const char *Data;
+ int status = U_PMF_PALETTE_get(contents, &Flags, &Elements, &Data, blimit);
+ if(status){
+ printf(" Palette: Flags:%X Elements:%u Colors:",Flags, Elements);
+ for(i=0; i<Elements; i++){
+ (void) U_PMF_ARGB_print(Data);
+ Data += sizeof(U_PMF_ARGB);
+ }
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PATHGRADIENTBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object
+*/
+int U_PMF_PATHGRADIENTBRUSHDATA_print(const char *contents, const char *blimit){
+ U_PMF_PATHGRADIENTBRUSHDATA Pgbd;
+ const char *Gradient;
+ const char *Boundary;
+ const char *Data=NULL;
+ unsigned int i;
+ int status = U_PMF_PATHGRADIENTBRUSHDATA_get(contents, &Pgbd, &Gradient, &Boundary, &Data, blimit);
+ if(status){
+ printf(" + PathGradientBrushData: Flags:%X WrapMode:%d, CenterColor:",Pgbd.Flags, Pgbd.WrapMode);
+ (void) U_PMF_ARGB_print((char *)&(Pgbd.CenterColor));
+ printf(" Center:");
+ (void) U_PMF_POINTF_S_print(&(Pgbd.Center));
+ printf(" Elements:%u\n",Pgbd.Elements);
+ if(Pgbd.Elements){
+ printf(" + SurroundingColor: ");
+ for(i=Pgbd.Elements; i; i--, Gradient+=4){
+ (void) U_PMF_ARGB_print(Gradient);
+ }
+ printf("\n");
+ }
+ if(Pgbd.Flags & U_BD_Path){
+ (void) U_PMF_BOUNDARYPATHDATA_print(Boundary, blimit);
+ }
+ else {
+ (void) U_PMF_BOUNDARYPOINTDATA_print(Boundary, blimit);
+ }
+ (void) U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_print(Data, Pgbd.Flags, blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PATHGRADIENTBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param BDFlag Describes optional values in contents
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object
+*/
+int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit){
+ if(BDFlag & (U_BD_Transform | U_BD_PresetColors | U_BD_BlendFactorsH | U_BD_FocusScales)){
+ printf(" + PathGradientBrushOptionalData: ");
+ }
+ if(BDFlag & U_BD_Transform){
+ U_PMF_TRANSFORMMATRIX_print(contents, blimit);
+ contents += sizeof(U_PMF_TRANSFORMMATRIX);
+ }
+ if(BDFlag & U_BD_PresetColors){ /* If this is present, BlendFactorsH will not be */
+ contents += U_PMF_BLENDCOLORS_print(contents, blimit);
+ }
+ if(BDFlag & U_BD_BlendFactorsH){/* If this is present, U_BD_PresetColors will not be */
+ contents += U_PMF_BLENDFACTORS_print(contents,"", blimit);
+ }
+ if(BDFlag & U_BD_FocusScales){
+ contents += U_PMF_BLENDFACTORS_print(contents,"", blimit);
+ U_PMF_FOCUSSCALEDATA_print(contents, blimit);
+ }
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_PATHPOINTTYPE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object
+*/
+int U_PMF_PATHPOINTTYPE_print(const char *contents, const char *blimit){
+ int Flags, Type;
+ int status = U_PMF_PATHPOINTTYPE_get(contents, &Flags, &Type, blimit);
+ if(status){
+ printf("{Flags:%X Type:",Flags);
+ (void) U_PMF_PATHPOINTTYPE_ENUM_print(Type);
+ printf("}");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PATHPOINTTYPERLE object
+ \return Number of elements in the run, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object
+*/
+int U_PMF_PATHPOINTTYPERLE_print(const char *contents, const char *blimit){
+ int Bezier, Elements, Type;
+ int status = U_PMF_PATHPOINTTYPERLE_get(contents, &Bezier, &Elements, &Type, blimit);
+ if(status){
+ status = Elements;
+ printf(" PathPointTypeRLE: Bezier:%c Elements:%u, Type: ",(Bezier ? 'Y' : 'N'), Elements);
+ (void) U_PMF_PATHPOINTTYPE_ENUM_print(Type);
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_PATHPOINTTYPERLE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object
+*/
+int U_PMF_PENDATA_print(const char *contents, const char *blimit){
+ uint32_t Flags, Unit;
+ U_FLOAT Width;
+ const char *Data;
+ int status = U_PMF_PENDATA_get(contents, &Flags, &Unit, &Width, &Data, blimit);
+ if(status){
+ printf(" + Pendata: Flags:%X Unit:%X Width:%f",Flags, Unit, Width);
+ (void) U_PMF_PENOPTIONALDATA_print(Data, Flags, blimit); /* prints a new line at end */
+ }
+ return(status);
+}
+
+
+
+/**
+ \brief Print data from a U_PMF_PENOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ \param Flags PenData Flags that determine which optionaldata fields are present in the record.
+
+ EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object
+*/
+int U_PMF_PENOPTIONALDATA_print(const char *contents, int Flags, const char *blimit){
+ U_PMF_TRANSFORMMATRIX Matrix;
+ int32_t StartCap;
+ int32_t EndCap;
+ uint32_t Join;
+ U_FLOAT MiterLimit;
+ int32_t Style;
+ int32_t DLCap;
+ U_FLOAT DLOffset;
+ const char *DLData;
+ int32_t Alignment;
+ const char *CmpndLineData;
+ const char *CSCapData;
+ const char *CECapData;
+ int status = U_PMF_PENOPTIONALDATA_get(
+ contents,
+ Flags, // determines which fields are filled
+ &Matrix,
+ &StartCap,
+ &EndCap,
+ &Join,
+ &MiterLimit,
+ &Style,
+ &DLCap,
+ &DLOffset,
+ &DLData,
+ &Alignment,
+ &CmpndLineData,
+ &CSCapData,
+ &CECapData,
+ blimit);
+ if(status){
+ if(Flags & U_PD_Transform){ (void) U_PMF_TRANSFORMMATRIX2_print(&Matrix);}
+ if(Flags & U_PD_StartCap){ printf(" StartCap:%d", StartCap );}
+ if(Flags & U_PD_EndCap){ printf(" EndCap:%d", EndCap );}
+ if(Flags & U_PD_Join){ printf(" Join:%X", Join );}
+ if(Flags & U_PD_MiterLimit){ printf(" MiterLimit:%f", MiterLimit );}
+ if(Flags & U_PD_LineStyle){ printf(" Style:%X", Style );}
+ if(Flags & U_PD_DLCap){ printf(" DLCap:%X", DLCap );}
+ if(Flags & U_PD_DLOffset){ printf(" DLOffset:%f", DLOffset );}
+ if(Flags & U_PD_DLData){ (void) U_PMF_DASHEDLINEDATA_print(DLData, blimit );}
+ if(Flags & U_PD_NonCenter){ printf(" Alignment:%d", Alignment );}
+ if(Flags & (U_PD_Transform | U_PD_StartCap | U_PD_EndCap |
+ U_PD_Join | U_PD_MiterLimit | U_PD_LineStyle |
+ U_PD_DLCap | U_PD_DLOffset |U_PD_DLData |U_PD_NonCenter)){ printf("\n"); }
+ if(Flags & U_PD_CLData){ (void) U_PMF_COMPOUNDLINEDATA_print(CmpndLineData, blimit); }
+ if(Flags & U_PD_CustomStartCap){ (void) U_PMF_CUSTOMSTARTCAPDATA_print(CSCapData, blimit); }
+ if(Flags & U_PD_CustomEndCap){ (void) U_PMF_CUSTOMENDCAPDATA_print(CECapData, blimit); }
+ }
+ return(status);
+}
+/**
+ \brief Print data from a U_PMF_POINT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object
+*/
+int U_PMF_POINT_print(const char **contents, const char *blimit){
+ U_FLOAT X, Y;
+ int status = U_PMF_POINT_get(contents, &X, &Y, blimit);
+ if(status){
+ printf("{%f,%f}", X, Y);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_POINT Structure
+ \return 1 on success, 0 on error
+ \param Point U_PMF_POINT Structure to print
+ EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object
+*/
+int U_PMF_POINT_S_print(U_PMF_POINT *Point){\
+ if(!Point){ return(0); }
+ printf("{%d,%d}", Point->X, Point->Y);
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_POINTF object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object
+*/
+int U_PMF_POINTF_print(const char **contents, const char *blimit){
+ U_FLOAT X, Y;
+ int status = U_PMF_POINTF_get(contents, &X, &Y, blimit);
+ if(status){
+ printf("{%f,%f}", X, Y);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_POINTF Structure
+ \return 1 on success, 0 on error
+ \param Point U_PMF_POINTF Structure to print
+ EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object
+*/
+int U_PMF_POINTF_S_print(U_PMF_POINTF *Point){
+ if(!Point){ return(0); }
+ printf("{%f,%f}", Point->X, Point->Y);
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_POINTR object
+ \return bytes traversed on success, 0 on error
+ \param contents Pointer to next data to print
+ \param Xpos X coordinate for current point
+ \param Ypos Y coordinate for current point
+ \param blimit one byte past the end of data
+
+ On each call the next relative offset is extracted, the current
+ coordinates are modified with that offset, and the pointer is
+ advanced to the next data point.
+
+ EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object
+*/
+int U_PMF_POINTR_print(const char **contents, U_FLOAT *Xpos, U_FLOAT *Ypos, const char *blimit){
+ U_FLOAT X, Y;
+ int status = U_PMF_POINTR_get(contents, &X, &Y, blimit);
+ *Xpos += X;
+ *Ypos += Y;
+ if(status){
+ printf("{%f,%f(%f,%f)}", *Xpos, *Ypos, X, Y);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_RECT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object
+*/
+int U_PMF_RECT_print(const char **contents, const char *blimit){
+ int16_t X, Y, Width, Height;
+ int status = U_PMF_RECT_get(contents, &X, &Y, &Width, &Height, blimit);
+ if(status){
+ printf("{UL{%d,%d},WH{%d,%d}}", X, Y, Width, Height);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_RECT Structure
+ \return 1 on success, 0 on error
+ \param Rect U_PMF_RECT structure
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+int U_PMF_RECT_S_print(U_PMF_RECT *Rect){
+ printf("{UL{%d,%d},WH{%d,%d}}", Rect->X, Rect->Y, Rect->Width, Rect->Height);
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_RECTF object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+int U_PMF_RECTF_print(const char **contents, const char *blimit){
+ U_FLOAT X, Y, Width, Height;
+ int status = U_PMF_RECTF_get(contents, &X, &Y, &Width, &Height, blimit);
+ if(status){
+ printf("{UL{%f,%f},WH{%f,%f}}", X, Y, Width, Height);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_RECTF Structure
+ \return 1 on success, 0 on error
+ \param Rect U_PMF_RECTF Structure
+ EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object
+*/
+int U_PMF_RECTF_S_print(U_PMF_RECTF *Rect){
+ printf("{UL{%f,%f},WH{%f,%f}}", Rect->X, Rect->Y, Rect->Width, Rect->Height);
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_REGIONNODE object
+ \return size on success, 0 on error
+ \param contents Record from which to print data
+ \param Level Tree level. This routine is recursive and could go down many levels. 1 is the top, >1 are child nodes.
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object
+*/
+int U_PMF_REGIONNODE_print(const char *contents, int Level, const char *blimit){
+ int len=4; /* Type will always be present */
+ uint32_t Type;
+ const char *Data;
+ int status = U_PMF_REGIONNODE_get(contents, &Type, &Data, blimit);
+ if(status){
+ printf("\n + RegionNode(Level:%d) { Type:%X(",Level,Type);
+ U_PMF_NODETYPE_print(Type);
+ printf(")");
+ if(Type >= U_RNDT_And && Type <= U_RNDT_Complement){
+ len += U_PMF_REGIONNODECHILDNODES_print(Data, Level+1, blimit);
+ }
+ else if(Type == U_RNDT_Rect){
+ len += sizeof(U_PMF_RECTF);
+ (void) U_PMF_RECTF_print(&Data, blimit);
+ printf("\n");
+ }
+ else if(Type == U_RNDT_Path){
+ len += U_PMF_REGIONNODEPATH_print(Data, blimit);
+ }
+ /* U_RNDT_Empty and U_RNDT_Infinite do not change the length */
+ else if(Type == U_RNDT_Empty ){ printf(" Empty" ); }
+ else if(Type == U_RNDT_Infinite ){ printf(" Infinite" ); }
+ printf(" + RegionNode(Level:%d) }",Level);
+ status = len; /* length of data + length of type */
+ }
+ printf("\n");
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_REGIONNODECHILDNODES object
+ \return size on success, 0 on error
+ \param contents Record from which to print data
+ \param Level Tree level. This routine is recursive and could go down many levels. 1 is the top, >1 are child nodes.
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object
+*/
+int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level, const char *blimit){
+ uint32_t size,rsize;
+ printf(" RegionNodeChildNodes:\n");
+ printf(" + RNCN__Left(Level:%d) {", Level);
+ size = U_PMF_REGIONNODE_print(contents, Level, blimit);
+ printf(" + RNCN__Left(Level:%d) },\n", Level);
+ if(size){
+ contents += size;
+ printf(" + RNCN_Right(Level:%d) {", Level);
+ rsize = U_PMF_REGIONNODE_print(contents, Level, blimit);
+ size += rsize;
+ printf(" + RNCN_Right(Level:%d) },\n",Level);
+ }
+ return(size);
+}
+
+/**
+ \brief Print data from a U_PMF_REGIONNODEPATH object
+ \return Size of data on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object
+*/
+int U_PMF_REGIONNODEPATH_print(const char *contents, const char * blimit){
+ int32_t Size;
+ const char *Data;
+ int status = U_PMF_REGIONNODEPATH_get(contents, &Size, &Data, blimit);
+ if(status){
+ printf(" RegionNodePath: \n");
+ (void) U_PMF_PATH_print(Data, blimit);
+ status = Size + 4; /* data sizee + the 4 bytes encoding the size */
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMF_SOLIDBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object
+*/
+int U_PMF_SOLIDBRUSHDATA_print(const char *contents, const char *blimit){
+ U_PMF_ARGB Color;
+ int status = U_PMF_SOLIDBRUSHDATA_get(contents, &Color, blimit);
+ if(status){
+ printf(" SolidBrushData: ");
+ (void) U_PMF_ARGB_print((char *) &Color);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_STRINGFORMATDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param TabStopCount Entries in TabStop array
+ \param RangeCount Entries in CharRange array
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object
+*/
+int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, const char *blimit){
+ const U_FLOAT *TabStops;
+ const U_PMF_CHARACTERRANGE *CharRange;
+ int status = U_PMF_STRINGFORMATDATA_get(contents, TabStopCount, RangeCount, &TabStops, &CharRange, blimit);
+ if(status){
+ printf(" SFdata: TabStopCount:%u RangeCount:%u\n", TabStopCount, RangeCount);
+
+ printf(" Tabstops:");
+ for(; TabStopCount; TabStopCount--,TabStops++){ printf(" %f",*TabStops); }
+ printf("\n");
+
+ printf(" CharRange:");
+ for(; RangeCount; RangeCount--,CharRange++){ printf(" {%d,%d}",CharRange->First,CharRange->Length); }
+ printf("\n");
+
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_TEXTUREBRUSHDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object
+*/
+int U_PMF_TEXTUREBRUSHDATA_print(const char *contents, const char *blimit){
+ uint32_t Flags;
+ int32_t WrapMode;
+ const char *Data;
+ int status = U_PMF_TEXTUREBRUSHDATA_get(contents, &Flags, &WrapMode, &Data, blimit);
+ if(status){
+ printf(" + TBdata: Flags:%X WrapMode:%d", Flags, WrapMode);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_TEXTUREBRUSHOPTIONALDATA object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param HasMatrix True if the record contains a matrix.
+ \param HasImage True if the record contains an image.
+ \param blimit one byte past the end of data
+
+ EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object
+*/
+int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasMatrix, int HasImage, const char *blimit){
+ U_PMF_TRANSFORMMATRIX Matrix;
+ U_PMF_TRANSFORMMATRIX *pMatrix;
+ const char *Image;
+ if(HasMatrix){ pMatrix = &Matrix; }
+ else { pMatrix = NULL; }
+ int status = U_PMF_TEXTUREBRUSHOPTIONALDATA_get(contents, HasImage, pMatrix, &Image, blimit);
+ if(status){
+ printf(" + TBOptdata: Image:%c", (HasImage ? 'Y' : 'N'));
+ (void) U_PMF_TRANSFORMMATRIX2_print(&Matrix);
+ (void) U_PMF_IMAGE_print(Image, blimit);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_TRANSFORMMATRIX object stored in file byte order.
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object
+*/
+int U_PMF_TRANSFORMMATRIX_print(const char *contents, const char *blimit){
+ U_PMF_TRANSFORMMATRIX Tm;
+ int status = U_PMF_TRANSFORMMATRIX_get(contents, &Tm, blimit);
+ if(status){
+ U_PMF_TRANSFORMMATRIX2_print(&Tm);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_TRANSFORMMATRIX structure
+ \return 1 on success, 0 on error
+ \param Tm U_PMF_TRANSFORMMATRIX structure
+ EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object
+*/
+int U_PMF_TRANSFORMMATRIX2_print(U_PMF_TRANSFORMMATRIX *Tm){
+ if(Tm){
+ printf(" Matrix:{%f,%f,%f,%f,%f,%f}", Tm->m11, Tm->m12, Tm->m21, Tm->m22, Tm->dX, Tm->dY);
+ }
+ else {
+ printf(" Matrix:(None)");
+ }
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_ROTMATRIX object
+ \return 1 on success, 0 on error
+ \param Rm U_PMF_ROTMATRIX object
+ NOT DOCUMENTED, like EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object, but missing offset values
+*/
+int U_PMF_ROTMATRIX2_print(U_PMF_ROTMATRIX *Rm){
+ printf(" Matrix:{%f,%f,%f,%f}", Rm->m11, Rm->m12, Rm->m21, Rm->m22);
+ return(1);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_BLUR object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object
+*/
+int U_PMF_IE_BLUR_print(const char *contents, const char *blimit){
+ U_FLOAT Radius;
+ uint32_t ExpandEdge;
+ int status = U_PMF_IE_BLUR_get(contents, &Radius, &ExpandEdge, blimit);
+ if(status){
+ printf("BlurEffect Radius:%f ExpandEdge:%u\n", Radius, ExpandEdge);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_BRIGHTNESSCONTRAST object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object
+*/
+int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents, const char *blimit){
+ int32_t Brightness, Contrast;
+ int status = U_PMF_IE_BRIGHTNESSCONTRAST_get(contents, &Brightness, &Contrast, blimit);
+ if(status){
+ printf("BrightnessContrastEffect Brightness:%d Contrast:%d\n", Brightness, Contrast);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_COLORBALANCE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object
+*/
+int U_PMF_IE_COLORBALANCE_print(const char *contents, const char *blimit){
+ int32_t CyanRed, MagentaGreen, YellowBlue;
+ int status = U_PMF_IE_COLORBALANCE_get(contents, &CyanRed, &MagentaGreen, &YellowBlue, blimit);
+ if(status){
+ printf("ColorBalanceEffect CyanRed:%d MagentaGreen:%d YellowBlue:%d\n", CyanRed, MagentaGreen, YellowBlue);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_COLORCURVE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object
+*/
+int U_PMF_IE_COLORCURVE_print(const char *contents, const char *blimit){
+ uint32_t Adjust, Channel;
+ int32_t Intensity;
+ int status = U_PMF_IE_COLORCURVE_get(contents, &Adjust, &Channel, &Intensity, blimit);
+ if(status){
+ printf("ColorBalanceEffect Adjust:%u Channel:%u Intensity:%d\n", Adjust, Channel, Intensity);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_COLORLOOKUPTABLE object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object
+*/
+int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents, const char *blimit){
+ const uint8_t *BLUT, *GLUT, *RLUT, *ALUT;
+ int status = U_PMF_IE_COLORLOOKUPTABLE_get(contents, &BLUT, &GLUT, &RLUT, &ALUT, blimit);
+ if(status){
+ printf("ColorLookupTableEffect \n");
+ U_PMF_UINT8_ARRAY_print(" BLUT:", BLUT, 256, "\n");
+ U_PMF_UINT8_ARRAY_print(" GLUT:", GLUT, 256, "\n");
+ U_PMF_UINT8_ARRAY_print(" RLUT:", RLUT, 256, "\n");
+ U_PMF_UINT8_ARRAY_print(" ALUT:", ALUT, 256, "\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_COLORMATRIX object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object
+*/
+int U_PMF_IE_COLORMATRIX_print(const char *contents, const char *blimit){
+ U_PMF_IE_COLORMATRIX Matrix;
+ int i,j;
+ int status = U_PMF_IE_COLORMATRIX_get(contents, &Matrix, blimit);
+ if(status){
+ printf("ColorMatrixEffect\n");
+ for(i=0;i<5;i++){
+ printf(" {");
+ for(j=0;j<4;i++){ printf("%f,",Matrix.M[i][j]); }
+ printf("%f}",Matrix.M[i][j]);
+ }
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_HUESATURATIONLIGHTNESS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object
+*/
+int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents, const char *blimit){
+ int32_t Hue, Saturation, Lightness;
+ int status = U_PMF_IE_HUESATURATIONLIGHTNESS_get(contents, &Hue, &Saturation, &Lightness, blimit);
+ if(status){
+ printf("HueSaturationLightnessEffect Hue:%d Saturation:%d Lightness:%d\n", Hue, Saturation, Lightness);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_LEVELS object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object
+*/
+int U_PMF_IE_LEVELS_print(const char *contents, const char *blimit){
+ int32_t Highlight, Midtone, Shadow;
+ int status = U_PMF_IE_LEVELS_get(contents, &Highlight, &Midtone, &Shadow, blimit);
+ if(status){
+ printf("LevelEffect Highlight:%d Midtone:%d Shadow:%d\n", Highlight, Midtone, Shadow);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_REDEYECORRECTION object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object
+*/
+int U_PMF_IE_REDEYECORRECTION_print(const char *contents, const char *blimit){
+ int32_t Elements;
+ U_RECTL *Rects;
+ int status = U_PMF_IE_REDEYECORRECTION_get(contents, &Elements, &Rects, blimit);
+ if(status){
+ printf("RedEyeCorrectionEffect Elements:%u", Elements);
+ for(; Elements; Elements--, Rects++){
+ printf(" ");
+ rectl_print(*Rects);
+ }
+ printf("\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_SHARPEN object
+ \return 1 on success, 0 on error
+ \param blimit one byte past the end of data
+ \param contents Record from which to print data
+ EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object
+*/
+int U_PMF_IE_SHARPEN_print(const char *contents, const char *blimit){
+ U_FLOAT Radius;
+ int32_t Sharpen;
+ int status = U_PMF_IE_SHARPEN_get(contents, &Radius, &Sharpen, blimit);
+ if(status){
+ printf("SharpenEffect Radius:%f Sharpen:%u\n", Radius, Sharpen);
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMF_IE_TINT object
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit one byte past the end of data
+ EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object
+*/
+int U_PMF_IE_TINT_print(const char *contents, const char *blimit){
+ int32_t Hue, Amount;
+ int status = U_PMF_IE_TINT_get(contents, &Hue, &Amount, blimit);
+ if(status){
+ printf("TintEffect Hue:%d Amount:%d\n", Hue, Amount);
+ }
+ return(status);
+}
+
+/* ***************************************************************************************** */
+/* EMF+ records, the EMF+ record header is printed separately, these print the contents only */
+/* ***************************************************************************************** */
+
+
+/**
+ \brief Print data from a U_PMR_OFFSETCLIP record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.1.1, Microsoft name: EmfPlusOffsetClip Record, Index 0x35
+*/
+int U_PMR_OFFSETCLIP_print(const char *contents){
+ U_PMF_CMN_HDR Header;
+ U_FLOAT dX,dY;
+ int status = U_PMR_OFFSETCLIP_get(contents, &Header, &dX, &dY);
+ if(status){
+ printf(" + dx:%f dy:%f\n",dX,dY);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_OFFSETCLIP record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.1.2, Microsoft name: EmfPlusResetClip Record, Index 0x31
+*/
+int U_PMR_RESETCLIP_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_SETCLIPPATH record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.1.3, Microsoft name: EmfPlusSetClipPath Record, Index 0x33
+*/
+int U_PMR_SETCLIPPATH_print(const char *contents){
+ int CMenum;
+ uint32_t PathID;
+ int status = U_PMR_SETCLIPPATH_get(contents, NULL, &PathID, &CMenum);
+ if(status){
+ printf(" + PathID:%u CMenum:%d\n",PathID,CMenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETCLIPRECT record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.1.4, Microsoft name: EmfPlusSetClipRect Record, Index 0x32
+*/
+int U_PMR_SETCLIPRECT_print(const char *contents){
+ int CMenum;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_SETCLIPRECT_get(contents, NULL, &CMenum, &Rect);
+ if(status){
+ printf(" + CMenum:%d(", CMenum);
+ U_PMF_COMBINEMODEENUMERATION_print(CMenum);
+ printf(") Rect:");
+ U_PMF_RECTF_S_print(&Rect);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETCLIPREGION record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.1.5, Microsoft name: EmfPlusSetClipRegion Record, Index 0x34
+*/
+int U_PMR_SETCLIPREGION_print(const char *contents){
+ int CMenum;
+ uint32_t PathID;
+ int status = U_PMR_SETCLIPREGION_get(contents, NULL, &PathID, &CMenum);
+ if(status){
+ printf(" + PathID:%u CMenum:%d(",PathID, CMenum);
+ U_PMF_COMBINEMODEENUMERATION_print(CMenum);
+ printf(")\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMR_COMMENT record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03
+*/
+int U_PMR_COMMENT_print(const char *contents){
+ U_PMF_CMN_HDR Header;
+ const char *Data;
+ unsigned int i=0;
+ int status = U_PMR_COMMENT_get(contents, &Header, &Data);
+ if(status){
+ const char *blimit = contents + Header.Size;
+ if(IS_MEM_UNSAFE(Data, Header.DataSize, blimit)){
+ printf(" corrupt record\n");
+ return(0);
+ }
+ /* try to print it, but only ASCII, bail on anything that is not ASCII */
+ printf(" + Data:");
+ for(i=0; i< Header.DataSize; i++,Data++){
+ if(!*Data)break;
+ if(*(unsigned const char *)Data <128){ printf("%c",*Data); }
+ else { break; }
+ }
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_ENDOFFILE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.3.1, Microsoft name: EmfPlusEndOfFile Record, Index 0x02
+*/
+int U_PMR_ENDOFFILE_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_ENDOFFILE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.3.2, Microsoft name: EmfPlusGetDC Record, Index 0x04
+*/
+int U_PMR_GETDC_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_HEADER record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.3.3, Microsoft name: EmfPlusHeader Record, Index 0x01
+*/
+int U_PMR_HEADER_print(const char *contents){
+ U_PMF_GRAPHICSVERSION Version;
+ int IsDual, IsVideo;
+ uint32_t LogicalDpiX, LogicalDpiY;
+ int status = U_PMR_HEADER_get(contents, NULL, &Version, &IsDual, &IsVideo, &LogicalDpiX, &LogicalDpiY);
+ if(status){
+ /* try to print it, but only ASCII, bail on anything that is not ASCII */
+ printf(" + ");
+ (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);;
+ printf(" IsDual:%c IsVideo:%d LogicalDpiX,y:{%u,%u}\n",(IsDual ? 'Y' : 'N'),IsVideo,LogicalDpiX, LogicalDpiY);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_CLEAR record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.1, Microsoft name: EmfPlusClear Record, Index 0x09
+*/
+int U_PMR_CLEAR_print(const char *contents){
+ U_PMF_ARGB Color;
+ int status = U_PMR_CLEAR_get(contents, NULL, &Color);
+ if(status){
+ /* try to print it, but only ASCII, bail on anything that is not ASCII */
+ printf(" + Color:");
+ (void) U_PMF_ARGB_print((char *) &Color);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWARC record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.2, Microsoft name: EmfPlusDrawArc Record, Index 0x12
+*/
+int U_PMR_DRAWARC_print(const char *contents){
+ uint32_t PenID;
+ int ctype;
+ U_FLOAT Start, Sweep;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_DRAWARC_get(contents, NULL, &PenID, &ctype, &Start, &Sweep, &Rect);
+ if(status){
+ printf(" + PenID:%u ctype:%d Start:%f Sweep:%f Rect:", PenID,ctype,Start,Sweep);
+ (void) U_PMF_VARRECTF_S_print(&Rect, 1);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWBEZIERS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.3, Microsoft name: EmfPlusDrawBeziers Record, Index 0x19
+*/
+int U_PMR_DRAWBEZIERS_print(const char *contents){
+ uint32_t PenID;
+ int ctype, RelAbs;
+ uint32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_DRAWBEZIERS_get(contents, NULL, &PenID, &ctype, &RelAbs, &Elements, &Points);
+ if(status){
+ printf(" + PenIdx:%u ctype:%d RelAbs:%d Elements:%u\n", PenID, ctype, RelAbs, Elements);
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWCLOSEDCURVE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+
+ Curve is a cardinal spline.
+ References sent by MS support:
+ http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+ http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+
+ EMF+ manual 2.3.4.4, Microsoft name: EmfPlusDrawClosedCurve Record, Index 0x17
+*/
+int U_PMR_DRAWCLOSEDCURVE_print(const char *contents){
+ uint32_t PenID;
+ int ctype, RelAbs;
+ U_FLOAT Tension;
+ uint32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_DRAWCLOSEDCURVE_get(contents, NULL, &PenID, &ctype, &RelAbs, &Tension, &Elements, &Points);
+ if(status){
+ printf(" + PenID:%u ctype:%d RelAbs:%d Tension:%f\n", PenID, ctype, RelAbs, Tension);
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWCURVE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+
+ Curve is a cardinal spline, using doubled terminator points to generate curves for the terminal segments.
+ References sent by MS support:
+ http://alvyray.com/Memos/CG/Pixar/spline77.pdf
+ http://msdn.microsoft.com/en-us/library/4cf6we5y(v=vs.110).aspx
+
+ EMF+ manual 2.3.4.5, Microsoft name: EmfPlusDrawCurve Record, Index 0x18
+*/
+int U_PMR_DRAWCURVE_print(const char *contents){
+ uint32_t PenID;
+ int ctype;
+ U_FLOAT Tension;
+ uint32_t Offset, NSegs, Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_DRAWCURVE_get(contents, NULL, &PenID, &ctype, &Tension, &Offset, &NSegs, &Elements, &Points);
+ if(status){
+ printf(" + PenID:%u ctype:%d Tension:%f Offset:%u NSegs:%u Elements:%u\n", PenID, ctype, Tension, Offset, NSegs, Elements);
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWDRIVERSTRING record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36
+*/
+int U_PMR_DRAWDRIVERSTRING_print(const char *contents){
+ unsigned int i;
+ uint32_t FontID;
+ int btype;
+ uint32_t BrushID, DSOFlags, HasMatrix, Elements;
+ uint16_t *Glyphs;
+ uint16_t *GlyphsIter;
+ U_PMF_POINTF *Points;
+ U_PMF_TRANSFORMMATRIX *Matrix;
+ int status = U_PMR_DRAWDRIVERSTRING_get(contents, NULL, &FontID, &btype,
+ &BrushID, &DSOFlags, &HasMatrix, &Elements,&Glyphs, &Points, &Matrix);
+ if(status){
+ printf(" + FontID:%u btype:%d BrushID:%u DSOFlags:%X Elements:%u\n", FontID,btype, BrushID, DSOFlags, Elements);
+
+ printf(" + Glyphs:");
+ if(*Glyphs){
+ for(GlyphsIter=Glyphs, i=0; i<Elements;i++, GlyphsIter++){ printf(" %u",*GlyphsIter); }
+ free(Glyphs);
+ }
+ else {
+ printf("(none)");
+ }
+ printf("\n");
+
+ printf(" + Positions:\n");
+ if(Points){
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf("(none)\n");
+ }
+
+ if(Matrix){
+ printf(" + ");
+ U_PMF_TRANSFORMMATRIX2_print(Matrix);
+ free(Matrix);
+ printf("\n");
+ }
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWELLIPSE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.7, Microsoft name: EmfPlusDrawEllipse Record, Index 0x0F
+*/
+int U_PMR_DRAWELLIPSE_print(const char *contents){
+ uint32_t PenID;
+ int ctype;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_DRAWELLIPSE_get(contents, NULL, &PenID, &ctype, &Rect);
+ if(status){
+ printf(" + PenID:%u ctype:%d", PenID,ctype);
+ (void) U_PMF_VARRECTF_S_print(&Rect, 1);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWIMAGE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.8, Microsoft name: EmfPlusDrawImage Record, Index 0x1A
+*/
+int U_PMR_DRAWIMAGE_print(const char *contents){
+ uint32_t ImgID, ImgAttrID;
+ int ctype;
+ int32_t SrcUnit;
+ U_PMF_RECTF SrcRect;
+ U_PMF_RECTF DstRect;
+ int status = U_PMR_DRAWIMAGE_get(contents, NULL, &ImgID, &ctype, &ImgAttrID, &SrcUnit, &SrcRect, &DstRect);
+ if(status){
+ printf(" + ImgID:%u ctype:%d ImgAttrID:%u SrcUnit:%d SrcRect:", ImgID, ctype, ImgAttrID, SrcUnit);
+ (void) U_PMF_RECTF_S_print(&SrcRect);
+ printf(" DstRect:");
+ (void) U_PMF_RECTF_S_print(&DstRect);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWIMAGEPOINTS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.9, Microsoft name: EmfPlusDrawImagePoints Record, Index 0x1B
+*/
+int U_PMR_DRAWIMAGEPOINTS_print(const char *contents){
+ uint32_t ImgID, ImgAttrID;
+ int ctype, etype, RelAbs;
+ int32_t SrcUnit;
+ U_PMF_RECTF SrcRect;
+ uint32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_DRAWIMAGEPOINTS_get(contents, NULL, &ImgID, &ctype, &etype, &RelAbs,
+ &ImgAttrID, &SrcUnit, &SrcRect, &Elements, &Points);
+ if(status){
+ printf(" + ImgID:%u ctype:%d etype:%d ImgAttrID:%u SrcUnit:%d Elements:%u SrcRect:",
+ ImgID, ctype, etype, ImgAttrID, SrcUnit, Elements);
+ (void) U_PMF_RECTF_S_print(&SrcRect);
+ printf("\n");
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMR_DRAWLINES record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.10, Microsoft name: EmfPlusDrawLines Record, Index 0x0D
+*/
+int U_PMR_DRAWLINES_print(const char *contents){
+ uint32_t PenIdx;
+ int ctype, dtype, RelAbs;
+ uint32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_DRAWLINES_get(contents, NULL, &PenIdx, &ctype, &dtype, &RelAbs, &Elements, &Points);
+ if(status){
+ printf(" + PenIdx:%d ctype:%d dtype:%d RelAbs:%d\n", PenIdx,ctype,dtype,RelAbs);
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWPATH record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.11, Microsoft name: EmfPlusDrawPath Record, Index 0x15
+*/
+int U_PMR_DRAWPATH_print(const char *contents){
+ uint32_t PathIdx, PenIdx;
+ int status = U_PMR_DRAWPATH_get(contents, NULL, &PathIdx, &PenIdx);
+ if(status){
+ printf(" + PathIdx:%d PenIdx:%d\n", PathIdx, PenIdx);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWPIE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.12, Microsoft name: EmfPlusDrawPie Record, Index 0x0D
+*/
+int U_PMR_DRAWPIE_print(const char *contents){
+ uint32_t PenID;
+ int ctype;
+ U_FLOAT Start, Sweep;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_DRAWPIE_get(contents, NULL, &PenID, &ctype, &Start, &Sweep, &Rect);
+ if(status){
+ printf(" + PenID:%u ctype:%d Start:%f Sweep:%f Rect:", PenID,ctype,Start,Sweep);
+ (void) U_PMF_VARRECTF_S_print(&Rect, 1);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWRECTS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B
+*/
+int U_PMR_DRAWRECTS_print(const char *contents){
+ uint32_t PenID;
+ int ctype;
+ uint32_t Elements;
+ U_PMF_RECTF *Rects=NULL;
+ U_PMF_CMN_HDR hdr;
+ int status = U_PMR_DRAWRECTS_get(contents, &hdr, &PenID, &ctype, &Elements, &Rects);
+ if(status){
+ printf(" + PenID:%u ctype:%d Elements:%u Rect:", PenID,ctype,Elements);
+ (void) U_PMF_VARRECTF_S_print(Rects, Elements);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ if(Rects)free(Rects);
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_DRAWSTRING record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.14, Microsoft name: EmfPlusDrawString Record, Index 0x1C
+*/
+int U_PMR_DRAWSTRING_print(const char *contents){
+ char *String8=NULL;
+ uint32_t FontID, BrushID, FormatID, Length;
+ int btype;
+ U_PMF_RECTF Rect;
+ uint16_t *String16;
+ int status = U_PMR_DRAWSTRING_get(contents, NULL, &FontID, &btype,
+ &BrushID, &FormatID, &Length, &Rect, &String16);
+ if(status){
+ printf(" + FontID:%u StringFormatID:%u btype:%d Length:%u Rect:", FontID, FormatID, btype, Length);
+ (void) U_PMF_RECTF_S_print(&Rect);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ if(String16){
+ String8 = U_Utf16leToUtf8(String16, Length, NULL);
+ free(String16);
+ if(String8){
+ printf(" String(as_UTF8):<%s>\n",String8);
+ free(String8);
+ }
+ }
+ else {
+ printf(" String(as_UTF8):(none)\n");
+ }
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLCLOSEDCURVE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.15, Microsoft name: EmfPlusFillClosedCurve Record, Index 0x16
+*/
+int U_PMR_FILLCLOSEDCURVE_print(const char *contents){
+ uint32_t BrushID;
+ int btype, ctype, ftype, RelAbs;
+ U_FLOAT Tension;
+ uint32_t Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_FILLCLOSEDCURVE_get(contents, NULL, &btype, &ctype, &ftype, &RelAbs,
+ &BrushID, &Tension, &Elements, &Points);
+ if(status){
+ printf(" + btype:%d ctype:%d ftype:%d RelAbs:%d Elements:%u",
+ btype, ctype, ftype, RelAbs, Elements);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ printf("\n");
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMR_FILLELLIPSE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.16, Microsoft name: EmfPlusFillEllipse Record, Index 0x0E
+*/
+int U_PMR_FILLELLIPSE_print(const char *contents){
+ int btype, ctype;
+ uint32_t BrushID;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_FILLELLIPSE_get(contents, NULL, &btype, &ctype, &BrushID, &Rect);
+ if(status){
+ printf(" + btype:%d ctype:%d",btype,ctype);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ (void) U_PMF_VARRECTF_S_print(&Rect, 1);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLPATH record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.17, Microsoft name: EmfPlusFillPath Record, Index 0x14
+*/
+int U_PMR_FILLPATH_print(const char *contents){
+ int btype;
+ uint32_t PathID, BrushID;
+ int status = U_PMR_FILLPATH_get(contents, NULL, &PathID, &btype, &BrushID);
+ if(status){
+ printf(" + PathID:%u btype:%d",PathID, btype);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLPIE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.18, Microsoft name: EmfPlusFillPie Record, Index 0x10
+*/
+int U_PMR_FILLPIE_print(const char *contents){
+ int btype, ctype;
+ U_FLOAT Start, Sweep;
+ uint32_t BrushID;
+ U_PMF_RECTF Rect;
+ int status = U_PMR_FILLPIE_get(contents, NULL, &btype, &ctype, &BrushID, &Start, &Sweep, &Rect);
+ if(status){
+ printf(" + btype:%d ctype:%d",btype,ctype);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ (void) U_PMF_VARRECTF_S_print(&Rect, 1);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLPOLYGON record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.19, Microsoft name: EmfPlusFillPolygon Record, Index 0x0C
+*/
+int U_PMR_FILLPOLYGON_print(const char *contents){
+ int btype, ctype, RelAbs;
+ uint32_t BrushID, Elements;
+ U_PMF_POINTF *Points;
+ int status = U_PMR_FILLPOLYGON_get(contents, NULL, &btype, &ctype, &RelAbs, &BrushID, &Elements, &Points);
+ if(status){
+ printf(" + btype:%d ctype:%d RelAbs:%d Elements:%u",btype,ctype,RelAbs,Elements);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ printf("\n");
+ U_PMF_VARPOINTF_S_print(Points, Elements);
+ free(Points);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLRECTS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A
+*/
+int U_PMR_FILLRECTS_print(const char *contents){
+ int btype, ctype;
+ uint32_t BrushID, Elements;
+ U_PMF_RECTF *Rects;
+ U_PMF_CMN_HDR hdr;
+ int status = U_PMR_FILLRECTS_get(contents, &hdr, &btype,&ctype, &BrushID, &Elements, &Rects);
+ if(status){
+ printf(" + btype:%d ctype:%d Elements:%u",btype,ctype,Elements);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ (void) U_PMF_VARRECTF_S_print(Rects, Elements);
+ free(Rects);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_FILLREGION record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.4.21, Microsoft name: EmfPlusFillRegion Record, Index 0x13
+*/
+int U_PMR_FILLREGION_print(const char *contents){
+ uint32_t RgnID, BrushID;
+ int btype, ctype;
+ int status = U_PMR_FILLREGION_get(contents, NULL, &RgnID, &btype, &ctype, &BrushID);
+ if(status){
+ printf(" + RgnID:%u btype:%d ctype:%d", RgnID, btype, ctype);
+ (void) U_PMF_VARBRUSHID_print(btype, BrushID);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_OBJECT record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ \param blimit One byte past the last record in memory.
+ \param ObjCont Structure that holds accumulated object.
+ \param term Flag used when an abnormal termination of a series of continuation records is encountered.
+ EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13
+
+ This is the ONLY EMF+ record type which needs an explicit blimit passed in. Since it glues
+ together multiple records, and calls itself recursively, the initial caller cannot determine
+ that all of the sizes will be OK from the first record's header.
+*/
+int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *ObjCont, int term){
+ U_PMF_CMN_HDR Header;
+ uint32_t ObjID;
+ int otype, ntype;
+ uint32_t TSize;
+ const char *Data;
+ int ttype,status;
+
+//int k; const char *cptr; for(cptr=contents, k=0; k<608;k++,cptr++){ printf("%3.3d %2.2X\n",k,*(uint8_t*)cptr); }; fflush(stdout);
+
+ /* Continued records are a pain. Each contains the total size of the continued object in the first 4 bytes
+ of data. When the total hits that then then the record is complete, even though the continuation bit will
+ still be set on that last record. Check for this and then print the terminated continued series.
+ */
+
+ if(term){ /* mode for handling unexpected end of accumulated object */
+ if(ObjCont->used == 0)return(0); /* no continued object pending */
+ printf(" + START Forced Termination of Accumulating object Bytes:%u ObjID:%u DeclaredType:%d(",
+ ObjCont->used, ObjCont->Id, ObjCont->Type);
+ U_PMF_OBJECTTYPEENUMERATION_print(ObjCont->Type);
+ ttype = ObjCont->Type & 0x3F;
+ printf(")\n");
+ status = 1;
+ }
+ else {
+ status = U_PMR_OBJECT_get(contents, &Header, &ObjID, &otype, &ntype, &TSize, &Data);
+ /* In a corrupt EMF+ file we might hit a new type of record before all the continuation records
+ expected have been found. If that happens terminate whatever we have accumulated so far, and then go on
+ to emit the new (unexpected) record. */
+ if(IS_MEM_UNSAFE(contents, Header.Size, blimit))return(0);
+ if(!status){
+ printf(" corrupt record\n");
+ return(status);
+ }
+ if((ObjCont->used > 0) && (U_OA_append(ObjCont, NULL, 0, otype, ObjID) < 0)){
+ U_PMR_OBJECT_print(contents, blimit, ObjCont, 1);
+ }
+ printf(" + ObjID:%u ObjType:%d(", ObjID, otype);
+ U_PMF_OBJECTTYPEENUMERATION_print(otype);
+ printf(") ntype:%d", ntype);
+ printf(" ContinueD:%c",( ObjCont->used ? 'Y' : 'N'));
+ printf(" ContinueB:%c",( ntype ? 'Y' : 'N'));
+ if(ntype){
+ U_OA_append(ObjCont, Data, Header.DataSize - 4, otype, ObjID); // The total byte count is not added to the object
+ printf(" TotalSize:%u",TSize);
+ printf(" Accumulated:%u",ObjCont->used);
+ }
+ else {
+ U_OA_append(ObjCont, Data, Header.DataSize, otype, ObjID); // The total byte count is not added to the object
+ }
+ printf("\n");
+ if(ntype && ObjCont->used < TSize)return(status);
+ /* preceding terminates any continued series for >= accumulated bytes */
+ ttype = otype;
+ }
+ if(status){
+ blimit = ObjCont->accum + ObjCont->used; /* more restrictive blimit, just to end of object */
+ switch(ttype){
+ case U_OT_Brush: (void) U_PMF_BRUSH_print(ObjCont->accum, blimit); break;
+ case U_OT_Pen: (void) U_PMF_PEN_print(ObjCont->accum, blimit); break;
+ case U_OT_Path: (void) U_PMF_PATH_print(ObjCont->accum, blimit); break;
+ case U_OT_Region: (void) U_PMF_REGION_print(ObjCont->accum, blimit); break;
+ case U_OT_Image: (void) U_PMF_IMAGE_print(ObjCont->accum, blimit); break;
+ case U_OT_Font: (void) U_PMF_FONT_print(ObjCont->accum, blimit); break;
+ case U_OT_StringFormat: (void) U_PMF_STRINGFORMAT_print(ObjCont->accum, blimit); break;
+ case U_OT_ImageAttributes: (void) U_PMF_IMAGEATTRIBUTES_print(ObjCont->accum, blimit); break;
+ case U_OT_CustomLineCap: (void) U_PMF_CUSTOMLINECAP_print(ObjCont->accum,"", blimit); break;
+ case U_OT_Invalid:
+ default:
+ printf("INVALID OBJECT TYPE!!!!\n");
+ break;
+ }
+ U_OA_clear(ObjCont);
+ }
+ if(term)printf(" + END Forced Termination of Accumulating object\n");
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SERIALIZABLEOBJECT record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38
+*/
+int U_PMR_SERIALIZABLEOBJECT_print(const char *contents){
+ uint8_t GUID[16];
+ uint32_t Size;
+ const char *Data;
+ char *string=NULL;
+ int iee;
+ int status = U_PMR_SERIALIZABLEOBJECT_get(contents, NULL, &GUID[0], &Size, &Data);
+ if(status){
+ string = U_PMF_CURLYGUID_set(&GUID[0]);
+ if(string){
+ printf(" + GUID:%s Size:%u",string,Size);
+ iee = U_PMF_KNOWNCURLYGUID_set(string); /* overwrites string with short text form */
+ printf("\n + Effect:");
+ free(string);
+ switch(iee){
+ case U_IEE_Unknown: printf("(undefined)\n"); break;
+ case U_IEE_BlurEffectGuid: U_PMF_IE_BLUR_print(Data, Data + sizeof(U_PMF_IE_BLUR)); break;
+ case U_IEE_BrightnessContrastEffectGuid: U_PMF_IE_BRIGHTNESSCONTRAST_print(Data, Data + sizeof(U_PMF_IE_BRIGHTNESSCONTRAST)); break;
+ case U_IEE_ColorBalanceEffectGuid: U_PMF_IE_COLORBALANCE_print(Data, Data + sizeof(U_PMF_IE_COLORBALANCE)); break;
+ case U_IEE_ColorCurveEffectGuid: U_PMF_IE_COLORCURVE_print(Data, Data + sizeof(U_PMF_IE_COLORCURVE)); break;
+ case U_IEE_ColorLookupTableEffectGuid: U_PMF_IE_COLORLOOKUPTABLE_print(Data, Data + sizeof(U_PMF_IE_COLORLOOKUPTABLE)); break;
+ case U_IEE_ColorMatrixEffectGuid: U_PMF_IE_COLORMATRIX_print(Data, Data + sizeof(U_PMF_IE_COLORMATRIX)); break;
+ case U_IEE_HueSaturationLightnessEffectGuid: U_PMF_IE_HUESATURATIONLIGHTNESS_print(Data, Data + sizeof(U_PMF_IE_HUESATURATIONLIGHTNESS)); break;
+ case U_IEE_LevelsEffectGuid: U_PMF_IE_LEVELS_print(Data, Data + sizeof(U_PMF_IE_LEVELS)); break;
+ case U_IEE_RedEyeCorrectionEffectGuid: U_PMF_IE_REDEYECORRECTION_print(Data, Data + sizeof(U_PMF_IE_REDEYECORRECTION)); break;
+ case U_IEE_SharpenEffectGuid: U_PMF_IE_SHARPEN_print(Data, Data + sizeof(U_PMF_IE_SHARPEN)); break;
+ case U_IEE_TintEffectGuid: U_PMF_IE_TINT_print(Data, Data + sizeof(U_PMF_IE_TINT)); break;
+ }
+ }
+ else {
+ printf(" + GUID:ERROR Size:%u\n",Size);
+ }
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETANTIALIASMODE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.1, Microsoft name: EmfPlusSetAntiAliasMode Record, Index 0x1E
+*/
+int U_PMR_SETANTIALIASMODE_print(const char *contents){
+ int SMenum, aatype;
+ int status = U_PMR_SETANTIALIASMODE_get(contents, NULL, &SMenum, &aatype);
+ if(status){
+ printf(" + SMenum:%d AntiAlias:%c\n",SMenum,(aatype ? 'Y' : 'N'));
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETCOMPOSITINGMODE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.2, Microsoft name: EmfPlusSetCompositingMode Record, Index 0x23
+*/
+int U_PMR_SETCOMPOSITINGMODE_print(const char *contents){
+ int CMenum;
+ int status = U_PMR_SETCOMPOSITINGMODE_get(contents, NULL, &CMenum);
+ if(status){
+ printf(" + CMenum:%d\n",CMenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETCOMPOSITINGQUALITY record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.3, Microsoft name: EmfPlusSetCompositingQuality Record, Index 0x24
+*/
+int U_PMR_SETCOMPOSITINGQUALITY_print(const char *contents){
+ int CQenum;
+ int status = U_PMR_SETCOMPOSITINGQUALITY_get(contents, NULL, &CQenum);
+ if(status){
+ printf(" + CQenum:%d\n",CQenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETINTERPOLATIONMODE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.4, Microsoft name: EmfPlusSetInterpolationMode Record, Index 0x21
+*/
+int U_PMR_SETINTERPOLATIONMODE_print(const char *contents){
+ int IMenum;
+ int status = U_PMR_SETINTERPOLATIONMODE_get(contents, NULL, &IMenum);
+ if(status){
+ printf(" + IMenum:%d\n",IMenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETPIXELOFFSETMODE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.5, Microsoft name: EmfPlusSetPixelOffsetMode Record, Index 0x22
+*/
+int U_PMR_SETPIXELOFFSETMODE_print(const char *contents){
+ int POMenum;
+ int status = U_PMR_SETPIXELOFFSETMODE_get(contents, NULL, &POMenum);
+ if(status){
+ printf(" + POMenum:%d\n",POMenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETRENDERINGORIGIN record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.6, Microsoft name: EmfPlusSetRenderingOrigin Record, Index 0x1D
+*/
+int U_PMR_SETRENDERINGORIGIN_print(const char *contents){
+ int32_t X, Y;
+ int status = U_PMR_SETRENDERINGORIGIN_get(contents, NULL, &X, &Y);
+ if(status){
+ printf(" + X:%d Y:%d\n", X, Y);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETTEXTCONTRAST record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.7, Microsoft name: EmfPlusSetTextContrast Record, Index 0x20
+*/
+int U_PMR_SETTEXTCONTRAST_print(const char *contents){
+ int GC;
+ int status = U_PMR_SETTEXTCONTRAST_get(contents, NULL, &GC);
+ if(status){
+ printf(" + GC:%d\n", GC);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETTEXTRENDERINGHINT record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.6.8, Microsoft name: EmfPlusSetTextRenderingHint Record, Index 0x1F
+*/
+int U_PMR_SETTEXTRENDERINGHINT_print(const char *contents){
+ int TRHenum;
+ int status = U_PMR_SETTEXTRENDERINGHINT_get(contents, NULL, &TRHenum);
+ if(status){
+ printf(" + TRHenum:%d\n",TRHenum);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_BEGINCONTAINER record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.7.1, Microsoft name: EmfPlusBeginContainer Record, Index 0x27
+*/
+int U_PMR_BEGINCONTAINER_print(const char *contents){
+ int UTenum;
+ U_PMF_RECTF DstRect, SrcRect;
+ uint32_t StackID;
+ int status = U_PMR_BEGINCONTAINER_get(contents, NULL, &UTenum, &DstRect, &SrcRect, &StackID);
+ if(status){
+ printf(" + UTenum:%d",UTenum);
+ printf(" DstRect:"); (void) U_PMF_RECTF_S_print(&DstRect);
+ printf(" SrcRect:"); (void) U_PMF_RECTF_S_print(&SrcRect);
+ printf(" StackID:%u\n", StackID);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_BEGINCONTAINERNOPARAMS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28
+*/
+int U_PMR_BEGINCONTAINERNOPARAMS_print(const char *contents){
+ uint32_t StackID;
+ int status = U_PMR_BEGINCONTAINERNOPARAMS_get(contents, NULL, &StackID);
+ if(status){
+ printf(" + StackID:%u\n", StackID);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_ENDCONTAINER record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29
+*/
+int U_PMR_ENDCONTAINER_print(const char *contents){
+ uint32_t StackID;
+ int status = U_PMR_ENDCONTAINER_get(contents, NULL, &StackID);
+ if(status){
+ printf(" + StackID:%u\n", StackID);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_RESTORE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26
+*/
+int U_PMR_RESTORE_print(const char *contents){
+ uint32_t StackID;
+ int status = U_PMR_RESTORE_get(contents, NULL, &StackID);
+ if(status){
+ printf(" + StackID:%u\n", StackID);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SAVE record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25
+*/
+int U_PMR_SAVE_print(const char *contents){
+ uint32_t StackID;
+ int status = U_PMR_SAVE_get(contents, NULL, &StackID);
+ if(status){
+ printf(" + StackID:%u\n", StackID);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETTSCLIP record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.8.1, Microsoft name: EmfPlusSetTSClip Record, Index 0x3A
+*/
+int U_PMR_SETTSCLIP_print(const char *contents){
+ int ctype;
+ uint32_t Elements;
+ U_PMF_RECTF *Rects;
+ int status = U_PMR_SETTSCLIP_get(contents, NULL, &ctype, &Elements, &Rects);
+ if(status){
+ printf(" + ctype:%d Elements:%u",ctype,Elements);
+ (void) U_PMF_VARRECTF_S_print(Rects, Elements);
+ free(Rects);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETTSGRAPHICS record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39
+*/
+int U_PMR_SETTSGRAPHICS_print(const char *contents){
+ int vgatype, pptype;
+ uint8_t AntiAliasMode, TextRenderHint, CompositingMode, CompositingQuality, FilterType, PixelOffset;
+ int16_t RenderOriginX, RenderOriginY;
+ uint16_t TextContrast;
+ U_PMF_TRANSFORMMATRIX WorldToDevice;
+ const char *Data;
+ int status = U_PMR_SETTSGRAPHICS_get(contents, NULL,
+ &vgatype, &pptype,
+ &AntiAliasMode, &TextRenderHint, &CompositingMode, &CompositingQuality,
+ &RenderOriginX, &RenderOriginY, &TextContrast, &FilterType,
+ &PixelOffset, &WorldToDevice, &Data);
+ if(status){
+ const char *blimit = contents + status;
+ printf(" + vgatype:%d pptype:%u",vgatype,pptype);
+ printf(" AntiAliasMode:%u TextRenderHint:%u CompositingMode:%u CompositingQuality:%u",
+ AntiAliasMode, TextRenderHint, CompositingMode, CompositingQuality);
+ printf(" RenderOriginX:%d RenderOriginY:%d",RenderOriginX, RenderOriginY);
+ printf(" TextContrast:%u",TextContrast);
+ printf(" WorldToDevice:");
+ U_PMF_TRANSFORMMATRIX2_print(&WorldToDevice);
+ if(pptype && !U_PMF_PALETTE_print(Data, blimit))return(0);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMR_MULTIPLYWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.1, Microsoft name: EmfPlusMultiplyWorldTransform Record, Index 0x2C
+*/
+int U_PMR_MULTIPLYWORLDTRANSFORM_print(const char *contents){
+ int xmtype;
+ U_PMF_TRANSFORMMATRIX Matrix;
+ int status = U_PMR_MULTIPLYWORLDTRANSFORM_get(contents, NULL, &xmtype, &Matrix);
+ if(status){
+ printf(" + xmtype:%d Multiply:%s",xmtype,(xmtype ? "Post" : "Pre"));
+ U_PMF_TRANSFORMMATRIX2_print(&Matrix);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_RESETWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B
+*/
+int U_PMR_RESETWORLDTRANSFORM_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_ROTATEWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.3, Microsoft name: EmfPlusRotateWorldTransform Record, Index 0x2F
+*/
+int U_PMR_ROTATEWORLDTRANSFORM_print(const char *contents){
+ int xmtype;
+ U_FLOAT Angle;
+ int status = U_PMR_ROTATEWORLDTRANSFORM_get(contents, NULL, &xmtype, &Angle);
+ if(status){
+ printf(" + xmtype:%d Multiply:%s Angle:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Angle);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SCALEWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.4, Microsoft name: EmfPlusScaleWorldTransform Record, Index 0x2E
+*/
+int U_PMR_SCALEWORLDTRANSFORM_print(const char *contents){
+ int xmtype;
+ U_FLOAT Sx, Sy;
+ int status = U_PMR_SCALEWORLDTRANSFORM_get(contents, NULL, &xmtype, &Sx, &Sy);
+ if(status){
+ printf(" + xmtype:%d Multiply:%s ScaleX:%f ScaleY:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Sx, Sy);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETPAGETRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.5, Microsoft name: EmfPlusSetPageTransform Record, Index 0x30
+*/
+int U_PMR_SETPAGETRANSFORM_print(const char *contents){
+ int UTenum;
+ U_FLOAT Scale;
+ int status = U_PMR_SETPAGETRANSFORM_get(contents, NULL, &UTenum, &Scale);
+ if(status){
+ printf(" + UTenum:%d Scale:%f\n",UTenum, Scale);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_SETWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.6, Microsoft name: EmfPlusSetWorldTransform Record, Index 0x2A
+*/
+int U_PMR_SETWORLDTRANSFORM_print(const char *contents){
+ U_PMF_TRANSFORMMATRIX Matrix;
+ int status = U_PMR_SETWORLDTRANSFORM_get(contents, NULL, &Matrix);
+ if(status){
+ printf(" + ");
+ U_PMF_TRANSFORMMATRIX2_print(&Matrix);
+ printf("\n");
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+/**
+ \brief Print data from a U_PMR_TRANSLATEWORLDTRANSFORM record
+ \return size of record in bytes on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual 2.3.9.7, Microsoft name: EmfPlusTranslateWorldTransform Record, Index 0x2D
+*/
+int U_PMR_TRANSLATEWORLDTRANSFORM_print(const char *contents){
+ int xmtype;
+ U_FLOAT Dx, Dy;
+ int status = U_PMR_TRANSLATEWORLDTRANSFORM_get(contents, NULL, &xmtype, &Dx, &Dy);
+ if(status){
+ printf(" + xmtype:%d Multiply:%s TranslateX:%f TranlateY:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Dx, Dy);
+ }
+ else {
+ printf(" corrupt record\n");
+ }
+ return(status);
+}
+
+
+/**
+ \brief Print data from a U_PMR_STROKEFILLPATH record
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+*/
+int U_PMR_STROKEFILLPATH_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_MULTIFORMATSTART record
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatStart Record, Index 0x05
+*/
+int U_PMR_MULTIFORMATSTART_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_MULTIFORMATSECTION record
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatSection Record, Index 0x06
+*/
+int U_PMR_MULTIFORMATSECTION_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+/**
+ \brief Print data from a U_PMR_MULTIFORMATEND record
+ \return 1 on success, 0 on error
+ \param contents Record from which to print data
+ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatEnd Record, Index 0x06
+*/
+int U_PMR_MULTIFORMATEND_print(const char *contents){
+ return(U_PMR_NODATAREC_print(contents));
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/upmf_print.h b/src/3rdparty/libuemf/upmf_print.h
new file mode 100644
index 000000000..a25374487
--- /dev/null
+++ b/src/3rdparty/libuemf/upmf_print.h
@@ -0,0 +1,181 @@
+/**
+ @file upmf_print.h
+
+ @brief Prototypes for functions for printing records from EMF files.
+*/
+
+/*
+File: upmf_print.h
+Version: 0.0.5
+Date: 28-APR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UPMF_PRINT_
+#define _UPMF_PRINT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "upmf.h" /* includes uemf.h */
+
+/* prototypes for simple types and enums used in PMR records */
+int U_PMF_CMN_HDR_print(const char *contents, U_PMF_CMN_HDR Header, int precnum, int off);
+int U_PMF_UINT8_ARRAY_print(const char *Start, const uint8_t *Array, int Elements, char *End);
+int U_PMF_BRUSHTYPEENUMERATION_print(int otype);
+int U_PMF_HATCHSTYLEENUMERATION_print(int hstype);
+int U_PMF_OBJECTTYPEENUMERATION_print(int otype);
+int U_PMF_PATHPOINTTYPE_ENUM_print(int Type);
+int U_PMF_PX_FMT_ENUM_print(int pfe);
+int U_PMF_NODETYPE_print(int Type);
+
+/* prototypes for objects used in PMR records */
+int U_PMF_BRUSH_print(const char *contents, const char *blimit);
+int U_PMF_CUSTOMLINECAP_print(const char *contents, const char *Which, const char *blimit);
+int U_PMF_FONT_print(const char *contents, const char *blimit);
+int U_PMF_IMAGE_print(const char *contents, const char *blimit);
+int U_PMF_IMAGEATTRIBUTES_print(const char *contents, const char *blimit);
+int U_PMF_PATH_print(const char *contents, const char *blimit);
+int U_PMF_PEN_print(const char *contents, const char *blimit);
+int U_PMF_REGION_print(const char *contents, const char *blimit);
+int U_PMF_STRINGFORMAT_print(const char *contents, const char *blimit);
+int U_PMF_ARGB_print(const char *contents);
+int U_PMF_BITMAP_print(const char *contents, const char *blimit);
+int U_PMF_BITMAPDATA_print(const char *contents, const char *blimit);
+int U_PMF_BLENDCOLORS_print(const char *contents, const char *blimit);
+int U_PMF_BLENDFACTORS_print(const char *contents, const char *type, const char *blimit);
+int U_PMF_BOUNDARYPATHDATA_print(const char *contents, const char *blimit);
+int U_PMF_BOUNDARYPOINTDATA_print(const char *contents, const char *blimit);
+int U_PMF_CHARACTERRANGE_print(const char *contents, const char *blimit);
+int U_PMF_COMPOUNDLINEDATA_print(const char *contents, const char *blimit);
+int U_PMF_COMPRESSEDIMAGE_print(const char *contents, const char *blimit);
+int U_PMF_CUSTOMENDCAPDATA_print(const char *contents, const char *blimit);
+int U_PMF_CUSTOMLINECAPARROWDATA_print(const char *contents, const char *blimit);
+int U_PMF_CUSTOMLINECAPDATA_print(const char *contents, const char *blimit);
+int U_PMF_CUSTOMLINECAPOPTIONALDATA_print(const char *contents, uint32_t Flags, const char *blimit);
+int U_PMF_CUSTOMSTARTCAPDATA_print(const char *contents, const char *blimit);
+int U_PMF_DASHEDLINEDATA_print(const char *contents, const char *blimit);
+int U_PMF_FILLPATHOBJ_print(const char *contents, const char *blimit);
+int U_PMF_FOCUSSCALEDATA_print(const char *contents, const char *blimit);
+int U_PMF_GRAPHICSVERSION_memsafe_print(const char *contents);
+int U_PMF_GRAPHICSVERSION_print(const char *contents, const char *blimit);
+int U_PMF_HATCHBRUSHDATA_print(const char *contents, const char *blimit);
+int U_PMF_LANGUAGEIDENTIFIER_print(U_PMF_LANGUAGEIDENTIFIER LId);
+int U_PMF_LINEARGRADIENTBRUSHDATA_print(const char *contents, const char *blimit);
+int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit);
+int U_PMF_LINEPATH_print(const char *contents, const char *blimit);
+int U_PMF_METAFILE_print(const char *contents, const char *blimit);
+int U_PMF_PALETTE_print(const char *contents, const char *blimit);
+int U_PMF_PATHGRADIENTBRUSHDATA_print(const char *contents, const char *blimit);
+int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit);
+int U_PMF_PATHPOINTTYPE_print(const char *contents, const char *blimit);
+int U_PMF_PATHPOINTTYPERLE_print(const char *contents, const char *blimit);
+int U_PMF_PENDATA_print(const char *contents, const char *blimit);
+int U_PMF_PENOPTIONALDATA_print(const char *contents, int Flags, const char *blimit);
+int U_PMF_POINT_print(const char **contents, const char *blimit);
+int U_PMF_POINTF_print(const char **contents, const char *blimit);
+int U_PMF_POINTR_print(const char **contents, U_FLOAT *Xpos, U_FLOAT *Ypos, const char *blimit);
+int U_PMF_POINT_S_print(U_PMF_POINT *Point);
+int U_PMF_POINTF_S_print(U_PMF_POINTF *Point);
+int U_PMF_RECT_print(const char **contents, const char *blimit);
+int U_PMF_RECTF_print(const char **contents, const char *blimit);
+int U_PMF_RECT_S_print(U_PMF_RECT *Rect);
+int U_PMF_RECTF_S_print(U_PMF_RECTF *Rect);
+int U_PMF_REGIONNODE_print(const char *contents, int Level, const char *blimit);
+int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level, const char *blimit);
+int U_PMF_REGIONNODEPATH_print(const char *contents, const char *blimit);
+int U_PMF_SOLIDBRUSHDATA_print(const char *contents, const char *blimit);
+int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, const char *blimit);
+int U_PMF_TEXTUREBRUSHDATA_print(const char *contents, const char *blimit);
+int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasMatrix, int HasImage, const char *blimit);
+int U_PMF_TRANSFORMMATRIX_print(const char *contents, const char *blimit);
+int U_PMF_TRANSFORMMATRIX2_print(U_PMF_TRANSFORMMATRIX *Matrix);
+int U_PMF_ROTMATRIX2_print(U_PMF_ROTMATRIX *Matrix);
+int U_PMF_IE_BLUR_print(const char *contents, const char *blimit);
+int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents, const char *blimit);
+int U_PMF_IE_COLORBALANCE_print(const char *contents, const char *blimit);
+int U_PMF_IE_COLORCURVE_print(const char *contents, const char *blimit);
+int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents, const char *blimit);
+int U_PMF_IE_COLORMATRIX_print(const char *contents, const char *blimit);
+int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents, const char *blimit);
+int U_PMF_IE_LEVELS_print(const char *contents, const char *blimit);
+int U_PMF_IE_REDEYECORRECTION_print(const char *contents, const char *blimit);
+int U_PMF_IE_SHARPEN_print(const char *contents, const char *blimit);
+int U_PMF_IE_TINT_print(const char *contents, const char *blimit);
+
+/* prototypes for PMR records */
+int U_PMR_OFFSETCLIP_print(const char *contents);
+int U_PMR_RESETCLIP_print(const char *contents);
+int U_PMR_SETCLIPPATH_print(const char *contents);
+int U_PMR_SETCLIPRECT_print(const char *contents);
+int U_PMR_SETCLIPREGION_print(const char *contents);
+int U_PMR_COMMENT_print(const char *contents);
+int U_PMR_ENDOFFILE_print(const char *contents);
+int U_PMR_GETDC_print(const char *contents);
+int U_PMR_HEADER_print(const char *contents);
+int U_PMR_CLEAR_print(const char *contents);
+int U_PMR_DRAWARC_print(const char *contents);
+int U_PMR_DRAWBEZIERS_print(const char *contents);
+int U_PMR_DRAWCLOSEDCURVE_print(const char *contents);
+int U_PMR_DRAWCURVE_print(const char *contents);
+int U_PMR_DRAWDRIVERSTRING_print(const char *contents);
+int U_PMR_DRAWELLIPSE_print(const char *contents);
+int U_PMR_DRAWIMAGE_print(const char *contents);
+int U_PMR_DRAWIMAGEPOINTS_print(const char *contents);
+int U_PMR_DRAWLINES_print(const char *contents);
+int U_PMR_DRAWPATH_print(const char *contents);
+int U_PMR_DRAWPIE_print(const char *contents);
+int U_PMR_DRAWRECTS_print(const char *contents);
+int U_PMR_DRAWSTRING_print(const char *contents);
+int U_PMR_FILLCLOSEDCURVE_print(const char *contents);
+int U_PMR_FILLELLIPSE_print(const char *contents);
+int U_PMR_FILLPATH_print(const char *contents);
+int U_PMR_FILLPIE_print(const char *contents);
+int U_PMR_FILLPOLYGON_print(const char *contents);
+int U_PMR_FILLRECTS_print(const char *contents);
+int U_PMR_FILLREGION_print(const char *contents);
+int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *ObjCont, int term);
+int U_PMR_SERIALIZABLEOBJECT_print(const char *contents);
+int U_PMR_SETANTIALIASMODE_print(const char *contents);
+int U_PMR_SETCOMPOSITINGMODE_print(const char *contents);
+int U_PMR_SETCOMPOSITINGQUALITY_print(const char *contents);
+int U_PMR_SETINTERPOLATIONMODE_print(const char *contents);
+int U_PMR_SETPIXELOFFSETMODE_print(const char *contents);
+int U_PMR_SETRENDERINGORIGIN_print(const char *contents);
+int U_PMR_SETTEXTCONTRAST_print(const char *contents);
+int U_PMR_SETTEXTRENDERINGHINT_print(const char *contents);
+int U_PMR_BEGINCONTAINER_print(const char *contents);
+int U_PMR_BEGINCONTAINERNOPARAMS_print(const char *contents);
+int U_PMR_ENDCONTAINER_print(const char *contents);
+int U_PMR_RESTORE_print(const char *contents);
+int U_PMR_SAVE_print(const char *contents);
+int U_PMR_SETTSCLIP_print(const char *contents);
+int U_PMR_SETTSGRAPHICS_print(const char *contents);
+int U_PMR_MULTIPLYWORLDTRANSFORM_print(const char *contents);
+int U_PMR_RESETWORLDTRANSFORM_print(const char *contents);
+int U_PMR_ROTATEWORLDTRANSFORM_print(const char *contents);
+int U_PMR_SCALEWORLDTRANSFORM_print(const char *contents);
+int U_PMR_SETPAGETRANSFORM_print(const char *contents);
+int U_PMR_SETWORLDTRANSFORM_print(const char *contents);
+int U_PMR_TRANSLATEWORLDTRANSFORM_print(const char *contents);
+int U_PMR_STROKEFILLPATH_print(const char *contents); /* not documented */
+int U_PMR_MULTIFORMATSTART_print(const char *contents); /* last of reserved but not used */
+int U_PMR_MULTIFORMATSECTION_print(const char *contents); /* last of reserved but not used */
+int U_PMR_MULTIFORMATEND_print(const char *contents); /* last of reserved but not used */
+
+int U_pmf_onerec_print(const char *contents, const char *blimit, int recnum, int off);
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UPMF_PRINT_ */
diff --git a/src/3rdparty/libuemf/uwmf.c b/src/3rdparty/libuemf/uwmf.c
new file mode 100644
index 000000000..50e4075d8
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf.c
@@ -0,0 +1,7039 @@
+/**
+ @file uwmf.c
+
+ @brief Functions for manipulating WMF files and structures.
+
+ [U_WMR*]_set all take data and return a pointer to memory holding the constructed record.
+ If something goes wrong a NULL pointer is returned.
+ [U_WMR*]_get takes a pointer to memory and returns the length of that record as well
+ as the values from it (in the provided fields, passed by reference.)
+ If something goes wrong, a size of 0 is returned.
+
+ The _set material comes first, then all of the _get material.
+
+ Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for
+ uninitialized data.
+
+ Compile with "SOL8" defined for Solaris 8 or 9 (Sparc).
+*/
+
+/*
+File: uwmf.c
+Version: 0.0.17
+Date: 28-MAR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2014 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h> /* for offsetof() */
+#include <string.h>
+#include <iconv.h>
+#include <wchar.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h> // for INT_MAX, INT_MIN
+#include <math.h> // for U_ROUND()
+#if 0
+#include <windef.h> //Not actually used, looking for collisions
+#include <winnt.h> //Not actually used, looking for collisions
+#include <wingdi.h> //Not actually used, looking for collisions
+#endif
+#include "uwmf.h"
+#include "uwmf_endian.h"
+#include "uemf_safe.h"
+
+/**
+ \brief Look up the full numeric type of a WMR record by type.
+
+ \return Full numeric value for this type of WMR record, Returns 0xFFFFFFFF if out of range.
+ \param idx WMR record type.
+
+*/
+uint32_t U_wmr_values(int idx){
+ int ret;
+ int U_WMR_VALUES[256]={
+ 0x0000, //!< U_WMR_EOF
+ 0x0201, //!< U_WMR_SETBKCOLOR
+ 0x0102, //!< U_WMR_SETBKMODE
+ 0x0103, //!< U_WMR_SETMAPMODE
+ 0x0104, //!< U_WMR_SETROP2
+ 0x0105, //!< U_WMR_SETRELABS
+ 0x0106, //!< U_WMR_SETPOLYFILLMODE
+ 0x0107, //!< U_WMR_SETSTRETCHBLTMODE
+ 0x0108, //!< U_WMR_SETTEXTCHAREXTRA
+ 0x0209, //!< U_WMR_SETTEXTCOLOR
+ 0x020A, //!< U_WMR_SETTEXTJUSTIFICATION
+ 0x020B, //!< U_WMR_SETWINDOWORG
+ 0x020C, //!< U_WMR_SETWINDOWEXT
+ 0x020D, //!< U_WMR_SETVIEWPORTORG
+ 0x020E, //!< U_WMR_SETVIEWPORTEXT
+ 0x020F, //!< U_WMR_OFFSETWINDOWORG
+ 0x0410, //!< U_WMR_SCALEWINDOWEXT
+ 0x0211, //!< U_WMR_OFFSETVIEWPORTORG
+ 0x0412, //!< U_WMR_SCALEVIEWPORTEXT
+ 0x0213, //!< U_WMR_LINETO
+ 0x0214, //!< U_WMR_MOVETO
+ 0x0415, //!< U_WMR_EXCLUDECLIPRECT
+ 0x0416, //!< U_WMR_INTERSECTCLIPRECT
+ 0x0817, //!< U_WMR_ARC
+ 0x0418, //!< U_WMR_ELLIPSE
+ 0x0419, //!< U_WMR_FLOODFILL
+ 0x081A, //!< U_WMR_PIE
+ 0x041B, //!< U_WMR_RECTANGLE
+ 0x061C, //!< U_WMR_ROUNDRECT
+ 0x061D, //!< U_WMR_PATBLT
+ 0x001E, //!< U_WMR_SAVEDC
+ 0x041F, //!< U_WMR_SETPIXEL
+ 0x0220, //!< U_WMR_OFFSETCLIPRGN
+ 0x0521, //!< U_WMR_TEXTOUT
+ 0x0922, //!< U_WMR_BITBLT
+ 0x0B23, //!< U_WMR_STRETCHBLT
+ 0x0324, //!< U_WMR_POLYGON
+ 0x0325, //!< U_WMR_POLYLINE
+ 0x0626, //!< U_WMR_ESCAPE
+ 0x0127, //!< U_WMR_RESTOREDC
+ 0x0228, //!< U_WMR_FILLREGION
+ 0x0429, //!< U_WMR_FRAMEREGION
+ 0x012A, //!< U_WMR_INVERTREGION
+ 0x012B, //!< U_WMR_PAINTREGION
+ 0x012C, //!< U_WMR_SELECTCLIPREGION
+ 0x012D, //!< U_WMR_SELECTOBJECT
+ 0x012E, //!< U_WMR_SETTEXTALIGN
+ 0x062F, //!< U_WMR_DRAWTEXT
+ 0x0830, //!< U_WMR_CHORD
+ 0x0231, //!< U_WMR_SETMAPPERFLAGS
+ 0x0A32, //!< U_WMR_EXTTEXTOUT
+ 0x0D33, //!< U_WMR_SETDIBTODEV
+ 0x0234, //!< U_WMR_SELECTPALETTE
+ 0x0035, //!< U_WMR_REALIZEPALETTE
+ 0x0436, //!< U_WMR_ANIMATEPALETTE
+ 0x0037, //!< U_WMR_SETPALENTRIES
+ 0x0538, //!< U_WMR_POLYPOLYGON
+ 0x0139, //!< U_WMR_RESIZEPALETTE
+ 0x003A, //!< U_WMR_3A
+ 0x003B, //!< U_WMR_3B
+ 0x003C, //!< U_WMR_3C
+ 0x003D, //!< U_WMR_3D
+ 0x003E, //!< U_WMR_3E
+ 0x003F, //!< U_WMR_3F
+ 0x0940, //!< U_WMR_DIBBITBLT
+ 0x0B41, //!< U_WMR_DIBSTRETCHBLT
+ 0x0142, //!< U_WMR_DIBCREATEPATTERNBRUSH
+ 0x0F43, //!< U_WMR_STRETCHDIB
+ 0x0044, //!< U_WMR_44
+ 0x0045, //!< U_WMR_45
+ 0x0046, //!< U_WMR_46
+ 0x0047, //!< U_WMR_47
+ 0x0548, //!< U_WMR_EXTFLOODFILL
+ 0x0049, //!< U_WMR_49
+ 0x004A, //!< U_WMR_4A
+ 0x004B, //!< U_WMR_4B
+ 0x014C, //!< U_WMR_4C
+ 0x014D, //!< U_WMR_4D
+ 0x004E, //!< U_WMR_4E
+ 0x004F, //!< U_WMR_4F
+ 0x0050, //!< U_WMR_50
+ 0x0051, //!< U_WMR_51
+ 0x0052, //!< U_WMR_52
+ 0x0053, //!< U_WMR_53
+ 0x0054, //!< U_WMR_54
+ 0x0055, //!< U_WMR_55
+ 0x0056, //!< U_WMR_56
+ 0x0057, //!< U_WMR_57
+ 0x0058, //!< U_WMR_58
+ 0x0059, //!< U_WMR_59
+ 0x005A, //!< U_WMR_5A
+ 0x005B, //!< U_WMR_5B
+ 0x005C, //!< U_WMR_5C
+ 0x005D, //!< U_WMR_5D
+ 0x005E, //!< U_WMR_5E
+ 0x005F, //!< U_WMR_5F
+ 0x0060, //!< U_WMR_60
+ 0x0061, //!< U_WMR_61
+ 0x0062, //!< U_WMR_62
+ 0x0063, //!< U_WMR_63
+ 0x0064, //!< U_WMR_64
+ 0x0065, //!< U_WMR_65
+ 0x0066, //!< U_WMR_66
+ 0x0067, //!< U_WMR_67
+ 0x0068, //!< U_WMR_68
+ 0x0069, //!< U_WMR_69
+ 0x006A, //!< U_WMR_6A
+ 0x006B, //!< U_WMR_6B
+ 0x006C, //!< U_WMR_6C
+ 0x006D, //!< U_WMR_6D
+ 0x006E, //!< U_WMR_6E
+ 0x006F, //!< U_WMR_6F
+ 0x0070, //!< U_WMR_70
+ 0x0071, //!< U_WMR_71
+ 0x0072, //!< U_WMR_72
+ 0x0073, //!< U_WMR_73
+ 0x0074, //!< U_WMR_74
+ 0x0075, //!< U_WMR_75
+ 0x0076, //!< U_WMR_76
+ 0x0077, //!< U_WMR_77
+ 0x0078, //!< U_WMR_78
+ 0x0079, //!< U_WMR_79
+ 0x007A, //!< U_WMR_7A
+ 0x007B, //!< U_WMR_7B
+ 0x007C, //!< U_WMR_7C
+ 0x007D, //!< U_WMR_7D
+ 0x007E, //!< U_WMR_7E
+ 0x007F, //!< U_WMR_7F
+ 0x0080, //!< U_WMR_80
+ 0x0081, //!< U_WMR_81
+ 0x0082, //!< U_WMR_82
+ 0x0083, //!< U_WMR_83
+ 0x0084, //!< U_WMR_84
+ 0x0085, //!< U_WMR_85
+ 0x0086, //!< U_WMR_86
+ 0x0087, //!< U_WMR_87
+ 0x0088, //!< U_WMR_88
+ 0x0089, //!< U_WMR_89
+ 0x008A, //!< U_WMR_8A
+ 0x008B, //!< U_WMR_8B
+ 0x008C, //!< U_WMR_8C
+ 0x008D, //!< U_WMR_8D
+ 0x008E, //!< U_WMR_8E
+ 0x008F, //!< U_WMR_8F
+ 0x0090, //!< U_WMR_90
+ 0x0091, //!< U_WMR_91
+ 0x0092, //!< U_WMR_92
+ 0x0093, //!< U_WMR_93
+ 0x0094, //!< U_WMR_94
+ 0x0095, //!< U_WMR_95
+ 0x0096, //!< U_WMR_96
+ 0x0097, //!< U_WMR_97
+ 0x0098, //!< U_WMR_98
+ 0x0099, //!< U_WMR_99
+ 0x009A, //!< U_WMR_9A
+ 0x009B, //!< U_WMR_9B
+ 0x009C, //!< U_WMR_9C
+ 0x009D, //!< U_WMR_9D
+ 0x009E, //!< U_WMR_9E
+ 0x009F, //!< U_WMR_9F
+ 0x00A0, //!< U_WMR_A0
+ 0x00A1, //!< U_WMR_A1
+ 0x00A2, //!< U_WMR_A2
+ 0x00A3, //!< U_WMR_A3
+ 0x00A4, //!< U_WMR_A4
+ 0x00A5, //!< U_WMR_A5
+ 0x00A6, //!< U_WMR_A6
+ 0x00A7, //!< U_WMR_A7
+ 0x00A8, //!< U_WMR_A8
+ 0x00A9, //!< U_WMR_A9
+ 0x00AA, //!< U_WMR_AA
+ 0x00AB, //!< U_WMR_AB
+ 0x00AC, //!< U_WMR_AC
+ 0x00AD, //!< U_WMR_AD
+ 0x00AE, //!< U_WMR_AE
+ 0x00AF, //!< U_WMR_AF
+ 0x00B0, //!< U_WMR_B0
+ 0x00B1, //!< U_WMR_B1
+ 0x00B2, //!< U_WMR_B2
+ 0x00B3, //!< U_WMR_B3
+ 0x00B4, //!< U_WMR_B4
+ 0x00B5, //!< U_WMR_B5
+ 0x00B6, //!< U_WMR_B6
+ 0x00B7, //!< U_WMR_B7
+ 0x00B8, //!< U_WMR_B8
+ 0x00B9, //!< U_WMR_B9
+ 0x00BA, //!< U_WMR_BA
+ 0x00BB, //!< U_WMR_BB
+ 0x00BC, //!< U_WMR_BC
+ 0x00BD, //!< U_WMR_BD
+ 0x00BE, //!< U_WMR_BE
+ 0x00BF, //!< U_WMR_BF
+ 0x00C0, //!< U_WMR_C0
+ 0x00C1, //!< U_WMR_C1
+ 0x00C2, //!< U_WMR_C2
+ 0x00C3, //!< U_WMR_C3
+ 0x00C4, //!< U_WMR_C4
+ 0x00C5, //!< U_WMR_C5
+ 0x00C6, //!< U_WMR_C6
+ 0x00C7, //!< U_WMR_C7
+ 0x00C8, //!< U_WMR_C8
+ 0x00C9, //!< U_WMR_C9
+ 0x00CA, //!< U_WMR_CA
+ 0x00CB, //!< U_WMR_CB
+ 0x00CC, //!< U_WMR_CC
+ 0x00CD, //!< U_WMR_CD
+ 0x00CE, //!< U_WMR_CE
+ 0x00CF, //!< U_WMR_CF
+ 0x00D0, //!< U_WMR_D0
+ 0x00D1, //!< U_WMR_D1
+ 0x00D2, //!< U_WMR_D2
+ 0x00D3, //!< U_WMR_D3
+ 0x00D4, //!< U_WMR_D4
+ 0x00D5, //!< U_WMR_D5
+ 0x00D6, //!< U_WMR_D6
+ 0x00D7, //!< U_WMR_D7
+ 0x00D8, //!< U_WMR_D8
+ 0x00D9, //!< U_WMR_D9
+ 0x00DA, //!< U_WMR_DA
+ 0x00DB, //!< U_WMR_DB
+ 0x00DC, //!< U_WMR_DC
+ 0x00DD, //!< U_WMR_DD
+ 0x00DE, //!< U_WMR_DE
+ 0x00DF, //!< U_WMR_DF
+ 0x00E0, //!< U_WMR_E0
+ 0x00E1, //!< U_WMR_E1
+ 0x00E2, //!< U_WMR_E2
+ 0x00E3, //!< U_WMR_E3
+ 0x00E4, //!< U_WMR_E4
+ 0x00E5, //!< U_WMR_E5
+ 0x00E6, //!< U_WMR_E6
+ 0x00E7, //!< U_WMR_E7
+ 0x00E8, //!< U_WMR_E8
+ 0x00E9, //!< U_WMR_E9
+ 0x00EA, //!< U_WMR_EA
+ 0x00EB, //!< U_WMR_EB
+ 0x00EC, //!< U_WMR_EC
+ 0x00ED, //!< U_WMR_ED
+ 0x00EE, //!< U_WMR_EE
+ 0x00EF, //!< U_WMR_EF
+ 0x01F0, //!< U_WMR_DELETEOBJECT
+ 0x00F1, //!< U_WMR_F1
+ 0x00F2, //!< U_WMR_F2
+ 0x00F3, //!< U_WMR_F3
+ 0x00F4, //!< U_WMR_F4
+ 0x00F5, //!< U_WMR_F5
+ 0x00F6, //!< U_WMR_F6
+ 0x00F7, //!< U_WMR_CREATEPALETTE
+ 0x00F8, //!< U_WMR_CREATEBRUSH
+ 0x01F9, //!< U_WMR_CREATEPATTERNBRUSH
+ 0x02FA, //!< U_WMR_CREATEPENINDIRECT
+ 0x02FB, //!< U_WMR_CREATEFONTINDIRECT
+ 0x02FC, //!< U_WMR_CREATEBRUSHINDIRECT
+ 0x02FD, //!< U_WMR_CREATEBITMAPINDIRECT
+ 0x06FE, //!< U_WMR_CREATEBITMAP
+ 0x06FF //!< U_WMR_CREATEREGION
+ };
+ if(idx<U_WMR_MIN || idx > U_WMR_MAX){ ret = 0xFFFFFFFF; }
+ else { ret = U_WMR_VALUES[idx]; }
+ return(ret);
+}
+
+/**
+ \brief Look up the name of the WMR record by type. Returns U_WMR_INVALID if out of range.
+
+ \return name of the WMR record, "U_WMR_INVALID" if out of range.
+ \param idx WMR record type.
+
+*/
+const char *U_wmr_names(int idx){
+ int ret;
+ static const char *U_WMR_NAMES[257]={
+ "U_WMR_EOF",
+ "U_WMR_SETBKCOLOR",
+ "U_WMR_SETBKMODE",
+ "U_WMR_SETMAPMODE",
+ "U_WMR_SETROP2",
+ "U_WMR_SETRELABS",
+ "U_WMR_SETPOLYFILLMODE",
+ "U_WMR_SETSTRETCHBLTMODE",
+ "U_WMR_SETTEXTCHAREXTRA",
+ "U_WMR_SETTEXTCOLOR",
+ "U_WMR_SETTEXTJUSTIFICATION",
+ "U_WMR_SETWINDOWORG",
+ "U_WMR_SETWINDOWEXT",
+ "U_WMR_SETVIEWPORTORG",
+ "U_WMR_SETVIEWPORTEXT",
+ "U_WMR_OFFSETWINDOWORG",
+ "U_WMR_SCALEWINDOWEXT",
+ "U_WMR_OFFSETVIEWPORTORG",
+ "U_WMR_SCALEVIEWPORTEXT",
+ "U_WMR_LINETO",
+ "U_WMR_MOVETO",
+ "U_WMR_EXCLUDECLIPRECT",
+ "U_WMR_INTERSECTCLIPRECT",
+ "U_WMR_ARC",
+ "U_WMR_ELLIPSE",
+ "U_WMR_FLOODFILL",
+ "U_WMR_PIE",
+ "U_WMR_RECTANGLE",
+ "U_WMR_ROUNDRECT",
+ "U_WMR_PATBLT",
+ "U_WMR_SAVEDC",
+ "U_WMR_SETPIXEL",
+ "U_WMR_OFFSETCLIPRGN",
+ "U_WMR_TEXTOUT",
+ "U_WMR_BITBLT",
+ "U_WMR_STRETCHBLT",
+ "U_WMR_POLYGON",
+ "U_WMR_POLYLINE",
+ "U_WMR_ESCAPE",
+ "U_WMR_RESTOREDC",
+ "U_WMR_FILLREGION",
+ "U_WMR_FRAMEREGION",
+ "U_WMR_INVERTREGION",
+ "U_WMR_PAINTREGION",
+ "U_WMR_SELECTCLIPREGION",
+ "U_WMR_SELECTOBJECT",
+ "U_WMR_SETTEXTALIGN",
+ "U_WMR_DRAWTEXT",
+ "U_WMR_CHORD",
+ "U_WMR_SETMAPPERFLAGS",
+ "U_WMR_EXTTEXTOUT",
+ "U_WMR_SETDIBTODEV",
+ "U_WMR_SELECTPALETTE",
+ "U_WMR_REALIZEPALETTE",
+ "U_WMR_ANIMATEPALETTE",
+ "U_WMR_SETPALENTRIES",
+ "U_WMR_POLYPOLYGON",
+ "U_WMR_RESIZEPALETTE",
+ "U_WMR_3A",
+ "U_WMR_3B",
+ "U_WMR_3C",
+ "U_WMR_3D",
+ "U_WMR_3E",
+ "U_WMR_3F",
+ "U_WMR_DIBBITBLT",
+ "U_WMR_DIBSTRETCHBLT",
+ "U_WMR_DIBCREATEPATTERNBRUSH",
+ "U_WMR_STRETCHDIB",
+ "U_WMR_44",
+ "U_WMR_45",
+ "U_WMR_46",
+ "U_WMR_47",
+ "U_WMR_EXTFLOODFILL",
+ "U_WMR_49",
+ "U_WMR_4A",
+ "U_WMR_4B",
+ "U_WMR_4C",
+ "U_WMR_4D",
+ "U_WMR_4E",
+ "U_WMR_4F",
+ "U_WMR_50",
+ "U_WMR_51",
+ "U_WMR_52",
+ "U_WMR_53",
+ "U_WMR_54",
+ "U_WMR_55",
+ "U_WMR_56",
+ "U_WMR_57",
+ "U_WMR_58",
+ "U_WMR_59",
+ "U_WMR_5A",
+ "U_WMR_5B",
+ "U_WMR_5C",
+ "U_WMR_5D",
+ "U_WMR_5E",
+ "U_WMR_5F",
+ "U_WMR_60",
+ "U_WMR_61",
+ "U_WMR_62",
+ "U_WMR_63",
+ "U_WMR_64",
+ "U_WMR_65",
+ "U_WMR_66",
+ "U_WMR_67",
+ "U_WMR_68",
+ "U_WMR_69",
+ "U_WMR_6A",
+ "U_WMR_6B",
+ "U_WMR_6C",
+ "U_WMR_6D",
+ "U_WMR_6E",
+ "U_WMR_6F",
+ "U_WMR_70",
+ "U_WMR_71",
+ "U_WMR_72",
+ "U_WMR_73",
+ "U_WMR_74",
+ "U_WMR_75",
+ "U_WMR_76",
+ "U_WMR_77",
+ "U_WMR_78",
+ "U_WMR_79",
+ "U_WMR_7A",
+ "U_WMR_7B",
+ "U_WMR_7C",
+ "U_WMR_7D",
+ "U_WMR_7E",
+ "U_WMR_7F",
+ "U_WMR_80",
+ "U_WMR_81",
+ "U_WMR_82",
+ "U_WMR_83",
+ "U_WMR_84",
+ "U_WMR_85",
+ "U_WMR_86",
+ "U_WMR_87",
+ "U_WMR_88",
+ "U_WMR_89",
+ "U_WMR_8A",
+ "U_WMR_8B",
+ "U_WMR_8C",
+ "U_WMR_8D",
+ "U_WMR_8E",
+ "U_WMR_8F",
+ "U_WMR_90",
+ "U_WMR_91",
+ "U_WMR_92",
+ "U_WMR_93",
+ "U_WMR_94",
+ "U_WMR_95",
+ "U_WMR_96",
+ "U_WMR_97",
+ "U_WMR_98",
+ "U_WMR_99",
+ "U_WMR_9A",
+ "U_WMR_9B",
+ "U_WMR_9C",
+ "U_WMR_9D",
+ "U_WMR_9E",
+ "U_WMR_9F",
+ "U_WMR_A0",
+ "U_WMR_A1",
+ "U_WMR_A2",
+ "U_WMR_A3",
+ "U_WMR_A4",
+ "U_WMR_A5",
+ "U_WMR_A6",
+ "U_WMR_A7",
+ "U_WMR_A8",
+ "U_WMR_A9",
+ "U_WMR_AA",
+ "U_WMR_AB",
+ "U_WMR_AC",
+ "U_WMR_AD",
+ "U_WMR_AE",
+ "U_WMR_AF",
+ "U_WMR_B0",
+ "U_WMR_B1",
+ "U_WMR_B2",
+ "U_WMR_B3",
+ "U_WMR_B4",
+ "U_WMR_B5",
+ "U_WMR_B6",
+ "U_WMR_B7",
+ "U_WMR_B8",
+ "U_WMR_B9",
+ "U_WMR_BA",
+ "U_WMR_BB",
+ "U_WMR_BC",
+ "U_WMR_BD",
+ "U_WMR_BE",
+ "U_WMR_BF",
+ "U_WMR_C0",
+ "U_WMR_C1",
+ "U_WMR_C2",
+ "U_WMR_C3",
+ "U_WMR_C4",
+ "U_WMR_C5",
+ "U_WMR_C6",
+ "U_WMR_C7",
+ "U_WMR_C8",
+ "U_WMR_C9",
+ "U_WMR_CA",
+ "U_WMR_CB",
+ "U_WMR_CC",
+ "U_WMR_CD",
+ "U_WMR_CE",
+ "U_WMR_CF",
+ "U_WMR_D0",
+ "U_WMR_D1",
+ "U_WMR_D2",
+ "U_WMR_D3",
+ "U_WMR_D4",
+ "U_WMR_D5",
+ "U_WMR_D6",
+ "U_WMR_D7",
+ "U_WMR_D8",
+ "U_WMR_D9",
+ "U_WMR_DA",
+ "U_WMR_DB",
+ "U_WMR_DC",
+ "U_WMR_DD",
+ "U_WMR_DE",
+ "U_WMR_DF",
+ "U_WMR_E0",
+ "U_WMR_E1",
+ "U_WMR_E2",
+ "U_WMR_E3",
+ "U_WMR_E4",
+ "U_WMR_E5",
+ "U_WMR_E6",
+ "U_WMR_E7",
+ "U_WMR_E8",
+ "U_WMR_E9",
+ "U_WMR_EA",
+ "U_WMR_EB",
+ "U_WMR_EC",
+ "U_WMR_ED",
+ "U_WMR_EE",
+ "U_WMR_EF",
+ "U_WMR_DELETEOBJECT",
+ "U_WMR_F1",
+ "U_WMR_F2",
+ "U_WMR_F3",
+ "U_WMR_F4",
+ "U_WMR_F5",
+ "U_WMR_F6",
+ "U_WMR_CREATEPALETTE",
+ "U_WMR_CREATEBRUSH",
+ "U_WMR_CREATEPATTERNBRUSH",
+ "U_WMR_CREATEPENINDIRECT",
+ "U_WMR_CREATEFONTINDIRECT",
+ "U_WMR_CREATEBRUSHINDIRECT",
+ "U_WMR_CREATEBITMAPINDIRECT",
+ "U_WMR_CREATEBITMAP",
+ "U_WMR_CREATEREGION"
+ };
+ if(idx<U_WMR_MIN || idx > U_WMR_MAX){ ret = 256; }
+ else { ret = idx; }
+ return(U_WMR_NAMES[ret]);
+}
+
+/**
+ \brief Text description of Escape record type.
+ \return name of the WMR record, "UNKNOWN_ESCAPE" if out of range.
+ \param idx Escape record type.
+*/
+const char *U_wmr_escnames(int idx){
+ const char *name;
+ if(idx>=1 && idx <= 0x0023){
+ switch(idx){
+ case 0x0001: name = "NEWFRAME"; break;
+ case 0x0002: name = "ABORTDOC"; break;
+ case 0x0003: name = "NEXTBAND"; break;
+ case 0x0004: name = "SETCOLORTABLE"; break;
+ case 0x0005: name = "GETCOLORTABLE"; break;
+ case 0x0006: name = "FLUSHOUT"; break;
+ case 0x0007: name = "DRAFTMODE"; break;
+ case 0x0008: name = "QUERYESCSUPPORT"; break;
+ case 0x0009: name = "SETABORTPROC"; break;
+ case 0x000A: name = "STARTDOC"; break;
+ case 0x000B: name = "ENDDOC"; break;
+ case 0x000C: name = "GETPHYSPAGESIZE"; break;
+ case 0x000D: name = "GETPRINTINGOFFSET"; break;
+ case 0x000E: name = "GETSCALINGFACTOR"; break;
+ case 0x000F: name = "META_ESCAPE_ENHANCED_METAFILE"; break;
+ case 0x0010: name = "SETPENWIDTH"; break;
+ case 0x0011: name = "SETCOPYCOUNT"; break;
+ case 0x0012: name = "SETPAPERSOURCE"; break;
+ case 0x0013: name = "PASSTHROUGH"; break;
+ case 0x0014: name = "GETTECHNOLOGY"; break;
+ case 0x0015: name = "SETLINECAP"; break;
+ case 0x0016: name = "SETLINEJOIN"; break;
+ case 0x0017: name = "SETMITERLIMIT"; break;
+ case 0x0018: name = "BANDINFO"; break;
+ case 0x0019: name = "DRAWPATTERNRECT"; break;
+ case 0x001A: name = "GETVECTORPENSIZE"; break;
+ case 0x001B: name = "GETVECTORBRUSHSIZE"; break;
+ case 0x001C: name = "ENABLEDUPLEX"; break;
+ case 0x001D: name = "GETSETPAPERBINS"; break;
+ case 0x001E: name = "GETSETPRINTORIENT"; break;
+ case 0x001F: name = "ENUMPAPERBINS"; break;
+ case 0x0020: name = "SETDIBSCALING"; break;
+ case 0x0021: name = "EPSPRINTING"; break;
+ case 0x0022: name = "ENUMPAPERMETRICS"; break;
+ case 0x0023: name = "GETSETPAPERMETRICS"; break;
+ }
+ }
+ else if(idx == 0x0025){ name = "POSTSCRIPT_DATA"; }
+ else if(idx == 0x0026){ name = "POSTSCRIPT_IGNORE"; }
+ else if(idx == 0x002A){ name = "GETDEVICEUNITS"; }
+ else if(idx == 0x0100){ name = "GETEXTENDEDTEXTMETRICS"; }
+ else if(idx == 0x0102){ name = "GETPAIRKERNTABLE"; }
+ else if(idx == 0x0200){ name = "EXTTEXTOUT"; }
+ else if(idx == 0x0201){ name = "GETFACENAME"; }
+ else if(idx == 0x0202){ name = "DOWNLOADFACE"; }
+ else if(idx == 0x0801){ name = "METAFILE_DRIVER"; }
+ else if(idx == 0x0C01){ name = "QUERYDIBSUPPORT"; }
+ else if(idx == 0x1000){ name = "BEGIN_PATH"; }
+ else if(idx == 0x1001){ name = "CLIP_TO_PATH"; }
+ else if(idx == 0x1002){ name = "END_PATH"; }
+ else if(idx == 0x100E){ name = "OPEN_CHANNEL"; }
+ else if(idx == 0x100F){ name = "DOWNLOADHEADER"; }
+ else if(idx == 0x1010){ name = "CLOSE_CHANNEL"; }
+ else if(idx == 0x1013){ name = "POSTSCRIPT_PASSTHROUGH"; }
+ else if(idx == 0x1014){ name = "ENCAPSULATED_POSTSCRIPT";}
+ else if(idx == 0x1015){ name = "POSTSCRIPT_IDENTIFY"; }
+ else if(idx == 0x1016){ name = "POSTSCRIPT_INJECTION"; }
+ else if(idx == 0x1017){ name = "CHECKJPEGFORMAT"; }
+ else if(idx == 0x1018){ name = "CHECKPNGFORMAT"; }
+ else if(idx == 0x1019){ name = "GET_PS_FEATURESETTING"; }
+ else if(idx == 0x101A){ name = "MXDC_ESCAPE"; }
+ else if(idx == 0x11D8){ name = "SPCLPASSTHROUGH2"; }
+ else { name = "UNKNOWN_ESCAPE"; }
+ return(name);
+}
+
+//! \cond
+/* one prototype from uwmf_endian. Put it here because end user should never need to see it, so
+not in uemf.h or uwmf_endian.h */
+void U_swap2(void *ul, unsigned int count);
+
+/**
+ \brief Check that the bitmap in the specified packed DIB is compatible with the record size
+
+ \return 1 on success, 0 on failure
+ \param record EMF record that contains a DIB pixel array
+ \param blimit one byte past the end of the record.
+
+ This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag
+ of bytes, and there is no possible way to derive from the known width and height how big it should be.
+
+ This should not be called directly by end user code.
+*/
+int packed_DIB_safe(
+ const char *record,
+ const char *blimit
+ ){
+ int dibparams = U_BI_UNKNOWN; // type of image not yet determined
+ const char *px = NULL; // DIB pixels
+ const U_RGBQUAD *ct = NULL; // DIB color table
+ int bs;
+ int usedbytes;
+
+ if(!bitmapinfo_safe(record, blimit))return(0); // this DIB has issues with colors fitting into the record
+ uint32_t numCt; // these values will be set in get_DIB_params
+ int32_t width, height, colortype, invert; // these values will be set in get_DIB_params
+ // next call returns pointers and values, but allocates no memory
+ dibparams = wget_DIB_params(record, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert);
+ // sanity checking
+ if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels
+ if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit
+
+ if(dibparams ==U_BI_RGB){
+ // this is the only DIB type where we can calculate how big it should be when stored in the WMF file
+ bs = colortype/8;
+ if(bs<1){
+ usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes
+ }
+ else {
+ usedbytes = width*bs;
+ }
+ if(IS_MEM_UNSAFE(px, usedbytes, blimit))return(0);
+ }
+ return(1);
+}
+
+//! \endcond
+
+/**
+ \brief Derive from bounding box and start and end arc, for WMF arc, chord, or pie records, the center, start, and end points, and the bounding rectangle.
+
+ \return 0 on success, other values on errors.
+ \param rclBox16 Bounding box of Arc
+ \param ArcStart16 Coordinates for Start of Arc
+ \param ArcEnd16 Coordinates for End of Arc
+ \param f1 1 if rotation angle >= 180, else 0
+ \param f2 Rotation direction, 1 if counter clockwise, else 0
+ \param center Center coordinates
+ \param start Start coordinates (point on the ellipse defined by rect)
+ \param end End coordinates (point on the ellipse defined by rect)
+ \param size W,H of the x,y axes of the bounding rectangle.
+*/
+int wmr_arc_points(
+ U_RECT16 rclBox16,
+ U_POINT16 ArcStart16,
+ U_POINT16 ArcEnd16,
+ int *f1,
+ int f2,
+ U_PAIRF *center,
+ U_PAIRF *start,
+ U_PAIRF *end,
+ U_PAIRF *size
+ ){
+ U_RECTL rclBox;
+ U_POINTL ArcStart,ArcEnd;
+ rclBox.left = rclBox16.left;
+ rclBox.top = rclBox16.top;
+ rclBox.right = rclBox16.right;
+ rclBox.bottom = rclBox16.bottom;
+ ArcStart.x = ArcStart16.x;
+ ArcStart.y = ArcStart16.y;
+ ArcEnd.x = ArcEnd16.x;
+ ArcEnd.y = ArcEnd16.y;
+ return emr_arc_points_common(&rclBox, &ArcStart, &ArcEnd, f1, f2, center, start, end, size);
+}
+
+/**
+ \brief A U_RECT16 may have its values swapped, L<->R and T<->B, this extracts the leftmost as left, and so forth.
+ \param rc U_RECT156 binary contents of an WMF file
+ \param left the leftmost of rc.left and rc.right
+ \param top the topmost of rc.top and rc.bottom
+ \param right the rightmost of rc.left and rc.right
+ \param bottom the bottommost of rc.top and rc.bottom
+*/
+void U_sanerect16(U_RECT16 rc, double *left, double *top, double *right, double *bottom){
+ if(rc.left < rc.right) { *left = rc.left; *right = rc.right; }
+ else { *left = rc.right; *right = rc.left; }
+ if(rc.top < rc.bottom){ *top = rc.top; *bottom = rc.bottom; }
+ else{ *top = rc.bottom; *bottom = rc.top; }
+}
+
+/* **********************************************************************************************
+These definitions are for code pieces that are used many times in the following implementation. These
+definitions are not needed in end user code, so they are here rather than in uwmf.h.
+*********************************************************************************************** */
+
+/**
+ \brief Get record size in bytes from U_WMR* record, which may not be aligned
+ \return number of bytes in record.
+*/
+uint32_t U_wmr_size(const U_METARECORD *record){
+ uint32_t Size16;
+ memcpy(&Size16,record, 4);
+ return(2*Size16);
+}
+
+//! \cond should never be called directly
+#define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \
+ if(A){\
+ if(!B)return(NULL); /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \
+ C = F;\
+ D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \
+ E = U_SIZE_BITMAPINFOHEADER + 4 * get_real_color_count((char *)&(B->bmiHeader)); /* bmiheader + colortable*/ \
+ }\
+ else { C = 0; D = 0; E=0; }
+//! \endcond
+
+/**
+ \brief Create and return a U_FONT structure.
+ \return pointer to the created U_FONT structure.
+ \param Height Height in Logical units
+ \param Width Average Width in Logical units
+ \param Escapement Angle in 0.1 degrees betweem escapement vector and X axis
+ \param Orientation Angle in 0.1 degrees between baseline and X axis
+ \param Weight LF_Weight Enumeration
+ \param Italic LF_Italic Enumeration
+ \param Underline LF_Underline Enumeration
+ \param StrikeOut LF_StrikeOut Enumeration
+ \param CharSet LF_CharSet Enumeration
+ \param OutPrecision LF_OutPrecision Enumeration
+ \param ClipPrecision LF_ClipPrecision Enumeration
+ \param Quality LF_Quality Enumeration
+ \param PitchAndFamily LF_PitchAndFamily Enumeration
+ \param FaceName Name of font. ANSI Latin1, null terminated.
+*/
+U_FONT *U_FONT_set(
+ int16_t Height, //!< Height in Logical units
+ int16_t Width, //!< Average Width in Logical units
+ int16_t Escapement, //!< Angle in 0.1 degrees betweem escapement vector and X axis
+ int16_t Orientation, //!< Angle in 0.1 degrees between baseline and X axis
+ int16_t Weight, //!< LF_Weight Enumeration
+ uint8_t Italic, //!< LF_Italic Enumeration
+ uint8_t Underline, //!< LF_Underline Enumeration
+ uint8_t StrikeOut, //!< LF_StrikeOut Enumeration
+ uint8_t CharSet, //!< LF_CharSet Enumeration
+ uint8_t OutPrecision, //!< LF_OutPrecision Enumeration
+ uint8_t ClipPrecision, //!< LF_ClipPrecision Enumeration
+ uint8_t Quality, //!< LF_Quality Enumeration
+ uint8_t PitchAndFamily, //!< LF_PitchAndFamily Enumeration
+ char *FaceName //!< Name of font. ANSI Latin1, null terminated.
+ ){
+ U_FONT *font;
+ int slen = 1 + strlen(FaceName); /* include terminator */
+ if(slen & 1)slen++; /* storage length even */
+ font = (U_FONT *) calloc(1,slen + U_SIZE_FONT_CORE); /* use calloc to auto fill in terminating '\0'*/
+ if(font){
+ font->Height = Height;
+ font->Width = Width;
+ font->Escapement = Escapement;
+ font->Orientation = Orientation;
+ font->Weight = Weight;
+ font->Italic = Italic;
+ font->Underline = Underline;
+ font->StrikeOut = StrikeOut;
+ font->CharSet = CharSet;
+ font->OutPrecision = OutPrecision;
+ font->ClipPrecision = ClipPrecision;
+ font->Quality = Quality;
+ font->PitchAndFamily = PitchAndFamily;
+ strcpy((char *)&font->FaceName, FaceName);
+ }
+ return(font);
+}
+
+/**
+ \brief Create and return a U_PLTENTRY structure.
+ \return the created U_PLTENTRY structure.
+ \param Color Color for the U_PLTENTRY
+*/
+U_PLTNTRY U_PLTNTRY_set(U_COLORREF Color){
+ U_PLTNTRY pe;
+ pe.Value = Color.Reserved;
+ pe.Blue = Color.Blue;
+ pe.Green = Color.Green;
+ pe.Red = Color.Red;
+ return(pe);
+}
+
+/**
+ \brief Create and return a U_PALETTE structure.
+ \return pointer to the created U_PALETTE structure.
+ \param Start Either 0x0300 or an offset into the Palette table
+ \param NumEntries Number of U_LOGPLTNTRY objects
+ \param PalEntries Pointer to array of PaletteEntry Objects
+*/
+U_PALETTE *U_PLTENTRY_set(
+ uint16_t Start, //!< Either 0x0300 or an offset into the Palette table
+ uint16_t NumEntries, //!< Number of U_LOGPLTNTRY objects
+ U_PLTNTRY *PalEntries //!< Pointer to array of PaletteEntry Objects
+ ){
+ U_PALETTE *Palette = NULL;
+ if(NumEntries){
+ Palette = malloc(4 + 4*NumEntries);
+ if(Palette){
+ Palette->Start = Start;
+ Palette->NumEntries = NumEntries;
+ memcpy(&Palette->PalEntries, PalEntries, NumEntries*4);
+ }
+ }
+ return(Palette);
+}
+
+/**
+ \brief Create and return a U_PEN structure.
+ \return the created U_PEN structure.
+ \param Style PenStyle Enumeration
+ \param Width Width of Pen
+ \param Color Pen Color.
+*/
+U_PEN U_PEN_set(
+ uint16_t Style, //!< PenStyle Enumeration
+ uint16_t Width, //!< Width of Pen
+ U_COLORREF Color //!< Pen Color.
+ ){
+ U_PEN p;
+ p.Style = Style;
+ p.Widthw[0] = Width;
+ p.Widthw[1] = 0; /* ignored */
+ p.Color.Red = Color.Red;
+ p.Color.Green = Color.Green;
+ p.Color.Blue = Color.Blue;
+ p.Color.Reserved = Color.Reserved;
+ return(p);
+}
+
+/**
+ \brief Create and return a U_RECT16 structure from Upper Left and Lower Right corner points.
+ \param ul upper left corner of rectangle
+ \param lr lower right corner of rectangle
+*/
+U_RECT16 U_RECT16_set(
+ U_POINT16 ul,
+ U_POINT16 lr
+ ){
+ U_RECT16 rect;
+ rect.left = ul.x;
+ rect.top = ul.y;
+ rect.right = lr.x;
+ rect.bottom = lr.y;
+ return(rect);
+}
+
+/**
+ \brief Create and return a U_BITMAP16 structure
+ \return pointer to the U_BITMAP16 structure, or NULL on failure
+ \param Type bitmap Type (not described at all in the WMF PDF)
+ \param Width bitmap width in pixels.
+ \param Height bitmap height in scan lines.
+ \param LineN each array line in Bits is a multiple of this (4 for a DIB)
+ \param BitsPixel number of adjacent color bits on each plane (R bits + G bits + B bits ????)
+ \param Bits bitmap pixel data. Bytes contained = (((Width * BitsPixel + 15) >> 4) << 1) * Height
+*/
+U_BITMAP16 *U_BITMAP16_set(
+ const int16_t Type,
+ const int16_t Width,
+ const int16_t Height,
+ const int16_t LineN,
+ const uint8_t BitsPixel,
+ const char *Bits
+ ){
+ U_BITMAP16 *bm16;
+ uint32_t irecsize;
+ int cbBits,iHeight;
+ int usedbytes;
+ int16_t WidthBytes; // total bytes per scan line (used and padding).
+
+ usedbytes = (Width * BitsPixel + 7)/8; // width of line in fully and partially occupied bytes
+ WidthBytes = (LineN * ((usedbytes + (LineN - 1) ) / LineN)); // Account for padding required by line alignment in the pixel array
+
+ iHeight = (Height < 0 ? -Height : Height); /* DIB can use a negative height, but it does not look like a Bitmap16 object can */
+ cbBits = WidthBytes * iHeight;
+ if(!Bits || cbBits<=0)return(NULL);
+ irecsize = U_SIZE_BITMAP16 + cbBits;
+ bm16 = (U_BITMAP16 *) malloc(irecsize);
+ if(bm16){
+ bm16->Type = Type;
+ bm16->Width = Width;
+ bm16->Height = iHeight;
+ bm16->WidthBytes = WidthBytes;
+ bm16->Planes = 1;
+ bm16->BitsPixel = BitsPixel;
+ memcpy((char *)bm16 + U_SIZE_BITMAP16,Bits,cbBits);
+ }
+ return(bm16);
+}
+
+/**
+ \brief Create and return a U_SCAN structure
+ \return U_SCAN structure
+ \param count Number of entries in the ScanLines array
+ \param top Y coordinate of the top scanline
+ \param bottom Y coordinate of the bottom scanline
+ \param ScanLines Array of 16 bit left/right pairs, array has 2*count entries
+*/
+U_SCAN *U_SCAN_set(
+ uint16_t count, //!< Number of entries in the ScanLines array
+ uint16_t top, //!< Y coordinate of the top scanline
+ uint16_t bottom, //!< Y coordinate of the bottom scanline
+ uint16_t *ScanLines //!< Array of 16 bit left/right pairs, array has 2*count entries
+ ){
+ U_SCAN *scan=NULL;
+ int size = 6 + count*4;
+ scan = malloc(size);
+ if(scan){
+ scan->count = count;
+ scan->top = top;
+ scan->bottom = bottom;
+ memcpy(&scan->ScanLines,ScanLines,4*count);
+ }
+ return(scan);
+}
+
+/**
+ \brief Create and return a U_REGION structure
+ \return pointer to created U_REGION structure or NULL on error
+ \param Size aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?)
+ \param sCount number of scan objects in region (docs say scanlines, but then no way to add sizes)
+ \param sMax largest number of points in any scan
+ \param sRect bounding rectangle
+ \param aScans series of U_SCAN objects to append. This is also an array of uint16_t, but should be handled as a bunch of U_SCAN objects tightly packed into the buffer.
+*/
+U_REGION *U_REGION_set(
+ int16_t Size, //!< aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?)
+ int16_t sCount, //!< number of scan objects in region (docs say scanlines, but then no way to add sizes)
+ int16_t sMax, //!< largest number of points in any scan
+ U_RECT16 sRect, //!< bounding rectangle
+ uint16_t *aScans //!< series of U_SCAN objects to append. This is also an array of uint16_t, but should be handled as a bunch of U_SCAN objects tightly packed into the buffer.
+ ){
+ U_REGION *region=NULL;
+ char *psc;
+ int scansize,i,off;
+ psc = (char *)aScans;
+ for(scansize=i=0; i<sCount; i++){
+ off = 6 + 4*(((U_SCAN *)psc)->count);
+ scansize += off;
+ psc += off;
+ }
+ region = malloc(U_SIZE_REGION + scansize);
+ if(region){
+ region->ignore1 = 0;
+ region->Type = 0x0006;
+ region->ignore2 = 0;
+ region->Size = Size;
+ region->sCount = sCount;
+ region->sMax = sMax;
+ region->sRect = sRect;
+ memcpy(&region->aScans,aScans,scansize);
+ }
+ return(region);
+}
+
+
+/**
+ \brief Create and return a U_WLOGBRUSH structure.
+ \return the created U_WLOGBRUSH structure.
+ \param Style BrushStyle Enumeration
+ \param Color Brush Color value
+ \param Hatch HatchStyle Enumeration
+*/
+U_WLOGBRUSH U_WLOGBRUSH_set(
+ uint16_t Style, //!< BrushStyle Enumeration
+ U_COLORREF Color, //!< Brush Color value
+ uint16_t Hatch //!< HatchStyle Enumeration
+ ){
+ U_WLOGBRUSH lb;
+ lb.Style = Style;
+ lb.Color.Red = Color.Red;
+ lb.Color.Green = Color.Green;
+ lb.Color.Blue = Color.Blue;
+ lb.Color.Reserved = Color.Reserved;
+ lb.Hatch = Hatch;
+ return(lb);
+}
+
+
+/**
+ \brief Create and return a U_PAIRF structure.
+ \return pointer to the created U_PAIRF structure.
+ \param x x value
+ \param y y value
+*/
+U_PAIRF *U_PAIRF_set(
+ float x, //!< x value
+ float y //!< y value
+ ){
+ U_PAIRF *pf=malloc(U_SIZE_PAIRF);
+ if(pf){
+ pf->x = x;
+ pf->y = y;
+ }
+ return(pf);
+}
+
+/* **********************************************************************************************
+These functions are used for Image conversions and other
+utility operations. Character type conversions are in uwmf_utf.c
+*********************************************************************************************** */
+
+/**
+ \brief Calculate the int16_t checksum of the buffer for the number of positions specified. This is XOR of all values.
+ \return checksum
+ \param buf array of uint16_t values
+ \param count number of members in buf
+
+*/
+int16_t U_16_checksum(int16_t *buf, int count){
+ int16_t result=0;
+ for(;count;count--){
+ result ^= *buf++;
+ }
+ return(result);
+}
+
+/**
+ \brief Dump a WMFHANDLES structure. Not for use in production code.
+ \param string Text to output before dumping eht structure
+ \param handle Handle
+ \param wht WMFHANDLES structure to dump
+*/
+void dumpwht(
+ char *string,
+ unsigned int *handle,
+ WMFHANDLES *wht
+ ){
+ uint32_t i;
+ printf("%s\n",string);
+ printf("lo: %d hi: %d peak: %d\n", wht->lolimit, wht->hilimit, wht->peak);
+ if(handle){
+ printf("handle: %d \n",*handle);
+ }
+ for(i=0;i<=5;i++){
+ printf("table[%d]: %d\n",i,wht->table[i]);
+ }
+}
+
+/**
+ \brief Make up an approximate dx array to pass to U_WMREXTTEXTOUT_set(), based on character height and weight.
+
+ Take abs. value of character height, get width by multiplying by 0.6, and correct weight
+ approximately, with formula (measured on screen for one text line of Arial).
+ Caller is responsible for free() on the returned pointer.
+
+ \return pointer to dx array
+ \param height character height (absolute value will be used)
+ \param weight LF_Weight Enumeration (character weight)
+ \param members Number of entries to put into dx
+
+*/
+int16_t *dx16_set(
+ int32_t height,
+ uint32_t weight,
+ uint32_t members
+ ){
+ uint32_t i, width;
+ int16_t *dx;
+ dx = (int16_t *) malloc(members * sizeof(int16_t));
+ if(dx){
+ if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL;
+ width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904));
+ for ( i = 0; i < members; i++ ){ dx[i] = (width > INT16_MAX ? INT16_MAX : width); }
+ }
+ return(dx);
+}
+/**
+ \brief Look up the properties (a bit map) of a type of WMR record.
+ Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc..
+ \return bitmap of WMR record properties, or U_WMR_INVALID on error or release of all memory.
+ \param type WMR record type. If U_WMR_INVALID release memory. (There is no U_WMR_INVALID WMR record type)
+
+*/
+uint32_t U_wmr_properties(uint32_t type){
+ static uint32_t *table=NULL;
+ uint32_t result = U_WMR_INVALID; // initialized to indicate an error (on a lookup) or nothing (on a memory release)
+ if(type == U_WMR_INVALID){
+ if(table)free(table);
+ table=NULL;
+ }
+ else if(type<=U_WMR_MAX){ // type is uint so always >=0, no need to test U_WMR_MIN, which is 0.
+ if(!table){
+ table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_WMR_MAX));
+ if(!table)return(result);
+ // 0x200 0x100 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01
+ // properties (U_DRAW_*) TEXT ALTERS ONLYTO VISIBLE
+ // NOFILL OBJECT PATH FORCE CLOSED NOTEMPTY
+ // Record Type
+ table[0x00] = 0x0A0; // U_WMREOF 0 0 1 0 1 0 0 0 0 0 Force out any pending draw
+ table[0x01] = 0x020; // U_WMRSETBKCOLOR 0 0 0 0 1 0 0 0 0 0
+ table[0x02] = 0x020; // U_WMRSETBKMODE 0 0 0 0 1 0 0 0 0 0
+ table[0x03] = 0x0A0; // U_WMRSETMAPMODE 0 0 1 0 1 0 0 0 0 0
+ table[0x04] = 0x0A0; // U_WMRSETROP2 0 0 1 0 1 0 0 0 0 0
+ table[0x05] = 0x000; // U_WMRSETRELABS 0 0 0 0 0 0 0 0 0 0 No idea what this is supposed to do
+ table[0x06] = 0x0A0; // U_WMRSETPOLYFILLMODE 0 0 1 0 1 0 0 0 0 0
+ table[0x07] = 0x0A0; // U_WMRSETSTRETCHBLTMODE 0 0 1 0 1 0 0 0 0 0
+ table[0x08] = 0x000; // U_WMRSETTEXTCHAREXTRA 0 0 0 0 0 0 0 0 0 0
+ table[0x09] = 0x020; // U_WMRSETTEXTCOLOR 0 0 0 0 1 0 0 0 0 0
+ table[0x0A] = 0x020; // U_WMRSETTEXTJUSTIFICATION 0 0 0 0 1 0 0 0 0 0
+ table[0x0B] = 0x0A0; // U_WMRSETWINDOWORG 0 0 1 0 1 0 0 0 0 0
+ table[0x0C] = 0x0A0; // U_WMRSETWINDOWEXT 0 0 1 0 1 0 0 0 0 0
+ table[0x0D] = 0x0A0; // U_WMRSETVIEWPORTORG 0 0 1 0 1 0 0 0 0 0
+ table[0x0E] = 0x0A0; // U_WMRSETVIEWPORTEXT 0 0 1 0 1 0 0 0 0 0
+ table[0x0F] = 0x000; // U_WMROFFSETWINDOWORG 0 0 0 0 0 0 0 0 0 0
+ table[0x10] = 0x000; // U_WMRSCALEWINDOWEXT 0 0 0 0 0 0 0 0 0 0
+ table[0x11] = 0x0A0; // U_WMROFFSETVIEWPORTORG 0 0 1 0 1 0 0 0 0 0
+ table[0x12] = 0x0A0; // U_WMRSCALEVIEWPORTEXT 0 0 1 0 1 0 0 0 0 0
+ table[0x13] = 0x28B; // U_WMRLINETO 1 0 1 0 0 0 1 0 1 1
+ table[0x14] = 0x289; // U_WMRMOVETO 1 0 1 0 0 0 1 0 0 1
+ table[0x15] = 0x0A0; // U_WMREXCLUDECLIPRECT 0 0 1 0 1 0 0 0 0 0
+ table[0x16] = 0x0A0; // U_WMRINTERSECTCLIPRECT 0 0 1 0 1 0 0 0 0 0
+ table[0x17] = 0x283; // U_WMRARC 1 0 1 0 0 0 0 0 1 1
+ table[0x18] = 0x087; // U_WMRELLIPSE 0 0 1 0 0 0 0 1 1 1
+ table[0x19] = 0x082; // U_WMRFLOODFILL 0 0 1 0 0 0 0 0 1 0
+ table[0x1A] = 0x087; // U_WMRPIE 0 0 1 0 0 0 0 1 1 1
+ table[0x1B] = 0x087; // U_WMRRECTANGLE 0 0 1 0 0 0 0 1 1 1
+ table[0x1C] = 0x087; // U_WMRROUNDRECT 0 0 1 0 0 0 0 1 1 1
+ table[0x1D] = 0x000; // U_WMRPATBLT 0 0 1 0 0 0 0 1 1 1
+ table[0x1E] = 0x0A0; // U_WMRSAVEDC 0 0 1 0 1 0 0 0 0 0
+ table[0x1F] = 0x082; // U_WMRSETPIXEL 0 0 1 0 0 0 0 0 1 0
+ table[0x20] = 0x0A0; // U_WMROFFSETCLIPRGN 0 0 1 0 1 0 0 0 0 0
+ table[0x21] = 0x002; // U_WMRTEXTOUT 0 0 0 0 0 0 0 0 1 0
+ table[0x22] = 0x082; // U_WMRBITBLT 0 0 1 0 0 0 0 0 1 0
+ table[0x23] = 0x082; // U_WMRSTRETCHBLT 0 0 1 0 0 0 0 0 1 0
+ table[0x24] = 0x083; // U_WMRPOLYGON 0 0 1 0 0 0 0 0 1 1
+ table[0x25] = 0x283; // U_WMRPOLYLINE 1 0 1 0 0 0 0 0 1 1
+ table[0x26] = 0x0A0; // U_WMRESCAPE 0 0 1 0 1 0 0 0 0 0
+ table[0x27] = 0x0A0; // U_WMRRESTOREDC 0 0 1 0 1 0 0 0 0 0
+ table[0x28] = 0x082; // U_WMRFILLREGION 0 0 1 0 0 0 0 0 1 0
+ table[0x29] = 0x082; // U_WMRFRAMEREGION 0 0 1 0 0 0 0 0 1 0
+ table[0x2A] = 0x082; // U_WMRINVERTREGION 0 0 1 0 0 0 0 0 1 0
+ table[0x2B] = 0x082; // U_WMRPAINTREGION 0 0 1 0 0 0 0 0 1 0
+ table[0x2C] = 0x0A0; // U_WMRSELECTCLIPREGION 0 0 1 0 1 0 0 0 0 0
+ table[0x2D] = 0x020; // U_WMRSELECTOBJECT 0 0 0 0 1 0 0 0 0 0
+ table[0x2E] = 0x020; // U_WMRSETTEXTALIGN 0 0 0 0 1 0 0 0 0 0
+ table[0x2F] = 0x002; // U_WMRDRAWTEXT 0 0 0 0 0 0 0 0 1 0 no idea what this is supposed to do
+ table[0x30] = 0x087; // U_WMRCHORD 0 0 1 0 0 0 0 1 1 1
+ table[0x31] = 0x0A0; // U_WMRSETMAPPERFLAGS 0 0 1 0 1 0 0 0 0 0
+ table[0x32] = 0x002; // U_WMREXTTEXTOUT 0 0 0 0 0 0 0 0 1 0
+ table[0x33] = 0x000; // U_WMRSETDIBTODEV 0 0 0 0 0 0 0 0 0 0
+ table[0x34] = 0x0A0; // U_WMRSELECTPALETTE 0 0 1 0 1 0 0 0 0 0
+ table[0x35] = 0x0A0; // U_WMRREALIZEPALETTE 0 0 1 0 1 0 0 0 0 0
+ table[0x36] = 0x0A0; // U_WMRANIMATEPALETTE 0 0 1 0 1 0 0 0 0 0
+ table[0x37] = 0x0A0; // U_WMRSETPALENTRIES 0 0 1 0 1 0 0 0 0 0
+ table[0x38] = 0x087; // U_WMRPOLYPOLYGON 0 0 1 0 0 0 0 1 1 1
+ table[0x39] = 0x0A0; // U_WMRRESIZEPALETTE 0 0 1 0 1 0 0 0 0 0
+ table[0x3A] = 0x000; // U_WMR3A 0 0 0 0 0 0 0 0 0 0
+ table[0x3B] = 0x000; // U_WMR3B 0 0 0 0 0 0 0 0 0 0
+ table[0x3C] = 0x000; // U_WMR3C 0 0 0 0 0 0 0 0 0 0
+ table[0x3D] = 0x000; // U_WMR3D 0 0 0 0 0 0 0 0 0 0
+ table[0x3E] = 0x000; // U_WMR3E 0 0 0 0 0 0 0 0 0 0
+ table[0x3F] = 0x000; // U_WMR3F 0 0 0 0 0 0 0 0 0 0
+ table[0x40] = 0x0A0; // U_WMRDIBBITBLT 0 0 1 0 1 0 0 0 0 0
+ table[0x41] = 0x0A0; // U_WMRDIBSTRETCHBLT 0 0 1 0 1 0 0 0 0 0
+ table[0x42] = 0x080; // U_WMRDIBCREATEPATTERNBRUSH 0 0 1 0 0 0 0 0 0 0 Not selected yet, so no change in drawing conditions
+ table[0x43] = 0x0A0; // U_WMRSTRETCHDIB 0 0 1 0 1 0 0 0 0 0
+ table[0x44] = 0x000; // U_WMR44 0 0 0 0 0 0 0 0 0 0
+ table[0x45] = 0x000; // U_WMR45 0 0 0 0 0 0 0 0 0 0
+ table[0x46] = 0x000; // U_WMR46 0 0 0 0 0 0 0 0 0 0
+ table[0x47] = 0x000; // U_WMR47 0 0 0 0 0 0 0 0 0 0
+ table[0x48] = 0x082; // U_WMREXTFLOODFILL 0 0 1 0 0 0 0 0 1 0
+ table[0x49] = 0x000; // U_WMR49 0 0 0 0 0 0 0 0 0 0
+ table[0x4A] = 0x000; // U_WMR4A 0 0 0 0 0 0 0 0 0 0
+ table[0x4B] = 0x000; // U_WMR4B 0 0 0 0 0 0 0 0 0 0
+ table[0x4C] = 0x000; // U_WMR4C 0 0 0 0 0 0 0 0 0 0
+ table[0x4D] = 0x000; // U_WMR4D 0 0 0 0 0 0 0 0 0 0
+ table[0x4E] = 0x000; // U_WMR4E 0 0 0 0 0 0 0 0 0 0
+ table[0x4F] = 0x000; // U_WMR4F 0 0 0 0 0 0 0 0 0 0
+ table[0x50] = 0x000; // U_WMR50 0 0 0 0 0 0 0 0 0 0
+ table[0x51] = 0x000; // U_WMR51 0 0 0 0 0 0 0 0 0 0
+ table[0x52] = 0x000; // U_WMR52 0 0 0 0 0 0 0 0 0 0
+ table[0x53] = 0x000; // U_WMR53 0 0 0 0 0 0 0 0 0 0
+ table[0x54] = 0x000; // U_WMR54 0 0 0 0 0 0 0 0 0 0
+ table[0x55] = 0x000; // U_WMR55 0 0 0 0 0 0 0 0 0 0
+ table[0x56] = 0x000; // U_WMR56 0 0 0 0 0 0 0 0 0 0
+ table[0x57] = 0x000; // U_WMR57 0 0 0 0 0 0 0 0 0 0
+ table[0x58] = 0x000; // U_WMR58 0 0 0 0 0 0 0 0 0 0
+ table[0x59] = 0x000; // U_WMR59 0 0 0 0 0 0 0 0 0 0
+ table[0x5A] = 0x000; // U_WMR5A 0 0 0 0 0 0 0 0 0 0
+ table[0x5B] = 0x000; // U_WMR5B 0 0 0 0 0 0 0 0 0 0
+ table[0x5C] = 0x000; // U_WMR5C 0 0 0 0 0 0 0 0 0 0
+ table[0x5D] = 0x000; // U_WMR5D 0 0 0 0 0 0 0 0 0 0
+ table[0x5E] = 0x000; // U_WMR5E 0 0 0 0 0 0 0 0 0 0
+ table[0x5F] = 0x000; // U_WMR5F 0 0 0 0 0 0 0 0 0 0
+ table[0x60] = 0x000; // U_WMR60 0 0 0 0 0 0 0 0 0 0
+ table[0x61] = 0x000; // U_WMR61 0 0 0 0 0 0 0 0 0 0
+ table[0x62] = 0x000; // U_WMR62 0 0 0 0 0 0 0 0 0 0
+ table[0x63] = 0x000; // U_WMR63 0 0 0 0 0 0 0 0 0 0
+ table[0x64] = 0x000; // U_WMR64 0 0 0 0 0 0 0 0 0 0
+ table[0x65] = 0x000; // U_WMR65 0 0 0 0 0 0 0 0 0 0
+ table[0x66] = 0x000; // U_WMR66 0 0 0 0 0 0 0 0 0 0
+ table[0x67] = 0x000; // U_WMR67 0 0 0 0 0 0 0 0 0 0
+ table[0x68] = 0x000; // U_WMR68 0 0 0 0 0 0 0 0 0 0
+ table[0x69] = 0x000; // U_WMR69 0 0 0 0 0 0 0 0 0 0
+ table[0x6A] = 0x000; // U_WMR6A 0 0 0 0 0 0 0 0 0 0
+ table[0x6B] = 0x000; // U_WMR6B 0 0 0 0 0 0 0 0 0 0
+ table[0x6C] = 0x000; // U_WMR6C 0 0 0 0 0 0 0 0 0 0
+ table[0x6D] = 0x000; // U_WMR6D 0 0 0 0 0 0 0 0 0 0
+ table[0x6E] = 0x000; // U_WMR6E 0 0 0 0 0 0 0 0 0 0
+ table[0x6F] = 0x000; // U_WMR6F 0 0 0 0 0 0 0 0 0 0
+ table[0x70] = 0x000; // U_WMR70 0 0 0 0 0 0 0 0 0 0
+ table[0x71] = 0x000; // U_WMR71 0 0 0 0 0 0 0 0 0 0
+ table[0x72] = 0x000; // U_WMR72 0 0 0 0 0 0 0 0 0 0
+ table[0x73] = 0x000; // U_WMR73 0 0 0 0 0 0 0 0 0 0
+ table[0x74] = 0x000; // U_WMR74 0 0 0 0 0 0 0 0 0 0
+ table[0x75] = 0x000; // U_WMR75 0 0 0 0 0 0 0 0 0 0
+ table[0x76] = 0x000; // U_WMR76 0 0 0 0 0 0 0 0 0 0
+ table[0x77] = 0x000; // U_WMR77 0 0 0 0 0 0 0 0 0 0
+ table[0x78] = 0x000; // U_WMR78 0 0 0 0 0 0 0 0 0 0
+ table[0x79] = 0x000; // U_WMR79 0 0 0 0 0 0 0 0 0 0
+ table[0x7A] = 0x000; // U_WMR7A 0 0 0 0 0 0 0 0 0 0
+ table[0x7B] = 0x000; // U_WMR7B 0 0 0 0 0 0 0 0 0 0
+ table[0x7C] = 0x000; // U_WMR7C 0 0 0 0 0 0 0 0 0 0
+ table[0x7D] = 0x000; // U_WMR7D 0 0 0 0 0 0 0 0 0 0
+ table[0x7E] = 0x000; // U_WMR7E 0 0 0 0 0 0 0 0 0 0
+ table[0x7F] = 0x000; // U_WMR7F 0 0 0 0 0 0 0 0 0 0
+ table[0x80] = 0x000; // U_WMR80 0 0 0 0 0 0 0 0 0 0
+ table[0x81] = 0x000; // U_WMR81 0 0 0 0 0 0 0 0 0 0
+ table[0x82] = 0x000; // U_WMR82 0 0 0 0 0 0 0 0 0 0
+ table[0x83] = 0x000; // U_WMR83 0 0 0 0 0 0 0 0 0 0
+ table[0x84] = 0x000; // U_WMR84 0 0 0 0 0 0 0 0 0 0
+ table[0x85] = 0x000; // U_WMR85 0 0 0 0 0 0 0 0 0 0
+ table[0x86] = 0x000; // U_WMR86 0 0 0 0 0 0 0 0 0 0
+ table[0x87] = 0x000; // U_WMR87 0 0 0 0 0 0 0 0 0 0
+ table[0x88] = 0x000; // U_WMR88 0 0 0 0 0 0 0 0 0 0
+ table[0x89] = 0x000; // U_WMR89 0 0 0 0 0 0 0 0 0 0
+ table[0x8A] = 0x000; // U_WMR8A 0 0 0 0 0 0 0 0 0 0
+ table[0x8B] = 0x000; // U_WMR8B 0 0 0 0 0 0 0 0 0 0
+ table[0x8C] = 0x000; // U_WMR8C 0 0 0 0 0 0 0 0 0 0
+ table[0x8D] = 0x000; // U_WMR8D 0 0 0 0 0 0 0 0 0 0
+ table[0x8E] = 0x000; // U_WMR8E 0 0 0 0 0 0 0 0 0 0
+ table[0x8F] = 0x000; // U_WMR8F 0 0 0 0 0 0 0 0 0 0
+ table[0x90] = 0x000; // U_WMR90 0 0 0 0 0 0 0 0 0 0
+ table[0x91] = 0x000; // U_WMR91 0 0 0 0 0 0 0 0 0 0
+ table[0x92] = 0x000; // U_WMR92 0 0 0 0 0 0 0 0 0 0
+ table[0x93] = 0x000; // U_WMR93 0 0 0 0 0 0 0 0 0 0
+ table[0x94] = 0x000; // U_WMR94 0 0 0 0 0 0 0 0 0 0
+ table[0x95] = 0x000; // U_WMR95 0 0 0 0 0 0 0 0 0 0
+ table[0x96] = 0x000; // U_WMR96 0 0 0 0 0 0 0 0 0 0
+ table[0x97] = 0x000; // U_WMR97 0 0 0 0 0 0 0 0 0 0
+ table[0x98] = 0x000; // U_WMR98 0 0 0 0 0 0 0 0 0 0
+ table[0x99] = 0x000; // U_WMR99 0 0 0 0 0 0 0 0 0 0
+ table[0x9A] = 0x000; // U_WMR9A 0 0 0 0 0 0 0 0 0 0
+ table[0x9B] = 0x000; // U_WMR9B 0 0 0 0 0 0 0 0 0 0
+ table[0x9C] = 0x000; // U_WMR9C 0 0 0 0 0 0 0 0 0 0
+ table[0x9D] = 0x000; // U_WMR9D 0 0 0 0 0 0 0 0 0 0
+ table[0x9E] = 0x000; // U_WMR9E 0 0 0 0 0 0 0 0 0 0
+ table[0x9F] = 0x000; // U_WMR9F 0 0 0 0 0 0 0 0 0 0
+ table[0xA0] = 0x000; // U_WMRA0 0 0 0 0 0 0 0 0 0 0
+ table[0xA1] = 0x000; // U_WMRA1 0 0 0 0 0 0 0 0 0 0
+ table[0xA2] = 0x000; // U_WMRA2 0 0 0 0 0 0 0 0 0 0
+ table[0xA3] = 0x000; // U_WMRA3 0 0 0 0 0 0 0 0 0 0
+ table[0xA4] = 0x000; // U_WMRA4 0 0 0 0 0 0 0 0 0 0
+ table[0xA5] = 0x000; // U_WMRA5 0 0 0 0 0 0 0 0 0 0
+ table[0xA6] = 0x000; // U_WMRA6 0 0 0 0 0 0 0 0 0 0
+ table[0xA7] = 0x000; // U_WMRA7 0 0 0 0 0 0 0 0 0 0
+ table[0xA8] = 0x000; // U_WMRA8 0 0 0 0 0 0 0 0 0 0
+ table[0xA9] = 0x000; // U_WMRA9 0 0 0 0 0 0 0 0 0 0
+ table[0xAA] = 0x000; // U_WMRAA 0 0 0 0 0 0 0 0 0 0
+ table[0xAB] = 0x000; // U_WMRAB 0 0 0 0 0 0 0 0 0 0
+ table[0xAC] = 0x000; // U_WMRAC 0 0 0 0 0 0 0 0 0 0
+ table[0xAD] = 0x000; // U_WMRAD 0 0 0 0 0 0 0 0 0 0
+ table[0xAE] = 0x000; // U_WMRAE 0 0 0 0 0 0 0 0 0 0
+ table[0xAF] = 0x000; // U_WMRAF 0 0 0 0 0 0 0 0 0 0
+ table[0xB0] = 0x000; // U_WMRB0 0 0 0 0 0 0 0 0 0 0
+ table[0xB1] = 0x000; // U_WMRB1 0 0 0 0 0 0 0 0 0 0
+ table[0xB2] = 0x000; // U_WMRB2 0 0 0 0 0 0 0 0 0 0
+ table[0xB3] = 0x000; // U_WMRB3 0 0 0 0 0 0 0 0 0 0
+ table[0xB4] = 0x000; // U_WMRB4 0 0 0 0 0 0 0 0 0 0
+ table[0xB5] = 0x000; // U_WMRB5 0 0 0 0 0 0 0 0 0 0
+ table[0xB6] = 0x000; // U_WMRB6 0 0 0 0 0 0 0 0 0 0
+ table[0xB7] = 0x000; // U_WMRB7 0 0 0 0 0 0 0 0 0 0
+ table[0xB8] = 0x000; // U_WMRB8 0 0 0 0 0 0 0 0 0 0
+ table[0xB9] = 0x000; // U_WMRB9 0 0 0 0 0 0 0 0 0 0
+ table[0xBA] = 0x000; // U_WMRBA 0 0 0 0 0 0 0 0 0 0
+ table[0xBB] = 0x000; // U_WMRBB 0 0 0 0 0 0 0 0 0 0
+ table[0xBC] = 0x000; // U_WMRBC 0 0 0 0 0 0 0 0 0 0
+ table[0xBD] = 0x000; // U_WMRBD 0 0 0 0 0 0 0 0 0 0
+ table[0xBE] = 0x000; // U_WMRBE 0 0 0 0 0 0 0 0 0 0
+ table[0xBF] = 0x000; // U_WMRBF 0 0 0 0 0 0 0 0 0 0
+ table[0xC0] = 0x000; // U_WMRC0 0 0 0 0 0 0 0 0 0 0
+ table[0xC1] = 0x000; // U_WMRC1 0 0 0 0 0 0 0 0 0 0
+ table[0xC2] = 0x000; // U_WMRC2 0 0 0 0 0 0 0 0 0 0
+ table[0xC3] = 0x000; // U_WMRC3 0 0 0 0 0 0 0 0 0 0
+ table[0xC4] = 0x000; // U_WMRC4 0 0 0 0 0 0 0 0 0 0
+ table[0xC5] = 0x000; // U_WMRC5 0 0 0 0 0 0 0 0 0 0
+ table[0xC6] = 0x000; // U_WMRC6 0 0 0 0 0 0 0 0 0 0
+ table[0xC7] = 0x000; // U_WMRC7 0 0 0 0 0 0 0 0 0 0
+ table[0xC8] = 0x000; // U_WMRC8 0 0 0 0 0 0 0 0 0 0
+ table[0xC9] = 0x000; // U_WMRC9 0 0 0 0 0 0 0 0 0 0
+ table[0xCA] = 0x000; // U_WMRCA 0 0 0 0 0 0 0 0 0 0
+ table[0xCB] = 0x000; // U_WMRCB 0 0 0 0 0 0 0 0 0 0
+ table[0xCC] = 0x000; // U_WMRCC 0 0 0 0 0 0 0 0 0 0
+ table[0xCD] = 0x000; // U_WMRCD 0 0 0 0 0 0 0 0 0 0
+ table[0xCE] = 0x000; // U_WMRCE 0 0 0 0 0 0 0 0 0 0
+ table[0xCF] = 0x000; // U_WMRCF 0 0 0 0 0 0 0 0 0 0
+ table[0xD0] = 0x000; // U_WMRD0 0 0 0 0 0 0 0 0 0 0
+ table[0xD1] = 0x000; // U_WMRD1 0 0 0 0 0 0 0 0 0 0
+ table[0xD2] = 0x000; // U_WMRD2 0 0 0 0 0 0 0 0 0 0
+ table[0xD3] = 0x000; // U_WMRD3 0 0 0 0 0 0 0 0 0 0
+ table[0xD4] = 0x000; // U_WMRD4 0 0 0 0 0 0 0 0 0 0
+ table[0xD5] = 0x000; // U_WMRD5 0 0 0 0 0 0 0 0 0 0
+ table[0xD6] = 0x000; // U_WMRD6 0 0 0 0 0 0 0 0 0 0
+ table[0xD7] = 0x000; // U_WMRD7 0 0 0 0 0 0 0 0 0 0
+ table[0xD8] = 0x000; // U_WMRD8 0 0 0 0 0 0 0 0 0 0
+ table[0xD9] = 0x000; // U_WMRD9 0 0 0 0 0 0 0 0 0 0
+ table[0xDA] = 0x000; // U_WMRDA 0 0 0 0 0 0 0 0 0 0
+ table[0xDB] = 0x000; // U_WMRDB 0 0 0 0 0 0 0 0 0 0
+ table[0xDC] = 0x000; // U_WMRDC 0 0 0 0 0 0 0 0 0 0
+ table[0xDD] = 0x000; // U_WMRDD 0 0 0 0 0 0 0 0 0 0
+ table[0xDE] = 0x000; // U_WMRDE 0 0 0 0 0 0 0 0 0 0
+ table[0xDF] = 0x000; // U_WMRDF 0 0 0 0 0 0 0 0 0 0
+ table[0xE0] = 0x000; // U_WMRE0 0 0 0 0 0 0 0 0 0 0
+ table[0xE1] = 0x000; // U_WMRE1 0 0 0 0 0 0 0 0 0 0
+ table[0xE2] = 0x000; // U_WMRE2 0 0 0 0 0 0 0 0 0 0
+ table[0xE3] = 0x000; // U_WMRE3 0 0 0 0 0 0 0 0 0 0
+ table[0xE4] = 0x000; // U_WMRE4 0 0 0 0 0 0 0 0 0 0
+ table[0xE5] = 0x000; // U_WMRE5 0 0 0 0 0 0 0 0 0 0
+ table[0xE6] = 0x000; // U_WMRE6 0 0 0 0 0 0 0 0 0 0
+ table[0xE7] = 0x000; // U_WMRE7 0 0 0 0 0 0 0 0 0 0
+ table[0xE8] = 0x000; // U_WMRE8 0 0 0 0 0 0 0 0 0 0
+ table[0xE9] = 0x000; // U_WMRE9 0 0 0 0 0 0 0 0 0 0
+ table[0xEA] = 0x000; // U_WMREA 0 0 0 0 0 0 0 0 0 0
+ table[0xEB] = 0x000; // U_WMREB 0 0 0 0 0 0 0 0 0 0
+ table[0xEC] = 0x000; // U_WMREC 0 0 0 0 0 0 0 0 0 0
+ table[0xED] = 0x000; // U_WMRED 0 0 0 0 0 0 0 0 0 0
+ table[0xEE] = 0x000; // U_WMREE 0 0 0 0 0 0 0 0 0 0
+ table[0xEF] = 0x000; // U_WMREF 0 0 0 0 0 0 0 0 0 0
+ table[0xF0] = 0x020; // U_WMRDELETEOBJECT 0 0 0 0 1 0 0 0 0 0
+ table[0xF1] = 0x000; // U_WMRF1 0 0 0 0 0 0 0 0 0 0
+ table[0xF2] = 0x000; // U_WMRF2 0 0 0 0 0 0 0 0 0 0
+ table[0xF3] = 0x000; // U_WMRF3 0 0 0 0 0 0 0 0 0 0
+ table[0xF4] = 0x000; // U_WMRF4 0 0 0 0 0 0 0 0 0 0
+ table[0xF5] = 0x000; // U_WMRF5 0 0 0 0 0 0 0 0 0 0
+ table[0xF6] = 0x000; // U_WMRF6 0 0 0 0 0 0 0 0 0 0
+ table[0xF7] = 0x120; // U_WMRCREATEPALETTE 0 1 0 0 1 0 0 0 0 0 Not selected yet, so no change in drawing conditions
+ table[0xF8] = 0x120; // U_WMRCREATEBRUSH 0 1 0 0 1 0 0 0 0 0 "
+ table[0xF9] = 0x120; // U_WMRCREATEPATTERNBRUSH 0 1 0 0 1 0 0 0 0 0 "
+ table[0xFA] = 0x120; // U_WMRCREATEPENINDIRECT 0 1 0 0 1 0 0 0 0 0 "
+ table[0xFB] = 0x120; // U_WMRCREATEFONTINDIRECT 0 1 0 0 1 0 0 0 0 0 "
+ table[0xFC] = 0x120; // U_WMRCREATEBRUSHINDIRECT 0 1 0 0 1 0 0 0 0 0 "
+ table[0xFD] = 0x020; // U_WMRCREATEBITMAPINDIRECT 0 0 0 0 1 0 0 0 0 0 "
+ table[0xFE] = 0x020; // U_WMRCREATEBITMAP 0 0 0 0 1 0 0 0 0 0 "
+ table[0xFF] = 0x120; // U_WMRCREATEREGION 0 1 0 0 1 0 0 0 0 0 "
+ }
+ result = table[type];
+ }
+ return(result);
+}
+
+/* **********************************************************************************************
+These functions are for setting up, appending to, and then tearing down an WMF structure, including
+writing the final data structure out to a file.
+*********************************************************************************************** */
+
+/**
+ \brief Duplicate an WMR record.
+ \param wmr record to duplicate
+*/
+char *wmr_dup(
+ const char *wmr
+ ){
+ char *dup;
+ uint32_t irecsize;
+
+ if(!wmr)return(NULL);
+ memcpy(&irecsize,wmr,4); /* Size16_4 field is at offset 0 */
+ irecsize *= 2;
+ dup=malloc(irecsize);
+ if(dup){ memcpy(dup,wmr,irecsize); }
+ return(dup);
+}
+
+
+/* some of these functions are identical to the emf ones, handled by defines in uemf.h,use the emf versions */
+
+/**
+ \brief Start constructing an wmf in memory. Supply the file name and initial size.
+ \return 0 for success, >=0 for failure.
+ \param name WMF filename (will be opened)
+ \param initsize Initialize WMF in memory to hold this many bytes
+ \param chunksize When needed increase WMF in memory by this number of bytes
+ \param wt WMF in memory
+
+
+*/
+int wmf_start(
+ const char *name,
+ const uint32_t initsize,
+ const uint32_t chunksize,
+ WMFTRACK **wt
+ ){
+ FILE *fp;
+ WMFTRACK *wtl=NULL;
+
+ if(initsize < 1)return(1);
+ if(chunksize < 1)return(2);
+ if(!name)return(3);
+ wtl = (WMFTRACK *) malloc(sizeof(WMFTRACK));
+ if(!wtl)return(4);
+ wtl->buf = malloc(initsize); // no need to zero the memory
+ if(!wtl->buf){
+ free(wtl);
+ return(5);
+ }
+ fp=wmf_fopen(name,U_WRITE);
+ if(!fp){
+ free(wtl->buf);
+ free(wtl);
+ return(6);
+ }
+ wtl->fp = fp;
+ wtl->allocated = initsize;
+ wtl->used = 0;
+ wtl->records = 0;
+ wtl->PalEntries = 0;
+ wtl->chunk = chunksize;
+ wtl->largest = 0; /* only used by WMF */
+ wtl->sumObjects = 0; /* only used by WMF */
+ (void) wmf_highwater(U_HIGHWATER_CLEAR);
+ *wt=wtl;
+ return(0);
+}
+
+/**
+ \brief Release memory for an wmf structure in memory. Call this after wmf_finish().
+ \return 0 on success, >=1 on failure
+ \param wt WMF in memory
+ Renamed to uwmf_free to avoid conflict with libwmf
+*/
+int uwmf_free(
+ WMFTRACK **wt
+ ){
+ WMFTRACK *wtl;
+ if(!wt)return(1);
+ wtl=*wt;
+ if(!wtl)return(2);
+ free(wtl->buf);
+ free(wtl);
+ *wt=NULL;
+ (void)wmf_highwater(U_HIGHWATER_CLEAR);
+ return(0);
+}
+
+/**
+ \brief Finalize the emf in memory and write it to the file.
+ \return 0 on success, >=1 on failure
+ \param wt WMF in memory
+*/
+int wmf_finish(
+ WMFTRACK *wt
+ ){
+ char *record;
+ int off;
+ uint32_t tmp;
+ uint16_t tmp16;
+
+ if(!wt->fp)return(1); // This could happen if something stomps on memory, otherwise should be caught in wmf_start
+
+ // Set the header fields which were unknown up until this point
+
+
+ if(((U_WMRPLACEABLE *) wt->buf)->Key == 0x9AC6CDD7){ off = U_SIZE_WMRPLACEABLE; }
+ else { off = 0; }
+
+ record = (wt->buf + off);
+ tmp = (wt->used)/2;
+ memcpy(record + offsetof(U_WMRHEADER,Sizew), &tmp, 4); /* 16 bit words in file. not aligned */
+ tmp = (wt->largest)/2;
+ memcpy(record + offsetof(U_WMRHEADER,maxSize), &tmp, 4); /* 16 bit words in largest record, not aligned */
+ uint32_t maxobj = wmf_highwater(U_HIGHWATER_READ);
+ if(maxobj > UINT16_MAX)return(3);
+ tmp16 = maxobj;
+ memcpy(record + offsetof(U_WMRHEADER,nObjects), &tmp16, 2); /* Total number of brushes, pens, and other graphics objects defined in this file */
+
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, WMF data must be Little Endian
+ U_wmf_endian(wt->buf,wt->used,1,0); // BE to LE, entire file
+#endif
+
+ (void) U_wmr_properties(U_WMR_INVALID); /* force the release of the lookup table memory, returned value is irrelevant */
+ if(1 != fwrite(wt->buf,wt->used,1,wt->fp))return(2);
+ (void) fclose(wt->fp);
+ wt->fp=NULL;
+ return(0);
+}
+
+/**
+ \brief Retrieve contents of an WMF file by name.
+ \return 0 on success, >=1 on failure
+ \param filename Name of file to open, including the path
+ \param contents Contents of the file. Buffer must be free()'d by caller.
+ \param length Number of bytes in Contents
+*/
+int wmf_readdata(
+ const char *filename,
+ char **contents,
+ size_t *length
+ ){
+ FILE *fp;
+ int status=0;
+
+ *contents=NULL;
+ fp=wmf_fopen(filename,U_READ);
+ if(!fp){ status = 1; }
+ else {
+ // read the entire file into memory
+ fseek(fp, 0, SEEK_END); // move to end
+ *length = ftell(fp);
+ rewind(fp);
+ *contents = (char *) malloc(*length);
+ if(!*contents){
+ status = 2;
+ }
+ else {
+ size_t inbytes = fread(*contents,*length,1,fp);
+ if(inbytes != 1){
+ free(*contents);
+ status = 3;
+ }
+ else {
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, WMF data is Little Endian
+ U_wmf_endian(*contents,*length,0,0); // LE to BE, entire file
+#endif
+ }
+ }
+ fclose(fp);
+ }
+ return(status);
+}
+
+/**
+ \brief Append an WMF record to a wmf in memory. This may reallocate buf memory.
+ \return 0 for success, >=1 for failure.
+ \param rec Record to append to WMF in memory
+ \param wt WMF in memory
+ \param freerec If true, free rec after append
+*/
+int wmf_append(
+ U_METARECORD *rec,
+ WMFTRACK *wt,
+ int freerec
+ ){
+ size_t deficit;
+ uint32_t wp;
+ uint32_t size;
+
+ size = U_wmr_size(rec);
+#ifdef U_VALGRIND
+ printf("\nbefore \n");
+ printf(" probe %d\n",memprobe(rec, size));
+ printf("after \n");
+#endif
+ if(!rec)return(1);
+ if(!wt)return(2);
+ if(size + wt->used > wt->allocated){
+ deficit = size + wt->used - wt->allocated;
+ if(deficit < wt->chunk)deficit = wt->chunk;
+ wt->allocated += deficit;
+ wt->buf = realloc(wt->buf,wt->allocated);
+ if(!wt->buf)return(3);
+ }
+ memcpy(wt->buf + wt->used, rec, size);
+ wt->used += size;
+ wt->records++;
+ if(wt->largest < size)wt->largest=size;
+ /* does the record create an object: brush, font, palette, pen, or region ?
+ Following EOF properties comes back as U_WMR_INVALID */
+ wp = U_wmr_properties(U_WMRTYPE(rec));
+ if((wp != U_WMR_INVALID) && (U_DRAW_OBJECT & wp))wt->sumObjects++;
+ if(freerec){ free(rec); }
+ return(0);
+}
+
+/**
+ \brief Append an WMF header to a wmf in memory. This may reallocate buf memory.
+ WMF header is not a normal record, method used to figure out its size is different.
+ \return 0 for success, >=1 for failure.
+ \param rec header to append to WMF in memory
+ \param wt WMF in memory
+ \param freerec If true, free rec after append
+*/
+int wmf_header_append(
+ U_METARECORD *rec,
+ WMFTRACK *wt,
+ int freerec
+ ){
+ size_t deficit;
+ unsigned int hsize;
+
+ hsize = (((U_WMRPLACEABLE *) rec)->Key == 0x9AC6CDD7 ? U_SIZE_WMRHEADER + U_SIZE_WMRPLACEABLE: U_SIZE_WMRHEADER);
+
+#ifdef U_VALGRIND
+ printf("\nbefore \n");
+ printf(" probe %d\n",memprobe(rec, hsize));
+ printf("after \n");
+#endif
+ if(!rec)return(1);
+ if(!wt)return(2);
+ if(U_wmr_size(rec) + wt->used > wt->allocated){
+ deficit = hsize + wt->used - wt->allocated;
+ if(deficit < wt->chunk)deficit = wt->chunk;
+ wt->allocated += deficit;
+ wt->buf = realloc(wt->buf,wt->allocated);
+ if(!wt->buf)return(3);
+ }
+ memcpy(wt->buf + wt->used, rec, hsize);
+ wt->used += hsize;
+ /* do NOT increment records count, this is not strictly a record */
+ if(wt->largest < hsize)wt->largest=hsize;
+ if(freerec){ free(rec); }
+ return(0);
+}
+
+/**
+ \brief Keep track of the largest number used.
+ \return The largest object number used.
+ \param setval U_HIGHWATER_READ only return value, U_HIGHWATER_CLEAR also set value to 0, anything else, set to this if higher than stored.
+*/
+int wmf_highwater(uint32_t setval){
+ static uint32_t value=0;
+ uint32_t retval;
+ if(setval == U_HIGHWATER_READ){
+ retval = value;
+ }
+ else if(setval == U_HIGHWATER_CLEAR){
+ retval = value;
+ value = 0;
+ }
+ else {
+ if(setval > value)value = setval;
+ retval = value;
+ }
+ return(retval);
+}
+
+/**
+ \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle.
+ \return 0 for success, >=1 for failure.
+ \param initsize Initialize with space for this number of handles
+ \param chunksize When needed increase space by this number of handles
+ \param wht WMF handle table
+*/
+int wmf_htable_create(
+ uint32_t initsize,
+ uint32_t chunksize,
+ WMFHANDLES **wht
+ ){
+ WMFHANDLES *whtl;
+
+ if(initsize<1)return(1);
+ if(chunksize<1)return(2);
+ whtl = (WMFHANDLES *) malloc(sizeof(WMFHANDLES));
+ if(!whtl)return(3);
+ whtl->table = malloc(initsize * sizeof(uint32_t));
+ if(!whtl->table){
+ free(whtl);
+ return(4);
+ }
+ memset(whtl->table , 0, initsize * sizeof(uint32_t)); // zero all slots in the table
+ whtl->allocated = initsize;
+ whtl->chunk = chunksize;
+ whtl->table[0] = 0; // This slot isn't actually ever used
+ whtl->lolimit = 1; // first available table entry
+ whtl->hilimit = 0; // no entries in the table yet.
+ whtl->peak = 0; // no entries in the table ever
+ *wht = whtl;
+ return(0);
+}
+
+/**
+ \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param wht WMF handle table
+
+*/
+int wmf_htable_delete(
+ uint32_t *ih,
+ WMFHANDLES *wht
+ ){
+ if(!wht)return(1);
+ if(!wht->table)return(2);
+ if(*ih < 1)return(4); // invalid handle
+ if(!wht->table[*ih])return(5); // requested table position was not in use
+ wht->table[*ih]=0; // remove handle from table
+ while(wht->hilimit>0 && !wht->table[wht->hilimit]){ // adjust hilimit
+ wht->hilimit--;
+ }
+ if(*ih < wht->lolimit)wht->lolimit = *ih; // adjust lolimit
+ *ih=0; // invalidate handle variable, so a second delete will of it is not possible
+ return(0);
+}
+
+/**
+ \brief Returns the index of the first free slot.
+ Call realloc() if needed. The slot is set to handle (indicates occupied) and the peak value is adjusted.
+ \return 0 for success, >=1 for failure.
+ \param ih handle
+ \param wht WMF handle table
+*/
+int wmf_htable_insert(
+ uint32_t *ih,
+ WMFHANDLES *wht
+ ){
+ size_t newsize;
+
+ if(!wht)return(1);
+ if(!wht->table)return(2);
+ if(!ih)return(4);
+ if(wht->lolimit >= wht->allocated - 1){ // need to reallocate
+ newsize=wht->allocated + wht->chunk;
+ wht->table = realloc(wht->table,newsize * sizeof(uint32_t));
+ if(!wht->table)return(5);
+ memset(&wht->table[wht->allocated] , 0, wht->chunk * sizeof(uint32_t)); // zero all NEW slots in the table
+ wht->allocated = newsize;
+ }
+ *ih = wht->lolimit; // handle that is inserted in first available slot
+ wht->table[*ih] = *ih; // handle goes into preexisting (but zero) slot in table, handle number is the same as the slot number
+ if(*ih > wht->hilimit){
+ wht->hilimit = *ih;
+ (void) wmf_highwater(wht->hilimit);
+ }
+ if(*ih > wht->peak){
+ wht->peak = *ih;
+ }
+ /* Find the next available slot, it will be at least one higher than the present position, and will have a zero in it. */
+ wht->lolimit++;
+ while(wht->lolimit<= wht->hilimit && wht->table[wht->lolimit]){ wht->lolimit++; }
+ return(0);
+}
+
+/**
+ \brief Free all memory in an htable. Sets the pointer to NULL.
+ \return 0 for success, >=1 for failure.
+ \param wht WMF handle table
+*/
+int wmf_htable_free(
+ WMFHANDLES **wht
+ ){
+ WMFHANDLES *whtl;
+ if(!wht)return(1);
+ whtl = *wht;
+ if(!whtl)return(2);
+ if(!whtl->table)return(3);
+ free(whtl->table);
+ free(whtl);
+ *wht=NULL;
+ return(0);
+}
+
+
+/* **********************************************************************************************
+These functions create standard structures used in the WMR records.
+*********************************************************************************************** */
+
+// hide these from Doxygen
+//! \cond
+/* **********************************************************************************************
+These functions contain shared code used by various U_WMR*_print functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+*********************************************************************************************** */
+
+/* These definitons only used here */
+#define U_SIZE_WMR_NOARGS 6
+#define U_SIZE_WMR_1ARG16 8
+#define U_SIZE_WMR_2ARG16 10
+#define U_SIZE_WMR_3ARG16 12
+#define U_SIZE_WMR_4ARG16 14
+#define U_SIZE_WMR_5ARG16 16
+#define U_SIZE_WMR_6ARG16 18
+#define U_SIZE_WMR_8ARG16 22
+
+char *U_WMRCORENONE_set(char *string){
+ printf("unimplemented creator for:%s\n",string);
+ return(NULL);
+}
+
+void U_WMRCORE_SETRECHEAD(char *record, uint32_t irecsize, int iType){
+ uint32_t Size16;
+ Size16 = irecsize/2;
+ memcpy(record,&Size16,4); /*Size16_4 is at offset 0 in the record */
+ ((U_METARECORD *) record)->iType = iType;
+ ((U_METARECORD *) record)->xb = U_WMR_XB_FROM_TYPE(iType);
+}
+
+/* records that have no arguments */
+char *U_WMRCORE_NOARGS_set(
+ int iType
+){
+ char *record=NULL;
+ uint32_t irecsize;
+ irecsize = U_SIZE_METARECORD;
+ record = malloc(irecsize);
+ if(record)U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ return(record);
+}
+
+
+/* records like U_WMRFLOODFILL and others. all args are optional, Color is not */
+char *U_WMRCORE_1U16_CRF_2U16_set(
+ int iType,
+ uint16_t *arg1,
+ U_COLORREF Color,
+ uint16_t *arg2,
+ uint16_t *arg3
+){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ irecsize = U_SIZE_METARECORD + U_SIZE_COLORREF;
+ if(arg1)irecsize+=2;
+ if(arg2)irecsize+=2;
+ if(arg3)irecsize+=2;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ if(arg1){ memcpy(record + off, arg1, 2); off+=2; }
+ memcpy(record + off, &Color, 4); off+=4;
+ if(arg2){ memcpy(record + off, arg2, 2); off+=2; }
+ if(arg3){ memcpy(record + off, arg3, 2); }
+ }
+ return(record);
+}
+
+/* records that have a single uint16_t argument like U_WMRSETMAPMODE
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_1U16_set(
+ int iType,
+ uint16_t arg1
+){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ irecsize = U_SIZE_WMR_1ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2);
+ }
+ return(record);
+}
+
+/* records that have two uint16_t arguments like U_WMRSETBKMODE
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_2U16_set(
+ int iType,
+ uint16_t arg1,
+ uint16_t arg2
+){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ irecsize = U_SIZE_WMR_2ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2); off+=2;
+ memcpy(record+off,&arg2,2);
+ }
+ return(record);
+}
+
+/* records that have four uint16_t arguments like U_WMRSCALEWINDOWEXT
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_4U16_set(
+ int iType,
+ uint16_t arg1,
+ uint16_t arg2,
+ uint16_t arg3,
+ uint16_t arg4
+){
+ char *record=NULL;
+ uint32_t irecsize, off;
+ irecsize = U_SIZE_WMR_4ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2); off+=2;
+ memcpy(record+off,&arg2,2); off+=2;
+ memcpy(record+off,&arg3,2); off+=2;
+ memcpy(record+off,&arg4,2);
+ }
+ return(record);
+}
+
+/* records that have five uint16_t arguments like U_WMRCREATEPENINDIRECT
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_5U16_set(
+ int iType,
+ uint16_t arg1,
+ uint16_t arg2,
+ uint16_t arg3,
+ uint16_t arg4,
+ uint16_t arg5
+){
+ char *record=NULL;
+ uint32_t irecsize, off;
+ irecsize = U_SIZE_WMR_5ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2); off+=2;
+ memcpy(record+off,&arg2,2); off+=2;
+ memcpy(record+off,&arg3,2); off+=2;
+ memcpy(record+off,&arg4,2); off+=2;
+ memcpy(record+off,&arg5,2);
+ }
+ return(record);
+}
+
+/* records that have size uint16_t arguments like U_ROUNDREC
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_6U16_set(
+ int iType,
+ uint16_t arg1,
+ uint16_t arg2,
+ uint16_t arg3,
+ uint16_t arg4,
+ uint16_t arg5,
+ uint16_t arg6
+){
+ char *record=NULL;
+ uint32_t irecsize, off;
+ irecsize = U_SIZE_WMR_6ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2); off+=2;
+ memcpy(record+off,&arg2,2); off+=2;
+ memcpy(record+off,&arg3,2); off+=2;
+ memcpy(record+off,&arg4,2); off+=2;
+ memcpy(record+off,&arg5,2); off+=2;
+ memcpy(record+off,&arg6,2);
+ }
+ return(record);
+}
+
+/* records that have eight uint16_t arguments like U_WMRARC
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_8U16_set(
+ int iType,
+ uint16_t arg1,
+ uint16_t arg2,
+ uint16_t arg3,
+ uint16_t arg4,
+ uint16_t arg5,
+ uint16_t arg6,
+ uint16_t arg7,
+ uint16_t arg8
+){
+ char *record=NULL;
+ uint32_t irecsize, off;
+ irecsize = U_SIZE_WMR_8ARG16;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&arg1,2); off+=2;
+ memcpy(record+off,&arg2,2); off+=2;
+ memcpy(record+off,&arg3,2); off+=2;
+ memcpy(record+off,&arg4,2); off+=2;
+ memcpy(record+off,&arg5,2); off+=2;
+ memcpy(record+off,&arg6,2); off+=2;
+ memcpy(record+off,&arg7,2); off+=2;
+ memcpy(record+off,&arg8,2);
+ }
+ return(record);
+}
+
+/* records that have
+ arg1 an (optional) (u)int16
+ arg2 an (optional( (u)int16
+ N16 number of (u)int16_t cells in array. may be zero
+ array of N16 (u)int16_t cells (or any structure that is 2N bytes in size), should be NULL if N16 is 0.
+ like U_WMRCREATEBRUSHINDIRECT with arg1=arg2=NULL
+*/
+char *U_WMRCORE_2U16_N16_set(
+ int iType,
+ const uint16_t *arg1,
+ const uint16_t *arg2,
+ const uint16_t N16,
+ const void *array
+ ){
+ char *record=NULL;
+ uint32_t irecsize, off;
+ irecsize = U_SIZE_METARECORD + N16*2;
+ if(arg1)irecsize += 2;
+ if(arg2)irecsize += 2;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ if(arg1){ memcpy(record+off,arg1,2); off+=2; }
+ if(arg2){ memcpy(record+off,arg2,2); off+=2; }
+ if(N16){ memcpy(record+off,array,2*N16); }
+ }
+ return(record);
+}
+
+
+
+/* records that set a U_PALETTE , then a count and then a uint16_t list like U_WMRANIMATEPALETTE
+ May also be used with int16_t with appropriate casts */
+char *U_WMRCORE_PALETTE_set(
+ int iType,
+ const U_PALETTE *Palette
+){
+ char *record=NULL;
+ uint32_t irecsize, off, nPE;
+ nPE = 4*Palette->NumEntries;
+ if(!nPE)return(NULL); /* What would it mean to load an empty palette??? */
+ irecsize = U_SIZE_METARECORD + 2 + 2 + nPE;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,iType);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off, &Palette->Start, 2); off+=2;
+ memcpy(record+off, &Palette->NumEntries, 2); off+=2;
+ memcpy(record+off, &Palette->PalEntries, nPE);
+ }
+ return(record);
+}
+
+//! \endcond
+
+/* **********************************************************************************************
+These functions are simpler or more convenient ways to generate the specified types of WMR records.
+Each should be called in preference to the underlying "base" WMR function.
+*********************************************************************************************** */
+
+
+/**
+ \brief Allocate and construct a U_WMRDELETEOBJECT record and also delete the requested object from the table.
+ Use this function instead of calling U_WMRDELETEOBJECT_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRDELETEOBJECT record, or NULL on error.
+ \param ihObject Pointer to handle to delete. This value is set to 0xFFFFFFFF if the function succeeds.
+ \param wht WMF handle table
+
+ Note that calling this function should always be conditional on the specifed object being defined. It is easy to
+ write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined.
+ Then a later modification, possibly quite far away in the code, causes it to be undefined. That distant change will
+ result in a failure when this function reutrns. That problem cannot be handled here because the only values which
+ may be returned are a valid U_WMRDELETEOBJECT record or a NULL, and other errors could result in the NULL.
+ So the object must be checked before the call.
+*/
+char *wdeleteobject_set(
+ uint32_t *ihObject,
+ WMFHANDLES *wht
+ ){
+ uint32_t saveObject=*ihObject; /* caller 0->N */
+ *ihObject += 1; /* caller 0->N --> 1->N+1 table*/
+ if(wmf_htable_delete(ihObject,wht))return(NULL); /* invalid handle or other problem, cannot be deleted */
+ *ihObject = 0xFFFFFFFF; /* EMF would have set to 0, but 0 is an allowed index in WMF */
+ return(U_WMRDELETEOBJECT_set(saveObject)); /* caller 0->N */
+}
+
+/**
+ \brief Allocate and construct a U_WMRSELECTOBJECT record, checks that the handle specified is one that can actually be selected.
+ Use this function instead of calling U_WMRSELECTOBJECT_set() directly.
+ Object Pointer in WMF (caller) is 0->N, so is record, so no correction to 1->N+1 needed here.
+ \return pointer to the U_WMRSELECTOBJECT record, or NULL on error.
+ \param ihObject handle to select
+ \param wht WMF handle table
+*/
+char *wselectobject_set(
+ uint32_t ihObject,
+ WMFHANDLES *wht
+ ){
+ /* WMF has no stock objects! */
+ if(ihObject > wht->hilimit)return(NULL); // handle this high is not in the table
+ /* caller uses 0->N, table uses 1->N+1 */
+ if(!wht->table[ihObject+1])return(NULL); // handle is not in the table, so cannot be selected
+ /* file uses 0->N */
+ return(U_WMRSELECTOBJECT_set(ihObject));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEPENINDIRECT record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEPENINDIRECT_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRCREATEPENINDIRECT record, or NULL on error.
+ \param ihPen handle to be used by new object
+ \param wht WMF handle table
+ \param pen Pen parameters (U_PEN)
+*/
+char *wcreatepenindirect_set(
+ uint32_t *ihPen,
+ WMFHANDLES *wht,
+ U_PEN pen
+ ){
+ if(wmf_htable_insert(ihPen, wht))return(NULL);
+ *ihPen -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEPENINDIRECT_set(pen));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEBRUSHINDIRECT record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEBRUSHINDIRECT_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRCREATEBRUSHINDIRECT record, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param wht WMF handle table
+ \param lb Brush parameters
+*/
+char *wcreatebrushindirect_set(
+ uint32_t *ihBrush,
+ WMFHANDLES *wht,
+ U_WLOGBRUSH lb
+ ){
+ if(wmf_htable_insert(ihBrush, wht))return(NULL);
+ *ihBrush -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEBRUSHINDIRECT_set(lb));
+}
+
+/**
+ \brief Allocate and construct a U_WMRDIBCREATEPATTERNBRUSH record from a DIB.
+ Use this function instead of calling U_WMRDIBCREATEPATTERNBRUSH_set() directly.
+ \return pointer to the U_WMRDIBCREATEPATTERNBRUSH record, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param wht WMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bmi Bitmap info
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *wcreatedibpatternbrush_srcdib_set(
+ uint32_t *ihBrush,
+ WMFHANDLES *wht,
+ const uint32_t iUsage,
+ const U_BITMAPINFO *Bmi,
+ const uint32_t cbPx,
+ const char *Px
+
+ ){
+ if(wmf_htable_insert(ihBrush, wht))return(NULL);
+ *ihBrush -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRDIBCREATEPATTERNBRUSH_set(U_BS_DIBPATTERNPT, iUsage, Bmi, cbPx, Px,NULL));
+}
+
+/**
+ \brief Allocate and construct a U_WMRDIBCREATEPATTERNBRUSH record from a U_BITMAP16 object.
+ Use this function instead of calling U_WMRDIBCREATEPATTERNBRUSH_set() directly.
+ \return pointer to the U_WMRDIBCREATEPATTERNBRUSH record, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param wht WMF handle table
+ \param iUsage DIBColors enumeration
+ \param Bm16 Pointer to a Bitmap16 object
+*/
+char *wcreatedibpatternbrush_srcbm16_set(
+ uint32_t *ihBrush,
+ WMFHANDLES *wht,
+ const uint32_t iUsage,
+ const U_BITMAP16 *Bm16
+ ){
+ if(wmf_htable_insert(ihBrush, wht))return(NULL);
+ *ihBrush -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRDIBCREATEPATTERNBRUSH_set(U_BS_PATTERN, iUsage, NULL, 0, NULL, Bm16));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEPATTERNBRUSH record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEPATTERNBRUSH_set() directly.
+ WARNING - U_WMRCREATEPATTERNBRUSH has been declared obsolete and application support is spotty -
+ use U_WMRDIBCREATEPATTERNBRUSH instead.
+ \return pointer to the U_WMRCREATEPATTERNBRUSH record, or NULL on error.
+ \param ihBrush handle to be used by new object
+ \param wht WMF handle table
+ \param Bm16 Pointer to a Bitmap16 structure (only first 10 bytes are used).
+ \param Pattern Pointer to a byte array described by Bm16. (Pattern may be a pointer to the BM16 Bits field.)
+*/
+char *wcreatepatternbrush_set(
+ uint32_t *ihBrush,
+ WMFHANDLES *wht,
+ U_BITMAP16 *Bm16,
+ char *Pattern
+ ){
+ if(wmf_htable_insert(ihBrush, wht))return(NULL);
+ *ihBrush -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEPATTERNBRUSH_set(Bm16, Pattern));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEFONTINDIRECT record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEFONTINDIRECT_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRCREATEFONTINDIRECT record, or NULL on error.
+ \param ihFont Font handle, will be created and returned
+ \param wht Pointer to structure holding all WMF handles
+ \param uf Pointer to Font parameters as U_FONT *
+*/
+char *wcreatefontindirect_set(
+ uint32_t *ihFont,
+ WMFHANDLES *wht,
+ U_FONT *uf
+ ){
+ if(wmf_htable_insert(ihFont, wht))return(NULL);
+ *ihFont -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEFONTINDIRECT_set(uf));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEPALETTE record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEPALETTE_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRCREATEPALETTE record, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param wht Pointer to structure holding all WMF handles
+ \param up Palette parameters
+*/
+char *wcreatepalette_set(
+ uint32_t *ihPal,
+ WMFHANDLES *wht,
+ U_PALETTE *up
+ ){
+ if(wmf_htable_insert(ihPal, wht))return(NULL);
+ *ihPal -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEPALETTE_set(up));
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETPALENTRIES record, create a handle and returns it
+ Use this function instead of calling U_WMRSETPALENTRIES_set() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_WMRSETPALENTRIES record, or NULL on error.
+ \param ihPal Palette handle, will be created and returned
+ \param wht Pointer to structure holding all WMF handles
+ \param Palettes Values to set with
+*/
+char *wsetpaletteentries_set(
+ uint32_t *ihPal,
+ WMFHANDLES *wht,
+ const U_PALETTE *Palettes
+ ){
+ if(wmf_htable_insert(ihPal, wht))return(NULL);
+ *ihPal -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRSETPALENTRIES_set(Palettes));
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEREGION record, create a handle and returns it
+ Use this function instead of calling U_WMRCREATEREGION() directly.
+ Object Pointer in WMF (caller) is 0->N, but in htable it is 1->N+1, make that correction here.
+ \return pointer to the U_REGIONS record, or NULL on error.
+ \param ihReg Region handle, will be created and returned
+ \param wht Pointer to structure holding all WMF handles
+ \param Region Values to set with
+*/
+char *wcreateregion_set(
+ uint32_t *ihReg,
+ WMFHANDLES *wht,
+ const U_REGION *Region
+ ){
+ if(wmf_htable_insert(ihReg, wht))return(NULL);
+ *ihReg -= 1; /* 1->N+1 --> 0->N */
+ return(U_WMRCREATEREGION_set(Region));
+}
+/* A few escape functions are implemented, just those that set a state or a single value */
+
+/**
+ \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it
+ Use this function instead of calling U_WMRESCAPE_set() directly.
+ \return pointer to the U_WMRESCAPE structure, or NULL on error.
+*/
+char *wbegin_path_set(void){
+ return(U_WMRESCAPE_set(U_MFE_BEGIN_PATH,0,NULL));
+}
+
+/**
+ \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it
+ Use this function instead of calling U_WMRESCAPE_set() directly.
+ \return pointer to the U_WMRESCAPE structure, or NULL on error.
+*/
+char *wend_path_set(void){
+ return(U_WMRESCAPE_set(U_MFE_END_PATH,0,NULL));
+}
+
+/**
+ \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it
+ Use this function instead of calling U_WMRESCAPE_set() directly.
+ \return pointer to the U_WMRESCAPE structure, or NULL on error.
+ \param Type PostScriptCap Enumeration, anything else is an error
+*/
+char *wlinecap_set(
+ int32_t Type
+ ){
+ char *record =NULL;
+ if(Type == U_WPS_CAP_NOTSET ||
+ Type == U_WPS_CAP_FLAT ||
+ Type == U_WPS_CAP_ROUND ||
+ Type == U_WPS_CAP_SQUARE){ record = U_WMRESCAPE_set(U_MFE_SETLINECAP,4,&Type); }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it
+ Use this function instead of calling U_WMRESCAPE_set() directly.
+ \return pointer to the U_WMRESCAPE structure, or NULL on error.
+ \param Type PostScriptCap Enumeration, anything else is an error
+*/
+char *wlinejoin_set(
+ int32_t Type
+ ){
+ char *record =NULL;
+ if(Type == U_WPS_JOIN_NOTSET ||
+ Type == U_WPS_JOIN_MITER ||
+ Type == U_WPS_JOIN_ROUND ||
+ Type == U_WPS_JOIN_BEVEL){ record = U_WMRESCAPE_set(U_MFE_SETLINEJOIN,4,&Type); }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct the specified U_WMRESCAPE structure, create a handle and returns it
+ Use this function instead of calling U_WMRESCAPE_set() directly.
+ \return pointer to the U_WMRESCAPE structure, or NULL on error.
+ \param limit PostScriptCap Enumeration, anything else is an error
+*/
+char *wmiterlimit_set(
+ int32_t limit
+ ){
+ return(U_WMRESCAPE_set(U_MFE_SETMITERLIMIT,4,&limit));
+}
+
+/* **********************************************************************************************
+These are the core WMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_WMR_* index number.
+*********************************************************************************************** */
+
+/**
+ \brief Set up fields for a (placeable) WMR_HEADER. Most of the fields are blank and are not set until all is written.
+ Typically values are something like (8.5,11.0), 1440 (Letter paper, 1440 DPI).
+ The scaled paper size must fit in the range 0<->32767 inclusive, because it must be represented by a signed 16bit number.
+ If the size + dpi result in out of range values a failure will result.
+ \return pointer to the WMF header record, or NULL on failure
+ \param size Pointer to page size (if NULL, not a placeable header) in inches. Values must be positive and scaled
+ \param dpi Logical units/inch. If 0 defaults to 1440.
+*/
+char *U_WMRHEADER_set(
+ U_PAIRF *size,
+ unsigned int dpi
+ ){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ double xmax,ymax;
+ int16_t xm16,ym16;
+ irecsize = (size ? U_SIZE_WMRHEADER + U_SIZE_WMRPLACEABLE : U_SIZE_WMRHEADER);
+ record = calloc(1,irecsize); /* most will be zero*/
+ off = 0;
+ if(record){
+ if(size){ /* placeable */
+ if(!dpi)dpi=1440;
+ xmax = U_ROUND((double) size->x * (double) dpi);
+ ymax = U_ROUND((double) size->y * (double) dpi);
+ if(xmax < 0 || ymax < 0 || xmax > 32767 || ymax > 32767){
+ free(record);
+ return(NULL);
+ }
+ xm16 = xmax;
+ ym16 = ymax;
+ ((U_WMRPLACEABLE *) record)->Key = 0x9AC6CDD7;
+ ((U_WMRPLACEABLE *) record)->HWmf = 0; /* Manual says number of 16 bit words in record, but all WMF examples had it as 0 */
+ ((U_WMRPLACEABLE *) record)->Dst.left = 0;
+ ((U_WMRPLACEABLE *) record)->Dst.top = 0;
+ ((U_WMRPLACEABLE *) record)->Dst.right = xm16;
+ ((U_WMRPLACEABLE *) record)->Dst.bottom = ym16;
+ ((U_WMRPLACEABLE *) record)->Inch = dpi;
+ ((U_WMRPLACEABLE *) record)->Reserved = 0;
+ ((U_WMRPLACEABLE *) record)->Checksum = U_16_checksum((int16_t *)record,10);
+ off = U_SIZE_WMRPLACEABLE;
+ }
+ ((U_WMRHEADER *) (record + off))->iType = 1;
+ ((U_WMRHEADER *) (record + off))->version = U_METAVERSION300;
+ ((U_WMRHEADER *) (record + off))->Size16w = U_SIZE_WMRHEADER/2;
+ }
+ return(record);
+}
+
+
+/**
+ \brief Allocate and construct a U_WMREOF record
+ \return pointer to the U_WMREOF record, or NULL on error.
+*/
+char *U_WMREOF_set(void){
+ return U_WMRCORE_NOARGS_set(U_WMR_EOF);
+}
+
+/**
+ \brief Create and return a U_WMRSETBKCOLOR record
+ \return pointer to the U_WMRSETBKCOLOR record, or NULL on error
+ \param Color Background Color.
+*/
+char *U_WMRSETBKCOLOR_set(U_COLORREF Color){
+ return U_WMRCORE_1U16_CRF_2U16_set(U_WMR_SETBKCOLOR,NULL,Color,NULL,NULL);
+}
+
+/**
+ \brief Create and return a U_WMRSETBKMODE record
+ \return pointer to the U_WMRSETBKMODE record, or NULL on error
+ \param Mode MixMode Enumeration
+*/
+char *U_WMRSETBKMODE_set(uint16_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETBKMODE, Mode, 0);
+}
+
+/**
+ \brief Create and return a U_WMRSETMAPMODE record
+ \return pointer to the U_WMRSETMAPMODE record, or NULL on error
+ \param Mode MapMode Enumeration
+*/
+char *U_WMRSETMAPMODE_set(uint16_t Mode){
+ return U_WMRCORE_1U16_set(U_WMR_SETMAPMODE, Mode);
+}
+
+/**
+ \brief Create and return a U_WMRSETROP2 record
+ \return pointer to the U_WMRSETROP2 record, or NULL on error
+ \param Mode Binary Raster Operation Enumeration
+*/
+char *U_WMRSETROP2_set(uint16_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETROP2, Mode, 0);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETRELABS record
+ \return pointer to the U_WMRSETRELABS record, or NULL on error.
+*/
+char *U_WMRSETRELABS_set(void){
+ return U_WMRCORE_NOARGS_set(U_WMR_SETRELABS);
+}
+
+/**
+ \brief Create and return a U_WMRSETPOLYFILLMODE record
+ \return pointer to the U_WMRSETPOLYFILLMODE record, or NULL on error
+ \param Mode PolyFillMode Enumeration
+*/
+char *U_WMRSETPOLYFILLMODE_set(uint16_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETPOLYFILLMODE, Mode, 0);
+}
+
+/**
+ \brief Create and return a U_WMRSETSTRETCHBLTMODE record
+ \return pointer to the U_WMRSETSTRETCHBLTMODE record, or NULL on error
+ \param Mode StretchMode Enumeration
+*/
+char *U_WMRSETSTRETCHBLTMODE_set(uint16_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETSTRETCHBLTMODE, Mode, 0);
+}
+
+/**
+ \brief Create and return a U_WMRSETTEXTCHAREXTRA record
+ \return pointer to the U_WMRSETTEXTCHAREXTRA record, or NULL on error
+ \param Mode Extra space in logical units to add to each character
+*/
+char *U_WMRSETTEXTCHAREXTRA_set(uint16_t Mode){
+ return U_WMRCORE_1U16_set(U_WMR_SETTEXTCHAREXTRA, Mode);
+}
+
+/**
+ \brief Create and return a U_WMRSETTEXTCOLOR record
+ \return pointer to the U_WMRSETTEXTCOLOR record, or NULL on error
+ \param Color Text Color.
+*/
+char *U_WMRSETTEXTCOLOR_set(U_COLORREF Color){
+ return U_WMRCORE_1U16_CRF_2U16_set(U_WMR_SETTEXTCOLOR,NULL,Color,NULL,NULL);
+}
+
+/**
+ \brief Create and return a U_WMRSETTEXTJUSTIFICATION record
+ \return pointer to the U_WMRSETTEXTJUSTIFICATION record, or NULL on error
+ \param Count Number of space characters in the line.
+ \param Extra Number of extra space characters to add to the line.
+*/
+char *U_WMRSETTEXTJUSTIFICATION_set(uint16_t Count, uint16_t Extra){
+ return U_WMRCORE_2U16_set(U_WMR_SETBKMODE, Count, Extra);
+}
+
+/**
+ \brief Create and return a U_WMRSETWINDOWORG record
+ \return pointer to the U_WMRSETWINDOWORG record, or NULL on error
+ \param coord Window Origin.
+*/
+char *U_WMRSETWINDOWORG_set(U_POINT16 coord){
+ return U_WMRCORE_2U16_set(U_WMR_SETWINDOWORG, U_U16(coord.y), U_U16(coord.x));
+}
+
+/**
+ \brief Create and return a U_WMRSETWINDOWEXT record
+ \return pointer to the U_WMRSETWINDOWEXT record, or NULL on error
+ \param extent Window Extent.
+*/
+char *U_WMRSETWINDOWEXT_set(U_POINT16 extent){
+ return U_WMRCORE_2U16_set(U_WMR_SETWINDOWEXT, U_U16(extent.y), U_U16(extent.x));
+}
+
+/**
+ \brief Create and return a U_WMRSETVIEWPORTORG record
+ \return pointer to the U_WMRSETVIEWPORTORG record, or NULL on error
+ \param coord Viewport Origin.
+*/
+char *U_WMRSETVIEWPORTORG_set(U_POINT16 coord){
+ return U_WMRCORE_2U16_set(U_WMR_SETVIEWPORTORG, U_U16(coord.y), U_U16(coord.x));
+}
+
+/**
+ \brief Create and return a U_WMRSETVIEWPORTEXT record
+ \return pointer to the U_WMRSETVIEWPORTEXT record, or NULL on error
+ \param extent Viewport Extent.
+*/
+char *U_WMRSETVIEWPORTEXT_set(U_POINT16 extent){
+ return U_WMRCORE_2U16_set(U_WMR_SETWINDOWEXT, U_U16(extent.y), U_U16(extent.x));
+}
+
+/**
+ \brief Create and return a U_WMROFFSETWINDOWORG record
+ \return pointer to the U_WMROFFSETWINDOWORG record, or NULL on error
+ \param offset Window offset in device units.
+*/
+char *U_WMROFFSETWINDOWORG_set(U_POINT16 offset){
+ return U_WMRCORE_2U16_set(U_WMR_OFFSETWINDOWORG, U_U16(offset.y), U_U16(offset.x));
+}
+
+/**
+ \brief Create and return a U_WMRSCALEWINDOWEXT record
+ \return pointer to the U_WMRSCALEWINDOWEXT record, or NULL on error
+ \param Denom {X,Y} denominators.
+ \param Num {X,Y} numerators.
+*/
+char *U_WMRSCALEWINDOWEXT_set(U_POINT16 Denom, U_POINT16 Num){
+ return U_WMRCORE_4U16_set(U_WMR_SCALEWINDOWEXT, U_U16(Denom.y), U_U16(Num.y), U_U16(Denom.x), U_U16(Num.x));
+}
+
+/**
+ \brief Create and return a U_WMROFFSETVIEWPORTORG record
+ \return pointer to the U_WMROFFSETVIEWPORTORG record, or NULL on error
+ \param offset Viewport offset in device units.
+*/
+char *U_WMROFFSETVIEWPORTORG_set(U_POINT16 offset){
+ return U_WMRCORE_2U16_set(U_WMR_OFFSETVIEWPORTORG, U_U16(offset.y), U_U16(offset.x));
+}
+
+/**
+ \brief Create and return a U_WMRSCALEVIEWPORTEXT record
+ \return pointer to the U_WMRSCALEVIEWPORTEXT record, or NULL on error
+ \param Denom {X,Y} denominators.
+ \param Num {X,Y} numerators.
+*/
+char *U_WMRSCALEVIEWPORTEXT_set(U_POINT16 Denom, U_POINT16 Num){
+ return U_WMRCORE_4U16_set(U_WMR_SCALEVIEWPORTEXT, U_U16(Denom.y), U_U16(Num.y), U_U16(Denom.x), U_U16(Num.x));
+}
+
+/**
+ \brief Create and return a U_WMRLINETO record
+ \return pointer to the U_WMRLINETO record, or NULL on error
+ \param coord Draw line to {X,Y}.
+*/
+char *U_WMRLINETO_set(U_POINT16 coord){
+ return U_WMRCORE_2U16_set(U_WMR_LINETO, U_U16(coord.y), U_U16(coord.x));
+}
+
+/**
+ \brief Create and return a U_WMRMOVETO record
+ \return pointer to the U_WMRMOVETO record, or NULL on error
+ \param coord Move to {X,Y}.
+*/
+char *U_WMRMOVETO_set(U_POINT16 coord){
+ return U_WMRCORE_2U16_set(U_WMR_MOVETO, U_U16(coord.y), U_U16(coord.x));
+}
+
+/**
+ \brief Create and return a U_WMREXCLUDECLIPRECT record
+ \return pointer to the U_WMREXCLUDECLIPRECT record, or NULL on error
+ \param rect Exclude rect from clipping region.
+*/
+char *U_WMREXCLUDECLIPRECT_set(U_RECT16 rect){
+ return U_WMRCORE_4U16_set(
+ U_WMR_EXCLUDECLIPRECT,
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRINTERSECTCLIPRECT record
+ \return pointer to the U_WMRINTERSECTCLIPRECT record, or NULL on error
+ \param rect Clipping region is intersection of existing clipping region with rect.
+*/
+char *U_WMRINTERSECTCLIPRECT_set(U_RECT16 rect){
+ return U_WMRCORE_4U16_set(
+ U_WMR_INTERSECTCLIPRECT,
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRARC record
+ \return pointer to the U_WMRARC record, or NULL on error
+ \param StartArc Start of Arc
+ \param EndArc End of Arc
+ \param rect Bounding rectangle.
+*/
+char *U_WMRARC_set(U_POINT16 StartArc, U_POINT16 EndArc, U_RECT16 rect){
+ return U_WMRCORE_8U16_set(
+ U_WMR_ARC,
+ U_U16(EndArc.y),
+ U_U16(EndArc.x),
+ U_U16(StartArc.y),
+ U_U16(StartArc.x),
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRELLIPSE record
+ \return pointer to the U_WMRELLIPSE record, or NULL on error
+ \param rect Bounding rectangle for Ellipse.
+*/
+char *U_WMRELLIPSE_set(U_RECT16 rect){
+ return U_WMRCORE_4U16_set(
+ U_WMR_ELLIPSE,
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRFLOODFILL record
+ \return pointer to the U_WMRFLOODFILL record, or NULL on error
+ \param Mode FloodFill Enumeration.
+ \param Color Color to Fill with.
+ \param coord Location to start fill.
+*/
+char *U_WMRFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord){
+ return U_WMRCORE_1U16_CRF_2U16_set(
+ U_WMR_FLOODFILL,
+ &Mode,
+ Color,
+ U_P16(coord.y),
+ U_P16(coord.x)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRPIE record
+ \return pointer to the U_WMRPIE record, or NULL on error
+ \param Radial1 Start of Pie
+ \param Radial2 End of Pie
+ \param rect Bounding rectangle.
+*/
+char *U_WMRPIE_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect){
+ return U_WMRCORE_8U16_set(
+ U_WMR_PIE,
+ U_U16(Radial2.y),
+ U_U16(Radial2.x),
+ U_U16(Radial1.y),
+ U_U16(Radial1.x),
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRRECTANGLE record
+ \return pointer to the U_WMRRECTANGLE record, or NULL on error
+ \param rect Boundaries.
+*/
+char *U_WMRRECTANGLE_set(U_RECT16 rect){
+ return U_WMRCORE_4U16_set(
+ U_WMR_RECTANGLE,
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Create and return a U_WMRROUNDRECT record
+ \return pointer to the U_WMRROUNDRECT record, or NULL on error
+ \param Width Horizontal rounding length.
+ \param Height Vertical rounding length.
+ \param rect Boundaries.
+*/
+char *U_WMRROUNDRECT_set(int16_t Width, int16_t Height, U_RECT16 rect){
+ return U_WMRCORE_6U16_set(
+ U_WMR_ROUNDRECT,
+ U_U16(Height),
+ U_U16(Width),
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Allocate and construct a U_WMRPATBLT record.
+ \return pointer to the U_WMRPATBLT record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param cwh W & H for Dst and Src in logical units
+ \param dwRop3 RasterOPeration Enumeration
+*/
+char *U_WMRPATBLT_set(
+ U_POINT16 Dst,
+ U_POINT16 cwh,
+ uint32_t dwRop3
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ U_WMRPATBLT *pmr;
+
+ irecsize = U_SIZE_WMRPATBLT;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_PATBLT);
+ pmr = (U_WMRPATBLT *) record;
+ memcpy(pmr->rop3w, &dwRop3, 4);
+ pmr->Height = cwh.y;
+ pmr->Width = cwh.x;
+ pmr->yDst = Dst.y;
+ pmr->xDst = Dst.x;
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSAVEDC record
+ \return pointer to the U_WMRSAVEDC record, or NULL on error.
+*/
+char *U_WMRSAVEDC_set(void){
+ return U_WMRCORE_NOARGS_set(U_WMR_SAVEDC);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETPIXEL record
+ \return pointer to the U_WMRSETPIXEL record, or NULL on error.
+ \param Color U_COLORREF color of the pixel
+ \param Coord U_POINT16 coordinates of the pixel
+*/
+char *U_WMRSETPIXEL_set(U_COLORREF Color, U_POINT16 Coord){
+ return U_WMRCORE_1U16_CRF_2U16_set(
+ U_WMR_SETPIXEL,
+ NULL,
+ Color,
+ U_P16(Coord.y),
+ U_P16(Coord.x)
+ );
+}
+
+/**
+ \brief Allocate and construct a U_WMROFFSETCLIPRGN record
+ \return pointer to the U_WMROFFSETCLIPRGN record, or NULL on error.
+ \param offset U_POINT16 x,y offset to apply to the clipping region.
+*/
+char *U_WMROFFSETCLIPRGN_set(U_POINT16 offset){
+ return U_WMRCORE_2U16_set(U_WMR_OFFSETCLIPRGN, U_U16(offset.y), U_U16(offset.x));
+}
+
+/**
+ \brief Allocate and construct a U_WMRTEXTOUT record.
+ \return pointer to the U_WMRTEXTOUT record, or NULL on error.
+ \param Dst Destinationin logical units
+ \param string Null terminated string to write. The terminator is NOT placed in the record!
+*/
+char *U_WMRTEXTOUT_set(U_POINT16 Dst, char *string){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ int L2;
+ int16_t Length;
+ irecsize = 2 + U_SIZE_METARECORD + 4; /* core + length + Dst */
+ Length = strlen(string);
+ L2 = ( Length & 1 ? Length + 1 : Length);
+ irecsize += L2;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_TEXTOUT);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&Length,2); off+=2;
+ memcpy(record+off,string,Length); off+=Length;
+ if(Length!=L2){
+ memset(record+off,0,1); off+=1;
+ }
+ memcpy(record+off,&Dst.y,2); off+=2;
+ memcpy(record+off,&Dst.x,2);
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRBITBLT record.
+ Note that unlike U_EMRBITBLT there is no scaling available - the Src and Dst
+ rectangles must be the same size.
+ \return pointer to the U_WMRBITBLT record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param cwh W & H for Dst and Src in logical units
+ \param Src Source UL corner in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bm16 (Optional) bitmap16 object
+*/
+char *U_WMRBITBLT_set(
+ U_POINT16 Dst,
+ U_POINT16 cwh,
+ U_POINT16 Src,
+ uint32_t dwRop3,
+ const U_BITMAP16 *Bm16
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ int cbBm16,cbBm164,off;
+ U_WMRBITBLT_PX *pmr_px;
+ U_WMRBITBLT_NOPX *pmr_nopx;
+
+ if(Bm16){
+ cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height;
+ cbBm164 = UP4(cbBm16);
+ irecsize = U_SIZE_WMRBITBLT_PX + cbBm164;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_BITBLT);
+ pmr_px = (U_WMRBITBLT_PX *) record;
+ memcpy(pmr_px->rop3w, &dwRop3, 4);
+ pmr_px->ySrc = Src.y;
+ pmr_px->xSrc = Src.x;
+ pmr_px->Height = cwh.y;
+ pmr_px->Width = cwh.x;
+ pmr_px->yDst = Dst.y;
+ pmr_px->xDst = Dst.x;
+ off = U_SIZE_WMRBITBLT_PX;
+ memcpy(record + off, Bm16, cbBm16); off += cbBm16;
+ if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16);
+ }
+ }
+ else {
+ irecsize = U_SIZE_WMRBITBLT_NOPX;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_BITBLT);
+ pmr_nopx = (U_WMRBITBLT_NOPX *) record;
+ memcpy(pmr_nopx->rop3w, &dwRop3, 4);
+ pmr_nopx->ySrc = Src.y;
+ pmr_nopx->xSrc = Src.x;
+ pmr_nopx->Height = cwh.y;
+ pmr_nopx->Width = cwh.x;
+ pmr_nopx->ignore = 0;
+ pmr_nopx->yDst = Dst.y;
+ pmr_nopx->xDst = Dst.x;
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSTRETCHBLT record.
+ \return pointer to the U_WMRSTRETCHBLT record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bm16 (Optional) bitmap16 object
+*/
+char *U_WMRSTRETCHBLT_set(
+ U_POINT16 Dst,
+ U_POINT16 cDst,
+ U_POINT16 Src,
+ U_POINT16 cSrc,
+ uint32_t dwRop3,
+ const U_BITMAP16 *Bm16
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ int cbBm16,cbBm164,off;
+ U_WMRSTRETCHBLT_PX *pmr_px;
+ U_WMRSTRETCHBLT_NOPX *pmr_nopx;
+
+ if(Bm16){
+ cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height;
+ cbBm164 = UP4(cbBm16);
+ irecsize = U_SIZE_WMRSTRETCHBLT_PX + cbBm164;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHBLT);
+ pmr_px = (U_WMRSTRETCHBLT_PX *) record;
+ memcpy(pmr_px->rop3w, &dwRop3, 4);
+ pmr_px->hSrc = cSrc.y;
+ pmr_px->wSrc = cSrc.x;
+ pmr_px->ySrc = Src.y;
+ pmr_px->xSrc = Src.x;
+ pmr_px->hDst = cDst.y;
+ pmr_px->wDst = cDst.x;
+ pmr_px->yDst = Dst.y;
+ pmr_px->xDst = Dst.x;
+ off = U_SIZE_WMRSTRETCHBLT_PX;
+ memcpy(record + off, Bm16, cbBm16); off += cbBm16;
+ if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16);
+ }
+ }
+ else {
+ irecsize = U_SIZE_WMRSTRETCHBLT_NOPX;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHBLT);
+ pmr_nopx = (U_WMRSTRETCHBLT_NOPX *) record;
+ memcpy(pmr_nopx->rop3w, &dwRop3, 4);
+ pmr_nopx->hSrc = cSrc.y;
+ pmr_nopx->wSrc = cSrc.x;
+ pmr_nopx->ySrc = Src.y;
+ pmr_nopx->xSrc = Src.x;
+ pmr_nopx->ignore = 0;
+ pmr_nopx->hDst = cDst.y;
+ pmr_nopx->wDst = cDst.x;
+ pmr_nopx->yDst = Dst.y;
+ pmr_nopx->xDst = Dst.x;
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRPOLYGON record.
+ \return pointer to the U_WMRPOLYGON record, or NULL on error.
+ \param Length Number of points in the Polygon
+ \param Data Array of Length points
+*/
+char *U_WMRPOLYGON_set(uint16_t Length, const U_POINT16 *Data){
+ return U_WMRCORE_2U16_N16_set(U_WMR_POLYGON, NULL, &Length, 2*Length, Data);
+}
+
+/**
+ \brief Allocate and construct a U_WMRPOLYLINE record.
+ \return pointer to the U_WMRPOLYLINE record, or NULL on error.
+ \param Length Number of points in the Polyline
+ \param Data Array of Length points
+*/
+char *U_WMRPOLYLINE_set(uint16_t Length, const U_POINT16 *Data){
+ return U_WMRCORE_2U16_N16_set(U_WMR_POLYLINE, NULL, &Length, 2*Length, Data);
+}
+
+/**
+ \brief Allocate and construct a U_WMRESCAPE record.
+ WARNING! Only three Escape record types are fully supported: SETLINECAP, SETLINEJOIN, SETMITERLIMIT.
+ Even these should not be set here directly, instead use the wsetlinecap_set(), wsetlinejoin_set(),
+ or wsetmiterlimit_set() functions.
+ Escape records created with this function, with the exception of the three named above, will not have
+ the byte orders in Data adjusted automatically. The user code must set Data to be little endian no
+ matter what the endianness of the current platform where the user code is running.
+ \return pointer to the U_WMRESCAPE record, or NULL on error.
+ \param Escape Escape function
+ \param Length Bytes in the Data
+ \param Data Array of Length bytes
+*/
+char *U_WMRESCAPE_set(uint16_t Escape, uint16_t Length, const void *Data){
+ return U_WMRCORE_2U16_N16_set(U_WMR_ESCAPE, &Escape, &Length, Length/2, Data);
+}
+
+/**
+ \brief Allocate and construct a U_WMRRESTOREDC record
+ \return pointer to the U_WMRRESTOREDC record, or NULL on error.
+ \param DC Drawing Context to restore. (negative is relative to current, positive is absolute)
+*/
+char *U_WMRRESTOREDC_set(int16_t DC){
+ return U_WMRCORE_1U16_set(U_WMR_RESTOREDC, DC);
+}
+
+/**
+ \brief Allocate and construct a U_WMRFILLREGION record.
+ \return pointer to the U_WMRFILLREGION record, or NULL on error.
+ \param Region Region to fill
+ \param Brush Brush to fill with
+*/
+char *U_WMRFILLREGION_set(uint16_t Region, uint16_t Brush){
+ return U_WMRCORE_2U16_set(U_WMR_FILLREGION, Region, Brush);
+}
+
+/**
+ \brief Allocate and construct a U_WMRFRAMEREGION record.
+ \return pointer to the U_WMRFRAMEREGION record, or NULL on error.
+ \param Region Index of region to frame in object table
+ \param Brush Index of brush to use in frame in object table
+ \param Height in logical units (of frame)
+ \param Width in logical units (of frame)
+*/
+char *U_WMRFRAMEREGION_set(uint16_t Region, uint16_t Brush, int16_t Height, int16_t Width){
+ return U_WMRCORE_4U16_set(U_WMR_FRAMEREGION, Region, Brush, U_U16(Height), U_U16(Width));
+}
+
+/**
+ \brief Allocate and construct a U_WMRINVERTREGION record.
+ \return pointer to the U_WMRINVERTREGION record, or NULL on error.
+ \param Region Index of region to invert.
+*/
+char *U_WMRINVERTREGION_set(uint16_t Region){
+ return U_WMRCORE_1U16_set(U_WMR_INVERTREGION, Region);
+}
+
+/**
+ \brief Allocate and construct a U_WMRPAINTREGION record.
+ \return pointer to the U_WMRPAINTREGION record, or NULL on error.
+ \param Region Index of region to paint with the current Brush.
+*/
+char *U_WMRPAINTREGION_set(uint16_t Region){
+ return U_WMRCORE_1U16_set(U_WMR_PAINTREGION, Region);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSELECTCLIPREGION record.
+ \return pointer to the U_WMRSELECTCLIPREGION record, or NULL on error.
+ \param Region Index of region to become clipping region..
+*/
+char *U_WMRSELECTCLIPREGION_set(uint16_t Region){
+ return U_WMRCORE_1U16_set(U_WMR_SELECTCLIPREGION, Region);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSELECTOBJECT record.
+ \return pointer to the U_WMRSELECTOBJECT record, or NULL on error.
+ \param object Index of object which is made active.
+*/
+char *U_WMRSELECTOBJECT_set(uint16_t object){
+ return U_WMRCORE_1U16_set(U_WMR_SELECTOBJECT, object);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETTEXTALIGN record.
+ \return pointer to the U_WMRSETTEXTALIGN record, or NULL on error.
+ \param Mode TextAlignment Enumeration.
+*/
+char *U_WMRSETTEXTALIGN_set(uint16_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETTEXTALIGN, Mode, 0);
+}
+
+/** in GDI and Wine, not in WMF manual..
+*/
+ char *U_WMRDRAWTEXT_set(void){
+ return U_WMRCORENONE_set("U_WMRDRAWTEXT");
+}
+
+/**
+ \brief Create and return a U_WMRCHORD record
+ \return pointer to the U_WMRCHORD record, or NULL on error
+ \param Radial1 Start of Chord
+ \param Radial2 End of Chord
+ \param rect Bounding rectangle.
+*/
+char *U_WMRCHORD_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect){
+ return U_WMRCORE_8U16_set(
+ U_WMR_CHORD,
+ U_U16(Radial2.y),
+ U_U16(Radial2.x),
+ U_U16(Radial1.y),
+ U_U16(Radial1.x),
+ U_U16(rect.bottom),
+ U_U16(rect.right),
+ U_U16(rect.top),
+ U_U16(rect.left)
+ );
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETMAPPERFLAGS record.
+ \return pointer to the U_WMRSETMAPPERFLAGS record, or NULL on error.
+ \param Mode If 1 bit set font mapper selects only matching aspect fonts.
+*/
+char *U_WMRSETMAPPERFLAGS_set(uint32_t Mode){
+ return U_WMRCORE_2U16_set(U_WMR_SETMAPPERFLAGS, 0xFFFF & Mode, Mode>>16);
+}
+
+/**
+ \brief Allocate and construct a U_WMREXTTEXTOUT record.
+ \return pointer to the U_WMREXTTEXTOUT record, or NULL on error.
+ \param Dst {X,Y} coordinates where the string is to be written.
+ \param Length Stringlength in bytes
+ \param Opts ExtTextOutOptions Flags
+ \param string String to write (Latin1 encoding)
+ \param dx Kerning information. Must have same number of entries as Length.
+ \param rect Used when when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts
+*/
+char *U_WMREXTTEXTOUT_set(U_POINT16 Dst, int16_t Length, uint16_t Opts,
+ const char *string, int16_t *dx, U_RECT16 rect){
+
+ char *record=NULL;
+ uint32_t irecsize,off;
+ int slen;
+ irecsize = U_SIZE_METARECORD + 8; /* 8 = y,x,Length,Opts*/
+ slen = ( Length & 1 ? Length + 1 : Length);
+ irecsize += slen;
+ if(dx)irecsize += 2*Length;
+ if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){
+ irecsize += U_SIZE_RECT16;
+ }
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_EXTTEXTOUT);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,&Dst.y,2); off+=2;
+ memcpy(record+off,&Dst.x,2); off+=2;
+ memcpy(record+off,&Length,2); off+=2;
+ memcpy(record+off,&Opts,2); off+=2;
+ if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){
+ memcpy(record+off,&rect.bottom,2); off+=2;
+ memcpy(record+off,&rect.right, 2); off+=2;
+ memcpy(record+off,&rect.top, 2); off+=2;
+ memcpy(record+off,&rect.left, 2); off+=2;
+ }
+ memcpy(record+off,string,strlen(string)); off+=Length;
+ if(Length!=slen){
+ memset(record+off,0,1); off+=1;
+ }
+ if(dx){
+ memcpy(record+off,dx,2*Length);
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETDIBTODEV record
+ \return pointer to the U_WMRSETDIBTODEV record, or NULL on error.
+*/
+char *U_WMRSETDIBTODEV_set(void){
+ return U_WMRCORENONE_set("U_WMRSETDIBTODEV");
+}
+
+/**
+ \brief Allocate and construct a U_WMRSELECTPALETTE record
+ \return pointer to the U_WMRSELECTPALETTE record, or NULL on error.
+ \param Palette Index of Palette to make active.
+*/
+char *U_WMRSELECTPALETTE_set(uint16_t Palette){
+ return U_WMRCORE_1U16_set(U_WMR_SELECTPALETTE, Palette);
+}
+
+/**
+ \brief Allocate and construct a U_WMRREALIZEPALETTE record
+ \return pointer to the U_WMRREALIZEPALETTE record, or NULL on error.
+*/
+char *U_WMRREALIZEPALETTE_set(void){
+ return U_WMRCORE_NOARGS_set(U_WMR_REALIZEPALETTE);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETPALENTRIES record
+ \return pointer to the U_WMRSETPALENTRIES record, or NULL on error.
+ \param Palette Redefines a set of RGB values for the current active Palette.
+*/
+char *U_WMRANIMATEPALETTE_set(U_PALETTE *Palette){
+ return U_WMRCORE_PALETTE_set(U_WMR_ANIMATEPALETTE, Palette);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSETPALENTRIES record
+ \return pointer to the U_WMRSETPALENTRIES record, or NULL on error.
+ \param Palette Defines a set of RGB values for the current active Palette.
+*/
+char *U_WMRSETPALENTRIES_set(const U_PALETTE *Palette){
+ return U_WMRCORE_PALETTE_set(U_WMR_SETPALENTRIES, Palette);
+}
+
+/**
+ \brief Allocate and construct a U_WMR_POLYPOLYGON record.
+ \return pointer to the U_WMR_POLYPOLYGON record, or NULL on error.
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param Points array of points
+*/
+char *U_WMRPOLYPOLYGON_set(
+ const uint16_t nPolys,
+ const uint16_t *aPolyCounts,
+ const U_POINT16 *Points
+ ){
+ char *record;
+ uint32_t irecsize;
+ int i,cbPolys,cbPoints,off;
+
+ cbPolys = sizeof(uint16_t)*nPolys;
+ for(i=cbPoints=0; i<nPolys; i++){ cbPoints += U_SIZE_POINT16*aPolyCounts[i]; }
+
+ if(nPolys==0 || cbPoints==0)return(NULL);
+
+ irecsize = U_SIZE_METARECORD + 2 + cbPolys + cbPoints; /* core WMR + nPolys + two array sizes in bytes */
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_POLYPOLYGON);
+ off = U_SIZE_METARECORD;
+ memcpy(record + off, &nPolys, 2); off+=2;
+ memcpy(record + off, aPolyCounts, cbPolys); off+=cbPolys;
+ memcpy(record + off, Points, cbPoints);
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRRESIZEPALETTE record
+ \return pointer to the U_WMRRESIZEPALETTE record, or NULL on error.
+ \param Palette Changes the size of the currently active Palette.
+*/
+char *U_WMRRESIZEPALETTE_set(uint16_t Palette){
+ return U_WMRCORE_1U16_set(U_WMR_RESIZEPALETTE, Palette);
+}
+
+//! \cond
+char *U_WMR3A_set(void){
+ return U_WMRCORENONE_set("U_WMR3A");
+}
+
+char *U_WMR3B_set(void){
+ return U_WMRCORENONE_set("U_WMR3B");
+}
+
+char *U_WMR3C_set(void){
+ return U_WMRCORENONE_set("U_WMR3C");
+}
+
+char *U_WMR3D_set(void){
+ return U_WMRCORENONE_set("U_WMR3D");
+}
+
+char *U_WMR3E_set(void){
+ return U_WMRCORENONE_set("U_WMR3E");
+}
+
+char *U_WMR3F_set(void){
+ return U_WMRCORENONE_set("U_WMR3F");
+}
+//! \endcond
+
+// U_WMRDIBBITBLT_set
+/**
+ \brief Allocate and construct a U_WMRDIBITBLT record.
+ \return pointer to the U_WMRDIBITBLT record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param Src Source UL corner in logical units
+ \param cwh W & H in logical units of Src and Dst
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_WMRDIBBITBLT_set(
+ U_POINT16 Dst,
+ U_POINT16 cwh,
+ U_POINT16 Src,
+ uint32_t dwRop3,
+ const U_BITMAPINFO *Bmi,
+ uint32_t cbPx,
+ const char *Px
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+ U_WMRDIBBITBLT_PX *pmr_px;
+ U_WMRDIBBITBLT_NOPX *pmr_nopx;
+
+
+ if(Px && Bmi){
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ irecsize = U_SIZE_WMRDIBBITBLT_PX + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBBITBLT);
+ pmr_px = (U_WMRDIBBITBLT_PX *) record;
+ memcpy(pmr_px->rop3w, &dwRop3, 4);
+ pmr_px->ySrc = Src.y;
+ pmr_px->xSrc = Src.x;
+ pmr_px->Height = cwh.y;
+ pmr_px->Width = cwh.x;
+ pmr_px->yDst = Dst.y;
+ pmr_px->xDst = Dst.x;
+ off = U_SIZE_WMRDIBBITBLT_PX;
+ memcpy(record + off, Bmi, cbBmi); off += cbBmi;
+ memcpy(record + off, Px, cbPx); off += cbPx;
+ if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage);
+ }
+ }
+ else if(!Px && !Bmi){
+ irecsize = U_SIZE_WMRDIBBITBLT_NOPX;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBBITBLT);
+ pmr_nopx = (U_WMRDIBBITBLT_NOPX *) record;
+ memcpy(pmr_nopx->rop3w, &dwRop3, 4);
+ pmr_nopx->ySrc = Src.y;
+ pmr_nopx->xSrc = Src.x;
+ pmr_nopx->ignore = 0;
+ pmr_nopx->Height = cwh.y;
+ pmr_nopx->Width = cwh.x;
+ pmr_nopx->yDst = Dst.y;
+ pmr_nopx->xDst = Dst.x;
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSTRETCHDIB record.
+ \return pointer to the U_WMRSTRETCHDIB record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_WMRDIBSTRETCHBLT_set(
+ U_POINT16 Dst,
+ U_POINT16 cDst,
+ U_POINT16 Src,
+ U_POINT16 cSrc,
+ uint32_t dwRop3,
+ const U_BITMAPINFO *Bmi,
+ uint32_t cbPx,
+ const char *Px
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+ U_WMRDIBSTRETCHBLT_PX *pmr_px;
+ U_WMRDIBSTRETCHBLT_NOPX *pmr_nopx;
+ if(Px && Bmi){
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ irecsize = U_SIZE_WMRDIBSTRETCHBLT_PX + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBSTRETCHBLT);
+ pmr_px = (U_WMRDIBSTRETCHBLT_PX *) record;
+ memcpy(pmr_px->rop3w, &dwRop3, 4);
+ pmr_px->hSrc = cSrc.y;
+ pmr_px->wSrc = cSrc.x;
+ pmr_px->ySrc = Src.y;
+ pmr_px->xSrc = Src.x;
+ pmr_px->hDst = cDst.y;
+ pmr_px->wDst = cDst.x;
+ pmr_px->yDst = Dst.y;
+ pmr_px->xDst = Dst.x;
+ off = U_SIZE_WMRDIBSTRETCHBLT_PX;
+ memcpy(record + off, Bmi, cbBmi); off += cbBmi;
+ memcpy(record + off, Px, cbPx); off += cbPx;
+ if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage);
+ }
+ }
+ else if(!Px && !Bmi){
+ irecsize = U_SIZE_WMRDIBSTRETCHBLT_NOPX;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBSTRETCHBLT);
+ pmr_nopx = (U_WMRDIBSTRETCHBLT_NOPX *) record;
+ memcpy(pmr_nopx->rop3w, &dwRop3, 4);
+ pmr_nopx->hSrc = cSrc.y;
+ pmr_nopx->wSrc = cSrc.x;
+ pmr_nopx->ySrc = Src.y;
+ pmr_nopx->xSrc = Src.x;
+ pmr_nopx->ignore = 0;
+ pmr_nopx->hDst = cDst.y;
+ pmr_nopx->wDst = cDst.x;
+ pmr_nopx->yDst = Dst.y;
+ pmr_nopx->xDst = Dst.x;
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRDIBCREATEPATTERNBRUSH record.
+ Accepts an image as either a DIB (Bmi/CbPx/Px defined) or a Bitmap16 (Bm16 defined).
+ \return pointer to the U_WMRDIBCREATEPATTERNBRUSH record, or NULL on error.
+ \param Style BrushStyle Enumeration
+ \param iUsage DIBcolors Enumeration
+ \param Bm16 pointer to U_BITMAP16 object for Style U_BS_PATTERN only
+ \param cbPx Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row), for use with Bmi
+ \param Px bitmap buffer, for use with Bmi
+ \param Bmi pointer to U_BITMAPINFO for all Style OTHER than U_BS_PATTERN
+*/
+char *U_WMRDIBCREATEPATTERNBRUSH_set(
+ const uint16_t Style,
+ const uint16_t iUsage,
+ const U_BITMAPINFO *Bmi,
+ const uint32_t cbPx,
+ const char *Px,
+ const U_BITMAP16 *Bm16
+ ){
+ char *record=NULL;
+ uint32_t irecsize;
+ int cbImage,cbImage4,cbBmi,cbBm16,cbBm164,off;
+
+ if(Style==U_BS_PATTERN && Bm16){
+ cbBm16 = U_SIZE_BITMAP16 + (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height;
+ cbBm164 = UP4(cbBm16);
+ irecsize = U_SIZE_WMRDIBCREATEPATTERNBRUSH + cbBm164;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBCREATEPATTERNBRUSH);
+ off = U_SIZE_METARECORD;
+ memcpy(record + off, &Style, 2); off+=2;
+ memcpy(record + off, &iUsage, 2); off+=2;
+ memcpy(record + off, Bm16, cbBm16); off += cbBm16;
+ if(cbBm164 - cbBm16)memset(record+off,0,cbBm164 - cbBm16);
+ }
+ }
+ else if(Bmi && Px){
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+ irecsize = U_SIZE_WMRDIBCREATEPATTERNBRUSH + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_DIBCREATEPATTERNBRUSH);
+ off = U_SIZE_METARECORD;
+ memcpy(record + off, &Style, 2); off+=2;
+ memcpy(record + off, &iUsage, 2); off+=2;
+ memcpy(record + off, Bmi, cbBmi); off += cbBmi;
+ memcpy(record + off, Px, cbImage); off += cbImage;
+ if(cbImage4 - cbImage)memset(record + off, 0, cbImage4 - cbImage);
+ }
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRSTRETCHDIB record.
+ \return pointer to the U_WMRSTRETCHDIB record, or NULL on error.
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param cUsage DIBColors Enumeration
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bmi (Optional) bitmapbuffer (U_BITMAPINFO section)
+ \param cbPx Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
+ \param Px (Optional) bitmapbuffer (pixel array section )
+*/
+char *U_WMRSTRETCHDIB_set(
+ U_POINT16 Dst,
+ U_POINT16 cDst,
+ U_POINT16 Src,
+ U_POINT16 cSrc,
+ uint16_t cUsage,
+ uint32_t dwRop3,
+ const U_BITMAPINFO *Bmi,
+ uint32_t cbPx,
+ const char *Px
+ ){
+ char *record;
+ uint32_t irecsize;
+ int cbImage,cbImage4,cbBmi,off;
+ U_WMRSTRETCHDIB *pmr;
+
+ SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
+
+ irecsize = U_SIZE_WMRSTRETCHDIB + cbBmi + cbImage4;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_STRETCHDIB);
+ pmr = (U_WMRSTRETCHDIB *) record;
+ memcpy(pmr->rop3w, &dwRop3, 4);
+ pmr->cUsage = cUsage;
+ pmr->hSrc = cSrc.y;
+ pmr->wSrc = cSrc.x;
+ pmr->ySrc = Src.y;
+ pmr->xSrc = Src.x;
+ pmr->hDst = cDst.y;
+ pmr->wDst = cDst.x;
+ pmr->yDst = Dst.y;
+ pmr->xDst = Dst.x;
+ off = U_SIZE_WMRSTRETCHDIB;
+ if(cbBmi){
+ memcpy(record + off, Bmi, cbBmi); off += cbBmi;
+ memcpy(record + off, Px, cbPx); off += cbPx;
+ if(cbImage4 - cbImage)memset(record+off,0,cbImage4 - cbImage);
+ }
+ }
+ return(record);
+}
+
+//! \cond
+char *U_WMR44_set(void){
+ return U_WMRCORENONE_set("U_WMR44");
+}
+
+char *U_WMR45_set(void){
+ return U_WMRCORENONE_set("U_WMR45");
+}
+
+char *U_WMR46_set(void){
+ return U_WMRCORENONE_set("U_WMR46");
+}
+
+char *U_WMR47_set(void){
+ return U_WMRCORENONE_set("U_WMR47");
+}
+//! \endcond
+
+/**
+ \brief Create and return a U_WMREXTFLOODFILL record
+ \return pointer to the U_WMREXTFLOODFILL record, or NULL on error
+ \param Mode FloodFill Enumeration.
+ \param Color Color to Fill with.
+ \param coord Location to start fill.
+*/
+char *U_WMREXTFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord){
+ return U_WMRCORE_1U16_CRF_2U16_set(
+ U_WMR_EXTFLOODFILL,
+ &Mode,
+ Color,
+ U_P16(coord.y),
+ U_P16(coord.x)
+ );
+}
+
+//! \cond
+char *U_WMR49_set(void){
+ return U_WMRCORENONE_set("U_WMR49");
+}
+
+char *U_WMR4A_set(void){
+ return U_WMRCORENONE_set("U_WMR4A");
+}
+
+char *U_WMR4B_set(void){
+ return U_WMRCORENONE_set("U_WMR4B");
+}
+
+char *U_WMR4C_set(void){
+ return U_WMRCORENONE_set("U_WMRRESETDOC");
+}
+
+char *U_WMR4D_set(void){
+ return U_WMRCORENONE_set("U_WMRSTARTDOC");
+}
+
+char *U_WMR4E_set(void){
+ return U_WMRCORENONE_set("U_WMR4E");
+}
+
+char *U_WMR4F_set(void){
+ return U_WMRCORENONE_set("U_WMRSTARTPAGE");
+}
+
+char *U_WMR50_set(void){
+ return U_WMRCORENONE_set("U_WMRENDPAGE");
+}
+
+char *U_WMR51_set(void){
+ return U_WMRCORENONE_set("U_WMR51");
+}
+
+char *U_WMRABORTDOC_set(void){
+ return U_WMRCORENONE_set("U_WMRABORTDOC");
+}
+
+char *U_WMR53_set(void){
+ return U_WMRCORENONE_set("U_WMR53");
+}
+
+char *U_WMR54_set(void){
+ return U_WMRCORENONE_set("U_WMR54");
+}
+
+char *U_WMR55_set(void){
+ return U_WMRCORENONE_set("U_WMR55");
+}
+
+char *U_WMR56_set(void){
+ return U_WMRCORENONE_set("U_WMR56");
+}
+
+char *U_WMR57_set(void){
+ return U_WMRCORENONE_set("U_WMR57");
+}
+
+char *U_WMR58_set(void){
+ return U_WMRCORENONE_set("U_WMR58");
+}
+
+char *U_WMR59_set(void){
+ return U_WMRCORENONE_set("U_WMR59");
+}
+
+char *U_WMR5A_set(void){
+ return U_WMRCORENONE_set("U_WMR5A");
+}
+
+char *U_WMR5B_set(void){
+ return U_WMRCORENONE_set("U_WMR5B");
+}
+
+char *U_WMR5C_set(void){
+ return U_WMRCORENONE_set("U_WMR5C");
+}
+
+char *U_WMR5D_set(void){
+ return U_WMRCORENONE_set("U_WMR5D");
+}
+
+char *U_WMR5E_set(void){
+ return U_WMRCORENONE_set("U_WMRENDDOC");
+}
+
+char *U_WMR5F_set(void){
+ return U_WMRCORENONE_set("U_WMR5F");
+}
+
+char *U_WMR60_set(void){
+ return U_WMRCORENONE_set("U_WMR60");
+}
+
+char *U_WMR61_set(void){
+ return U_WMRCORENONE_set("U_WMR61");
+}
+
+char *U_WMR62_set(void){
+ return U_WMRCORENONE_set("U_WMR62");
+}
+
+char *U_WMR63_set(void){
+ return U_WMRCORENONE_set("U_WMR63");
+}
+
+char *U_WMR64_set(void){
+ return U_WMRCORENONE_set("U_WMR64");
+}
+
+char *U_WMR65_set(void){
+ return U_WMRCORENONE_set("U_WMR65");
+}
+
+char *U_WMR66_set(void){
+ return U_WMRCORENONE_set("U_WMR66");
+}
+
+char *U_WMR67_set(void){
+ return U_WMRCORENONE_set("U_WMR67");
+}
+
+char *U_WMR68_set(void){
+ return U_WMRCORENONE_set("U_WMR68");
+}
+
+char *U_WMR69_set(void){
+ return U_WMRCORENONE_set("U_WMR69");
+}
+
+char *U_WMR6A_set(void){
+ return U_WMRCORENONE_set("U_WMR6A");
+}
+
+char *U_WMR6B_set(void){
+ return U_WMRCORENONE_set("U_WMR6B");
+}
+
+char *U_WMR6C_set(void){
+ return U_WMRCORENONE_set("U_WMR6C");
+}
+
+char *U_WMR6D_set(void){
+ return U_WMRCORENONE_set("U_WMR6D");
+}
+
+char *U_WMR6E_set(void){
+ return U_WMRCORENONE_set("U_WMR6E");
+}
+
+char *U_WMR6F_set(void){
+ return U_WMRCORENONE_set("U_WMR6F");
+}
+
+char *U_WMR70_set(void){
+ return U_WMRCORENONE_set("U_WMR70");
+}
+
+char *U_WMR71_set(void){
+ return U_WMRCORENONE_set("U_WMR71");
+}
+
+char *U_WMR72_set(void){
+ return U_WMRCORENONE_set("U_WMR72");
+}
+
+char *U_WMR73_set(void){
+ return U_WMRCORENONE_set("U_WMR73");
+}
+
+char *U_WMR74_set(void){
+ return U_WMRCORENONE_set("U_WMR74");
+}
+
+char *U_WMR75_set(void){
+ return U_WMRCORENONE_set("U_WMR75");
+}
+
+char *U_WMR76_set(void){
+ return U_WMRCORENONE_set("U_WMR76");
+}
+
+char *U_WMR77_set(void){
+ return U_WMRCORENONE_set("U_WMR77");
+}
+
+char *U_WMR78_set(void){
+ return U_WMRCORENONE_set("U_WMR78");
+}
+
+char *U_WMR79_set(void){
+ return U_WMRCORENONE_set("U_WMR79");
+}
+
+char *U_WMR7A_set(void){
+ return U_WMRCORENONE_set("U_WMR7A");
+}
+
+char *U_WMR7B_set(void){
+ return U_WMRCORENONE_set("U_WMR7B");
+}
+
+char *U_WMR7C_set(void){
+ return U_WMRCORENONE_set("U_WMR7C");
+}
+
+char *U_WMR7D_set(void){
+ return U_WMRCORENONE_set("U_WMR7D");
+}
+
+char *U_WMR7E_set(void){
+ return U_WMRCORENONE_set("U_WMR7E");
+}
+
+char *U_WMR7F_set(void){
+ return U_WMRCORENONE_set("U_WMR7F");
+}
+
+char *U_WMR80_set(void){
+ return U_WMRCORENONE_set("U_WMR80");
+}
+
+char *U_WMR81_set(void){
+ return U_WMRCORENONE_set("U_WMR81");
+}
+
+char *U_WMR82_set(void){
+ return U_WMRCORENONE_set("U_WMR82");
+}
+
+char *U_WMR83_set(void){
+ return U_WMRCORENONE_set("U_WMR83");
+}
+
+char *U_WMR84_set(void){
+ return U_WMRCORENONE_set("U_WMR84");
+}
+
+char *U_WMR85_set(void){
+ return U_WMRCORENONE_set("U_WMR85");
+}
+
+char *U_WMR86_set(void){
+ return U_WMRCORENONE_set("U_WMR86");
+}
+
+char *U_WMR87_set(void){
+ return U_WMRCORENONE_set("U_WMR87");
+}
+
+char *U_WMR88_set(void){
+ return U_WMRCORENONE_set("U_WMR88");
+}
+
+char *U_WMR89_set(void){
+ return U_WMRCORENONE_set("U_WMR89");
+}
+
+char *U_WMR8A_set(void){
+ return U_WMRCORENONE_set("U_WMR8A");
+}
+
+char *U_WMR8B_set(void){
+ return U_WMRCORENONE_set("U_WMR8B");
+}
+
+char *U_WMR8C_set(void){
+ return U_WMRCORENONE_set("U_WMR8C");
+}
+
+char *U_WMR8D_set(void){
+ return U_WMRCORENONE_set("U_WMR8D");
+}
+
+char *U_WMR8E_set(void){
+ return U_WMRCORENONE_set("U_WMR8E");
+}
+
+char *U_WMR8F_set(void){
+ return U_WMRCORENONE_set("U_WMR8F");
+}
+
+char *U_WMR90_set(void){
+ return U_WMRCORENONE_set("U_WMR90");
+}
+
+char *U_WMR91_set(void){
+ return U_WMRCORENONE_set("U_WMR91");
+}
+
+char *U_WMR92_set(void){
+ return U_WMRCORENONE_set("U_WMR92");
+}
+
+char *U_WMR93_set(void){
+ return U_WMRCORENONE_set("U_WMR93");
+}
+
+char *U_WMR94_set(void){
+ return U_WMRCORENONE_set("U_WMR94");
+}
+
+char *U_WMR95_set(void){
+ return U_WMRCORENONE_set("U_WMR95");
+}
+
+char *U_WMR96_set(void){
+ return U_WMRCORENONE_set("U_WMR96");
+}
+
+char *U_WMR97_set(void){
+ return U_WMRCORENONE_set("U_WMR97");
+}
+
+char *U_WMR98_set(void){
+ return U_WMRCORENONE_set("U_WMR98");
+}
+
+char *U_WMR99_set(void){
+ return U_WMRCORENONE_set("U_WMR99");
+}
+
+char *U_WMR9A_set(void){
+ return U_WMRCORENONE_set("U_WMR9A");
+}
+
+char *U_WMR9B_set(void){
+ return U_WMRCORENONE_set("U_WMR9B");
+}
+
+char *U_WMR9C_set(void){
+ return U_WMRCORENONE_set("U_WMR9C");
+}
+
+char *U_WMR9D_set(void){
+ return U_WMRCORENONE_set("U_WMR9D");
+}
+
+char *U_WMR9E_set(void){
+ return U_WMRCORENONE_set("U_WMR9E");
+}
+
+char *U_WMR9F_set(void){
+ return U_WMRCORENONE_set("U_WMR9F");
+}
+
+char *U_WMRA0_set(void){
+ return U_WMRCORENONE_set("U_WMRA0");
+}
+
+char *U_WMRA1_set(void){
+ return U_WMRCORENONE_set("U_WMRA1");
+}
+
+char *U_WMRA2_set(void){
+ return U_WMRCORENONE_set("U_WMRA2");
+}
+
+char *U_WMRA3_set(void){
+ return U_WMRCORENONE_set("U_WMRA3");
+}
+
+char *U_WMRA4_set(void){
+ return U_WMRCORENONE_set("U_WMRA4");
+}
+
+char *U_WMRA5_set(void){
+ return U_WMRCORENONE_set("U_WMRA5");
+}
+
+char *U_WMRA6_set(void){
+ return U_WMRCORENONE_set("U_WMRA6");
+}
+
+char *U_WMRA7_set(void){
+ return U_WMRCORENONE_set("U_WMRA7");
+}
+
+char *U_WMRA8_set(void){
+ return U_WMRCORENONE_set("U_WMRA8");
+}
+
+char *U_WMRA9_set(void){
+ return U_WMRCORENONE_set("U_WMRA9");
+}
+
+char *U_WMRAA_set(void){
+ return U_WMRCORENONE_set("U_WMRAA");
+}
+
+char *U_WMRAB_set(void){
+ return U_WMRCORENONE_set("U_WMRAB");
+}
+
+char *U_WMRAC_set(void){
+ return U_WMRCORENONE_set("U_WMRAC");
+}
+
+char *U_WMRAD_set(void){
+ return U_WMRCORENONE_set("U_WMRAD");
+}
+
+char *U_WMRAE_set(void){
+ return U_WMRCORENONE_set("U_WMRAE");
+}
+
+char *U_WMRAF_set(void){
+ return U_WMRCORENONE_set("U_WMRAF");
+}
+
+char *U_WMRB0_set(void){
+ return U_WMRCORENONE_set("U_WMRB0");
+}
+
+char *U_WMRB1_set(void){
+ return U_WMRCORENONE_set("U_WMRB1");
+}
+
+char *U_WMRB2_set(void){
+ return U_WMRCORENONE_set("U_WMRB2");
+}
+
+char *U_WMRB3_set(void){
+ return U_WMRCORENONE_set("U_WMRB3");
+}
+
+char *U_WMRB4_set(void){
+ return U_WMRCORENONE_set("U_WMRB4");
+}
+
+char *U_WMRB5_set(void){
+ return U_WMRCORENONE_set("U_WMRB5");
+}
+
+char *U_WMRB6_set(void){
+ return U_WMRCORENONE_set("U_WMRB6");
+}
+
+char *U_WMRB7_set(void){
+ return U_WMRCORENONE_set("U_WMRB7");
+}
+
+char *U_WMRB8_set(void){
+ return U_WMRCORENONE_set("U_WMRB8");
+}
+
+char *U_WMRB9_set(void){
+ return U_WMRCORENONE_set("U_WMRB9");
+}
+
+char *U_WMRBA_set(void){
+ return U_WMRCORENONE_set("U_WMRBA");
+}
+
+char *U_WMRBB_set(void){
+ return U_WMRCORENONE_set("U_WMRBB");
+}
+
+char *U_WMRBC_set(void){
+ return U_WMRCORENONE_set("U_WMRBC");
+}
+
+char *U_WMRBD_set(void){
+ return U_WMRCORENONE_set("U_WMRBD");
+}
+
+char *U_WMRBE_set(void){
+ return U_WMRCORENONE_set("U_WMRBE");
+}
+
+char *U_WMRBF_set(void){
+ return U_WMRCORENONE_set("U_WMRBF");
+}
+
+char *U_WMRC0_set(void){
+ return U_WMRCORENONE_set("U_WMRC0");
+}
+
+char *U_WMRC1_set(void){
+ return U_WMRCORENONE_set("U_WMRC1");
+}
+
+char *U_WMRC2_set(void){
+ return U_WMRCORENONE_set("U_WMRC2");
+}
+
+char *U_WMRC3_set(void){
+ return U_WMRCORENONE_set("U_WMRC3");
+}
+
+char *U_WMRC4_set(void){
+ return U_WMRCORENONE_set("U_WMRC4");
+}
+
+char *U_WMRC5_set(void){
+ return U_WMRCORENONE_set("U_WMRC5");
+}
+
+char *U_WMRC6_set(void){
+ return U_WMRCORENONE_set("U_WMRC6");
+}
+
+char *U_WMRC7_set(void){
+ return U_WMRCORENONE_set("U_WMRC7");
+}
+
+char *U_WMRC8_set(void){
+ return U_WMRCORENONE_set("U_WMRC8");
+}
+
+char *U_WMRC9_set(void){
+ return U_WMRCORENONE_set("U_WMRC9");
+}
+
+char *U_WMRCA_set(void){
+ return U_WMRCORENONE_set("U_WMRCA");
+}
+
+char *U_WMRCB_set(void){
+ return U_WMRCORENONE_set("U_WMRCB");
+}
+
+char *U_WMRCC_set(void){
+ return U_WMRCORENONE_set("U_WMRCC");
+}
+
+char *U_WMRCD_set(void){
+ return U_WMRCORENONE_set("U_WMRCD");
+}
+
+char *U_WMRCE_set(void){
+ return U_WMRCORENONE_set("U_WMRCE");
+}
+
+char *U_WMRCF_set(void){
+ return U_WMRCORENONE_set("U_WMRCF");
+}
+
+char *U_WMRD0_set(void){
+ return U_WMRCORENONE_set("U_WMRD0");
+}
+
+char *U_WMRD1_set(void){
+ return U_WMRCORENONE_set("U_WMRD1");
+}
+
+char *U_WMRD2_set(void){
+ return U_WMRCORENONE_set("U_WMRD2");
+}
+
+char *U_WMRD3_set(void){
+ return U_WMRCORENONE_set("U_WMRD3");
+}
+
+char *U_WMRD4_set(void){
+ return U_WMRCORENONE_set("U_WMRD4");
+}
+
+char *U_WMRD5_set(void){
+ return U_WMRCORENONE_set("U_WMRD5");
+}
+
+char *U_WMRD6_set(void){
+ return U_WMRCORENONE_set("U_WMRD6");
+}
+
+char *U_WMRD7_set(void){
+ return U_WMRCORENONE_set("U_WMRD7");
+}
+
+char *U_WMRD8_set(void){
+ return U_WMRCORENONE_set("U_WMRD8");
+}
+
+char *U_WMRD9_set(void){
+ return U_WMRCORENONE_set("U_WMRD9");
+}
+
+char *U_WMRDA_set(void){
+ return U_WMRCORENONE_set("U_WMRDA");
+}
+
+char *U_WMRDB_set(void){
+ return U_WMRCORENONE_set("U_WMRDB");
+}
+
+char *U_WMRDC_set(void){
+ return U_WMRCORENONE_set("U_WMRDC");
+}
+
+char *U_WMRDD_set(void){
+ return U_WMRCORENONE_set("U_WMRDD");
+}
+
+char *U_WMRDE_set(void){
+ return U_WMRCORENONE_set("U_WMRDE");
+}
+
+char *U_WMRDF_set(void){
+ return U_WMRCORENONE_set("U_WMRDF");
+}
+
+char *U_WMRE0_set(void){
+ return U_WMRCORENONE_set("U_WMRE0");
+}
+
+char *U_WMRE1_set(void){
+ return U_WMRCORENONE_set("U_WMRE1");
+}
+
+char *U_WMRE2_set(void){
+ return U_WMRCORENONE_set("U_WMRE2");
+}
+
+char *U_WMRE3_set(void){
+ return U_WMRCORENONE_set("U_WMRE3");
+}
+
+char *U_WMRE4_set(void){
+ return U_WMRCORENONE_set("U_WMRE4");
+}
+
+char *U_WMRE5_set(void){
+ return U_WMRCORENONE_set("U_WMRE5");
+}
+
+char *U_WMRE6_set(void){
+ return U_WMRCORENONE_set("U_WMRE6");
+}
+
+char *U_WMRE7_set(void){
+ return U_WMRCORENONE_set("U_WMRE7");
+}
+
+char *U_WMRE8_set(void){
+ return U_WMRCORENONE_set("U_WMRE8");
+}
+
+char *U_WMRE9_set(void){
+ return U_WMRCORENONE_set("U_WMRE9");
+}
+
+char *U_WMREA_set(void){
+ return U_WMRCORENONE_set("U_WMREA");
+}
+
+char *U_WMREB_set(void){
+ return U_WMRCORENONE_set("U_WMREB");
+}
+
+char *U_WMREC_set(void){
+ return U_WMRCORENONE_set("U_WMREC");
+}
+
+char *U_WMRED_set(void){
+ return U_WMRCORENONE_set("U_WMRED");
+}
+
+char *U_WMREE_set(void){
+ return U_WMRCORENONE_set("U_WMREE");
+}
+
+char *U_WMREF_set(void){
+ return U_WMRCORENONE_set("U_WMREF");
+}
+//! \endcond
+
+/**
+ \brief Create and return a U_WMRDELETEOBJECT record
+ \return pointer to the U_WMRDELETEOBJECT record, or NULL on error
+ \param object Index of object to delete.
+*/
+char *U_WMRDELETEOBJECT_set(uint16_t object){
+ return U_WMRCORE_1U16_set(U_WMR_DELETEOBJECT, object);
+}
+
+//! \cond
+char *U_WMRF1_set(void){
+ return U_WMRCORENONE_set("U_WMRF1");
+}
+
+char *U_WMRF2_set(void){
+ return U_WMRCORENONE_set("U_WMRF2");
+}
+
+char *U_WMRF3_set(void){
+ return U_WMRCORENONE_set("U_WMRF3");
+}
+
+char *U_WMRF4_set(void){
+ return U_WMRCORENONE_set("U_WMRF4");
+}
+
+char *U_WMRF5_set(void){
+ return U_WMRCORENONE_set("U_WMRF5");
+}
+
+char *U_WMRF6_set(void){
+ return U_WMRCORENONE_set("U_WMRF6");
+}
+//! \endcond
+
+/**
+ \brief Create and return a U_WMRCREATEPALETTE record
+ \return pointer to the U_WMRCREATEPALETTE record, or NULL on error
+ \param Palette Create a Palette object.
+*/
+char *U_WMRCREATEPALETTE_set(U_PALETTE *Palette){
+ return U_WMRCORE_PALETTE_set(U_WMR_CREATEPALETTE, Palette);
+}
+
+//! \cond
+char *U_WMRF8_set(void){
+ return U_WMRCORENONE_set("U_WMRF8");
+}
+//! \endcond
+
+/**
+ \brief Allocate and construct a U_WMRCREATEPATTERNBRUSH record.
+ WARNING - U_WMRCREATEPATTERNBRUSH has been declared obsolete and application support is spotty -
+ use U_WMRDIBCREATEPATTERNBRUSH instead.
+ \return pointer to the U_WMRCREATEPATTERNBRUSH record, or NULL on error.
+ \param Bm16 Pointer to a Bitmap16 Object, only the first 10 bytes are used.
+ \param Pattern byte array pattern, described by Bm16, for brush
+*/
+char *U_WMRCREATEPATTERNBRUSH_set(
+ U_BITMAP16 *Bm16,
+ char *Pattern
+ ){
+ char *record;
+ uint32_t irecsize,off,cbPat;
+ if(!Bm16 || !Pattern)return(NULL);
+
+ cbPat = (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height;
+ irecsize = U_SIZE_METARECORD + 14 + 18 + cbPat; /* core WMR + truncated Bm16 + 18 spaces bytes + pattern */
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEPATTERNBRUSH);
+ off = U_SIZE_METARECORD;
+ memcpy(record + off, Bm16, 14); off+=14; /* Truncated bitmap16 object, last 4 bytes are to be ignored*/
+ memset(record + off, 0, 18); off+=18; /* 18 bytes of zero, which are ignored */
+ memcpy(record + off, Pattern, cbPat); /* The pattern array */
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEPENINDIRECT record.
+ \return pointer to the U_WMRCREATEPENINDIRECT record, or NULL on error.
+ \param pen Parameters of the pen object to create.
+*/
+char *U_WMRCREATEPENINDIRECT_set(U_PEN pen){
+ return U_WMRCORE_2U16_N16_set(U_WMR_CREATEPENINDIRECT, NULL, NULL, U_SIZE_PEN/2, &pen);
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEFONTINDIRECT record.
+ \return pointer to the U_WMRCREATEFONTINDIRECT record, or NULL on error.
+ \param font Parameters of the font object to create.
+*/
+char *U_WMRCREATEFONTINDIRECT_set(U_FONT *font){
+ char *record=NULL;
+ uint32_t irecsize,off,flen;
+ flen = 1 + strlen((char *)font->FaceName); /* include the null terminator in the count */
+ if(flen & 1) flen++; /* make the allocation end line up at an even byte */
+ irecsize = U_SIZE_METARECORD + U_SIZE_FONT_CORE + flen;
+ record = calloc(1,irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEFONTINDIRECT);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,font,U_SIZE_FONT_CORE + flen);
+ }
+ return(record);
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEBRUSHINDIRECT record.
+ \return pointer to the U_WMRCREATEBRUSHINDIRECT record, or NULL on error.
+ \param brush Parameters of the brush object to create.
+*/
+char *U_WMRCREATEBRUSHINDIRECT_set(U_WLOGBRUSH brush){
+ return U_WMRCORE_2U16_N16_set(U_WMR_CREATEBRUSHINDIRECT, NULL, NULL, U_SIZE_WLOGBRUSH/2, &brush);
+}
+
+/** in GDI and Wine, not in WMF manual.
+*/
+char *U_WMRCREATEBITMAPINDIRECT_set(void){
+ return U_WMRCORENONE_set("U_WMRCREATEBITMAPINDIRECT");
+}
+
+/** in GDI and Wine, not in WMF manual.
+*/
+ char *U_WMRCREATEBITMAP_set(void){
+ return U_WMRCORENONE_set("U_WMRCREATEBITMAP");
+}
+
+/**
+ \brief Allocate and construct a U_WMRCREATEREGION record.
+ \return pointer to the U_WMRCREATEREGION record, or NULL on error.
+ \param region Parameters of the region object to create.
+*/
+char *U_WMRCREATEREGION_set(const U_REGION *region){
+ char *record=NULL;
+ uint32_t irecsize,off;
+ irecsize = U_SIZE_METARECORD + region->Size;
+ record = malloc(irecsize);
+ if(record){
+ U_WMRCORE_SETRECHEAD(record,irecsize,U_WMR_CREATEREGION);
+ off = U_SIZE_METARECORD;
+ memcpy(record+off,region,region->Size);
+ }
+ return(record);
+}
+
+
+/* all of the *_set are above, all of the *_get are below */
+
+/* **********************************************************************************************
+These functions are used for Image conversions and other
+utility operations. Character type conversions are in uwmf_utf.c
+*********************************************************************************************** */
+
+
+/**
+ \brief Make up an approximate dx array to pass to U_WMREXTTEXTOUT_get(), based on character height and weight.
+
+ Take abs. value of character height, get width by multiplying by 0.6, and correct weight
+ approximately, with formula (measured on screen for one text line of Arial).
+ Caller is responsible for free() on the returned pointer.
+
+ \return pointer to dx array
+ \param height character height (absolute value will be used)
+ \param weight LF_Weight Enumeration (character weight)
+ \param members Number of entries to put into dx
+
+*/
+int16_t *dx16_get(
+ int32_t height,
+ uint32_t weight,
+ uint32_t members
+ ){
+ uint32_t i, width;
+ int16_t *dx;
+ dx = (int16_t *) malloc(members * sizeof(int16_t));
+ if(dx){
+ if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL;
+ width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904));
+ for ( i = 0; i < members; i++ ){ dx[i] = (width > INT16_MAX ? INT16_MAX : width); }
+ }
+ return(dx);
+}
+
+/**
+ \brief Return the size of a WMF record, or 0 if it is found to be invalid.
+ A valid record will have a size that does not cause it to extend
+ beyond the end of data in memory.
+ A valid record will not be smaller than the smallest possible WMF record.
+ \return size of the record in bytes, 0 on failure
+ \param contents record to extract data from
+ \param blimit one byte past the last WMF record in memory.
+*/
+size_t U_WMRRECSAFE_get(
+ const char *contents,
+ const char *blimit
+ ){
+ size_t size=0;
+ uint32_t Size16;
+ memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4), 4);
+ size = 2*Size16;
+ /* Record is not self consistent - described size past the end of WMF in memory */
+ if(size < U_SIZE_METARECORD || IS_MEM_UNSAFE(contents, size, blimit))size=0;
+ return(size);
+}
+
+
+/* **********************************************************************************************
+These functions create standard structures used in the WMR records.
+*********************************************************************************************** */
+
+// hide these from Doxygen
+//! \cond
+/* **********************************************************************************************
+These functions contain shared code used by various U_WMR*_get functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+*********************************************************************************************** */
+
+int U_WMRCORENONE_get(char *string){
+ printf("unimplemented creator for:%s\n",string);
+ return(0);
+}
+
+/* Returns the record size in bytes for a valid record, or 0 for an invalid record.
+ A valid record's size is at least as large as the minimum size passed in through minsize.
+ Use U_WMRRECSAFE_get() to check if the record extends too far in memory.
+*/
+int U_WMRCORE_RECSAFE_get(
+ const char *contents,
+ int minsize
+){
+ int size=0;
+ uint32_t Size16;
+ memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4),4);
+ size = 2*Size16;
+ if(size < minsize)size=0;
+ return(size);
+}
+
+
+/* records like U_WMRFLOODFILL and others. all args are optional, Color is not */
+int U_WMRCORE_1U16_CRF_2U16_get(
+ const char *contents,
+ uint16_t *arg1,
+ U_COLORREF *Color,
+ uint16_t *arg2,
+ uint16_t *arg3
+ ){
+ int size = 0;
+ int off = U_SIZE_METARECORD;
+ if(arg1){ memcpy(arg1, contents + off, 2); off+=2; size+=2;}
+ memcpy(Color, contents + off, 4); off+=4; size+=4;
+ if(arg2){ memcpy(arg2, contents + off, 2); off+=2; size+=2;}
+ if(arg3){ memcpy(arg3, contents + off, 2); size+=2;}
+ return(size);
+}
+
+/* records that have a single uint16_t argument like U_WMRSETMAPMODE
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_1U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ memcpy(arg1, contents + off, 2);
+ return(size);
+}
+
+/* records that have two uint16_t arguments like U_WMRSETBKMODE
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_2U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ memcpy(arg1, contents + off, 2); off+=2;
+ memcpy(arg2, contents + off, 2);
+ return(size);
+}
+
+/* records that have four uint16_t arguments like U_WMRSCALEWINDOWEXT
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_4U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2,
+ uint16_t *arg3,
+ uint16_t *arg4
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ memcpy(arg1, contents + off, 2); off+=2;
+ memcpy(arg2, contents + off, 2); off+=2;
+ memcpy(arg3, contents + off, 2); off+=2;
+ memcpy(arg4, contents + off, 2);
+ return(size);
+}
+
+/* records that have five uint16_t arguments like U_WMRCREATEPENINDIRECT
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_5U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2,
+ uint16_t *arg3,
+ uint16_t *arg4,
+ uint16_t *arg5
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ memcpy(arg1, contents + off, 2); off+=2;
+ memcpy(arg2, contents + off, 2); off+=2;
+ memcpy(arg3, contents + off, 2); off+=2;
+ memcpy(arg4, contents + off, 2); off+=2;
+ memcpy(arg5, contents + off, 2);
+ return(size);
+}
+
+/* records that have six uint16_t arguments like U_ROUNDREC
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_6U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2,
+ uint16_t *arg3,
+ uint16_t *arg4,
+ uint16_t *arg5,
+ uint16_t *arg6
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ memcpy(arg1, contents + off, 2); off+=2;
+ memcpy(arg2, contents + off, 2); off+=2;
+ memcpy(arg3, contents + off, 2); off+=2;
+ memcpy(arg4, contents + off, 2); off+=2;
+ memcpy(arg5, contents + off, 2); off+=2;
+ memcpy(arg6, contents + off, 2);
+ return(size);
+}
+
+/* records that have eight uint16_t arguments like U_WMRARC
+ May also be used with int16_t with appropriate casts */
+int U_WMRCORE_8U16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2,
+ uint16_t *arg3,
+ uint16_t *arg4,
+ uint16_t *arg5,
+ uint16_t *arg6,
+ uint16_t *arg7,
+ uint16_t *arg8
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ memcpy(arg1, contents + off, 2); off+=2;
+ memcpy(arg2, contents + off, 2); off+=2;
+ memcpy(arg3, contents + off, 2); off+=2;
+ memcpy(arg4, contents + off, 2); off+=2;
+ memcpy(arg5, contents + off, 2); off+=2;
+ memcpy(arg6, contents + off, 2); off+=2;
+ memcpy(arg7, contents + off, 2); off+=2;
+ memcpy(arg8, contents + off, 2);
+ return(size);
+}
+
+/* records that have
+ arg1 an (optional) (u)int16
+ arg2 an (optional( (u)int16
+ array of data cells or just a bunch of data. Passed as a char because the structures in the WMF in memory may
+ not be aligned properly for those structures. Caller has to take them apart - carefully.
+ like U_WMRCREATEBRUSHINDIRECT with arg1=arg2=NULL
+*/
+int U_WMRCORE_2U16_N16_get(
+ const char *contents,
+ int minsize,
+ uint16_t *arg1,
+ uint16_t *arg2,
+ const char **array
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ if(arg1){ memcpy(arg1, contents + off, 2); off+=2; }
+ if(arg2){ memcpy(arg2, contents + off, 2); off+=2; }
+ *array = (contents + off);
+ return(size);
+}
+
+
+
+/* records that get a U_PALETTE like U_WMRANIMATEPALETTE. Fills in the first two fields of U_PALETTE only, and returns
+ returns a separateepointer to the PalEntries[] array. This pointer is most likely not aligned with the data.
+ */
+int U_WMRCORE_PALETTE_get(
+ const char *contents,
+ int minsize,
+ U_PALETTE *Palette,
+ const char **PalEntries
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, minsize);
+ if(!size)return(0);
+ contents += offsetof(U_WMRANIMATEPALETTE, Palette);
+ memset(Palette, 0, (U_SIZE_PALETTE));
+ memcpy(Palette, contents, (U_SIZE_PALETTE));
+ *PalEntries = (contents + offsetof(U_PALETTE, PalEntries));
+ return(size);
+}
+
+//! \endcond
+
+/**
+ \brief Return parameters from a bitmapcoreheader.
+ All are returned as 32 bit integers, regardless of their internal representation.
+
+ \param BmiCh char * pointer to a U_BITMAPCOREHEADER. Note, data may not be properly aligned.
+ \param Size size of the coreheader in bytes
+ \param Width; Width of pixel array
+ \param Height; Height of pixel array
+ \param BitCount Pixel Format (BitCount Enumeration)
+*/
+void U_BITMAPCOREHEADER_get(
+ const char *BmiCh,
+ uint32_t *Size,
+ int32_t *Width,
+ int32_t *Height,
+ int32_t *BitCount
+ ){
+ uint32_t utmp4;
+ uint16_t utmp2;
+ memcpy(&utmp4, BmiCh + offsetof(U_BITMAPCOREHEADER,Size_4), 4); *Size = utmp4;
+ memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,Width), 2); *Width = utmp2;
+ memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,Height), 2); *Height = utmp2;
+ memcpy(&utmp2, BmiCh + offsetof(U_BITMAPCOREHEADER,BitCount), 2); *BitCount = utmp2;
+}
+
+/**
+ \brief Return parameters from a bitinfoheader.
+ All are returned as 32 bit integers, regardless of their internal representation.
+
+ \param Bmih char * pointer to a U_BITMAPINFOHEADER. Note, data may not be properly aligned.
+ \param Size Structure size in bytes
+ \param Width Bitmap width in pixels
+ \param Height Bitmap height in pixels, may be negative.
+ \param Planes Planes (must be 1)
+ \param BitCount BitCount Enumeration (determines number of RBG colors)
+ \param Compression BI_Compression Enumeration
+ \param SizeImage Image size in bytes or 0 = "default size (calculated from geometry?)"
+ \param XPelsPerMeter X Resolution in pixels/meter
+ \param YPelsPerMeter Y Resolution in pixels/meter
+ \param ClrUsed Number of bmciColors in U_BITMAPINFO/U_BITMAPCOREINFO that are used by the bitmap
+ \param ClrImportant Number of bmciColors needed (0 means all).
+
+
+*/
+void U_BITMAPINFOHEADER_get(
+ const char *Bmih,
+ uint32_t *Size,
+ int32_t *Width,
+ int32_t *Height,
+ uint32_t *Planes,
+ uint32_t *BitCount,
+ uint32_t *Compression,
+ uint32_t *SizeImage,
+ int32_t *XPelsPerMeter,
+ int32_t *YPelsPerMeter,
+ uint32_t *ClrUsed,
+ uint32_t *ClrImportant
+ ){
+ int32_t tmp4;
+ uint32_t utmp4;
+ uint16_t utmp2;
+
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSize ), 4); *Size = utmp4;
+ memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biWidth ), 4); *Width = tmp4;
+ memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biHeight ), 4); *Height = tmp4;
+ memcpy(&utmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biPlanes ), 2); *Planes = utmp2;
+ memcpy(&utmp2, Bmih + offsetof(U_BITMAPINFOHEADER,biBitCount ), 2); *BitCount = utmp2;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biCompression ), 4); *Compression = utmp4;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biSizeImage ), 4); *SizeImage = utmp4;
+ memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biXPelsPerMeter), 4); *XPelsPerMeter = tmp4;
+ memcpy( &tmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biYPelsPerMeter), 4); *YPelsPerMeter = tmp4;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrUsed ), 4); *ClrUsed = utmp4;
+ memcpy(&utmp4, Bmih + offsetof(U_BITMAPINFOHEADER,biClrImportant ), 4); *ClrImportant = utmp4;
+}
+
+/**
+ \brief Assume a packed DIB and get the parameters from it, use by DBI_to_RGBA()
+
+ \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid.
+ \param dib pointer to the start of the DIB in the record
+ \param px pointer to DIB pixel array
+ \param ct pointer to DIB color table
+ \param numCt DIB color table number of entries, for PNG or JPG returns the number of bytes in the image
+ \param width Width of pixel array
+ \param height Height of pixel array (always returned as a positive number)
+ \param colortype DIB BitCount Enumeration
+ \param invert If DIB rows are in opposite order from RGBA rows
+*/
+int wget_DIB_params(
+ const char *dib,
+ const char **px,
+ const U_RGBQUAD **ct,
+ uint32_t *numCt,
+ int32_t *width,
+ int32_t *height,
+ int32_t *colortype,
+ int32_t *invert
+ ){
+ uint32_t bic;
+ uint32_t Size;
+ bic = U_BI_RGB; // this information is not in the coreheader;
+ U_BITMAPCOREHEADER_get(dib, &Size, width, height, colortype);
+ if(Size != 0xC ){ //BitmapCoreHeader
+ /* if biCompression is not U_BI_RGB some or all of the following might not hold real values.
+ Ignore most of the information returned from the bitmapinfoheader.
+ */
+ uint32_t uig4;
+ int32_t ig4;
+ U_BITMAPINFOHEADER_get(dib, &uig4, width, height,&uig4, (uint32_t *) colortype, &bic, &uig4, &ig4, &ig4, &uig4, &uig4);
+ }
+ if(*height < 0){
+ *height = -*height;
+ *invert = 1;
+ }
+ else {
+ *invert = 0;
+ }
+ *px = dib + U_SIZE_BITMAPINFOHEADER;
+ if(bic == U_BI_RGB){
+ *numCt = get_real_color_count(dib);
+ if(*numCt){
+ *ct = (U_RGBQUAD *) (dib + U_SIZE_BITMAPINFOHEADER);
+ *px += U_SIZE_COLORREF * (*numCt);
+ }
+ else { *ct = NULL; }
+ }
+ else {
+ memcpy(numCt, dib + offsetof(U_BITMAPINFOHEADER,biSizeImage), 4);
+ *ct = NULL;
+ }
+ return(bic);
+}
+
+
+
+/* **********************************************************************************************
+These are the core WMR functions, each extracts data from a particular type of record.
+In general routines fill in structures which have been passed in by the caller, and zero them
+if that (optional) structure is not present.
+Because the WMF records may not be aligned they are generally copied into the supplied
+ aligned structs, so that the caller may retrieve fields with the usual sorts of
+ structure operations: Struct.field or (*Struct)->field.
+A few routines return pointers to data regions in the record.
+They are listed in order by the corresponding U_WMR_* index number.
+*********************************************************************************************** */
+
+/**
+ \brief Get data from a (placeable) WMR_HEADER.
+ \return size of the record in bytes, 0 on failure
+ \param contents record to extract data from
+ \param blimit one byte past the last WMF record in memory.
+ \param Placeable U_WMRPLACEABLE data, if any
+ \param Header U_WMRHEADER data, if any
+*/
+int wmfheader_get(
+ const char *contents,
+ const char *blimit,
+ U_WMRPLACEABLE *Placeable,
+ U_WMRHEADER *Header
+ ){
+ uint32_t Key;
+ int size=0;
+ if(!contents || !Placeable || !Header || !blimit)return(0);
+ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0);
+ memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4);
+ if(Key == 0x9AC6CDD7){
+ size += U_SIZE_WMRPLACEABLE;
+ if(IS_MEM_UNSAFE(contents, size, blimit))return(0);
+ memcpy(Placeable, contents, U_SIZE_WMRPLACEABLE);
+ contents += U_SIZE_WMRPLACEABLE;
+ }
+ else {
+ memset(Placeable, 0, U_SIZE_WMRPLACEABLE);
+ }
+ if(IS_MEM_UNSAFE(contents, size + U_SIZE_WMRHEADER, blimit))return(0);
+ size += 2* (*(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)));
+ if(IS_MEM_UNSAFE(contents, size, blimit))return(0);
+ memcpy(Header, contents, U_SIZE_WMRHEADER);
+ return(size);
+}
+
+
+/**
+ \brief Get data from a U_WMREOF record
+ \return size of record in bytes, or 0 on error
+ \param contents record to extract data from
+*/
+int U_WMREOF_get(
+ const char *contents
+ ){
+ return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMREOF)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETBKCOLOR record
+ \return length of the U_WMRSETBKCOLOR record, or NULL on error
+ \param contents record to extract data from
+ \param Color Background Color.
+*/
+int U_WMRSETBKCOLOR_get(
+ const char *contents,
+ U_COLORREF *Color
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETBKCOLOR));
+ if(!size)return(0);
+ memcpy(Color,contents + offsetof(U_WMRSETBKCOLOR,Color),U_SIZE_COLORREF);
+ return(size);
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETBKMODE record
+ \return length of the U_WMRSETBKMODE record, or NULL on error
+ \param contents record to extract data from
+ \param Mode MixMode Enumeration
+*/
+int U_WMRSETBKMODE_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETBKMODE), Mode));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETMAPMODE record
+ \return length of the U_WMRSETMAPMODE record, or NULL on error
+ \param contents record to extract data from
+ \param Mode MapMode Enumeration
+*/
+int U_WMRSETMAPMODE_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETMAPMODE), Mode));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETROP2 record
+ \return length of the U_WMRSETROP2 record, or NULL on error
+ \param contents record to extract data from
+ \param Mode Binary Raster Operation Enumeration
+*/
+int U_WMRSETROP2_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETROP2), Mode));
+}
+
+/**
+ \brief Get data from a U_WMRSETRELABS record
+ \return length of the U_WMRSETRELABS record in bytes, or 0 on error
+ \param contents record to extract data from
+*/
+int U_WMRSETRELABS_get(
+ const char *contents
+ ){
+ return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETRELABS)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETPOLYFILLMODE record
+ \return length of the U_WMRSETPOLYFILLMODE record, or NULL on error
+ \param contents record to extract data from
+ \param Mode PolyFillMode Enumeration
+*/
+int U_WMRSETPOLYFILLMODE_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETPOLYFILLMODE), Mode));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETSTRETCHBLTMODE record
+ \return length of the U_WMRSETSTRETCHBLTMODE record, or NULL on error
+ \param contents record to extract data from
+ \param Mode StretchMode Enumeration
+*/
+int U_WMRSETSTRETCHBLTMODE_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETSTRETCHBLTMODE), Mode));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETTEXTCHAREXTRA record
+ \return length of the U_WMRSETTEXTCHAREXTRA record, or NULL on error
+ \param contents record to extract data from
+ \param Mode Extra space in logical units to add to each character
+*/
+int U_WMRSETTEXTCHAREXTRA_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return(U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETTEXTCHAREXTRA), Mode));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETTEXTCOLOR record
+ \return length of the U_WMRSETTEXTCOLOR record, or NULL on error
+ \param contents record to extract data from
+ \param Color Text Color.
+*/
+int U_WMRSETTEXTCOLOR_get(
+ const char *contents,
+ U_COLORREF *Color
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETTEXTCOLOR));
+ if(!size)return(0);
+ memcpy(Color,contents + offsetof(U_WMRSETTEXTCOLOR,Color),U_SIZE_COLORREF);
+ return(size);
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETTEXTJUSTIFICATION record
+ \return length of the U_WMRSETTEXTJUSTIFICATION record, or NULL on error
+ \param contents record to extract data from
+ \param Count Number of space characters in the line.
+ \param Extra Number of extra space characters to add to the line.
+*/
+int U_WMRSETTEXTJUSTIFICATION_get(
+ const char *contents,
+ uint16_t *Count,
+ uint16_t *Extra
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETTEXTJUSTIFICATION), Count, Extra));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETWINDOWORG record
+ \return length of the U_WMRSETWINDOWORG record, or NULL on error
+ \param contents record to extract data from
+ \param coord Window Origin.
+*/
+int U_WMRSETWINDOWORG_get(
+ const char *contents,
+ U_POINT16 * coord
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETWINDOWORG), U_P16(coord->y), U_P16(coord->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETWINDOWEXT record
+ \return length of the U_WMRSETWINDOWEXT record, or NULL on error
+ \param contents record to extract data from
+ \param extent Window Extent.
+*/
+int U_WMRSETWINDOWEXT_get(
+ const char *contents,
+ U_POINT16 * extent
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETWINDOWEXT), U_P16(extent->y), U_P16(extent->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETVIEWPORTORG record
+ \return length of the U_WMRSETVIEWPORTORG record, or NULL on error
+ \param contents record to extract data from
+ \param coord Viewport Origin.
+*/
+int U_WMRSETVIEWPORTORG_get(
+ const char *contents,
+ U_POINT16 * coord
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETVIEWPORTORG), U_P16(coord->y), U_P16(coord->x)));
+
+}
+
+/**
+ \brief Retrieve values from a U_WMRSETVIEWPORTEXT record
+ \return length of the U_WMRSETVIEWPORTEXT record, or NULL on error
+ \param contents record to extract data from
+ \param extent Viewport Extent.
+*/
+int U_WMRSETVIEWPORTEXT_get(
+ const char *contents,
+ U_POINT16 * extent
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRSETVIEWPORTEXT), U_P16(extent->y), U_P16(extent->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMROFFSETWINDOWORG record
+ \return length of the U_WMROFFSETWINDOWORG record, or NULL on error
+ \param contents record to extract data from
+ \param offset Window offset in device units.
+*/
+int U_WMROFFSETWINDOWORG_get(
+ const char *contents,
+ U_POINT16 * offset
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETWINDOWORG), U_P16(offset->y), U_P16(offset->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSCALEWINDOWEXT record
+ \return length of the U_WMRSCALEWINDOWEXT record, or NULL on error
+ \param contents record to extract data from
+ \param Denom {X,Y} denominators.
+ \param Num {X,Y} numerators.
+*/
+int U_WMRSCALEWINDOWEXT_get(
+ const char *contents,
+ U_POINT16 * Denom,
+ U_POINT16 * Num
+ ){
+ return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRSCALEWINDOWEXT), U_P16(Denom->y), U_P16(Denom->x), U_P16(Num->y), U_P16(Num->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMROFFSETVIEWPORTORG record
+ \return length of the U_WMROFFSETVIEWPORTORG record, or NULL on error
+ \param contents record to extract data from
+ \param offset Viewport offset in device units.
+*/
+int U_WMROFFSETVIEWPORTORG_get(
+ const char *contents,
+ U_POINT16 * offset
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETVIEWPORTORG), U_P16(offset->y), U_P16(offset->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRSCALEVIEWPORTEXT record
+ \return length of the U_WMRSCALEVIEWPORTEXT record, or NULL on error
+ \param contents record to extract data from
+ \param Denom {X,Y} denominators.
+ \param Num {X,Y} numerators.
+*/
+int U_WMRSCALEVIEWPORTEXT_get(
+ const char *contents,
+ U_POINT16 * Denom,
+ U_POINT16 * Num
+ ){
+ return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRSCALEVIEWPORTEXT), U_P16(Denom->y), U_P16(Denom->x), U_P16(Num->y), U_P16(Num->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRLINETO record
+ \return length of the U_WMRLINETO record, or NULL on error
+ \param contents record to extract data from
+ \param coord Draw line to {X,Y}.
+*/
+int U_WMRLINETO_get(
+ const char *contents,
+ U_POINT16 * coord
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRLINETO), U_P16(coord->y), U_P16(coord->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRMOVETO record
+ \return length of the U_WMRMOVETO record, or NULL on error
+ \param contents record to extract data from
+ \param coord Move to {X,Y}.
+*/
+int U_WMRMOVETO_get(
+ const char *contents,
+ U_POINT16 * coord
+ ){
+ return(U_WMRCORE_2U16_get(contents, (U_SIZE_WMRMOVETO), U_P16(coord->y), U_P16(coord->x)));
+}
+
+/**
+ \brief Retrieve values from a U_WMREXCLUDECLIPRECT record
+ \return length of the U_WMREXCLUDECLIPRECT record, or NULL on error
+ \param contents record to extract data from
+ \param rect Exclude rect from clipping region.
+*/
+int U_WMREXCLUDECLIPRECT_get(
+ const char *contents,
+ U_RECT16 *rect
+ ){
+ return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMREXCLUDECLIPRECT), U_P16(rect->bottom), U_P16(rect->right), U_P16(rect->top), U_P16(rect->left)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRINTERSECTCLIPRECT record
+ \return length of the U_WMRINTERSECTCLIPRECT record, or NULL on error
+ \param contents record to extract data from
+ \param rect Clipping region is intersection of existing clipping region with rect.
+*/
+int U_WMRINTERSECTCLIPRECT_get(
+ const char *contents,
+ U_RECT16 *rect
+ ){
+ return(U_WMRCORE_4U16_get(contents, (U_SIZE_WMRINTERSECTCLIPRECT), U_P16(rect->bottom), U_P16(rect->right), U_P16(rect->top), U_P16(rect->left)));
+}
+
+/**
+ \brief Retrieve values from a U_WMRARC record
+ \return length of the U_WMRARC record, or NULL on error
+ \param contents record to extract data from
+ \param StartArc Start of Arc
+ \param EndArc End of Arc
+ \param rect Bounding rectangle.
+*/
+int U_WMRARC_get(
+ const char *contents,
+ U_POINT16 *StartArc,
+ U_POINT16 *EndArc,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_8U16_get(
+ contents,
+ (U_SIZE_WMRARC),
+ U_P16(EndArc->y),
+ U_P16(EndArc->x),
+ U_P16(StartArc->y),
+ U_P16(StartArc->x),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Retrieve values from a U_WMRELLIPSE record
+ \return length of the U_WMRELLIPSE record, or NULL on error
+ \param contents record to extract data from
+ \param rect Bounding rectangle for Ellipse.
+*/
+int U_WMRELLIPSE_get(
+ const char *contents,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_4U16_get(
+ contents,
+ (U_SIZE_WMRELLIPSE),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Retrieve values from a U_WMRFLOODFILL record
+ \return length of the U_WMRFLOODFILL record, or NULL on error
+ \param contents record to extract data from
+ \param Mode FloodFill Enumeration.
+ \param Color Color to Fill with.
+ \param coord Location to start fill.
+*/
+int U_WMRFLOODFILL_get(
+ const char *contents,
+ uint16_t *Mode,
+ U_COLORREF *Color,
+ U_POINT16 *coord
+ ){
+ return U_WMRCORE_1U16_CRF_2U16_get(
+ contents,
+ Mode,
+ Color,
+ U_P16(coord->y),
+ U_P16(coord->x)
+ );
+}
+
+/**
+ \brief Retrieve values from a U_WMRPIE record
+ \return length of the U_WMRPIE record, or NULL on error
+ \param contents record to extract data from
+ \param Radial1 Start of Pie
+ \param Radial2 End of Pie
+ \param rect Bounding rectangle.
+*/
+int U_WMRPIE_get(
+ const char *contents,
+ U_POINT16 *Radial1,
+ U_POINT16 *Radial2,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_8U16_get(
+ contents,
+ (U_SIZE_WMRPIE),
+ U_P16(Radial2->y),
+ U_P16(Radial2->x),
+ U_P16(Radial1->y),
+ U_P16(Radial1->x),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Retrieve values from a U_WMRRECTANGLE record
+ \return length of the U_WMRRECTANGLE record, or NULL on error
+ \param contents record to extract data from
+ \param rect Boundaries.
+*/
+int U_WMRRECTANGLE_get(
+ const char *contents,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_4U16_get(
+ contents,
+ (U_SIZE_WMRRECTANGLE),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Retrieve values from a U_WMRROUNDRECT record
+ \return length of the U_WMRROUNDRECT record, or NULL on error
+ \param contents record to extract data from
+ \param Width Horizontal rounding length.
+ \param Height Vertical rounding length.
+ \param rect Boundaries.
+*/
+int U_WMRROUNDRECT_get(
+ const char *contents,
+ int16_t *Width,
+ int16_t *Height,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_6U16_get(
+ contents,
+ (U_SIZE_WMRROUNDRECT),
+ U_PP16(Height),
+ U_PP16(Width),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Get data from a U_WMRPATBLT record.
+ \return length of the U_WMRPATBLT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param cwh W & H for Dst and Src in logical units
+ \param dwRop3 RasterOPeration Enumeration
+*/
+int U_WMRPATBLT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cwh,
+ uint32_t *dwRop3
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRPATBLT));
+ if(!size)return(0);
+ memcpy(dwRop3, ( contents + offsetof(U_WMRPATBLT, rop3w)), 4);
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRPATBLT, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRPATBLT, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRPATBLT, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRPATBLT, xDst ));
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSAVEDC record
+ \return length of the U_WMRSAVEDC record in bytes, or 0 on error
+ \param contents record to extract data from
+*/
+int U_WMRSAVEDC_get(
+ const char *contents
+ ){
+ return(U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSAVEDC)));
+}
+
+/**
+ \brief Get data from a U_WMRSETPIXEL record
+ \return length of the U_WMRSETPIXEL record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Color pointer to a U_COLORREF variable where the color will be stored.
+ \param Coord pointer to a U_POINT16 variable where the coordinates will be stored.
+*/
+int U_WMRSETPIXEL_get(
+ const char *contents,
+ U_COLORREF *Color,
+ U_POINT16 *Coord){
+ return U_WMRCORE_1U16_CRF_2U16_get(
+ contents,
+ NULL,
+ Color,
+ U_P16(Coord->y),
+ U_P16(Coord->x)
+ );
+}
+
+/**
+ \brief Get data from a U_WMROFFSETCLIPRGN record
+ \return length of the U_WMROFFSETCLIPRGN record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param offset pointer to a U_POINT16 variable where the x,y offsets will be stored.
+*/
+int U_WMROFFSETCLIPRGN_get(
+ const char *contents,
+ U_POINT16 *offset
+ ){
+ return U_WMRCORE_2U16_get(contents, (U_SIZE_WMROFFSETCLIPRGN), U_P16(offset->y), U_P16(offset->x));
+}
+
+/**
+ \brief Get data from a U_WMRTEXTOUT record
+ \return length of the U_WMRTEXTOUT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst coordinates where text will be written
+ \param Length Number of characters in string.
+ \param string Pointer to string in WMF buffer in memory. This text is generally NOT null terminated!!!
+*/
+int U_WMRTEXTOUT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ int16_t *Length,
+ const char **string
+ ){
+ int16_t L2;
+ int off;
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRTEXTOUT));
+ if(!size)return(0);
+ *Length = *(int16_t *)(contents + offsetof(U_WMRTEXTOUT, Length));
+ *string = contents + offsetof(U_WMRTEXTOUT, String); /* May not be null terminated!!! */
+ L2 = *Length;
+ if(L2 & 1)L2++;
+ off = U_SIZE_METARECORD + 2 + L2;
+ memcpy(&Dst->y, contents + off, 2); off+=2;
+ memcpy(&Dst->x, contents + off, 2);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRBITBLT record.
+ Note that unlike U_EMRBITBLT there is no scaling available - the Src and Dst
+ rectangles must be the same size.
+ \return length of the U_WMRBITBLT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param cwh W & H for Dst and Src in logical units
+ \param Src Source UL corner in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bm16 bitmap16 object (fields in it are all 0 if no bitmap is used)
+ \param px pointer to bitmap in memory, or NULL if not used
+*/
+int U_WMRBITBLT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cwh,
+ U_POINT16 * Src,
+ uint32_t *dwRop3,
+ U_BITMAP16 *Bm16,
+ const char **px
+ ){
+ uint8_t xb;
+ uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRBITBLT_NOPX));
+ if(!size)return(0);
+ xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb));
+ if(U_TEST_NOPXB(size,xb)){ /* no bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRBITBLT_NOPX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, xSrc ));
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_NOPX, xDst ));
+ memset(Bm16, 0, U_SIZE_BITMAP16);
+ *px = NULL;
+ }
+ else { /* yes bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRBITBLT_PX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, xSrc ));
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRBITBLT_PX, xDst ));
+ memcpy(Bm16, ( contents + offsetof(U_WMRBITBLT_PX, bitmap)), U_SIZE_BITMAP16);
+ *px = ( contents + offsetof(U_WMRBITBLT_PX, bitmap) + U_SIZE_BITMAP16);
+ }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSTRETCHBLT record.
+ \return length of the U_WMRSTRETCHBLT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param Bm16 bitmap16 object (fields in it are all 0 if no bitmap is used)
+ \param px pointer to bitmap in memory, or NULL if not used
+*/
+int U_WMRSTRETCHBLT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cDst,
+ U_POINT16 * Src,
+ U_POINT16 * cSrc,
+ uint32_t *dwRop3,
+ U_BITMAP16 *Bm16,
+ const char **px
+ ){
+ uint8_t xb;
+ uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSTRETCHBLT_NOPX));
+ if(!size)return(0);
+ xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb));
+ if(U_TEST_NOPXB(size,xb)){ /* no bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHBLT_NOPX, rop3w)), 4);
+ cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, hSrc ));
+ cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, wSrc ));
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, xSrc ));
+ cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, hDst ));
+ cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, wDst ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_NOPX, xDst ));
+ memset(Bm16, 0, U_SIZE_BITMAP16);
+ *px = NULL;
+ }
+ else { /* yes bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHBLT_PX, rop3w)), 4);
+ cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, hSrc ));
+ cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, wSrc ));
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, xSrc ));
+ cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, hDst ));
+ cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, wDst ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHBLT_PX, xDst ));
+ memcpy(Bm16, ( contents + offsetof(U_WMRSTRETCHBLT_PX, bitmap)), U_SIZE_BITMAP16);
+ *px = ( contents + offsetof(U_WMRSTRETCHBLT_PX, bitmap) + U_SIZE_BITMAP16);
+ }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRPOLYGON record.
+ \return length of the U_WMRPOLYGON record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Length Number of points in the Polygon
+ \param Data pointer to array of U_POINT16 in memory. Pointer may not be aligned properly for structures.
+*/
+int U_WMRPOLYGON_get(
+ const char *contents,
+ uint16_t *Length,
+ const char **Data
+ ){
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data);
+ if(size){
+ int iLength = (*Length)*sizeof(U_POINT16);
+ if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0);
+ }
+ return size;
+}
+
+/**
+ \brief Get data from a U_WMRPOLYLINE record.
+ \return length of the U_WMRPOLYLINE record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Length Number of points in the Polyline
+ \param Data pointer to array of U_POINT16 in memory. Pointer may not be aligned properly for structures.
+*/
+int U_WMRPOLYLINE_get(
+ const char *contents,
+ uint16_t *Length,
+ const char **Data
+ ){
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data);
+ if(size){
+ int iLength = (*Length)*sizeof(U_POINT16);
+ if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0);
+ }
+ return size;
+}
+
+/**
+ \brief Get data from a U_WMRESCAPE record.
+ WARNING! Only three Escape record types are fully supported: SETLINECAP, SETLINEJOIN, SETMITERLIMIT.
+ Even these should not be set here directly, instead use the wsetlinecap_get(), wsetlinejoin_get(),
+ or wsetmiterlimit_get() functions.
+ Escape records created with this function, with the exception of the three named above, will not have
+ the byte orders in Data adjusted automatically. The user code must set Data to be little endian no
+ matter what the endianness of the current platform where the user code is running.
+ \return length of the U_WMRESCAPE record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Escape Escape function
+ \param Length Bytes in the Data
+ \param Data Array of Length bytes
+*/
+int U_WMRESCAPE_get(
+ const char *contents,
+ uint16_t *Escape,
+ uint16_t *Length,
+ const char **Data
+ ){
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data);
+ if(size){
+ int iLength=*Length;
+ if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0);
+ }
+ return size;
+}
+
+/**
+ \brief Get data from a U_WMRRESTOREDC record
+ \return length of the U_WMRRESTOREDC record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param DC DC to restore (relative if negative, absolute if positive)
+*/
+int U_WMRRESTOREDC_get(
+ const char *contents,
+ int16_t *DC
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRRESTOREDC), (uint16_t *)DC); // signed, but it is just a memcpy, so this works
+}
+
+/**
+ \brief Get data from a U_WMRFILLREGION record.
+ \return length of the U_WMRFILLREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region Region to fill
+ \param Brush Brush to fill with
+*/
+int U_WMRFILLREGION_get(
+ const char *contents,
+ uint16_t *Region,
+ uint16_t *Brush
+ ){
+ return U_WMRCORE_2U16_get(contents, (U_SIZE_WMRFILLREGION), Region, Brush);
+}
+
+/**
+ \brief Get data from a U_WMRFRAMEREGION record.
+ \return length of the U_WMRFRAMEREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region Index of region to frame in object table
+ \param Brush Index of brush to use in frame in object table
+ \param Height in logical units (of frame)
+ \param Width in logical units (of frame)
+*/
+int U_WMRFRAMEREGION_get(
+ const char *contents,
+ uint16_t *Region,
+ uint16_t *Brush,
+ int16_t *Height,
+ int16_t *Width
+ ){
+ return U_WMRCORE_4U16_get(contents, (U_SIZE_WMRFRAMEREGION), Region, Brush, U_PP16(Height), U_PP16(Width));
+}
+
+/**
+ \brief Get data from a U_WMRINVERTREGION record.
+ \return length of the U_WMRINVERTREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region Index of region to invert.
+*/
+int U_WMRINVERTREGION_get(
+ const char *contents,
+ uint16_t *Region
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRINVERTREGION), Region);
+}
+
+/**
+ \brief Get data from a U_WMRPAINTREGION record.
+ \return length of the U_WMRPAINTREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region Index of region to paint with the current Brush.
+*/
+int U_WMRPAINTREGION_get(
+ const char *contents,
+ uint16_t *Region
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRPAINTREGION), Region);
+}
+
+/**
+ \brief Get data from a U_WMRSELECTCLIPREGION record.
+ \return length of the U_WMRSELECTCLIPREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region Index of region to become clipping region..
+*/
+int U_WMRSELECTCLIPREGION_get(
+ const char *contents,
+ uint16_t *Region
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTCLIPREGION), Region);
+
+}
+
+/**
+ \brief Get data from a U_WMRSELECTOBJECT record.
+ \return length of the U_WMRSELECTOBJECT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Object Index of object which is made active.
+*/
+int U_WMRSELECTOBJECT_get(
+ const char *contents,
+ uint16_t *Object
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTOBJECT), Object);
+}
+
+/**
+ \brief Get data from a U_WMRSETTEXTALIGN record.
+ \return length of the U_WMRSETTEXTALIGN record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Mode TextAlignment Enumeration.
+*/
+int U_WMRSETTEXTALIGN_get(
+ const char *contents,
+ uint16_t *Mode
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSETTEXTALIGN), Mode);
+}
+
+/** in GDI and Wine, not in WMF manual.
+*/
+int U_WMRDRAWTEXT_get(void){ /* in Wine, not in WMF PDF. */
+ return U_WMRCORENONE_get("U_WMRDRAWTEXT");
+}
+
+/**
+ \brief Retrieve values from a U_WMRCHORD record
+ \return length of the U_WMRCHORD record, or NULL on error
+ \param contents record to extract data from
+ \param Radial1 Start of Chord
+ \param Radial2 End of Chord
+ \param rect Bounding rectangle.
+*/
+int U_WMRCHORD_get(
+ const char *contents,
+ U_POINT16 *Radial1,
+ U_POINT16 *Radial2,
+ U_RECT16 *rect
+ ){
+ return U_WMRCORE_8U16_get(
+ contents,
+ (U_SIZE_WMRCHORD),
+ U_P16(Radial2->y),
+ U_P16(Radial2->x),
+ U_P16(Radial1->y),
+ U_P16(Radial1->x),
+ U_P16(rect->bottom),
+ U_P16(rect->right),
+ U_P16(rect->top),
+ U_P16(rect->left)
+ );
+}
+
+/**
+ \brief Get data from a U_WMRSETMAPPERFLAGS record.
+ \return length of the U_WMRSETMAPPERFLAGS record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Mode If 1 bit set font mapper selects only matching aspect fonts.
+*/
+int U_WMRSETMAPPERFLAGS_get(
+ const char *contents,
+ uint32_t *Mode
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETMAPPERFLAGS));
+ if(!size)return(0);
+ memcpy(Mode, contents + U_SIZE_METARECORD, 4);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMREXTTEXTOUT record.
+ \return length of the U_WMREXTTEXTOUT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst {X,Y} coordinates where the string is to be written.
+ \param Length Stringlength in bytes
+ \param Opts ExtTextOutOptions Flags
+ \param string String to write (Latin1 encoding)
+ \param dx Kerning information. Must have same number of entries as Length.
+ \param rect Used when when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts
+*/
+int U_WMREXTTEXTOUT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ int16_t *Length,
+ uint16_t *Opts,
+ const char **string,
+ const int16_t **dx,
+ U_RECT16 *rect
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMREXTTEXTOUT));
+ int off = U_SIZE_METARECORD;
+ if(!size)return(0);
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, y ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, x ));
+ *Length = *(int16_t *)( contents + offsetof(U_WMREXTTEXTOUT, Length ));
+ *Opts = *(uint16_t *)(contents + offsetof(U_WMREXTTEXTOUT, Opts ));
+ off = U_SIZE_WMREXTTEXTOUT;
+ if(*Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){ memcpy(rect, (contents + off), U_SIZE_RECT16); off += U_SIZE_RECT16; }
+ else { memset(rect, 0, U_SIZE_RECT16); }
+ *string = (contents + off);
+ off += 2*((*Length +1)/2);
+ if(*Length){ *dx = (int16_t *)(contents + off); }
+ else { *dx = NULL; }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSETDIBTODEV record
+ \return length of the U_WMRSETDIBTODEV record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst UL corner of Dst rect in logical units
+ \param cwh Width and Height in logical units
+ \param Src UL corner of Src rect in logical units
+ \param cUsage ColorUsage enumeration
+ \param ScanCount Number of scan lines in Src
+ \param StartScan First Scan line in Src
+ \param dib DeviceIndependentBitmap object
+*/
+int U_WMRSETDIBTODEV_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cwh,
+ U_POINT16 * Src,
+ uint16_t *cUsage,
+ uint16_t *ScanCount,
+ uint16_t *StartScan,
+ const char **dib
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSETDIBTODEV));
+ if(!size)return(0);
+ *cUsage = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, cUsage ));
+ *ScanCount = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, ScanCount ));
+ *StartScan = *(uint16_t *)(contents + offsetof(U_WMRSETDIBTODEV, StartScan ));
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xSrc ));
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xDst ));
+ *dib = ( contents + offsetof(U_WMRSETDIBTODEV, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSELECTPALETTE record
+ \return length of the U_WMRSELECTPALETTE record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Palette Index of Palette to make active.
+*/
+int U_WMRSELECTPALETTE_get(
+ const char *contents,
+ uint16_t *Palette
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRSELECTPALETTE), Palette);
+}
+
+/**
+ \brief Get data from a U_WMRREALIZEPALETTE record
+ \return length of the U_WMRREALIZEPALETTE record in bytes, or 0 on error
+ \param contents record to extract data from
+*/
+int U_WMRREALIZEPALETTE_get(
+ const char *contents
+ ){
+ return U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRREALIZEPALETTE));
+}
+
+/**
+ \brief Get data from a U_WMRSETPALENTRIES record
+ \return length of the U_WMRSETPALENTRIES record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Palette Redefines a set of RGB values for the current active Palette.
+ \param PalEntries Array of Palette Entries
+*/
+int U_WMRANIMATEPALETTE_get(
+ const char *contents,
+ U_PALETTE *Palette,
+ const char **PalEntries
+ ){
+ return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRANIMATEPALETTE), Palette, PalEntries);
+}
+
+/**
+ \brief Get data from a U_WMRSETPALENTRIES record
+ \return length of the U_WMRSETPALENTRIES record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Palette Defines a set of RGB values for the current active Palette.
+ \param PalEntries Array of Palette Entries
+*/
+int U_WMRSETPALENTRIES_get(
+ const char *contents,
+ U_PALETTE *Palette,
+ const char **PalEntries
+ ){
+ return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRSETPALENTRIES), Palette, PalEntries);
+}
+
+/**
+ \brief Get data from a U_WMR_POLYPOLYGON record.
+ \return length of the U_WMR_POLYPOLYGON record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param Points pointer to array of U_POINT16 in memory. Probably not aligned.
+*/
+int U_WMRPOLYPOLYGON_get(
+ const char *contents,
+ uint16_t *nPolys,
+ const uint16_t **aPolyCounts,
+ const char **Points
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRPOLYPOLYGON));
+ if(!size)return(0);
+ contents += offsetof(U_WMRPOLYPOLYGON, PPolygon);
+ memcpy(nPolys, contents + offsetof(U_POLYPOLYGON, nPolys), 2);
+ *aPolyCounts = (uint16_t *)(contents + offsetof(U_POLYPOLYGON, aPolyCounts));
+ *Points = (contents + offsetof(U_POLYPOLYGON, aPolyCounts) + *nPolys*2);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRRESIZEPALETTE record
+ \return length of the U_WMRRESIZEPALETTE record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Palette Changes the size of the currently active Palette.
+*/
+int U_WMRRESIZEPALETTE_get(
+ const char *contents,
+ uint16_t *Palette
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRRESIZEPALETTE), Palette);
+}
+
+//! \cond
+int U_WMR3A_get(void){
+ return U_WMRCORENONE_get("U_WMR3A");
+}
+
+int U_WMR3B_get(void){
+ return U_WMRCORENONE_get("U_WMR3B");
+}
+
+int U_WMR3C_get(void){
+ return U_WMRCORENONE_get("U_WMR3C");
+}
+
+int U_WMR3D_get(void){
+ return U_WMRCORENONE_get("U_WMR3D");
+}
+
+int U_WMR3E_get(void){
+ return U_WMRCORENONE_get("U_WMR3E");
+}
+
+int U_WMR3F_get(void){
+ return U_WMRCORENONE_get("U_WMR3F");
+}
+//! \endcond
+
+// U_WMRDIBBITBLT_get
+/**
+ \brief Get data from a U_WMRDIBITBLT record.
+ \return length of the U_WMRDIBITBLT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param Src Source UL corner in logical units
+ \param cwh W & H in logical units of Src and Dst
+ \param dwRop3 RasterOPeration Enumeration
+ \param dib pointer to dib in WMF in memory. Most likely not aligned.
+*/
+int U_WMRDIBBITBLT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cwh,
+ U_POINT16 * Src,
+ uint32_t *dwRop3,
+ const char **dib
+ ){
+ uint8_t xb;
+ uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBBITBLT_NOPX));
+ if(!size)return(0);
+ xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb));
+ if(U_TEST_NOPXB(size,xb)){ /* no bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRDIBBITBLT_NOPX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, xSrc ));
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_NOPX, xDst ));
+ *dib = NULL;
+ }
+ else { /* yes bitmap */
+ memcpy(dwRop3, ( contents + offsetof(U_WMRDIBBITBLT_PX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xSrc ));
+ cwh->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, Height ));
+ cwh->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, Width ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xDst ));
+ *dib = ( contents + offsetof(U_WMRDIBBITBLT_PX, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSTRETCHDIB record.
+ \return length of the U_WMRSTRETCHDIB record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param dwRop3 RasterOPeration Enumeration
+ \param dib pointer to dib in WMF in memory. Most likely not aligned.
+*/
+int U_WMRDIBSTRETCHBLT_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cDst,
+ U_POINT16 * Src,
+ U_POINT16 * cSrc,
+ uint32_t *dwRop3,
+ const char **dib
+ ){
+ uint8_t xb;
+ uint32_t size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBSTRETCHBLT_NOPX));
+ if(!size)return(0);
+ xb = *(uint8_t *)( contents + offsetof(U_METARECORD, xb));
+ if(U_TEST_NOPXB(size,xb)){ /* no bitmap */
+ memcpy(dwRop3 , ( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, xSrc ));
+ cSrc->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, hSrc ));
+ cSrc->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, wSrc ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, xDst ));
+ cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, hDst ));
+ cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_NOPX, wDst ));
+ *dib = NULL;
+ }
+ else { /* yes bitmap */
+ memcpy(dwRop3 , ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, rop3w)), 4);
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, xSrc ));
+ cSrc->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hSrc ));
+ cSrc->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wSrc ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, xDst ));
+ cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hDst ));
+ cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wDst ));
+ *dib = ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRDIBCREATEPATTERNBRUSH record.
+ Returns an image as either a DIB (Bmi/CbPx/Px defined) or a Bitmap16 (Bm16 defined).
+ WARNING - U_WMRCREATEPATTERNBRUSH has been declared obsolete and application support is spotty -
+ this function is still valid though, for those instances where old WMF input files are encountered.
+ \return length of the U_WMRDIBCREATEPATTERNBRUSH record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Style BrushStyle Enumeration
+ \param cUsage DIBcolors Enumeration
+ \param Bm16 pointer to a U_BITMAP16 in WMF in memory. Most likely not aligned. NULL if dib is used instead.
+ \param dib pointer to a dib in WMF in memory. Most likely not aligned. NULL if Bm16 is used instead.
+ */
+int U_WMRDIBCREATEPATTERNBRUSH_get(
+ const char *contents,
+ uint16_t *Style,
+ uint16_t *cUsage,
+ const char **Bm16,
+ const char **dib
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRDIBCREATEPATTERNBRUSH));
+ if(!size)return(0);
+
+ *Style = *(uint16_t *)(contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Style ));
+ *cUsage = *(uint16_t *)(contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, cUsage ));
+ if(*Style == U_BS_PATTERN){
+ *Bm16 = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ *dib = NULL;
+ /* The WMF spec says that Style == U_BS_PATTERN _SHOULD_ be a bitmap16.
+ However there are instances when it is actually a DIB. U_WMRDIBCREATEPATTERNBRUSH_get
+ tries to detect this by looking for bogus values when the BM16 is interpreted as such,
+ and if it finds them, then it returns a dib instead.
+ */
+ U_BITMAP16 TmpBm16;
+ memcpy(&TmpBm16, *Bm16, U_SIZE_BITMAP16);
+ if(TmpBm16.Width <= 0 || TmpBm16.Height <= 0 || TmpBm16.Planes != 1 || TmpBm16.BitsPixel == 0){
+ *Bm16 = NULL;
+ *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ }
+ }
+ else { /* from DIB */
+ *Bm16 = NULL;
+ *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ }
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRSTRETCHDIB record.
+ \return length of the U_WMRSTRETCHDIB record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Dst Destination UL corner in logical units
+ \param cDst Destination W & H in logical units
+ \param Src Source UL corner in logical units
+ \param cSrc Source W & H in logical units
+ \param cUsage DIBColors Enumeration
+ \param dwRop3 RasterOPeration Enumeration
+ \param dib (Optional) device independent bitmap
+*/
+int U_WMRSTRETCHDIB_get(
+ const char *contents,
+ U_POINT16 * Dst,
+ U_POINT16 * cDst,
+ U_POINT16 * Src,
+ U_POINT16 * cSrc,
+ uint16_t *cUsage,
+ uint32_t *dwRop3,
+ const char **dib
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRSTRETCHDIB));
+ if(!size)return(0);
+
+ memcpy(dwRop3, ( contents + offsetof(U_WMRSTRETCHDIB, rop3w)), 4);
+ *cUsage = *(uint16_t *)( contents + offsetof(U_WMRSTRETCHDIB, cUsage ));
+ cSrc->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, hSrc ));
+ cSrc->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, wSrc ));
+ Src->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, ySrc ));
+ Src->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xSrc ));
+ cDst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, hDst ));
+ cDst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, wDst ));
+ Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, yDst ));
+ Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xDst ));
+ *dib = ( contents + offsetof(U_WMRSTRETCHDIB, dib ));
+ if(!packed_DIB_safe(*dib, *dib+size))return(0);
+ return(size);
+}
+
+//! \cond
+int U_WMR44_get(void){
+ return U_WMRCORENONE_get("U_WMR44");
+}
+
+int U_WMR45_get(void){
+ return U_WMRCORENONE_get("U_WMR45");
+}
+
+int U_WMR46_get(void){
+ return U_WMRCORENONE_get("U_WMR46");
+}
+
+int U_WMR47_get(void){
+ return U_WMRCORENONE_get("U_WMR47");
+}
+//! \endcond
+
+/**
+ \brief Retrieve values from a U_WMREXTFLOODFILL record
+ \return length of the U_WMREXTFLOODFILL record, or NULL on error
+ \param contents record to extract data from
+ \param Mode FloodFill Enumeration.
+ \param Color Color to Fill with.
+ \param coord Location to start fill.
+*/
+int U_WMREXTFLOODFILL_get(
+ const char *contents,
+ uint16_t *Mode,
+ U_COLORREF *Color,
+ U_POINT16 * coord
+ ){
+ return U_WMRCORE_1U16_CRF_2U16_get(
+ contents,
+ Mode,
+ Color,
+ U_P16(coord->y),
+ U_P16(coord->x)
+ );
+}
+
+//! \cond
+int U_WMR49_get(void){
+ return U_WMRCORENONE_get("U_WMR49");
+}
+
+int U_WMR4A_get(void){
+ return U_WMRCORENONE_get("U_WMR4A");
+}
+
+int U_WMR4B_get(void){
+ return U_WMRCORENONE_get("U_WMR4B");
+}
+
+int U_WMR4C_get(void){
+ return U_WMRCORENONE_get("U_WMRRESETDOC");
+}
+
+int U_WMR4D_get(void){
+ return U_WMRCORENONE_get("U_WMRSTARTDOC");
+}
+
+int U_WMR4E_get(void){
+ return U_WMRCORENONE_get("U_WMR4E");
+}
+
+int U_WMR4F_get(void){
+ return U_WMRCORENONE_get("U_WMRSTARTPAGE");
+}
+
+int U_WMR50_get(void){
+ return U_WMRCORENONE_get("U_WMRENDPAGE");
+}
+
+int U_WMR51_get(void){
+ return U_WMRCORENONE_get("U_WMR51");
+}
+
+int U_WMRABORTDOC_get(void){
+ return U_WMRCORENONE_get("U_WMRABORTDOC");
+}
+
+int U_WMR53_get(void){
+ return U_WMRCORENONE_get("U_WMR53");
+}
+
+int U_WMR54_get(void){
+ return U_WMRCORENONE_get("U_WMR54");
+}
+
+int U_WMR55_get(void){
+ return U_WMRCORENONE_get("U_WMR55");
+}
+
+int U_WMR56_get(void){
+ return U_WMRCORENONE_get("U_WMR56");
+}
+
+int U_WMR57_get(void){
+ return U_WMRCORENONE_get("U_WMR57");
+}
+
+int U_WMR58_get(void){
+ return U_WMRCORENONE_get("U_WMR58");
+}
+
+int U_WMR59_get(void){
+ return U_WMRCORENONE_get("U_WMR59");
+}
+
+int U_WMR5A_get(void){
+ return U_WMRCORENONE_get("U_WMR5A");
+}
+
+int U_WMR5B_get(void){
+ return U_WMRCORENONE_get("U_WMR5B");
+}
+
+int U_WMR5C_get(void){
+ return U_WMRCORENONE_get("U_WMR5C");
+}
+
+int U_WMR5D_get(void){
+ return U_WMRCORENONE_get("U_WMR5D");
+}
+
+int U_WMR5E_get(void){
+ return U_WMRCORENONE_get("U_WMRENDDOC");
+}
+
+int U_WMR5F_get(void){
+ return U_WMRCORENONE_get("U_WMR5F");
+}
+
+int U_WMR60_get(void){
+ return U_WMRCORENONE_get("U_WMR60");
+}
+
+int U_WMR61_get(void){
+ return U_WMRCORENONE_get("U_WMR61");
+}
+
+int U_WMR62_get(void){
+ return U_WMRCORENONE_get("U_WMR62");
+}
+
+int U_WMR63_get(void){
+ return U_WMRCORENONE_get("U_WMR63");
+}
+
+int U_WMR64_get(void){
+ return U_WMRCORENONE_get("U_WMR64");
+}
+
+int U_WMR65_get(void){
+ return U_WMRCORENONE_get("U_WMR65");
+}
+
+int U_WMR66_get(void){
+ return U_WMRCORENONE_get("U_WMR66");
+}
+
+int U_WMR67_get(void){
+ return U_WMRCORENONE_get("U_WMR67");
+}
+
+int U_WMR68_get(void){
+ return U_WMRCORENONE_get("U_WMR68");
+}
+
+int U_WMR69_get(void){
+ return U_WMRCORENONE_get("U_WMR69");
+}
+
+int U_WMR6A_get(void){
+ return U_WMRCORENONE_get("U_WMR6A");
+}
+
+int U_WMR6B_get(void){
+ return U_WMRCORENONE_get("U_WMR6B");
+}
+
+int U_WMR6C_get(void){
+ return U_WMRCORENONE_get("U_WMR6C");
+}
+
+int U_WMR6D_get(void){
+ return U_WMRCORENONE_get("U_WMR6D");
+}
+
+int U_WMR6E_get(void){
+ return U_WMRCORENONE_get("U_WMR6E");
+}
+
+int U_WMR6F_get(void){
+ return U_WMRCORENONE_get("U_WMR6F");
+}
+
+int U_WMR70_get(void){
+ return U_WMRCORENONE_get("U_WMR70");
+}
+
+int U_WMR71_get(void){
+ return U_WMRCORENONE_get("U_WMR71");
+}
+
+int U_WMR72_get(void){
+ return U_WMRCORENONE_get("U_WMR72");
+}
+
+int U_WMR73_get(void){
+ return U_WMRCORENONE_get("U_WMR73");
+}
+
+int U_WMR74_get(void){
+ return U_WMRCORENONE_get("U_WMR74");
+}
+
+int U_WMR75_get(void){
+ return U_WMRCORENONE_get("U_WMR75");
+}
+
+int U_WMR76_get(void){
+ return U_WMRCORENONE_get("U_WMR76");
+}
+
+int U_WMR77_get(void){
+ return U_WMRCORENONE_get("U_WMR77");
+}
+
+int U_WMR78_get(void){
+ return U_WMRCORENONE_get("U_WMR78");
+}
+
+int U_WMR79_get(void){
+ return U_WMRCORENONE_get("U_WMR79");
+}
+
+int U_WMR7A_get(void){
+ return U_WMRCORENONE_get("U_WMR7A");
+}
+
+int U_WMR7B_get(void){
+ return U_WMRCORENONE_get("U_WMR7B");
+}
+
+int U_WMR7C_get(void){
+ return U_WMRCORENONE_get("U_WMR7C");
+}
+
+int U_WMR7D_get(void){
+ return U_WMRCORENONE_get("U_WMR7D");
+}
+
+int U_WMR7E_get(void){
+ return U_WMRCORENONE_get("U_WMR7E");
+}
+
+int U_WMR7F_get(void){
+ return U_WMRCORENONE_get("U_WMR7F");
+}
+
+int U_WMR80_get(void){
+ return U_WMRCORENONE_get("U_WMR80");
+}
+
+int U_WMR81_get(void){
+ return U_WMRCORENONE_get("U_WMR81");
+}
+
+int U_WMR82_get(void){
+ return U_WMRCORENONE_get("U_WMR82");
+}
+
+int U_WMR83_get(void){
+ return U_WMRCORENONE_get("U_WMR83");
+}
+
+int U_WMR84_get(void){
+ return U_WMRCORENONE_get("U_WMR84");
+}
+
+int U_WMR85_get(void){
+ return U_WMRCORENONE_get("U_WMR85");
+}
+
+int U_WMR86_get(void){
+ return U_WMRCORENONE_get("U_WMR86");
+}
+
+int U_WMR87_get(void){
+ return U_WMRCORENONE_get("U_WMR87");
+}
+
+int U_WMR88_get(void){
+ return U_WMRCORENONE_get("U_WMR88");
+}
+
+int U_WMR89_get(void){
+ return U_WMRCORENONE_get("U_WMR89");
+}
+
+int U_WMR8A_get(void){
+ return U_WMRCORENONE_get("U_WMR8A");
+}
+
+int U_WMR8B_get(void){
+ return U_WMRCORENONE_get("U_WMR8B");
+}
+
+int U_WMR8C_get(void){
+ return U_WMRCORENONE_get("U_WMR8C");
+}
+
+int U_WMR8D_get(void){
+ return U_WMRCORENONE_get("U_WMR8D");
+}
+
+int U_WMR8E_get(void){
+ return U_WMRCORENONE_get("U_WMR8E");
+}
+
+int U_WMR8F_get(void){
+ return U_WMRCORENONE_get("U_WMR8F");
+}
+
+int U_WMR90_get(void){
+ return U_WMRCORENONE_get("U_WMR90");
+}
+
+int U_WMR91_get(void){
+ return U_WMRCORENONE_get("U_WMR91");
+}
+
+int U_WMR92_get(void){
+ return U_WMRCORENONE_get("U_WMR92");
+}
+
+int U_WMR93_get(void){
+ return U_WMRCORENONE_get("U_WMR93");
+}
+
+int U_WMR94_get(void){
+ return U_WMRCORENONE_get("U_WMR94");
+}
+
+int U_WMR95_get(void){
+ return U_WMRCORENONE_get("U_WMR95");
+}
+
+int U_WMR96_get(void){
+ return U_WMRCORENONE_get("U_WMR96");
+}
+
+int U_WMR97_get(void){
+ return U_WMRCORENONE_get("U_WMR97");
+}
+
+int U_WMR98_get(void){
+ return U_WMRCORENONE_get("U_WMR98");
+}
+
+int U_WMR99_get(void){
+ return U_WMRCORENONE_get("U_WMR99");
+}
+
+int U_WMR9A_get(void){
+ return U_WMRCORENONE_get("U_WMR9A");
+}
+
+int U_WMR9B_get(void){
+ return U_WMRCORENONE_get("U_WMR9B");
+}
+
+int U_WMR9C_get(void){
+ return U_WMRCORENONE_get("U_WMR9C");
+}
+
+int U_WMR9D_get(void){
+ return U_WMRCORENONE_get("U_WMR9D");
+}
+
+int U_WMR9E_get(void){
+ return U_WMRCORENONE_get("U_WMR9E");
+}
+
+int U_WMR9F_get(void){
+ return U_WMRCORENONE_get("U_WMR9F");
+}
+
+int U_WMRA0_get(void){
+ return U_WMRCORENONE_get("U_WMRA0");
+}
+
+int U_WMRA1_get(void){
+ return U_WMRCORENONE_get("U_WMRA1");
+}
+
+int U_WMRA2_get(void){
+ return U_WMRCORENONE_get("U_WMRA2");
+}
+
+int U_WMRA3_get(void){
+ return U_WMRCORENONE_get("U_WMRA3");
+}
+
+int U_WMRA4_get(void){
+ return U_WMRCORENONE_get("U_WMRA4");
+}
+
+int U_WMRA5_get(void){
+ return U_WMRCORENONE_get("U_WMRA5");
+}
+
+int U_WMRA6_get(void){
+ return U_WMRCORENONE_get("U_WMRA6");
+}
+
+int U_WMRA7_get(void){
+ return U_WMRCORENONE_get("U_WMRA7");
+}
+
+int U_WMRA8_get(void){
+ return U_WMRCORENONE_get("U_WMRA8");
+}
+
+int U_WMRA9_get(void){
+ return U_WMRCORENONE_get("U_WMRA9");
+}
+
+int U_WMRAA_get(void){
+ return U_WMRCORENONE_get("U_WMRAA");
+}
+
+int U_WMRAB_get(void){
+ return U_WMRCORENONE_get("U_WMRAB");
+}
+
+int U_WMRAC_get(void){
+ return U_WMRCORENONE_get("U_WMRAC");
+}
+
+int U_WMRAD_get(void){
+ return U_WMRCORENONE_get("U_WMRAD");
+}
+
+int U_WMRAE_get(void){
+ return U_WMRCORENONE_get("U_WMRAE");
+}
+
+int U_WMRAF_get(void){
+ return U_WMRCORENONE_get("U_WMRAF");
+}
+
+int U_WMRB0_get(void){
+ return U_WMRCORENONE_get("U_WMRB0");
+}
+
+int U_WMRB1_get(void){
+ return U_WMRCORENONE_get("U_WMRB1");
+}
+
+int U_WMRB2_get(void){
+ return U_WMRCORENONE_get("U_WMRB2");
+}
+
+int U_WMRB3_get(void){
+ return U_WMRCORENONE_get("U_WMRB3");
+}
+
+int U_WMRB4_get(void){
+ return U_WMRCORENONE_get("U_WMRB4");
+}
+
+int U_WMRB5_get(void){
+ return U_WMRCORENONE_get("U_WMRB5");
+}
+
+int U_WMRB6_get(void){
+ return U_WMRCORENONE_get("U_WMRB6");
+}
+
+int U_WMRB7_get(void){
+ return U_WMRCORENONE_get("U_WMRB7");
+}
+
+int U_WMRB8_get(void){
+ return U_WMRCORENONE_get("U_WMRB8");
+}
+
+int U_WMRB9_get(void){
+ return U_WMRCORENONE_get("U_WMRB9");
+}
+
+int U_WMRBA_get(void){
+ return U_WMRCORENONE_get("U_WMRBA");
+}
+
+int U_WMRBB_get(void){
+ return U_WMRCORENONE_get("U_WMRBB");
+}
+
+int U_WMRBC_get(void){
+ return U_WMRCORENONE_get("U_WMRBC");
+}
+
+int U_WMRBD_get(void){
+ return U_WMRCORENONE_get("U_WMRBD");
+}
+
+int U_WMRBE_get(void){
+ return U_WMRCORENONE_get("U_WMRBE");
+}
+
+int U_WMRBF_get(void){
+ return U_WMRCORENONE_get("U_WMRBF");
+}
+
+int U_WMRC0_get(void){
+ return U_WMRCORENONE_get("U_WMRC0");
+}
+
+int U_WMRC1_get(void){
+ return U_WMRCORENONE_get("U_WMRC1");
+}
+
+int U_WMRC2_get(void){
+ return U_WMRCORENONE_get("U_WMRC2");
+}
+
+int U_WMRC3_get(void){
+ return U_WMRCORENONE_get("U_WMRC3");
+}
+
+int U_WMRC4_get(void){
+ return U_WMRCORENONE_get("U_WMRC4");
+}
+
+int U_WMRC5_get(void){
+ return U_WMRCORENONE_get("U_WMRC5");
+}
+
+int U_WMRC6_get(void){
+ return U_WMRCORENONE_get("U_WMRC6");
+}
+
+int U_WMRC7_get(void){
+ return U_WMRCORENONE_get("U_WMRC7");
+}
+
+int U_WMRC8_get(void){
+ return U_WMRCORENONE_get("U_WMRC8");
+}
+
+int U_WMRC9_get(void){
+ return U_WMRCORENONE_get("U_WMRC9");
+}
+
+int U_WMRCA_get(void){
+ return U_WMRCORENONE_get("U_WMRCA");
+}
+
+int U_WMRCB_get(void){
+ return U_WMRCORENONE_get("U_WMRCB");
+}
+
+int U_WMRCC_get(void){
+ return U_WMRCORENONE_get("U_WMRCC");
+}
+
+int U_WMRCD_get(void){
+ return U_WMRCORENONE_get("U_WMRCD");
+}
+
+int U_WMRCE_get(void){
+ return U_WMRCORENONE_get("U_WMRCE");
+}
+
+int U_WMRCF_get(void){
+ return U_WMRCORENONE_get("U_WMRCF");
+}
+
+int U_WMRD0_get(void){
+ return U_WMRCORENONE_get("U_WMRD0");
+}
+
+int U_WMRD1_get(void){
+ return U_WMRCORENONE_get("U_WMRD1");
+}
+
+int U_WMRD2_get(void){
+ return U_WMRCORENONE_get("U_WMRD2");
+}
+
+int U_WMRD3_get(void){
+ return U_WMRCORENONE_get("U_WMRD3");
+}
+
+int U_WMRD4_get(void){
+ return U_WMRCORENONE_get("U_WMRD4");
+}
+
+int U_WMRD5_get(void){
+ return U_WMRCORENONE_get("U_WMRD5");
+}
+
+int U_WMRD6_get(void){
+ return U_WMRCORENONE_get("U_WMRD6");
+}
+
+int U_WMRD7_get(void){
+ return U_WMRCORENONE_get("U_WMRD7");
+}
+
+int U_WMRD8_get(void){
+ return U_WMRCORENONE_get("U_WMRD8");
+}
+
+int U_WMRD9_get(void){
+ return U_WMRCORENONE_get("U_WMRD9");
+}
+
+int U_WMRDA_get(void){
+ return U_WMRCORENONE_get("U_WMRDA");
+}
+
+int U_WMRDB_get(void){
+ return U_WMRCORENONE_get("U_WMRDB");
+}
+
+int U_WMRDC_get(void){
+ return U_WMRCORENONE_get("U_WMRDC");
+}
+
+int U_WMRDD_get(void){
+ return U_WMRCORENONE_get("U_WMRDD");
+}
+
+int U_WMRDE_get(void){
+ return U_WMRCORENONE_get("U_WMRDE");
+}
+
+int U_WMRDF_get(void){
+ return U_WMRCORENONE_get("U_WMRDF");
+}
+
+int U_WMRE0_get(void){
+ return U_WMRCORENONE_get("U_WMRE0");
+}
+
+int U_WMRE1_get(void){
+ return U_WMRCORENONE_get("U_WMRE1");
+}
+
+int U_WMRE2_get(void){
+ return U_WMRCORENONE_get("U_WMRE2");
+}
+
+int U_WMRE3_get(void){
+ return U_WMRCORENONE_get("U_WMRE3");
+}
+
+int U_WMRE4_get(void){
+ return U_WMRCORENONE_get("U_WMRE4");
+}
+
+int U_WMRE5_get(void){
+ return U_WMRCORENONE_get("U_WMRE5");
+}
+
+int U_WMRE6_get(void){
+ return U_WMRCORENONE_get("U_WMRE6");
+}
+
+int U_WMRE7_get(void){
+ return U_WMRCORENONE_get("U_WMRE7");
+}
+
+int U_WMRE8_get(void){
+ return U_WMRCORENONE_get("U_WMRE8");
+}
+
+int U_WMRE9_get(void){
+ return U_WMRCORENONE_get("U_WMRE9");
+}
+
+int U_WMREA_get(void){
+ return U_WMRCORENONE_get("U_WMREA");
+}
+
+int U_WMREB_get(void){
+ return U_WMRCORENONE_get("U_WMREB");
+}
+
+int U_WMREC_get(void){
+ return U_WMRCORENONE_get("U_WMREC");
+}
+
+int U_WMRED_get(void){
+ return U_WMRCORENONE_get("U_WMRED");
+}
+
+int U_WMREE_get(void){
+ return U_WMRCORENONE_get("U_WMREE");
+}
+
+int U_WMREF_get(void){
+ return U_WMRCORENONE_get("U_WMREF");
+}
+//! \endcond
+
+/**
+ \brief Get data from a U_WMRDELETEOBJECT record.
+ \return length of the U_WMRDELETEOBJECT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Object Index of object which is made active.
+*/
+int U_WMRDELETEOBJECT_get(
+ const char *contents,
+ uint16_t *Object
+ ){
+ return U_WMRCORE_1U16_get(contents, (U_SIZE_WMRDELETEOBJECT), Object);
+}
+
+//! \cond
+int U_WMRF1_get(void){
+ return U_WMRCORENONE_get("U_WMRF1");
+}
+
+int U_WMRF2_get(void){
+ return U_WMRCORENONE_get("U_WMRF2");
+}
+
+int U_WMRF3_get(void){
+ return U_WMRCORENONE_get("U_WMRF3");
+}
+
+int U_WMRF4_get(void){
+ return U_WMRCORENONE_get("U_WMRF4");
+}
+
+int U_WMRF5_get(void){
+ return U_WMRCORENONE_get("U_WMRF5");
+}
+
+int U_WMRF6_get(void){
+ return U_WMRCORENONE_get("U_WMRF6");
+}
+//! \endcond
+
+/**
+ \brief Retrieve values from a U_WMRCREATEPALETTE record
+ \return length of the U_WMRCREATEPALETTE record, or NULL on error
+ \param contents record to extract data from
+ \param Palette Create a Palette object.
+ \param PalEntries Array of Palette Entries
+*/
+int U_WMRCREATEPALETTE_get(
+ const char *contents,
+ U_PALETTE *Palette,
+ const char **PalEntries
+ ){
+ return U_WMRCORE_PALETTE_get(contents, (U_SIZE_WMRCREATEPALETTE), Palette, PalEntries);
+}
+
+//! \cond
+int U_WMRF8_get(void){
+ return U_WMRCORENONE_get("U_WMRF8");
+}
+//! \endcond
+
+/**
+ \brief Get data from a U_WMRCREATEPATTERNBRUSH record.
+ Warning - application support for U_WMRCREATEPATTERNBRUSH is spotty, better to use U_WMRDIBCREATEPATTERNBRUSH.
+ \return length of the U_WMRCREATEPATTERNBRUSH record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Bm16 truncated Bitmap16 structure from record, only tge first 14 bytes hold data.
+ \param pasize Number of bytes in Pattern
+ \param Pattern byte array pattern, described by Bm16, for brush
+*/
+int U_WMRCREATEPATTERNBRUSH_get(
+ const char *contents,
+ U_BITMAP16 *Bm16,
+ int *pasize,
+ const char **Pattern
+ ){
+ int off = U_SIZE_METARECORD;
+ /* size in next one is
+ 6 (core header) + 14 (truncated bitmap16) + 18 bytes reserved + 2 bytes (at least) for data */
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_METARECORD + 14 + 18 + 2));
+ if(!size)return(0);
+ memset(Bm16, 0, U_SIZE_BITMAP16);
+ /* BM16 is truncated in this record type to 14 bytes, last 4 bytes must be ignored, so they are not even copied */
+ memcpy(Bm16, contents + off, 10);
+ *pasize = (((Bm16->Width * Bm16->BitsPixel + 15) >> 4) << 1) * Bm16->Height;
+ off += 32; /* skip [14 bytes of truncated bitmap16 object and 18 bytes of reserved */
+ *Pattern = (contents + off);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRCREATEPENINDIRECT record.
+ \return length of the U_WMRCREATEPENINDIRECT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param pen pointer to a U_PEN object to fill.
+*/
+int U_WMRCREATEPENINDIRECT_get(
+ const char *contents,
+ U_PEN *pen
+ ){
+ int size = U_WMRCORE_RECSAFE_get(contents, (U_SIZE_WMRCREATEPENINDIRECT));
+ if(!size)return(0);
+ memcpy(pen, contents + offsetof(U_WMRCREATEPENINDIRECT, pen), U_SIZE_PEN);
+ return(size);
+}
+
+/**
+ \brief Get data from a U_WMRCREATEFONTINDIRECT record.
+ \return length of the U_WMRCREATEFONTINDIRECT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param font pointer to array of U_FONT structure in memory. Pointer may not be aligned properly for structure.
+*/
+int U_WMRCREATEFONTINDIRECT_get(
+ const char *contents,
+ const char **font
+ ){
+ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font);
+ if(size){
+ if(IS_MEM_UNSAFE(*font, U_SIZE_FONT_CORE, contents+size))return(0);
+ if(contents + size - *font > U_SIZE_FONT_CORE + 32)return(0); // font name must fit in a 32 bit field
+ }
+ return size;
+}
+
+/**
+ \brief Get data from a U_WMRCREATEBRUSHINDIRECT record.
+ \return length of the U_WMRCREATEBRUSHINDIRECT record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param brush pointer to U_WLOGBRUSH structure in memory. Pointer may not be aligned properly for structure.
+*/
+int U_WMRCREATEBRUSHINDIRECT_get(
+ const char *contents,
+ const char **brush
+ ){
+ // U_SIZE_WMRCREATEBRUSHINDIRECT is everything, no variable part, so the test below is sufficient
+ return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEBRUSHINDIRECT), NULL, NULL, brush);
+}
+
+/** in GDI and Wine, not in WMF manual.
+*/
+int U_WMRCREATEBITMAPINDIRECT_get(void){
+ return U_WMRCORENONE_get("U_WMRCREATEBITMAPINDIRECT");
+}
+
+/** in GDI and Wine, not in WMF manual.
+*/
+int U_WMRCREATEBITMAP_get(void){
+ return U_WMRCORENONE_get("U_WMRCREATEBITMAP");
+}
+
+/**
+ \brief Get data from a U_WMRCREATEREGION record.
+ \return length of the U_WMRCREATEREGION record in bytes, or 0 on error
+ \param contents record to extract data from
+ \param Region pointer to U_REGION structure in memory. Pointer may not be aligned properly for structure.
+
+ Caller must check at the returned Region does not extend outside of the record!
+*/
+int U_WMRCREATEREGION_get(
+ const char *contents,
+ const char **Region
+ ){
+ return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region);
+}
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uwmf.h b/src/3rdparty/libuemf/uwmf.h
new file mode 100644
index 000000000..529232ca9
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf.h
@@ -0,0 +1,2677 @@
+/**
+ @file uwmf.h
+
+ @brief Structures, definitions, and function prototypes for WMF files.
+
+ WMF file Record structure information has been derived from Mingw and Wine header files, and from
+ Microsoft's WMF Information pdf, release date July 5,2012, link from here:
+
+ http://msdn2.microsoft.com/en-us/library/cc250370.aspx
+
+ If the direct link fails the document may be found
+ by searching for: "[MS-WMF]: Windows Metafile Format"
+
+ *********************************** IMPORTANT!!! **********************************************
+ WMF is a 16 bit file type that has some 32 bit integers embedded in it. In
+ a few cases these 32 bit fields are not aligned in the structures defined in uwmf.h, but
+ in most cases they are. So when creating the individual WMF records the functions in
+ uwmf.c can usually use a regular assignment operation for the 32 bit fields. However, once the
+ records are part of a WMF file in memory there is no guaranty that any 32 bit type will be correctly
+ aligned. Similarly, many WMF structures contain embedded other structures which would "naturally"
+ be passed by pointer, but since their alignment may not be what malloc() would have created for that
+ type, the outcome of that operation is not defined by the C standard. (Per Eric Sosman, section
+ 6.3.2.3p7 of the standard.)
+
+ For this reason, the _print, _swap and any read operations must pass structures with unknown alignment
+ as a (char *), and pull out the data using memcpy() or some equivalent
+ that will not segfault when it tries to read a 32 bit value that is not aligned
+ on a 4 byte boundary. Failure to do so will result in nonportable code. You have been warned!
+
+ Problem areas:
+ The Size16_4 field of all WMF records may NOT be assumed to 4 byte aligned.
+ DIB's U_BITMAPINFOHEADER 32 bit fields may not be aligned.
+ *********************************** IMPORTANT!!! **********************************************
+
+*/
+
+/*
+File: uwmf.h
+Version: 0.0.13
+Date: 26-JAN-2016
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UWMF_
+#define _UWMF_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "uemf.h" /* many structures/defs in common, pull in the EMF ones as a basis */
+#include "uemf_utf.h"
+#include "uwmf_endian.h"
+
+
+/** HighWater Enumeration not in WMF manual
+ @{
+*/
+#define U_HIGHWATER_READ 0x00000000 //!< nondestructive read of highwater value
+#define U_HIGHWATER_CLEAR 0xFFFFFFFF //!< destructive read, value is reset to 0
+/** @} */
+
+
+
+
+// ***********************************************************************************
+// Value Enumerations and other predefined constants, alphabetical order by group
+
+/* RecordType Enumeration WMF manual 2.1.1.1 */
+/** WMF manual 2.1.1.1
+ \brief WMR Record types
+*/
+enum U_WMR_TYPES{
+ U_WMR_EOF, //!< 0x0000 U_WMREOF record
+ U_WMR_SETBKCOLOR, //!< 0x0201 U_WMRSETBKCOLOR record
+ U_WMR_SETBKMODE, //!< 0x0102 U_WMRSETBKMODE record
+ U_WMR_SETMAPMODE, //!< 0x0103 U_WMRSETMAPMODE record
+ U_WMR_SETROP2, //!< 0x0104 U_WMRSETROP2 record
+ U_WMR_SETRELABS, //!< 0x0105 U_WMRSETRELABS record
+ U_WMR_SETPOLYFILLMODE, //!< 0x0106 U_WMRSETPOLYFILLMODE record
+ U_WMR_SETSTRETCHBLTMODE, //!< 0x0107 U_WMRSETSTRETCHBLTMODE record
+ U_WMR_SETTEXTCHAREXTRA, //!< 0x0108 U_WMRSETTEXTCHAREXTRA record
+ U_WMR_SETTEXTCOLOR, //!< 0x0209 U_WMRSETTEXTCOLOR record
+ U_WMR_SETTEXTJUSTIFICATION, //!< 0x020A U_WMRSETTEXTJUSTIFICATION record
+ U_WMR_SETWINDOWORG, //!< 0x020B U_WMRSETWINDOWORG record
+ U_WMR_SETWINDOWEXT, //!< 0x020C U_WMRSETWINDOWEXT record
+ U_WMR_SETVIEWPORTORG, //!< 0x020D U_WMRSETVIEWPORTORG record
+ U_WMR_SETVIEWPORTEXT, //!< 0x020E U_WMRSETVIEWPORTEXT record
+ U_WMR_OFFSETWINDOWORG, //!< 0x020F U_WMROFFSETWINDOWORG record
+ U_WMR_SCALEWINDOWEXT, //!< 0x0410 U_WMRSCALEWINDOWEXT record
+ U_WMR_OFFSETVIEWPORTORG, //!< 0x0211 U_WMROFFSETVIEWPORTORG record
+ U_WMR_SCALEVIEWPORTEXT, //!< 0x0412 U_WMRSCALEVIEWPORTEXT record
+ U_WMR_LINETO, //!< 0x0213 U_WMRLINETO record
+ U_WMR_MOVETO, //!< 0x0214 U_WMRMOVETO record
+ U_WMR_EXCLUDECLIPRECT, //!< 0x0415 U_WMREXCLUDECLIPRECT record
+ U_WMR_INTERSECTCLIPRECT, //!< 0x0416 U_WMRINTERSECTCLIPRECT record
+ U_WMR_ARC, //!< 0x0817 U_WMRARC record
+ U_WMR_ELLIPSE, //!< 0x0418 U_WMRELLIPSE record
+ U_WMR_FLOODFILL, //!< 0x0419 U_WMRFLOODFILL record
+ U_WMR_PIE, //!< 0x081A U_WMRPIE record
+ U_WMR_RECTANGLE, //!< 0x041B U_WMRRECTANGLE record
+ U_WMR_ROUNDRECT, //!< 0x061C U_WMRROUNDRECT record
+ U_WMR_PATBLT, //!< 0x061D U_WMRPATBLT record
+ U_WMR_SAVEDC, //!< 0x001E U_WMRSAVEDC record
+ U_WMR_SETPIXEL, //!< 0x041F U_WMRSETPIXEL record
+ U_WMR_OFFSETCLIPRGN, //!< 0x0220 U_WMROFFSETCLIPRGN record
+ U_WMR_TEXTOUT, //!< 0x0521 U_WMRTEXTOUT record
+ U_WMR_BITBLT, //!< 0x0922 U_WMRBITBLT record
+ U_WMR_STRETCHBLT, //!< 0x0B23 U_WMRSTRETCHBLT record
+ U_WMR_POLYGON, //!< 0x0324 U_WMRPOLYGON record
+ U_WMR_POLYLINE, //!< 0x0325 U_WMRPOLYLINE record
+ U_WMR_ESCAPE, //!< 0x0626 U_WMRESCAPE record
+ U_WMR_RESTOREDC, //!< 0x0127 U_WMRRESTOREDC record
+ U_WMR_FILLREGION, //!< 0x0228 U_WMRFILLREGION record
+ U_WMR_FRAMEREGION, //!< 0x0429 U_WMRFRAMEREGION record
+ U_WMR_INVERTREGION, //!< 0x012A U_WMRINVERTREGION record
+ U_WMR_PAINTREGION, //!< 0x012B U_WMRPAINTREGION record
+ U_WMR_SELECTCLIPREGION, //!< 0x012C U_WMRSELECTCLIPREGION record
+ U_WMR_SELECTOBJECT, //!< 0x012D U_WMRSELECTOBJECT record
+ U_WMR_SETTEXTALIGN, //!< 0x012E U_WMRSETTEXTALIGN record
+ U_WMR_DRAWTEXT, //!< 0x062F U_WMRDRAWTEXT record
+ U_WMR_CHORD, //!< 0x0830 U_WMRCHORD record
+ U_WMR_SETMAPPERFLAGS, //!< 0x0231 U_WMRSETMAPPERFLAGS record
+ U_WMR_EXTTEXTOUT, //!< 0x0A32 U_WMREXTTEXTOUT record
+ U_WMR_SETDIBTODEV, //!< 0x0D33 U_WMRSETDIBTODEV record
+ U_WMR_SELECTPALETTE, //!< 0x0234 U_WMRSELECTPALETTE record
+ U_WMR_REALIZEPALETTE, //!< 0x0035 U_WMRREALIZEPALETTE record
+ U_WMR_ANIMATEPALETTE, //!< 0x0436 U_WMRANIMATEPALETTE record
+ U_WMR_SETPALENTRIES, //!< 0x0037 U_WMRSETPALENTRIES record
+ U_WMR_POLYPOLYGON, //!< 0x0538 U_WMRPOLYPOLYGON record
+ U_WMR_RESIZEPALETTE, //!< 0x0139 U_WMRRESIZEPALETTE record
+ U_WMR_3A, //!< 0x003A U_WMR3A record
+ U_WMR_3B, //!< 0x003B U_WMR3B record
+ U_WMR_3C, //!< 0x003C U_WMR3C record
+ U_WMR_3D, //!< 0x003D U_WMR3D record
+ U_WMR_3E, //!< 0x003E U_WMR3E record
+ U_WMR_3F, //!< 0x003F U_WMR3F record
+ U_WMR_DIBBITBLT, //!< 0x0940 U_WMRDIBBITBLT record
+ U_WMR_DIBSTRETCHBLT, //!< 0x0B41 U_WMRDIBSTRETCHBLT record
+ U_WMR_DIBCREATEPATTERNBRUSH, //!< 0x0142 U_WMRDIBCREATEPATTERNBRUSH record
+ U_WMR_STRETCHDIB, //!< 0x0F43 U_WMRSTRETCHDIB record
+ U_WMR_44, //!< 0x0044 U_WMR44 record
+ U_WMR_45, //!< 0x0045 U_WMR45 record
+ U_WMR_46, //!< 0x0046 U_WMR46 record
+ U_WMR_47, //!< 0x0047 U_WMR47 record
+ U_WMR_EXTFLOODFILL, //!< 0x0548 U_WMREXTFLOODFILL record
+ U_WMR_49, //!< 0x0049 U_WMR49 record
+ U_WMR_4A, //!< 0x004A U_WMR4A record
+ U_WMR_4B, //!< 0x004B U_WMR4B record
+ U_WMR_4C, //!< 0x014C U_WMR4C record
+ U_WMR_4D, //!< 0x014D U_WMR4D record
+ U_WMR_4E, //!< 0x004E U_WMR4E record
+ U_WMR_4F, //!< 0x004F U_WMR4F record
+ U_WMR_50, //!< 0x0050 U_WMR50 record
+ U_WMR_51, //!< 0x0051 U_WMR51 record
+ U_WMR_52, //!< 0x0052 U_WMR52 record
+ U_WMR_53, //!< 0x0053 U_WMR53 record
+ U_WMR_54, //!< 0x0054 U_WMR54 record
+ U_WMR_55, //!< 0x0055 U_WMR55 record
+ U_WMR_56, //!< 0x0056 U_WMR56 record
+ U_WMR_57, //!< 0x0057 U_WMR57 record
+ U_WMR_58, //!< 0x0058 U_WMR58 record
+ U_WMR_59, //!< 0x0059 U_WMR59 record
+ U_WMR_5A, //!< 0x005A U_WMR5A record
+ U_WMR_5B, //!< 0x005B U_WMR5B record
+ U_WMR_5C, //!< 0x005C U_WMR5C record
+ U_WMR_5D, //!< 0x005D U_WMR5D record
+ U_WMR_5E, //!< 0x005E U_WMR5E record
+ U_WMR_5F, //!< 0x005F U_WMR5F record
+ U_WMR_60, //!< 0x0060 U_WMR60 record
+ U_WMR_61, //!< 0x0061 U_WMR61 record
+ U_WMR_62, //!< 0x0062 U_WMR62 record
+ U_WMR_63, //!< 0x0063 U_WMR63 record
+ U_WMR_64, //!< 0x0064 U_WMR64 record
+ U_WMR_65, //!< 0x0065 U_WMR65 record
+ U_WMR_66, //!< 0x0066 U_WMR66 record
+ U_WMR_67, //!< 0x0067 U_WMR67 record
+ U_WMR_68, //!< 0x0068 U_WMR68 record
+ U_WMR_69, //!< 0x0069 U_WMR69 record
+ U_WMR_6A, //!< 0x006A U_WMR6A record
+ U_WMR_6B, //!< 0x006B U_WMR6B record
+ U_WMR_6C, //!< 0x006C U_WMR6C record
+ U_WMR_6D, //!< 0x006D U_WMR6D record
+ U_WMR_6E, //!< 0x006E U_WMR6E record
+ U_WMR_6F, //!< 0x006F U_WMR6F record
+ U_WMR_70, //!< 0x0070 U_WMR70 record
+ U_WMR_71, //!< 0x0071 U_WMR71 record
+ U_WMR_72, //!< 0x0072 U_WMR72 record
+ U_WMR_73, //!< 0x0073 U_WMR73 record
+ U_WMR_74, //!< 0x0074 U_WMR74 record
+ U_WMR_75, //!< 0x0075 U_WMR75 record
+ U_WMR_76, //!< 0x0076 U_WMR76 record
+ U_WMR_77, //!< 0x0077 U_WMR77 record
+ U_WMR_78, //!< 0x0078 U_WMR78 record
+ U_WMR_79, //!< 0x0079 U_WMR79 record
+ U_WMR_7A, //!< 0x007A U_WMR7A record
+ U_WMR_7B, //!< 0x007B U_WMR7B record
+ U_WMR_7C, //!< 0x007C U_WMR7C record
+ U_WMR_7D, //!< 0x007D U_WMR7D record
+ U_WMR_7E, //!< 0x007E U_WMR7E record
+ U_WMR_7F, //!< 0x007F U_WMR7F record
+ U_WMR_80, //!< 0x0080 U_WMR80 record
+ U_WMR_81, //!< 0x0081 U_WMR81 record
+ U_WMR_82, //!< 0x0082 U_WMR82 record
+ U_WMR_83, //!< 0x0083 U_WMR83 record
+ U_WMR_84, //!< 0x0084 U_WMR84 record
+ U_WMR_85, //!< 0x0085 U_WMR85 record
+ U_WMR_86, //!< 0x0086 U_WMR86 record
+ U_WMR_87, //!< 0x0087 U_WMR87 record
+ U_WMR_88, //!< 0x0088 U_WMR88 record
+ U_WMR_89, //!< 0x0089 U_WMR89 record
+ U_WMR_8A, //!< 0x008A U_WMR8A record
+ U_WMR_8B, //!< 0x008B U_WMR8B record
+ U_WMR_8C, //!< 0x008C U_WMR8C record
+ U_WMR_8D, //!< 0x008D U_WMR8D record
+ U_WMR_8E, //!< 0x008E U_WMR8E record
+ U_WMR_8F, //!< 0x008F U_WMR8F record
+ U_WMR_90, //!< 0x0090 U_WMR90 record
+ U_WMR_91, //!< 0x0091 U_WMR91 record
+ U_WMR_92, //!< 0x0092 U_WMR92 record
+ U_WMR_93, //!< 0x0093 U_WMR93 record
+ U_WMR_94, //!< 0x0094 U_WMR94 record
+ U_WMR_95, //!< 0x0095 U_WMR95 record
+ U_WMR_96, //!< 0x0096 U_WMR96 record
+ U_WMR_97, //!< 0x0097 U_WMR97 record
+ U_WMR_98, //!< 0x0098 U_WMR98 record
+ U_WMR_99, //!< 0x0099 U_WMR99 record
+ U_WMR_9A, //!< 0x009A U_WMR9A record
+ U_WMR_9B, //!< 0x009B U_WMR9B record
+ U_WMR_9C, //!< 0x009C U_WMR9C record
+ U_WMR_9D, //!< 0x009D U_WMR9D record
+ U_WMR_9E, //!< 0x009E U_WMR9E record
+ U_WMR_9F, //!< 0x009F U_WMR9F record
+ U_WMR_A0, //!< 0x00A0 U_WMRA0 record
+ U_WMR_A1, //!< 0x00A1 U_WMRA1 record
+ U_WMR_A2, //!< 0x00A2 U_WMRA2 record
+ U_WMR_A3, //!< 0x00A3 U_WMRA3 record
+ U_WMR_A4, //!< 0x00A4 U_WMRA4 record
+ U_WMR_A5, //!< 0x00A5 U_WMRA5 record
+ U_WMR_A6, //!< 0x00A6 U_WMRA6 record
+ U_WMR_A7, //!< 0x00A7 U_WMRA7 record
+ U_WMR_A8, //!< 0x00A8 U_WMRA8 record
+ U_WMR_A9, //!< 0x00A9 U_WMRA9 record
+ U_WMR_AA, //!< 0x00AA U_WMRAA record
+ U_WMR_AB, //!< 0x00AB U_WMRAB record
+ U_WMR_AC, //!< 0x00AC U_WMRAC record
+ U_WMR_AD, //!< 0x00AD U_WMRAD record
+ U_WMR_AE, //!< 0x00AE U_WMRAE record
+ U_WMR_AF, //!< 0x00AF U_WMRAF record
+ U_WMR_B0, //!< 0x00B0 U_WMRB0 record
+ U_WMR_B1, //!< 0x00B1 U_WMRB1 record
+ U_WMR_B2, //!< 0x00B2 U_WMRB2 record
+ U_WMR_B3, //!< 0x00B3 U_WMRB3 record
+ U_WMR_B4, //!< 0x00B4 U_WMRB4 record
+ U_WMR_B5, //!< 0x00B5 U_WMRB5 record
+ U_WMR_B6, //!< 0x00B6 U_WMRB6 record
+ U_WMR_B7, //!< 0x00B7 U_WMRB7 record
+ U_WMR_B8, //!< 0x00B8 U_WMRB8 record
+ U_WMR_B9, //!< 0x00B9 U_WMRB9 record
+ U_WMR_BA, //!< 0x00BA U_WMRBA record
+ U_WMR_BB, //!< 0x00BB U_WMRBB record
+ U_WMR_BC, //!< 0x00BC U_WMRBC record
+ U_WMR_BD, //!< 0x00BD U_WMRBD record
+ U_WMR_BE, //!< 0x00BE U_WMRBE record
+ U_WMR_BF, //!< 0x00BF U_WMRBF record
+ U_WMR_C0, //!< 0x00C0 U_WMRC0 record
+ U_WMR_C1, //!< 0x00C1 U_WMRC1 record
+ U_WMR_C2, //!< 0x00C2 U_WMRC2 record
+ U_WMR_C3, //!< 0x00C3 U_WMRC3 record
+ U_WMR_C4, //!< 0x00C4 U_WMRC4 record
+ U_WMR_C5, //!< 0x00C5 U_WMRC5 record
+ U_WMR_C6, //!< 0x00C6 U_WMRC6 record
+ U_WMR_C7, //!< 0x00C7 U_WMRC7 record
+ U_WMR_C8, //!< 0x00C8 U_WMRC8 record
+ U_WMR_C9, //!< 0x00C9 U_WMRC9 record
+ U_WMR_CA, //!< 0x00CA U_WMRCA record
+ U_WMR_CB, //!< 0x00CB U_WMRCB record
+ U_WMR_CC, //!< 0x00CC U_WMRCC record
+ U_WMR_CD, //!< 0x00CD U_WMRCD record
+ U_WMR_CE, //!< 0x00CE U_WMRCE record
+ U_WMR_CF, //!< 0x00CF U_WMRCF record
+ U_WMR_D0, //!< 0x00D0 U_WMRD0 record
+ U_WMR_D1, //!< 0x00D1 U_WMRD1 record
+ U_WMR_D2, //!< 0x00D2 U_WMRD2 record
+ U_WMR_D3, //!< 0x00D3 U_WMRD3 record
+ U_WMR_D4, //!< 0x00D4 U_WMRD4 record
+ U_WMR_D5, //!< 0x00D5 U_WMRD5 record
+ U_WMR_D6, //!< 0x00D6 U_WMRD6 record
+ U_WMR_D7, //!< 0x00D7 U_WMRD7 record
+ U_WMR_D8, //!< 0x00D8 U_WMRD8 record
+ U_WMR_D9, //!< 0x00D9 U_WMRD9 record
+ U_WMR_DA, //!< 0x00DA U_WMRDA record
+ U_WMR_DB, //!< 0x00DB U_WMRDB record
+ U_WMR_DC, //!< 0x00DC U_WMRDC record
+ U_WMR_DD, //!< 0x00DD U_WMRDD record
+ U_WMR_DE, //!< 0x00DE U_WMRDE record
+ U_WMR_DF, //!< 0x00DF U_WMRDF record
+ U_WMR_E0, //!< 0x00E0 U_WMRE0 record
+ U_WMR_E1, //!< 0x00E1 U_WMRE1 record
+ U_WMR_E2, //!< 0x00E2 U_WMRE2 record
+ U_WMR_E3, //!< 0x00E3 U_WMRE3 record
+ U_WMR_E4, //!< 0x00E4 U_WMRE4 record
+ U_WMR_E5, //!< 0x00E5 U_WMRE5 record
+ U_WMR_E6, //!< 0x00E6 U_WMRE6 record
+ U_WMR_E7, //!< 0x00E7 U_WMRE7 record
+ U_WMR_E8, //!< 0x00E8 U_WMRE8 record
+ U_WMR_E9, //!< 0x00E9 U_WMRE9 record
+ U_WMR_EA, //!< 0x00EA U_WMREA record
+ U_WMR_EB, //!< 0x00EB U_WMREB record
+ U_WMR_EC, //!< 0x00EC U_WMREC record
+ U_WMR_ED, //!< 0x00ED U_WMRED record
+ U_WMR_EE, //!< 0x00EE U_WMREE record
+ U_WMR_EF, //!< 0x00EF U_WMREF record
+ U_WMR_DELETEOBJECT, //!< 0x01F0 U_WMRDELETEOBJECT record
+ U_WMR_F1, //!< 0x00F1 U_WMRF1 record
+ U_WMR_F2, //!< 0x00F2 U_WMRF2 record
+ U_WMR_F3, //!< 0x00F3 U_WMRF3 record
+ U_WMR_F4, //!< 0x00F4 U_WMRF4 record
+ U_WMR_F5, //!< 0x00F5 U_WMRF5 record
+ U_WMR_F6, //!< 0x00F6 U_WMRF6 record
+ U_WMR_CREATEPALETTE, //!< 0x00F7 U_WMRCREATEPALETTE record
+ U_WMR_F8 , //!< 0x00F8 U_WMRF8 record
+ U_WMR_CREATEPATTERNBRUSH, //!< 0x01F9 U_WMRCREATEPATTERNBRUSH record
+ U_WMR_CREATEPENINDIRECT, //!< 0x02FA U_WMRCREATEPENINDIRECT record
+ U_WMR_CREATEFONTINDIRECT, //!< 0x02FB U_WMRCREATEFONTINDIRECT record
+ U_WMR_CREATEBRUSHINDIRECT, //!< 0x02FC U_WMRCREATEBRUSHINDIRECT record
+ U_WMR_CREATEBITMAPINDIRECT, //!< 0x02FD U_WMRCREATEBITMAPINDIRECT record
+ U_WMR_CREATEBITMAP, //!< 0x06FE U_WMRCREATEBITMAP record
+ U_WMR_CREATEREGION, //!< 0x06FF U_WMRCREATEREGION record
+};
+#define U_WMR_MIN 0 //!< Minimum U_WMR_ value.
+#define U_WMR_MAX 255 //!< Maximum U_WMR_ value.
+#define U_WMR_MASK 0xFF //!< Mask for enumerator (lower) byte
+#define U_WMR_INVALID 0xFFFFFFFF //!< Indicates "Not a valid U_WMR_* value"
+
+
+/** BinaryRasterOperation Enumeration WMF manual 2.1.1.2
+
+ Same as U_EMF_EMRSETROP2 in uemf.h
+*/
+
+/** BitCount Enumeration WMF manual 2.1.1.3
+ \defgroup U_WMF_AltBitCount_Qualifiers WMF Alternate names for the values under EMF Bitcount Enumeration in uemf.h
+ @{
+*/
+#define BI_BITCOUNT_0 U_BCBM_EXPLICIT //!< Derived from JPG or PNG compressed image or ?
+#define BI_BITCOUNT_1 U_BCBM_MONOCHROME //!< 2 colors. bmiColors array has two entries
+#define BI_BITCOUNT_2 U_BCBM_COLOR4 //!< 2^4 colors. bmiColors array has 16 entries
+#define BI_BITCOUNT_3 U_BCBM_COLOR8 //!< 2^8 colors. bmiColors array has 256 entries
+#define BI_BITCOUNT_4 U_BCBM_COLOR16 //!< 2^16 colors. bmiColors is not used. Pixels are 5 bits B,G,R with 1 unused bit
+#define BI_BITCOUNT_5 U_BCBM_COLOR24 //!< 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
+#define BI_BITCOUNT_6 U_BCBM_COLOR32 //!< 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
+/** @} */
+
+/* BrushStyle Enumeration WMF manual 2.1.1.4
+ Same as "EMF LB_Style Enumeration" in uemf.h
+*/
+
+/* CharacterSet Enumeration WMF manual 2.1.1.5
+ Same as "EMF LF_CharSet Enumeration" in uemf.h
+*/
+
+/** ColorUsage Enumeration WMF manual 2.1.1.6
+ For cUsage fields in various DIB related records.
+ \defgroup U_WMF_Extra_iUsageSrc_Qualifiers WMF Extra DIBColors Enumeration
+ WMF is the same as "EMF DIBColors Enumeration" in uemf.h, except it also supports
+ this one extra value.
+ @{
+*/
+#define U_DIB_PAL_INDICES 2 //!< No color table, pixels are logical palette indices.
+/** @} */
+
+/** Compression Enumeration WMF manual 2.1.1.7
+ Same as "EMF BI_Compression Enumeration" in uemf.h with these additions
+ \defgroup U_WMF_EXTRA_BITMAPINFOHEADER_biCompression_Qualifiers WMF Extra BI_Compression Enumerations, none are implemented
+ @{
+*/
+#define U_BI_CMYK 0x000B //!< CMYK uncompressed
+#define U_BI_CMYKRLE8 0x000C //!< CMYK RLE8 compression
+#define U_BI_CMYKRLE4 = 0x000D //!< CMYK RLE4 compression
+/** @} */
+
+/* FamilyFont Enumeration WMF manual 2.1.1.8
+ Only used in a PitchAndFamily object, defined there
+*/
+
+/* FloodFill Enumeration WMF manual 2.1.1.9
+ Same as "EMF FloodFill Enumeration" in uemf.h
+*/
+
+/* FontQuality Enumeration WMF manual 2.1.1.10
+ Same as "EMF LF_Quality Enumeration" in uemf.h
+*/
+
+/* GamutMappingIntent Enumeration WMF manual 2.1.1.11
+ Same as "EMF LCS_Intent Enumeration" in uemf.h
+*/
+
+/* HatchStyle Enumeration WMF manual 2.1.1.12
+ Same as "EMF HatchStyle Enumeration" in uemf.h
+*/
+
+/* Layout Enumeration WMF manual 2.1.1.13
+ Same as "EMF Mirroring Enumeration" in uemf.h
+*/
+
+/** LogicalColorSpace Enumeration WMF manual 2.1.1.14
+ Not used presently, applies in BitmapV4Header
+ @{
+*/
+/* U_LCS_CALIBRATED_RGB is defined in uemf.h under LCS_CSType Enumeration, WMF manual also defines it, but do not replicate define.
+#define U_LCS_CALIBRATED_RGB 0x00000000 //!< calibrated RGB
+*/
+#define U_LCS_sRGB 0x73524742 //!< ASCII for "sRGB"
+#define U_LCS_WINDOWS_COLOR_SPACE 0x57696E20 //!< ASCII for "Win "
+/** @} */
+
+/* LogicalColorSpaceV5 Enumeration WMF manual 2.1.1.15
+ Same as "EMF Profile Enumeration" in uemf.h
+*/
+
+/* MapMode Enumeration WMF manual 2.1.1.16
+ Same as "EMF MapMode Enumeration" in uemf.h
+*/
+
+/** MetaFilesEscape Enumeration WMF manual 2.1.1.17
+ \defgroup U_WMF_MFEscape_Qualifiers WMF Metafile Escape record types
+ For U_WMRESCAPE eFunc field
+ @{
+*/
+#define U_MFE_NEWFRAME 0x0001 //!< NEWFRAME escape type
+#define U_MFE_ABORTDOC 0x0002 //!< ABORTDOC escape type
+#define U_MFE_NEXTBAND 0x0003 //!< NEXTBAND escape type
+#define U_MFE_SETCOLORTABLE 0x0004 //!< SETCOLORTABLE escape type
+#define U_MFE_GETCOLORTABLE 0x0005 //!< GETCOLORTABLE escape type
+#define U_MFE_FLUSHOUT 0x0006 //!< FLUSHOUT escape type
+#define U_MFE_DRAFTMODE 0x0007 //!< DRAFTMODE escape type
+#define U_MFE_QUERYESCSUPPORT 0x0008 //!< QUERYESCSUPPORT escape type
+#define U_MFE_SETABORTPROC 0x0009 //!< SETABORTPROC escape type
+#define U_MFE_STARTDOC 0x000A //!< STARTDOC escape type
+#define U_MFE_ENDDOC 0x000B //!< ENDDOC escape type
+#define U_MFE_GETPHYSPAGESIZE 0x000C //!< GETPHYSPAGESIZE escape type
+#define U_MFE_GETPRINTINGOFFSET 0x000D //!< GETPRINTINGOFFSET escape type
+#define U_MFE_GETSCALINGFACTOR 0x000E //!< GETSCALINGFACTOR escape type
+#define U_MFE_META_ESCAPE_ENHANCED_METAFILE 0x000F //!< META_ESCAPE_ENHANCED_METAFILE escape type
+#define U_MFE_SETPENWIDTH 0x0010 //!< SETPENWIDTH escape type
+#define U_MFE_SETCOPYCOUNT 0x0011 //!< SETCOPYCOUNT escape type
+#define U_MFE_SETPAPERSOURCE 0x0012 //!< SETPAPERSOURCE escape type
+#define U_MFE_PASSTHROUGH 0x0013 //!< PASSTHROUGH escape type
+#define U_MFE_GETTECHNOLOGY 0x0014 //!< GETTECHNOLOGY escape type
+#define U_MFE_SETLINECAP 0x0015 //!< SETLINECAP escape type
+#define U_MFE_SETLINEJOIN 0x0016 //!< SETLINEJOIN escape type
+#define U_MFE_SETMITERLIMIT 0x0017 //!< SETMITERLIMIT escape type
+#define U_MFE_BANDINFO 0x0018 //!< BANDINFO escape type
+#define U_MFE_DRAWPATTERNRECT 0x0019 //!< DRAWPATTERNRECT escape type
+#define U_MFE_GETVECTORPENSIZE 0x001A //!< GETVECTORPENSIZE escape type
+#define U_MFE_GETVECTORBRUSHSIZE 0x001B //!< GETVECTORBRUSHSIZE escape type
+#define U_MFE_ENABLEDUPLEX 0x001C //!< ENABLEDUPLEX escape type
+#define U_MFE_GETSETPAPERBINS 0x001D //!< GETSETPAPERBINS escape type
+#define U_MFE_GETSETPRINTORIENT 0x001E //!< GETSETPRINTORIENT escape type
+#define U_MFE_ENUMPAPERBINS 0x001F //!< ENUMPAPERBINS escape type
+#define U_MFE_SETDIBSCALING 0x0020 //!< SETDIBSCALING escape type
+#define U_MFE_EPSPRINTING 0x0021 //!< EPSPRINTING escape type
+#define U_MFE_ENUMPAPERMETRICS 0x0022 //!< ENUMPAPERMETRICS escape type
+#define U_MFE_GETSETPAPERMETRICS 0x0023 //!< GETSETPAPERMETRICS escape type
+#define U_MFE_POSTSCRIPT_DATA 0x0025 //!< POSTSCRIPT_DATA escape type
+#define U_MFE_POSTSCRIPT_IGNORE 0x0026 //!< POSTSCRIPT_IGNORE escape type
+#define U_MFE_GETDEVICEUNITS 0x002A //!< GETDEVICEUNITS escape type
+#define U_MFE_GETEXTENDEDTEXTMETRICS 0x0100 //!< GETEXTENDEDTEXTMETRICS escape type
+#define U_MFE_GETPAIRKERNTABLE 0x0102 //!< GETPAIRKERNTABLE escape type
+#define U_MFE_EXTTEXTOUT 0x0200 //!< EXTTEXTOUT escape type
+#define U_MFE_GETFACENAME 0x0201 //!< GETFACENAME escape type
+#define U_MFE_DOWNLOADFACE 0x0202 //!< DOWNLOADFACE escape type
+#define U_MFE_METAFILE_DRIVER 0x0801 //!< METAFILE_DRIVER escape type
+#define U_MFE_QUERYDIBSUPPORT 0x0C01 //!< QUERYDIBSUPPORT escape type
+#define U_MFE_BEGIN_PATH 0x1000 //!< BEGIN_PATH escape type
+#define U_MFE_CLIP_TO_PATH 0x1001 //!< CLIP_TO_PATH escape type
+#define U_MFE_END_PATH 0x1002 //!< END_PATH escape type
+#define U_MFE_OPEN_CHANNEL 0x100E //!< OPEN_CHANNEL escape type
+#define U_MFE_DOWNLOADHEADER 0x100F //!< DOWNLOADHEADER escape type
+#define U_MFE_CLOSE_CHANNEL 0x1010 //!< CLOSE_CHANNEL escape type
+#define U_MFE_POSTSCRIPT_PASSTHROUGH 0x1013 //!< POSTSCRIPT_PASSTHROUGH escape type
+#define U_MFE_ENCAPSULATED_POSTSCRIPT 0x1014 //!< ENCAPSULATED_POSTSCRIPT escape type
+#define U_MFE_POSTSCRIPT_IDENTIFY 0x1015 //!< POSTSCRIPT_IDENTIFY escape type
+#define U_MFE_POSTSCRIPT_INJECTION 0x1016 //!< POSTSCRIPT_INJECTION escape type
+#define U_MFE_CHECKJPEGFORMAT 0x1017 //!< CHECKJPEGFORMAT escape type
+#define U_MFE_CHECKPNGFORMAT 0x1018 //!< CHECKPNGFORMAT escape type
+#define U_MFE_GET_PS_FEATURESETTING 0x1019 //!< GET_PS_FEATURESETTING escape type
+#define U_MFE_MXDC_ESCAPE 0x101A //!< MXDC_ESCAPE escape type
+#define U_MFE_SPCLPASSTHROUGH2 0x11D8 //!< SPCLPASSTHROUGH2 escape type
+/** @} */
+
+/** MetafileType Enumeration WMF manual 2.1.1.18
+ @{
+*/
+#define U_MEMORYMETAFILE 0x0001 //!< memory metafile (never used by libUWMF)
+#define U_DISKMETAFILE 0x0002 //!< disk metafile (always used by libUWMF)
+/** @} */
+
+/** MetafileVersion Enumeration WMF manual 2.1.1.19
+ @{
+*/
+
+#define U_METAVERSION100 0x0100 //!< DIBs not allowed
+#define U_METAVERSION300 0x0300 //!< DIBs allowed
+/** @} */
+
+/* MixMode Enumeration WMF manual 2.1.1.20
+ Same as "EMF BackgroundMode Enumeration" in uemf.h
+*/
+
+/* OutPrecision Enumeration WMF manual 2.1.1.21
+ Same as "EMF LF_OutPrecision Enumeration" in uemf.h
+*/
+
+/** PaletteEntryFlag Enumeration WMF manual 2.1.1.22
+ @{
+*/
+#define U_PC_RESERVED 0x01 //!< used for animation
+#define U_PC_EXPLICIT 0x02 //!< low order word is palette index
+#define U_PC_NOCOLLAPSE 0x04 //!< store as new color in palette, do not match to existing color
+/** @} */
+
+/** PenStyle Enumeration WMF manual 2.1.1.23
+ Same as "EMF PenStyle Enumeration" in uemf.h,
+ EXCEPT no values >0xFFFF are used, in particular there is no U_PS_GEOMETRIC (ie, all are U_PS_COSMETIC).
+ Apparently because there is no U_PS_GEOMETRIC, U_PS_JOIN* and U_PS_ENDCAP* are also ignored by XP SP3 Preview
+ (which defaults to a rounded cap) and PowerPoint 2003 (which defaults to square cap). The behavior
+ was the same when escape records for JOIN and ENDCAP are used. Bottom line, WMF line formatting seems
+ to be very hit and miss from application to application.
+*/
+
+/* PitchFont Enumeration WMF manual 2.1.1.24
+ These are only used in PitchAndFamily object, defined there.
+*/
+
+/* PolyFillMode Enumeration WMF manual 2.1.1.25
+ These are the first two emtries in "EMF PolygonFillMode Enumeration" in uemf.h
+
+*/
+
+/** PostScriptCap Enumeration WMF manual 2.1.1.26
+ These are used in Escape Cap
+ @{
+*/
+#define U_WPS_CAP_NOTSET -2
+#define U_WPS_CAP_FLAT 0
+#define U_WPS_CAP_ROUND 1
+#define U_WPS_CAP_SQUARE 2
+/** @} */
+
+/* PostScriptClipping Enumeration WMF manual 2.1.1.27
+ PostFeatureSetting Enumeration WMF manual 2.1.1.28
+
+ These are used by postscript drivers, not supported by libUWEMF.
+*/
+
+/** PostScrioptJoin Enumeration WMF manual 2.1.1.29
+ These are used in Escape Cap
+ @{
+*/
+#define U_WPS_JOIN_NOTSET -2
+#define U_WPS_JOIN_MITER 0
+#define U_WPS_JOIN_ROUND 1
+#define U_WPS_JOIN_BEVEL 2
+/** @} */
+
+/* StretchMode Enumeration WMF manual 2.1.1.30
+ Same as "EMF StretchMode Enumeration" in uemf.h
+
+*/
+
+/* TernaryRasterOperation Enumeration WMF manual 2.1.1.31
+ Same as "EMF Ternary Raster Operation Enumeration" in uemf.h
+ Only partially supported in libUWMF.h
+*/
+
+/* ClipPrecision Flags WMF manual 2.1.2.1
+ Same as "EMF LF_ClipPrecision Enumeration" in uemf.h
+*/
+
+/* ExtTextOutOptions Flags WMF manual 2.1.2.2
+ These are a subset of "EMF ExtTextOutOptions Enumeration" in uemf.h
+
+ Not defined for WMF: U_ETO_NONE, U_ETO_GRAYED, U_ETO_NORECT,
+ U_ETO_SMALL_CHARS,U_ETO_IGNORELANGUAGE,U_ETO_REVERSE_INDEX_MAP
+
+ Defined for WMF: U_ETO_OPAQUE, U_ETO_CLIPPED, U_ETO_GLYPH_INDEX,
+ U_ETO_RTLREADING,_ETO_NUMERICSLOCAL,U_ETO_NUMERICSLATIN,
+ U_ETO_PDY
+*/
+
+/* TextAlignment Enumeration WMF manual 2.1.2.3
+ VertialTextAlignment Enumeration WMF manual 2.1.2.4
+ These are both in "EMF TextAlignment Enumeration" in uemf.h
+*/
+
+
+
+// ***************************************************************************
+// Miscellaneous Values
+/* TextAlignmentMode Flags WMF manual 2.1.2.3
+ VerticalTextAlignmentMode Flags WMF manual 2.1.2.4
+ Same as "EMF TextAlignment Enumeration" in uemf.h
+*/
+
+/** \defgroup U_WMF_MinimumRecord_sizes WMF Size in bytes of core record types.
+
+ The size of the object/record is USUALLY not the same
+ as the sizeof() of the corresponding struct, so in general it is unsafe to use sizeof() with this code.
+
+ Always use the U_SIZE_x instead!!!!
+
+ Note that some records may actually be much, much longer than their minimum size as they include strings,
+ bitmaps, and such.
+
+ Documentation for each value is:
+ + = same as struct size
+ or
+ X = different from struct size
+ followed by
+ Number (sizeof(struct) == size of the struct in bytes.)
+
+ @{
+*/
+#define U_SIZE_PAIRF 8 /**< + 8 this might be different on 64 bit platform */
+#define U_SIZE_COLORREF 4 /**< + 4 */
+#define U_SIZE_BRUSH 8 /**< + 8 */
+#define U_SIZE_FONT 19 /**< X 20 */
+#define U_SIZE_FONT_CORE 18 /**< X 20 Like U_FONT, but minus the FaceName part */
+#define U_SIZE_PLTNTRY 4 /**< + 4 */
+#define U_SIZE_PALETTE 8 /**< + 8 */
+#define U_SIZE_PEN 10 /**< + 10 */
+#define U_SIZE_POINT16 4 /**< + 4 */
+#define U_SIZE_RECT16 8 /**< + 8 */
+#define U_SIZE_REGION 20 /**< X 22 20 is minums the variable part */
+#define U_SIZE_BITMAP16 10 /**< + 10 */
+#define U_SIZE_BITMAPCOREHEADER 12 /**< + 12 */
+// also defined in uemf.h, avoid redefining. Same value in both places, of course.
+// # define U_SIZE_BITMAPINFOHEADER 40 /**< + 40 */
+#define U_SIZE_BITMAPV4HEADER 108 /**< ? 108 not tested */
+#define U_SIZE_BITMAPV5HEADER 124 /**< ? 124 not tested */
+#define U_SIZE_WLOGBRUSH 8 /**< + 8 */
+#define U_SIZE_POLYPOLYGON 4 /**< + 4 */
+#define U_SIZE_SCAN 8 /**< + 8 */
+#define U_SIZE_METARECORD 6 /**< X 8 */
+#define U_SIZE_WMRPLACEABLE 22 /**< X 24 */
+#define U_SIZE_WMRHEADER 18 /**< X 20 */
+#define U_SIZE_WMREOF 6 /**< X 8 */
+#define U_SIZE_WMRSETRELABS 6 /**< X 8 */
+#define U_SIZE_WMRSAVEDC 6 /**< X 8 */
+#define U_SIZE_WMRRESTOREDC 8 /**< * 8 */
+#define U_SIZE_WMRREALIZEPALETTE 6 /**< X 8 */
+#define U_SIZE_WMRSETBKCOLOR 10 /**< X 12 */
+#define U_SIZE_WMRSETTEXTCOLOR 10 /**< X 12 */
+#define U_SIZE_WMRSETBKMODE 8 /**< X 12 last 2 bytes are optional */
+#define U_SIZE_WMRSETROP2 8 /**< X 12 last 2 bytes are optional */
+#define U_SIZE_WMRSETPOLYFILLMODE 8 /**< X 12 last 2 bytes are optional */
+#define U_SIZE_WMRSETSTRETCHBLTMODE 8 /**< X 12 last 2 bytes are optional */
+#define U_SIZE_WMRSETTEXTALIGN 8 /**< X 12 last 2 bytes are optional */
+#define U_SIZE_WMRSETMAPMODE 8 /**< + 8 */
+#define U_SIZE_WMRSETTEXTCHAREXTRA 8 /**< + 8 */
+#define U_SIZE_WMRSETTEXTJUSTIFICATION 10 /**< X 12 */
+#define U_SIZE_WMRSETWINDOWORG 10 /**< X 12 */
+#define U_SIZE_WMRSETWINDOWEXT 10 /**< X 12 */
+#define U_SIZE_WMRSETVIEWPORTORG 10 /**< X 12 */
+#define U_SIZE_WMRSETVIEWPORTEXT 10 /**< X 12 */
+#define U_SIZE_WMROFFSETWINDOWORG 10 /**< X 12 */
+#define U_SIZE_WMROFFSETVIEWPORTORG 10 /**< X 12 */
+#define U_SIZE_WMRLINETO 10 /**< X 12 */
+#define U_SIZE_WMRMOVETO 10 /**< X 12 */
+#define U_SIZE_WMROFFSETCLIPRGN 10 /**< X 12 */
+#define U_SIZE_WMRSCALEWINDOWEXT 14 /**< X 16 */
+#define U_SIZE_WMRSCALEVIEWPORTEXT 14 /**< X 16 */
+#define U_SIZE_WMREXCLUDECLIPRECT 14 /**< X 16 */
+#define U_SIZE_WMRINTERSECTCLIPRECT 14 /**< X 16 */
+#define U_SIZE_WMRARC 22 /**< X 24 */
+#define U_SIZE_WMRELLIPSE 14 /**< X 16 */
+#define U_SIZE_WMRRECTANGLE 14 /**< X 16 */
+#define U_SIZE_WMRFLOODFILL 16 /**< + 16 */
+#define U_SIZE_WMREXTFLOODFILL 16 /**< + 16 */
+#define U_SIZE_WMRSETPIXEL 14 /**< X 16 */
+#define U_SIZE_WMRPIE 22 /**< X 24 */
+#define U_SIZE_WMRCHORD 22 /**< X 24 */
+#define U_SIZE_WMRROUNDRECT 18 /**< X 20 */
+#define U_SIZE_WMRPATBLT 18 /**< X 20 */
+#define U_SIZE_WMRTEXTOUT 8 /**< X 12 (not including String,y,x) */
+#define U_SIZE_WMRBITBLT_NOPX 24 /**< + 24 */
+#define U_SIZE_WMRBITBLT_PX 22 /**< X 32 */
+#define U_SIZE_WMRSTRETCHBLT_NOPX 28 /**< + 28 */
+#define U_SIZE_WMRSTRETCHBLT_PX 26 /**< X 36 */
+#define U_SIZE_WMRPOLYGON 10 /**< X 12 */
+#define U_SIZE_WMRPOLYLINE 10 /**< X 12 */
+#define U_SIZE_WMRESCAPE 10 /**< X 12 Data field could be completely absent */
+#define U_SIZE_WMRFILLREGION 10 /**< X 12 */
+#define U_SIZE_WMRFRAMEREGION 14 /**< X 16 */
+#define U_SIZE_WMRINVERTREGION 8 /**< + 8 */
+#define U_SIZE_WMRPAINTREGION 8 /**< + 8 */
+#define U_SIZE_WMRSELECTCLIPREGION 8 /**< + 8 */
+#define U_SIZE_WMRSELECTOBJECT 8 /**< + 8 */
+#define U_SIZE_WMRSELECTPALETTE 8 /**< + 8 */
+#define U_SIZE_WMRRESIZEPALETTE 8 /**< + 8 */
+#define U_SIZE_WMRDELETEOBJECT 8 /**< + 8 */
+#define U_SIZE_WMRDRAWTEXT 6 /**< X 8 */
+#define U_SIZE_WMRCREATEBITMAPINDIRECT 6 /**< X 8 */
+#define U_SIZE_WMRCREATEBITMAP 6 /**< X 8 */
+#define U_SIZE_WMRSETMAPPERFLAGS 10 /**< X 12 */
+#define U_SIZE_WMREXTTEXTOUT 14 /**< X 16 */
+#define U_SIZE_WMRSETDIBTODEV 22 /**< X 28 */
+#define U_SIZE_WMRANIMATEPALETTE 14 /**< X 16 */
+#define U_SIZE_WMRSETPALENTRIES 14 /**< X 16 */
+#define U_SIZE_WMRCREATEPALETTE 14 /**< X 16 */
+#define U_SIZE_WMRPOLYPOLYGON 10 /**< X 12 */
+#define U_SIZE_WMRDIBBITBLT_NOPX 24 /**< + 24 */
+#define U_SIZE_WMRDIBBITBLT_PX 22 /**< X 24 */
+#define U_SIZE_WMRDIBSTRETCHBLT_NOPX 28 /**< + 28 */
+#define U_SIZE_WMRDIBSTRETCHBLT_PX 26 /**< X 28 */
+#define U_SIZE_WMRDIBCREATEPATTERNBRUSH 10 /**< X 12 */
+#define U_SIZE_WMRSTRETCHDIB 28 /**< X 32 */
+#define U_SIZE_WMRCREATEPATTERNBRUSH 6 /**< X 8 */
+#define U_SIZE_WMRCREATEPENINDIRECT 16 /**< + 16 */
+#define U_SIZE_WMRCREATEFONTINDIRECT 26 /**< X 28 */
+#define U_SIZE_WMRCREATEBRUSHINDIRECT 14 /**< X 16 */
+#define U_SIZE_WMRCREATEREGION 26 /**< X 28 */
+#define U_SIZE_WMRCREATEREGION_CORE 24 /**< X 28 Like U_SIZE_WMRCREATEREGION minus the variable part */
+/** @} */
+
+
+// ***************************************************************************
+// Macros
+
+/** \defgroup U_WMF_Common_macros WMF Common Macros
+Because Size16_4 may not be aligned no tests should dereference it directly from a pointer.
+in NOPX tests cast causes uint8_t to promote to uint32_t, without it c++ compiler complains about
+comparison of int with unsigned int
+ @{
+*/
+#define U_TEST_NOPX2(A,B) (A == (uint32_t) (B + 3)) //!< A is Size16_4 (extracted and aligned), B = xb true if no bitmap associated with the structure, used with some BLT records.
+#define U_TEST_NOPXB(A,B) (A/2 == (uint32_t) (B + 3)) //!< A is Size16_4 (extracted and aligned)*2, B = xb, true if no bitmap associated with the structure, used with some BLT records.
+#define U_WMRTYPE(A) (((U_METARECORD *)A)->iType) //!< Get iType from U_WMR* record.
+#define U_WMRXB(A) (((U_METARECORD *)A)->xb) //!< Get xb from U_WMR* record.
+#define U_WMR_XB_FROM_TYPE(A) ((uint8_t) (U_wmr_values(A)>>8)) //!< Get xb from type value.
+#define U_U16(A) (*(uint16_t *)&A) //!< interpret a 16 bit type as uint16_t.
+#define U_P16(A) ( (uint16_t *)&A) //!< pass any 16 bit type as a pointer to a uint16_t.
+#define U_PP16(A) ( (uint16_t *) A) //!< pass any pointer to a 16 bit type as a pointer to a uint16_t.
+
+/** @} */
+
+/* ************************************************************
+ WMF structures OTHER than those corresponding to complete U_WMR_* records
+ ************************************************************ */
+
+/** Brush Object WMF manual 2.2.1.1
+
+ Documentation is muddy, bColor and bHatch fields have different meanings depending on
+ the value of bStyle. Unclear if bHatch bytes are present in some cases from the
+ documentation.
+
+ style Color Data
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored Bitmap16 object holding patern
+ U_BS_DIBPATTERNPT ColorUsage Enum DIB object
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+typedef struct {
+ uint16_t Style; //!< BrushStyle Enumeration
+ U_COLORREF Color; //!< Brush Color value, 32 bit value is not aligned.
+ uint8_t Data[1]; //!< Brush pattern information, variable size and format
+} U_BRUSH;
+
+
+/** Font Object WMF manual 2.2.1.2
+ Warning, only pass by pointer, passing by value will will truncate in Facename!
+*/
+typedef struct {
+ int16_t Height; //!< Height in Logical units
+ int16_t Width; //!< Average Width in Logical units
+ int16_t Escapement; //!< Angle in 0.1 degrees betweem escapement vector and X axis
+ int16_t Orientation; //!< Angle in 0.1 degrees between baseline and X axis
+ int16_t Weight; //!< LF_Weight Enumeration
+ uint8_t Italic; //!< LF_Italic Enumeration
+ uint8_t Underline; //!< LF_Underline Enumeration
+ uint8_t StrikeOut; //!< LF_StrikeOut Enumeration
+ uint8_t CharSet; //!< LF_CharSet Enumeration
+ uint8_t OutPrecision; //!< LF_OutPrecision Enumeration
+ uint8_t ClipPrecision; //!< LF_ClipPrecision Enumeration
+ uint8_t Quality; //!< LF_Quality Enumeration
+ uint8_t PitchAndFamily; //!< LF_PitchAndFamily Enumeration
+ uint8_t FaceName[1]; //!< Name of font. ANSI Latin1, null terminated.
+} U_FONT;
+
+/** PaletteEntry Object WMF manual 2.2.2.13
+ Note, NOT compatiable with U_LOGPLTNTRY
+ Out of PDF order because needed for next struture.
+*/
+typedef struct {
+ uint8_t Value; //!< 0 or PaletteEntryFlag Enumeration
+ uint8_t Blue; //!< Palette entry Blue Intensity
+ uint8_t Green; //!< Palette entry Green Intensity
+ uint8_t Red; //!< Palette entry Red Intensity
+} U_PLTNTRY;
+
+/** Palette Object WMF manual 2.2.1.3
+ NOT Same as "EMF LogPalette Object" in uemf.h because Palette Entries have reversed colors.
+ Values for palVersion are expanded
+
+ Start must be 0x0300 (as for EMF) with U_WMRCREATEPALETTE but is an offset
+ for U_WMRSETPALENTRIES and U_ANIMATEPALETTE
+*/
+typedef struct {
+ uint16_t Start; //!< Either 0x0300 or an offset into the Palette table
+ uint16_t NumEntries; //!< Number of U_LOGPLTNTRY objects
+ U_PLTNTRY PalEntries[1]; //!< Array of PaletteEntry Objects
+} U_PALETTE;
+
+/** Pen Object WMF manual 2.2.1.4
+*/
+typedef struct {
+ uint16_t Style; //!< PenStyle Enumeration
+ uint16_t Widthw[2]; //!< reassemble/store the Pen Width in object dimensions using Widthw, the 32 bit value is not aligned
+ U_COLORREF Color; //!< Pen Color, the 32 bit value is not aligned.
+} U_PEN;
+
+/** Rect Object WMF manual 2.2.2.18
+ \brief Coordinates of the upper left, lower right corner.
+ Note that the coordinate system is 0,0 in the upper left corner
+ of the screen an N,M in the lower right corner.
+ Microsoft name: RECT Object COLLIDES with EMF Rect Object.
+
+ This one is out of order because it is needed early.
+*/
+typedef struct {
+ int16_t left; //!< left coordinate
+ int16_t top; //!< top coordinate
+ int16_t right; //!< right coordinate
+ int16_t bottom; //!< bottom coordinate
+} U_RECT16;
+
+#define U_RCL16_DEF (U_RECT16){0,0,-1,-1} //!< Use this when no bounds are needed.
+
+/** Region Object WMF manual 2.2.1.5
+*/
+typedef struct {
+ uint16_t ignore1; //!< unused value
+ uint16_t Type; //!< must be 0x0006.
+ uint16_t ignore2; //!< unused value
+ int16_t Size; //!< aScans in bytes + regions size in bytes (size of this header plus all U_SCAN objects?)
+ int16_t sCount; //!< number of scanlines in region
+ int16_t sMax; //!< largest number of points in any scan
+ U_RECT16 sRect; //!< bounding rectangle
+ uint16_t aScans[1]; //!< series of appended U_SCAN objects
+} U_REGION;
+
+/** Bitmap16 Object WMF manual 2.2.2.1
+
+ The U_BITMAP16 core is always followed by
+ uint8_t Bits[1]; //!< bitmap pixel data. Bytes contained = (((Width * BitsPixel + 15) >> 4) << 1) * Height
+ Note that in U_WMRCREATEPATTERNBRUSH Bits is always [4].
+
+*/
+typedef struct {
+ int16_t Type; //!< "bitmap type" MS PDF does not define this field beyond this.
+ int16_t Width; //!< bitmap width in pixels.
+ int16_t Height; //!< bitmap height in scan lines.
+ int16_t WidthBytes; //!< bytes per scan line.
+ uint8_t Planes; //!< must be 1.
+ uint8_t BitsPixel; //!< number of adjacent color bits on each plane (R bits + G bits + B bits ????)
+} U_BITMAP16;
+
+/** BitmapCoreHeader Object WMF manual 2.2.2.2
+*/
+typedef struct {
+ uint16_t Size_4[2]; //!< size of U_BITMAPCOREHEADER in bytes.
+ uint16_t Width; //!< DIB width in pixels.
+ uint16_t Height; //!< DIB height in pixels.
+ uint16_t Planes; //!< must be 1
+ uint16_t BitCount; //!< Pixel Format (BitCount Enumeration)
+} U_BITMAPCOREHEADER;
+
+
+/** BitmapInfoHeader Object WMF manual 2.2.2.3
+ Same as "EMF BITMAPINFOHEADER Object" in uemf.h
+ use U_BITMAPINFOHEADER
+*/
+
+//! \cond
+/** BitmapV4Header Object WMF manual 2.2.2.4
+*/
+typedef struct {
+ uint32_t bV4Size;
+ int32_t bV4Width;
+ int32_t bV4Height;
+ uint16_t bV4Planes;
+ uint16_t bV4BitCount;
+ uint32_t bV4Compression;
+ uint32_t bV4SizeImage;
+ int32_t bV4XPelsPerMeter;
+ int32_t bV4YPelsPerMeter;
+ uint32_t bV4ClrUsed;
+ uint32_t bV4ClrImportant;
+ uint32_t bV4RedMask;
+ uint32_t bV4GreenMask;
+ uint32_t bV4BlueMask;
+ uint32_t bV4AlphaMask;
+ uint32_t bV4CSType;
+ U_CIEXYZTRIPLE bV4EndPoints;
+ uint32_t bV4GammaRed;
+ uint32_t bV4GammaGreen;
+ uint32_t bV4GammaBlue;
+} U_BITMAPV4HEADER; //!< For ?
+
+
+/** BitmapV5Header Object WMF manual 2.2.2.5
+*/
+typedef struct {
+ uint32_t bV5Size;
+ int32_t bV5Width;
+ int32_t bV5Height;
+ uint16_t bV5Planes;
+ uint16_t bV5BitCount;
+ uint32_t bV5Compression;
+ uint32_t bV5SizeImage;
+ int32_t bV5XPelsPerMeter;
+ int32_t bV5YPelsPerMeter;
+ uint32_t bV5ClrUsed;
+ uint32_t bV5ClrImportant;
+ uint32_t bV5RedMask;
+ uint32_t bV5GreenMask;
+ uint32_t bV5BlueMask;
+ uint32_t bV5AlphaMask;
+ uint32_t bV5CSType;
+ U_CIEXYZTRIPLE bV5Endpoints;
+ uint32_t bV5GammaRed;
+ uint32_t bV5GammaGreen;
+ uint32_t bV5GammaBlue;
+ uint32_t bV5Intent;
+ uint32_t bV5ProfileData;
+ uint32_t bV5ProfileSize;
+ uint32_t bV5Reserved;
+} U_BITMAPV5HEADER; //!< For ?
+//! \endcond
+
+
+
+/** CIEXYZ Object WMF manual 2.2.2.6
+ Same as "EMF CIEXYZ Object" in uemf.h
+*/
+
+/** CIEXYZTriple Object WMF manual 2.2.2.7
+ Same as "EMF CIEXYZTRIPLE Object" in uemf.h
+*/
+
+/** ColorRef Object WMF manual 2.2.2.8
+ Same as "EMF COLORREF Object" in uemf.h
+*/
+
+/** DeviceIndependentBitmap Object WMF manual 2.2.2.9
+This "object" has an organization, but not one that can be easily expressed with a C struct. It consists of
+three parts, all of which have variable size:
+
+ DIBHeaderInfo BitmapCoreHeader or BitmapInfoHeader Object
+ Colors Array of RGBQuad Objects or uint16_t that make a color table, as determined from the DIBHeaderInfo field.
+ BitMapBuffer Array of bytes containing the image.
+
+*/
+
+/** WLogBrush Object WMF manual 2.2.2.10
+ Not compatible with EMF LogBrush object!
+
+ style Color Hatch
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined)
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+typedef struct {
+ uint16_t Style; //!< BrushStyle Enumeration
+ U_COLORREF Color; //!< Brush Color value, 32 bit value is not aligned.
+ uint16_t Hatch; //!< HatchStyle Enumeration
+} U_WLOGBRUSH;
+
+/* LogColorSpace Object WMF manual 2.2.2.11
+ Same as "EMF LOGCOLORSPACEA Object" in uemf.h
+ use U_LOGCOLORSPACEA
+*/
+
+/* LogColorSpaceW Object WMF manual 2.2.2.12
+ Same as "EMF LOGCOLORSPACEW Object" in uemf.h
+ use U_LOGCOLORSPACEW
+*/
+
+
+/* PaletteEntry Object WMF manual 2.2.2.13
+ moved up before Palette Object */
+
+/* PitchAndFamily Enumerations WMF manual 2.2.2.14
+ Same as "EMF LF_PitchAndFamily Enumeration" in uemf.h
+*/
+
+/* PointL Object WMF manual 2.2.2.15
+ Same as "EMF Point Object" in uemf.h
+*/
+
+/* PointS Object WMF manual 2.2.2.16
+ Same as "EMF POINTS Object" in uemf.h
+*/
+
+/* PolyPolygon Object WMF manual 2.2.2.17 */
+/** WMF manual 2.2.2.17
+
+ There is an array "aPoints" of uint16_t after aPolyCounts that holds the coordinates.
+
+ Presumably it is in order [x1,y1],[x2,y2],etc. The documentation does not say, it might have
+ y then x.
+
+ aPoints starts at aPolyCounts[nPolys]
+*/
+typedef struct {
+ uint16_t nPolys; //!< Number of polygons
+ uint16_t aPolyCounts[1]; //!< Number of points in each polygon (sequential)
+} U_POLYPOLYGON;
+
+/* Rect Object WMF manual 2.2.2.18
+ This one is out of order, had to be created much earlier than this
+*/
+
+/* RectL Object WMF manual 2.2.2.19
+ Same as "EMF RECT Object" in uemf.h
+*/
+
+/* RGBQuad Object WMF manual 2.2.2.20
+ Same as "EMF RGBQUAD Object" in uemf.h
+*/
+
+/** Scan Object WMF manual 2.2.2.21 */
+/** WMF manual 2.2.2.21
+
+ Mandatory field "count2" must follow ScanLines, but it cannot be placed into the struct because
+ ScanLines has variable size. "count2" is
+ an uint16_t value which must have the same value as count.
+*/
+typedef struct {
+ uint16_t count; //!< Number of entries in the ScanLines array
+ uint16_t top; //!< Y coordinate of the top scanline
+ uint16_t bottom; //!< Y coordinate of the bottom scanline
+ uint16_t ScanLines[1]; //!< Array of 16 bit left/right pairs
+} U_SCAN;
+
+/** SizeL Object WMF manual 2.2.2.22
+ Same as "EMF SIZEL Object" in uemf.h
+*/
+
+
+/** First three fields of MOST WMF records (not WMR_HEADER and WMR_PLACEABLE!)
+
+ This Sshould only used for accessing size and type fields.
+ It is NOT used as a prefix like U_EMR in uemf.h because it may cause alignment issues.
+ Microsoft name: WMF Object
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+} U_METARECORD;
+
+/** WMF manual 2.3.2.3 META_PLACEABLE
+ If present this must immediately precede the header.
+ It is not enumerated as an WMR record type.
+ This only ever occurs at the start of a WMF file, so the two uint32_t values will always be aligned.
+*/
+typedef struct {
+ uint32_t Key; //!< MUST be 0x9AC6CDD7
+ uint16_t HWmf; //!< 0. (Always. Manual says total number of 16bit words in record, but no examples found like that)
+ U_RECT16 Dst; //!< Destination bounding box in logical units
+ uint16_t Inch; //!< Logical units/inch (convention if not specified: 1440 logical units/inch)
+ uint32_t Reserved; //!< must be 0
+ uint16_t Checksum; //!< Checksum of preceding 10 16 bit values
+} U_WMRPLACEABLE;
+
+/** WMF manual 2.3.2.2 META_HEADER
+*/
+typedef struct {
+ uint8_t iType; //!< RecordType Enumeration, must be 1
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Size16w; //!< Total number of 16bit words in record
+ uint16_t version; //!< Metafile version Enumeration
+ uint16_t Sizew[2]; //!< reassemble/store the Size (16 bit words in entire file) using Sizew, the 32 bit value is not aligned
+ uint16_t nObjects; //!< Total number of brushes, pens, and other graphics objects defined in this file
+ uint32_t maxSize; //!< Largest record in file, in number of 16bit words (This uint32_t is aligned)
+ uint16_t nMembers; //!< Unused, should be 0
+} U_WMRHEADER;
+
+
+// ***********************************************************************************
+// The following structures correspond to U_WMR_# records
+
+/* Index 00 U_WMREOF WMF manual 2.3.2.1 META_EOF */
+/** WMF manual 2.3.2.1 META_EOF
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+} U_WMREOF,
+ U_WMRSETRELABS, //!< WMF manual 2.3.5.21
+ U_WMRSAVEDC, //!< WMF manual 2.3.5.11
+ U_WMRREALIZEPALETTE; //!< WMF manual 2.3.5.8
+
+/* Index 01 U_WMRSETBKCOLOR WMF manual 2.3.5.14 */
+/** WMF manual 2.3.5.14
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_COLORREF Color; //!< Color value, the 32 bit value is not aligned.
+} U_WMRSETBKCOLOR,
+ U_WMRSETTEXTCOLOR; //!< WMF manual 2.3.5.26
+
+/* Index 02 U_WMRSETBKMODE WMF manual 2.3.5.15 */
+/** WMF manual 2.3.5.15
+mode = MixMode Enumeration.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Mode; //!< Various Enumeraton.
+ uint16_t Reserved; //!< Ignore (ALSO OPTIONAL - FIELD MAY NOT BE PRESENT!!!!)
+} U_WMRSETBKMODE,
+ U_WMRSETPOLYFILLMODE, //!< WMF manual 2.3.5.20 Mode = PolyFillMode Enumeration.
+ U_WMRSETROP2, //!< WMF manual 2.3.5.22 Binary Raster Operation Enumeration.
+ U_WMRSETSTRETCHBLTMODE, //!< WMF manual 2.3.5.23 Mode = StretchMode Enumeration
+ U_WMRSETTEXTALIGN; //!< WMF manual 2.3.5.24 Mode = TextAlignment Enumeration.
+
+/* Index 03 U_WMRSETMAPMODE WMF manual 2.3.5.17 */
+/** WMF manual 2.3.5.17
+Mode = MapMode Enumeration.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Mode; //!< Various Enumeraton and other
+} U_WMRSETMAPMODE,
+ U_WMRSETTEXTCHAREXTRA; //!< WMF manual 2.3.5.25, Mode = Extra space in logical units to add to each character
+
+/* Index 04 U_WMRSETROP2 WMF manual 2.3.5.22 See Index 02 */
+
+/* Index 05 U_WMRSETRELABS WMF manual 2.3.5.21 See Index 00*/
+
+/* Index 06 U_WMRSETPOLYFILLMODE WMF manual 2.3.5.20 See Index 02
+ Index 07 U_WMRSETSTRETCHBLTMODE WMF manual 2.3.5.23 */
+
+/* Index 08 U_WMRSETTEXTCHAREXTRA WMF manual 2.3.5.25 See Index 03*/
+
+/* Index 09 U_WMRSETTEXTCOLOR WMF manual 2.3.5.26 see Index 01 */
+
+/* Index 0A U_WMRSETTEXTJUSTIFICATION WMF manual 2.3.5.27 */
+/** WMF manual 2.3.5.27
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Count; //!< Number of space characters in the line
+ uint16_t Extra; //!< Number of extra space characters to add to the line
+} U_WMRSETTEXTJUSTIFICATION;
+
+/* Index 0B U_WMRSETWINDOWORG WMF manual 2.3.5.31
+ Index 0C U_WMRSETWINDOWEXT WMF manual 2.3.5.30
+ Index 0D U_WMRSETVIEWPORTORG WMF manual 2.3.5.29
+ Index 0E U_WMRSETVIEWPORTEXT WMF manual 2.3.5.28
+ Index 0F U_WMROFFSETWINDOWORG WMF manual 2.3.5.7
+ Index 0F U_WMROFFSETVIEWPORTORG WMF manual 2.3.5.6
+ Index 13 U_WMRLINETO WMF manual 2.3.3.10
+ Index 14 U_WMRMOVETO WMF manual 2.3.3.4
+ Index 20 U_WMROFFSETCLIPRGN WMF manual 2.3.5.5
+*/
+/** WMF manual 2.3.5.31
+Window X,Y origin
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t y; //!< Y value (note order!)
+ int16_t x; //!< X value
+} U_WMRSETWINDOWORG,
+ U_WMRSETWINDOWEXT, //!< WMF manual 2.3.5.30, Window X,Y extent
+ U_WMRSETVIEWPORTORG, //!< WMF manual 2.3.5.29, Viewport X,Y origin
+ U_WMRSETVIEWPORTEXT, //!< WMF manual 2.3.5.28, Viewport X,Y extent
+ U_WMROFFSETWINDOWORG, //!< WMF manual 2.3.5.7, Window X,Y offset in device units
+ U_WMROFFSETVIEWPORTORG, //!< WMF manual 2.3.5.6, Viewport X,Y offset in device units
+ U_WMRLINETO, //!< WMF manual 2.3.3.10, Endpoint X,Y in logical units
+ U_WMRMOVETO, //!< WMF manual 2.3.3.4, Destination X,Y in logical units
+ U_WMROFFSETCLIPRGN; //!< WMF manual 2.3.5.5, Y offset in logical units
+
+/* Index 10 U_WMRSCALEWINDOWEXT WMF manual 2.3.5.13
+ Index 12 U_WMRSCALEVIEWPORTEXT WMF manual 2.3.5.12
+*/
+/** WMF manual 2.3.5.13
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t yDenom; //!< Y denominator
+ int16_t yNum; //!< Y numerator
+ int16_t xDenom; //!< X denominator
+ int16_t xNum; //!< X numerator
+} U_WMRSCALEWINDOWEXT,
+ U_WMRSCALEVIEWPORTEXT; //!< WMF manual 2.3.5.12
+
+/* Index 11 U_WMROFFSETVIEWPORTORG WMF manual 2.3.5.6 see Index 0B */
+
+/* Index 12 U_WMRSCALEVIEWPORTEXT WMF manual 2.3.5.12 see Index 10 */
+
+/* Index 13 U_WMRLINETO WMF manual 2.3.3.10 see index 0B
+ Index 14 U_WMRMOVETO WMF manual 2.3.5.4 */
+
+/* Index 15 U_WMREXCLUDECLIPRECT WMF manual 2.3.5.2
+ Index 16 U_WMRINTERSECTCLIPRECT WMF manual 2.3.5.3
+*/
+/** WMF manual 2.3.5.2
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t Bottom; //!< Coordinates in logical units
+ int16_t Right; //!< Coordinates in logical units
+ int16_t Top; //!< Coordinates in logical units
+ int16_t Left; //!< Coordinates in logical units
+} U_WMREXCLUDECLIPRECT,
+ U_WMRINTERSECTCLIPRECT; //!< WMF manual 2.3.5.3
+
+/* Index 17 U_WMRARC WMF manual 2.3.3.1 */
+/** WMF manual 2.3.3.1
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t yEndArc; //!< Coordinates in logical units
+ int16_t xEndArc; //!< Coordinates in logical units
+ int16_t yStartArc; //!< Coordinates in logical units
+ int16_t xStartArc; //!< Coordinates in logical units
+ int16_t Bottom; //!< Coordinates in logical units
+ int16_t Right; //!< Coordinates in logical units
+ int16_t Top; //!< Coordinates in logical units
+ int16_t Left; //!< Coordinates in logical units
+} U_WMRARC;
+
+/* Index 18 U_WMRELLIPSE WMF manual 2.3.3.3
+ Index 1B U_WMRRECTANGLE WMF manual 2.3.3.17
+*/
+/** WMF manual 2.3.3.3
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t Bottom; //!< Coordinates in logical units
+ int16_t Right; //!< Coordinates in logical units
+ int16_t Top; //!< Coordinates in logical units
+ int16_t Left; //!< Coordinates in logical units
+} U_WMRELLIPSE,
+ U_WMRRECTANGLE; //!< WMF manual 2.3.3.17
+
+/* Index 19 U_WMRFLOODFILL WMF manual 2.3.3.7
+ Index 48 U_WMREXTFLOODFILL WMF manual 2.3.3.4
+*/
+/** WMF manual 2.3.3.7
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t Mode; //!< FloodFill Enumeration
+ U_COLORREF Color; //!< Color
+ int16_t y; //!< Y
+ int16_t x; //!< X
+} U_WMRFLOODFILL,
+ U_WMREXTFLOODFILL; //!< WMF manual 2.3.3.7
+
+/* Index 1A U_WMRPIE WMF manual 2.3.3.13
+ Index 30 U_WMRCHORD WMF manual 2.3.3.2
+*/
+/** WMF manual 2.3.3.13
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t yRadial2; //!< in logical units
+ int16_t xRadial2; //!< in logical units
+ int16_t yRadial1; //!< in logical units
+ int16_t xRadial1; //!< in logical units
+ int16_t Bottom; //!< in logical units
+ int16_t Right; //!< in logical units
+ int16_t Top; //!< in logical units
+ int16_t Left; //!< in logical units
+} U_WMRPIE,
+ U_WMRCHORD; //!< WMF manual 2.3.3.2
+
+/* Index 1B U_WMRRECTANGLE WMF manual 2.3.3.17 See Index 18 */
+
+/* Index 1C U_WMRROUNDRECT WMF manual 2.3.3.18 */
+/** WMF manual 2.3.3.18
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t Height; //!< in logical units (rounded corner)
+ int16_t Width; //!< in logical units (rounded corner)
+ int16_t Bottom; //!< in logical units
+ int16_t Right; //!< in logical units
+ int16_t Top; //!< in logical units
+ int16_t Left; //!< in logical units
+} U_WMRROUNDRECT;
+
+/* Index 1D U_WMRPATBLT WMF manual 2.3.3.12
+*/
+/** WMF manual 2.3.3.12
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the rop3 Ternary raster operation using rop3w, as the 32 bit value is not aligned
+ int16_t Height; //!< in logical units (of Rect to Fill)
+ int16_t Width; //!< in logical units (of Rect to Fill)
+ int16_t yDst; //!< in logical units (UL corner to fill)
+ int16_t xDst; //!< in logical units (UL corner to fill)
+} U_WMRPATBLT;
+
+/* Index 1E U_WMRSAVEDC WMF manual 2.3.5.11 See Index 00*/
+
+/* Index 1F U_WMRSETPIXEL WMF manual 2.3.3.19 */
+/** WMF manual 2.3.3.19
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_COLORREF Color; //!< Color
+ int16_t y; //!< Y
+ int16_t x; //!< X
+} U_WMRSETPIXEL;
+
+/* Index 20 U_WMROFFSETCLIPRGN WMF manual 2.3.5.5 See Index 0B*/
+
+/* Index 21 U_WMRTEXTOUT WMF manual 2.3.3.20
+*/
+/** WMF manual 2.3.3.20
+Also part of the record, following String, and so at variable positions:
+
+int16_t y; start position
+
+int16_t x; start position
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t Length; //!< Stringlength in bytes
+ uint8_t String; //!< String to write, storage area must be 2n bytes.
+} U_WMRTEXTOUT;
+
+/* Index 22 U_WMRBITBLT WMF manual 2.3.1.1
+*/
+/** WMF manual 2.3.1.1
+
+ This is a variable structure the core/invariant part extends to xSrc.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2
+
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t ignore; //!< ignore
+ int16_t Height; //!< in logical units (of Src and Dst rects)
+ int16_t Width; //!< in logical units (of Src and Dst rects)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+} U_WMRBITBLT_NOPX;
+
+/** WMF manual 2.3.1.1
+
+ This is a variable structure the core/invariant part extends to xSrc.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2
+
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t Height; //!< in logical units (of Src and Dst rects)
+ int16_t Width; //!< in logical units (of Src and Dst rects)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ U_BITMAP16 bitmap; //!< Src bitmap
+} U_WMRBITBLT_PX;
+
+
+/* Index 23 U_WMRSTRETCHBLT WMF manual 2.3.1.5 */
+/** WMF manual 2.3.1.5
+
+ This is a variable structure the core/invariant part extends to xSrc.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t hSrc; //!< Height in logical units of Src rect
+ int16_t wSrc; //!< Wdith in logical units of Dst rect
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t ignore; //!< ignored
+ int16_t hDst; //!< Height in logical units of Dst rect
+ int16_t wDst; //!< Wdith in logical units of Dst rect
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+} U_WMRSTRETCHBLT_NOPX;
+
+
+/* Index 23 U_WMRSTRETCHBLT WMF manual 2.3.1.5 */
+/** WMF manual 2.3.1.5
+
+ This is a variable structure the core/invariant part extends to xSrc.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t hSrc; //!< Height in logical units of Src rect
+ int16_t wSrc; //!< Wdith in logical units of Dst rect
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t hDst; //!< Height in logical units of Dst rect
+ int16_t wDst; //!< Wdith in logical units of Dst rect
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ U_BITMAP16 bitmap; //!< Src bitmap
+} U_WMRSTRETCHBLT_PX;
+
+/* Index 24 U_WMRPOLYGON WMF manual 2.3.3.15
+ Index 25 U_WMRPOLYLINE WMF manual 2.3.3.14
+*/
+/** WMF manual 2.3.3.15
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t nPoints; //!< Number of points in aPoints
+ U_POINT16 aPoints[1]; //!< Array of points
+} U_WMRPOLYGON,
+ U_WMRPOLYLINE; //!< WMF manual 2.3.3.14
+
+/* Index 26 U_WMRESCAPE WMF manual 2.3.6.1 */
+/** WMF manual 2.3.6.1
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t eFunc; //!< Escape function
+ uint16_t nBytes; //!< bytes in the data array
+ uint8_t Data[1]; //!< data array
+} U_WMRESCAPE;
+
+/* Index 27 U_WMRRESTOREDC WMF manual 2.3.5.10 */
+/** WMF manual 2.3.5.10
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t DC; //!< DC to restore (negative is relative to current, positive is absolute)
+} U_WMRRESTOREDC;
+
+/* Index 28 U_WMRFILLREGION WMF manual 2.3.3.6 */
+/** WMF manual 2.3.3.6
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Region; //!< Index of region to fill in object table
+ uint16_t Brush; //!< Index of brush to use in object table
+} U_WMRFILLREGION;
+
+/* Index 29 U_WMRFRAMEREGION WMF manual 2.3.3.8 */
+/** WMF manual 2.3.3.8
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Region; //!< Index of region to frame in object table
+ uint16_t Brush; //!< Index of brush to use in frame in object table
+ int16_t Height; //!< in logical units (of frame)
+ int16_t Width; //!< in logical units (of frame)
+} U_WMRFRAMEREGION;
+
+/* Index 2A U_WMRINVERTREGION WMF manual 2.3.3.9
+ Index 2B U_WMRPAINTREGION WMF manual 2.3.3.11
+ Index 2C U_WMRSELECTCLIPREGION WMF manual 2.3.4.9
+ Index 2D U_WMRSELECTOBJECT WMF manual 2.3.4.10
+ Index 34 U_WMRSELECTPALETTE WMF manual 2.3.4.11
+ Index 39 U_WMRRESIZEPALETTE WMF manual 2.3.5.9
+ Index F0 U_WMRDELETEOBJECT WMF manual 2.3.4.7
+*/
+/** WMF manual 2.3.3.9
+invert region
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t index; //!< (usually) index of region/object in object table
+} U_WMRINVERTREGION,
+ U_WMRPAINTREGION, //!< WMF manual 2.3.3.11, paint region
+ U_WMRSELECTCLIPREGION, //!< WMF manual 2.3.4.9, select as clip region
+ U_WMRSELECTOBJECT, //!< WMF manual 2.3.4.10, select object
+ U_WMRSELECTPALETTE, //!< WMF manual 2.3.4.11, select palette object
+ U_WMRRESIZEPALETTE, //!< WMF manual 2.3.5.9, resize the system palette to "index"
+ U_WMRDELETEOBJECT; //!< WMF manual 2.3.4.7, delete object
+
+/* Index 2E U_WMRSETTEXTALIGN WMF manual 2.3.5.24 See Index 02 */
+
+/* Index 2F U_WMRDRAWTEXT in GDI and Wine, not documented in WMF manual.
+ Index FE U_WMRCREATEBITMAP in GDI and Wine, not documented in WMF manual.
+ Index FD U_WMRCREATEBITMAPINDIRECT in GDI and Wine, not documented in WMF manual.
+
+ no documentation found, this part of these records, at least, must be correct */
+/** in GDI and Wine, not documented in WMF manual.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+} U_WMRDRAWTEXT,
+ U_WMRCREATEBITMAPINDIRECT, //!< in GDI and Wine, not documented in WMF manual.
+ U_WMRCREATEBITMAP; //!< in GDI and Wine, not documented in WMF manual.
+
+/* Index 30 U_WMRCHORD WMF manual 2.3.3.2 See Index 1A */
+
+/* Index 31 U_WMRSETMAPPERFLAGS WMF manual 2.3.5.18 */
+/** WMF manual 2.3.5.18
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t valuew[2]; //!< if 1 bit set font mapper selects only matching aspect fonts. reassemble/store the value using valuew, the 32 bit value is not aligned.
+} U_WMRSETMAPPERFLAGS;
+
+/* Index 32 U_WMREXTTEXTOUT WMF manual 2.3.3.5
+*/
+/** WMF manual 2.3.3.5
+
+ Variable size record. Optional fields which follow the struct fields are:
+
+ U_RECT16 Rect; Only present when U_ETO_OPAQUE or U_ETO_CLIPPED bits are set in Opts
+ uint8_t String; String to write, storage area must be 2n bytes.
+ int16_t Dx; Kerning information. Must have same number of entries as Length.
+ Dx is present when
+ 2*Size16_4[2] -14 - 2*((Length + 1)/2)) - 8*(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)) == 2*Length
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ int16_t y; //!< in logical units (draw point)
+ int16_t x; //!< in logical units (draw point)
+ int16_t Length; //!< Stringlength in bytes
+ uint16_t Opts; //!< ExtTextOutOptions Flags
+} U_WMREXTTEXTOUT;
+
+/* Index 33 U_WMRSETDIBTODEV WMF manual 2.3.1.4 */
+/** WMF manual 2.3.1.4
+
+ Constant part of record is shown. It is followed by a DeviceIndependentBitmap Object
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t cUsage; //!< ColorUsage Enumeration
+ uint16_t ScanCount; //!< Number of scan lines in Src
+ uint16_t StartScan; //!< First Scan line in Src
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t Height; //!< in logical units (of Src and Dst)
+ int16_t Width; //!< in logical units (of Src and Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ uint8_t dib[1]; //!< DeviceIndependentBitmap object
+} U_WMRSETDIBTODEV;
+
+/* Index 34 U_WMRSELECTPALETTE WMF manual 2.3.4.11 See Index 2A */
+
+/* Index 35 U_WMRREALIZEPALETTE WMF manual 2.3.5.8 See Index 00 */
+
+/* Index 36 U_WMRANIMATEPALETTE WMF manual 2.3.5.1
+ Index 37 U_WMRSETPALENTRIES WMF manual 2.3.5.19
+ Index F7 U_WMRCREATEPALETTE WMF manual 2.3.4.3
+*/
+/** WMF manual 2.3.5.1
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_PALETTE Palette; //!< Palette object
+} U_WMRANIMATEPALETTE,
+ U_WMRSETPALENTRIES, //!< WMF manual 2.3.5.19
+ U_WMRCREATEPALETTE; //!< WMF manual 2.3.4.3
+
+/* Index 38 U_WMRPOLYPOLYGON WMF manual 2.3.3.16 */
+/** WMF manual 2.3.3.16
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_POLYPOLYGON PPolygon; //!< PolyPolygon object (size is variable!)
+} U_WMRPOLYPOLYGON;
+
+/* Index 39 U_WMRRESIZEPALETTE WMF manual 2.3.5.9 See Index 2A */
+
+/* Index 40 U_WMRDIBBITBLT WMF manual 2.3.1.2
+*/
+/** WMF manual 2.3.1.2
+
+ The PX form is a variable structure the core/invariant part extends to xDst, and that is
+ followed by a DeviceInvariantBitmap object which starts at "dib".
+ The NOPX form is a constant structure.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ uint16_t ignore; //!< ignore
+ int16_t Height; //!< in logical units (of Src and Dst)
+ int16_t Width; //!< in logical units (of Src and Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+} U_WMRDIBBITBLT_NOPX;
+
+/** WMF manual 2.3.1.2
+
+ The PX form is a variable structure the core/invariant part extends to xDst, and that is
+ followed by a DeviceInvariantBitmap object which starts at "dib".
+ The NOPX form is a constant structure.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t Height; //!< in logical units (of Src and Dst)
+ int16_t Width; //!< in logical units (of Src and Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ uint8_t dib[1]; //!< DeviceIndependentBitmap object
+} U_WMRDIBBITBLT_PX;
+
+/* Index 41 U_WMRDIBSTRETCHBLT WMF manual 2.3.1.3 */
+/** WMF manual 2.3.1.3
+
+ The PX form is a variable structure the core/invariant part extends to xDst, and that is
+ followed by a DeviceInvariantBitmap object which starts at "dib".
+ The NOPX form is a constant structure.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t hSrc; //!< in logical units (of Src)
+ int16_t wSrc; //!< in logical units (of Src)
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ uint16_t ignore; //!< ignore
+ int16_t hDst; //!< in logical units (of Dst)
+ int16_t wDst; //!< in logical units (of Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+} U_WMRDIBSTRETCHBLT_NOPX;
+
+/** WMF manual 2.3.1.3
+
+ The PX form is a variable structure the core/invariant part extends to xDst, and that is
+ followed by a DeviceInvariantBitmap object which starts at "dib".
+ The NOPX form is a constant structure.
+
+ if RecordSize == ((xb) + 3) then there is no bitmap and use the _NOPX form, otherwise use the _PX form
+ Use Macro U_TEST_NOPX2.
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ int16_t hSrc; //!< in logical units (of Src)
+ int16_t wSrc; //!< in logical units (of Src)
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t hDst; //!< in logical units (of Dst)
+ int16_t wDst; //!< in logical units (of Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ uint8_t dib[1]; //!< DeviceIndependentBitmap object
+} U_WMRDIBSTRETCHBLT_PX;
+
+
+/* Index 42 U_WMRDIBCREATEPATTERNBRUSH WMF manual 2.3.4.8
+*/
+/** WMF manual 2.3.4.8
+
+ style cUsage Brush created
+ U_BS_SOLID like U_BS_DIBPATTERNPT
+ U_BS_NULL like U_BS_DIBPATTERNPT
+ U_BS_HATCHED like U_BS_DIBPATTERNPT
+ U_BS_DIBPATTERNPT ColorUsage enumer. U_BS_DIBPATTERNPT brush from DIB in Src
+ U_BS_PATTERN ColorUsage enumer. U_BS_PATTERN brush from Bitmap16 object in Src
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t Style; //!< BrushStyle Enumeration
+ uint16_t cUsage; //!< See table above
+ uint8_t Src[1]; //!< DeviceIndependentBitmap or Bitmap16 object
+} U_WMRDIBCREATEPATTERNBRUSH;
+
+/* Index 43 U_WMRSTRETCHDIB WMF manual 2.3.1.6 */
+/** WMF manual 2.3.1.6
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ uint16_t rop3w[2]; //!< reassemble/store the Ternary raster operation rop3 value using rop3w, the 32 bit value is not aligned.
+ uint16_t cUsage; //!< ColorUsage Enumeration
+ int16_t hSrc; //!< in logical units (of Src)
+ int16_t wSrc; //!< in logical units (of Src)
+ int16_t ySrc; //!< in logical units (UL corner of Src rect)
+ int16_t xSrc; //!< in logical units (UL corner of Src rect)
+ int16_t hDst; //!< in logical units (of Dst)
+ int16_t wDst; //!< in logical units (of Dst)
+ int16_t yDst; //!< in logical units (UL corner of Dst rect)
+ int16_t xDst; //!< in logical units (UL corner of Dst rect)
+ uint8_t dib[1]; //!< DeviceIndependentBitmap object
+} U_WMRSTRETCHDIB;
+
+/* Index 48 U_WMREXTFLOODFILL WMF manual 2.3.3.4 See Index 19*/
+/* Index 4C U_WMR4C */
+/* Index 4D U_WMR4D */
+/* Index 4F U_WMR4F */
+/* Index 50 U_WMR50 */
+/* Index 52 U_WMR52 */
+/* Index 5E U_WMR5E */
+/* Index 5F U_WMR5F */
+/* Index 60 U_WMR60 */
+/* Index 61 U_WMR61 */
+/* Index 62 U_WMR62 */
+/* Index 63 U_WMR63 */
+/* Index 64 U_WMR64 */
+/* Index 65 U_WMR65 */
+/* Index 66 U_WMR66 */
+/* Index 67 U_WMR67 */
+/* Index 68 U_WMR68 */
+/* Index 69 U_WMR69 */
+/* Index 6A U_WMR6A */
+/* Index 6B U_WMR6B */
+/* Index 6C U_WMR6C */
+/* Index 6D U_WMR6D */
+/* Index 6E U_WMR6E */
+/* Index 6F U_WMR6F */
+/* Index 70 U_WMR70 */
+/* Index 71 U_WMR71 */
+/* Index 72 U_WMR72 */
+/* Index 73 U_WMR73 */
+/* Index 74 U_WMR74 */
+/* Index 75 U_WMR75 */
+/* Index 76 U_WMR76 */
+/* Index 77 U_WMR77 */
+/* Index 78 U_WMR78 */
+/* Index 79 U_WMR79 */
+/* Index 7A U_WMR7A */
+/* Index 7B U_WMR7B */
+/* Index 7C U_WMR7C */
+/* Index 7D U_WMR7D */
+/* Index 7E U_WMR7E */
+/* Index 7F U_WMR7F */
+/* Index 80 U_WMR80 */
+/* Index 81 U_WMR81 */
+/* Index 82 U_WMR82 */
+/* Index 83 U_WMR83 */
+/* Index 84 U_WMR84 */
+/* Index 85 U_WMR85 */
+/* Index 86 U_WMR86 */
+/* Index 87 U_WMR87 */
+/* Index 88 U_WMR88 */
+/* Index 89 U_WMR89 */
+/* Index 8A U_WMR8A */
+/* Index 8B U_WMR8B */
+/* Index 8C U_WMR8C */
+/* Index 8D U_WMR8D */
+/* Index 8E U_WMR8E */
+/* Index 8F U_WMR8F */
+/* Index 90 U_WMR90 */
+/* Index 91 U_WMR91 */
+/* Index 92 U_WMR92 */
+/* Index 93 U_WMR93 */
+/* Index 94 U_WMR94 */
+/* Index 95 U_WMR95 */
+/* Index 96 U_WMR96 */
+/* Index 97 U_WMR97 */
+/* Index 98 U_WMR98 */
+/* Index 99 U_WMR99 */
+/* Index 9A U_WMR9A */
+/* Index 9B U_WMR9B */
+/* Index 9C U_WMR9C */
+/* Index 9D U_WMR9D */
+/* Index 9E U_WMR9E */
+/* Index 9F U_WMR9F */
+/* Index A0 U_WMRA0 */
+/* Index A1 U_WMRA1 */
+/* Index A2 U_WMRA2 */
+/* Index A3 U_WMRA3 */
+/* Index A4 U_WMRA4 */
+/* Index A5 U_WMRA5 */
+/* Index A6 U_WMRA6 */
+/* Index A7 U_WMRA7 */
+/* Index A8 U_WMRA8 */
+/* Index A9 U_WMRA9 */
+/* Index AA U_WMRAA */
+/* Index AB U_WMRAB */
+/* Index AC U_WMRAC */
+/* Index AD U_WMRAD */
+/* Index AE U_WMRAE */
+/* Index AF U_WMRAF */
+/* Index B0 U_WMRB0 */
+/* Index B1 U_WMRB1 */
+/* Index B2 U_WMRB2 */
+/* Index B3 U_WMRB3 */
+/* Index B4 U_WMRB4 */
+/* Index B5 U_WMRB5 */
+/* Index B6 U_WMRB6 */
+/* Index B7 U_WMRB7 */
+/* Index B8 U_WMRB8 */
+/* Index B9 U_WMRB9 */
+/* Index BA U_WMRBA */
+/* Index BB U_WMRBB */
+/* Index BC U_WMRBC */
+/* Index BD U_WMRBD */
+/* Index BE U_WMRBE */
+/* Index BF U_WMRBF */
+/* Index C0 U_WMRC0 */
+/* Index C1 U_WMRC1 */
+/* Index C2 U_WMRC2 */
+/* Index C3 U_WMRC3 */
+/* Index C4 U_WMRC4 */
+/* Index C5 U_WMRC5 */
+/* Index C6 U_WMRC6 */
+/* Index C7 U_WMRC7 */
+/* Index C8 U_WMRC8 */
+/* Index C9 U_WMRC9 */
+/* Index CA U_WMRCA */
+/* Index CB U_WMRCB */
+/* Index CC U_WMRCC */
+/* Index CD U_WMRCD */
+/* Index CE U_WMRCE */
+/* Index CF U_WMRCF */
+/* Index D0 U_WMRD0 */
+/* Index D1 U_WMRD1 */
+/* Index D2 U_WMRD2 */
+/* Index D3 U_WMRD3 */
+/* Index D4 U_WMRD4 */
+/* Index D5 U_WMRD5 */
+/* Index D6 U_WMRD6 */
+/* Index D7 U_WMRD7 */
+/* Index D8 U_WMRD8 */
+/* Index D9 U_WMRD9 */
+/* Index DA U_WMRDA */
+/* Index DB U_WMRDB */
+/* Index DC U_WMRDC */
+/* Index DD U_WMRDD */
+/* Index DE U_WMRDE */
+/* Index DF U_WMRDF */
+/* Index E0 U_WMRE0 */
+/* Index E1 U_WMRE1 */
+/* Index E2 U_WMRE2 */
+/* Index E3 U_WMRE3 */
+/* Index E4 U_WMRE4 */
+/* Index E5 U_WMRE5 */
+/* Index E6 U_WMRE6 */
+/* Index E7 U_WMRE7 */
+/* Index E8 U_WMRE8 */
+/* Index E9 U_WMRE9 */
+/* Index EA U_WMREA */
+/* Index EB U_WMREB */
+/* Index EC U_WMREC */
+/* Index ED U_WMRED */
+/* Index EE U_WMREE */
+/* Index EF U_WMREF */
+/* Index F0 U_WMRDELETEOBJECT WMF manual 2.3.4.7 See Index 2A */
+/* Index F1 U_WMRF1 */
+/* Index F2 U_WMRF2 */
+/* Index F3 U_WMRF3 */
+/* Index F4 U_WMRF4 */
+/* Index F5 U_WMRF5 */
+
+/* Index F7 U_WMRCREATEPALETTE WMF manual 2.3.4.3 See Index 36*/
+
+/* Index F8 U_WMRF8 */
+/* Index F9 U_WMRCREATEPATTERNBRUSH WMF manual 2.3.4.4 */
+/** WMF manual 2.3.4.4
+
+ WARNING - U_WMRCREATEPATTERNBRUSH has been declared obsolete and application support is spotty -
+ use U_WMRDIBCREATEPATTERNBRUSH instead.
+
+ This record is peculiar...
+
+ After the core structure there is:
+
+ A truncated U_BITMAP16. Only the first 14 bytes are present, and the last 4 bytes (bits section) are ignored.
+ 18 zero bytes (reserved)
+ A pattern. The pattern is a byte array whose size is set by the fields in the U_BITMAP16 structure as follows:
+
+ (((Width * BitsPixel + 15) >> 4) << 1) * Height
+
+ brush created has style U_BS_PATTERN.
+
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+} U_WMRCREATEPATTERNBRUSH;
+
+/* Index FA U_WMRCREATEPENINDIRECT WMF manual 2.3.4.5 */
+/** WMF manual 2.3.4.5
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_PEN pen; //!< Pen Object
+} U_WMRCREATEPENINDIRECT;
+
+/* Index FB U_WMRCREATEFONTINDIRECT WMF manual 2.3.4.2 */
+/** WMF manual 2.3.4.2
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_FONT font; //!< Font Object
+} U_WMRCREATEFONTINDIRECT;
+
+/* Index FC U_WMRCREATEBRUSHINDIRECT WMF manual 2.3.4.1 */
+/** WMF manual 2.3.4.1
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_WLOGBRUSH brush; //!< WLogBrush Object
+} U_WMRCREATEBRUSHINDIRECT;
+
+/* Index FD U_WMRCREATEBITMAPINDIRECT in GDI and Wine, not in WMF manual, see index 2F */
+
+/* Index FE U_WMRCREATEBITMAP in GDI and Wine, not in WMF manual, see index 2F */
+
+/* Index FF U_WMRCREATEREGION WMF manual 2.3.4.6 */
+/** WMF manual 2.3.4.6
+*/
+typedef struct {
+ uint16_t Size16_4[2]; //!< Total number of 16bit words in record
+ uint8_t iType; //!< RecordType Enumeration
+ uint8_t xb; //!< Extra high order byte associated with record type
+ U_REGION region; //!< Region Object
+} U_WMRCREATEREGION;
+
+
+
+// ************************************************************************************************
+// Utility function structures
+
+/**
+ Storage for keeping track of properties of the growing WMF file as records are added.
+*/
+typedef struct {
+ FILE *fp; //!< Open file
+ size_t allocated; //!< Size of the buffer
+ size_t used; //!< Amount consumed
+ uint32_t records; //!< Number of records already contained
+ uint16_t ignore; //!< size padding,not used
+ uint32_t PalEntries; //!< Number of PalEntries (set from U_EMREOF)
+ uint32_t chunk; //!< Number of bytes to add when more space is needed
+ char *buf; //!< Buffer for constructing the EMF in memory
+ uint32_t largest; //!< Largest record size, in bytes (used by WMF, not by EMF)
+ uint32_t sumObjects; //!< Number of objects appended (used by WMF, not by EMF) [ also see wmf_highwater() ]
+} WMFTRACK;
+
+/**
+ The various create functions need a place to put their handles, these are stored in the table below.
+ We don't actually do anything much with these handles, that is up to whatever program finally plays back the WMF, but
+ we do need to keep track of the numbers so that they are not accidentally reused. (Also WMF files have rules
+ about how object handles must be numbered, for instance, the lowest possible number must always be used. These
+ are different from EMF object handles.) This structure is used for staying in conformance with these rules.
+
+ There are no stock objects in WMF files.
+*/
+typedef struct {
+ uint32_t *table; //!< Array Buffer for constructing the WMF in memory
+ size_t allocated; //!< Slots in the buffer
+ size_t chunk; //!< Number to add if a realloc is required
+ uint32_t lolimit; //!< Lowest unoccupied table slot, may be a hole created by a deleteobject.
+ uint32_t hilimit; //!< Highest table slot occupied (currently)
+ uint32_t peak; //!< Highest table slot occupied (ever)
+} WMFHANDLES;
+
+//! \cond
+// ************************************************************************************************
+// Prototypes (_set first, then _get)
+char *wmr_dup(const char *wmr);
+int wmf_start(const char *name, uint32_t initsize, uint32_t chunksize, WMFTRACK **wt);
+int uwmf_free(WMFTRACK **wt);
+int wmf_finish(WMFTRACK *wt);
+int wmf_append(U_METARECORD *rec, WMFTRACK *wt, int freerec);
+int wmf_header_append(U_METARECORD *rec,WMFTRACK *et, int freerec);
+int wmf_readdata(const char *filename, char **contents, size_t*length);
+#define wmf_fopen emf_fopen
+int wmf_highwater(uint32_t setval);
+int wmf_htable_create(uint32_t initsize, uint32_t chunksize, WMFHANDLES **wht);
+int wmf_htable_delete(uint32_t *ih, WMFHANDLES *wht);
+int wmf_htable_insert(uint32_t *ih, WMFHANDLES *wht);
+int wmf_htable_free(WMFHANDLES **wht);
+int16_t U_16_checksum(int16_t *buf, int count);
+int16_t *dx16_set( int32_t height, uint32_t weight, uint32_t members);
+uint32_t U_wmr_properties(uint32_t type);
+
+uint32_t U_wmr_size(const U_METARECORD *record);
+uint32_t U_wmr_values(int idx);
+const char *U_wmr_names(int idx);
+const char *U_wmr_escnames(int idx);
+
+void U_sanerect16(U_RECT16 rc, double *left, double *top, double *right, double *bottom);
+
+
+U_FONT *U_FONT_set(int16_t Height, int16_t Width, int16_t Escapement, int16_t Orientation,
+ int16_t Weight, uint8_t Italic, uint8_t Underline, uint8_t StrikeOut,
+ uint8_t CharSet, uint8_t OutPrecision, uint8_t ClipPrecision,
+ uint8_t Quality, uint8_t PitchAndFamily, char *FaceName);
+U_PLTNTRY U_PLTNTRY_set(U_COLORREF Color);
+U_PALETTE *U_PLTENTRY_set(uint16_t Start, uint16_t NumEntries, U_PLTNTRY *Entries);
+U_PEN U_PEN_set(uint16_t Style, uint16_t Width, U_COLORREF Color);
+U_RECT16 U_RECT16_set(U_POINT16 ul,U_POINT16 lr);
+U_BITMAP16 *U_BITMAP16_set(const int16_t Type, const int16_t Width, const int16_t Height,
+ const int16_t LineN, const uint8_t BitsPixel, const char *Bits);
+U_SCAN *U_SCAN_set(uint16_t count, uint16_t top, uint16_t bottom, uint16_t *ScanLines);
+U_REGION *U_REGION_set(int16_t Size, int16_t sCount, int16_t sMax, U_RECT16 sRect, uint16_t *aScans);
+U_WLOGBRUSH U_WLOGBRUSH_set(uint16_t Style, U_COLORREF Color, uint16_t Hatch);
+U_PAIRF *U_PAIRF_set(float x, float y);
+
+char *wdeleteobject_set(uint32_t *ihObject, WMFHANDLES *wht);
+char *wselectobject_set(uint32_t ihObject, WMFHANDLES *wht );
+char *wcreatepenindirect_set(uint32_t *ihPen, WMFHANDLES *wht, U_PEN pen);
+char *wcreatebrushindirect_set(uint32_t *ihBrush, WMFHANDLES *wht, U_WLOGBRUSH lb);
+char *wcreatedibpatternbrush_srcdib_set(uint32_t *ihBrush, WMFHANDLES *wht,
+ uint32_t iUsage, const U_BITMAPINFO *Bmi, uint32_t cbPx, const char *Px);
+char *wcreatedibpatternbrush_srcbm16_set(uint32_t *ihBrush, WMFHANDLES *wht,
+ uint32_t iUsage, const U_BITMAP16 *Bm16);
+char *wcreatepatternbrush_set(uint32_t *ihBrush, WMFHANDLES *wht, U_BITMAP16 *Bm16, char *Pattern);
+char *wcreatefontindirect_set(uint32_t *ihFont, WMFHANDLES *wht, U_FONT *uf);
+char *wcreatepalette_set(uint32_t *ihPal, WMFHANDLES *wht, U_PALETTE *up);
+char *wsetpaletteentries_set(uint32_t *ihPal, WMFHANDLES *wht, const U_PALETTE *Palletes);
+char *wcreateregion_set(uint32_t *ihReg, WMFHANDLES *wht, const U_REGION *Region);
+char *wbegin_path_set(void);
+char *wend_path_set(void);
+char *wlinecap_set(int32_t Type);
+char *wlinejoin_set(int32_t Type);
+char *wmiterlimit_set(int32_t limit);
+
+
+char *U_WMRHEADER_set(U_PAIRF *size,unsigned int dpi);
+char *U_WMREOF_set(void);
+char *U_WMRSETBKCOLOR_set(U_COLORREF Color);
+char *U_WMRSETBKMODE_set(uint16_t Mode);
+char *U_WMRSETMAPMODE_set(uint16_t Mode);
+char *U_WMRSETROP2_set(uint16_t Mode);
+char *U_WMRSETRELABS_set(void);
+char *U_WMRSETPOLYFILLMODE_set(uint16_t Mode);
+char *U_WMRSETSTRETCHBLTMODE_set(uint16_t Mode);
+char *U_WMRSETTEXTCHAREXTRA_set(uint16_t Mode);
+char *U_WMRSETTEXTCOLOR_set(U_COLORREF Color);
+char *U_WMRSETTEXTJUSTIFICATION_set(uint16_t Count, uint16_t Extra);
+char *U_WMRSETWINDOWORG_set(U_POINT16 coord);
+char *U_WMRSETWINDOWEXT_set(U_POINT16 extent);
+char *U_WMRSETVIEWPORTORG_set(U_POINT16 coord);
+char *U_WMRSETVIEWPORTEXT_set(U_POINT16 extent);
+char *U_WMROFFSETWINDOWORG_set(U_POINT16 offset);
+char *U_WMRSCALEWINDOWEXT_set(U_POINT16 Denom, U_POINT16 Num);
+char *U_WMROFFSETVIEWPORTORG_set(U_POINT16 offset);
+char *U_WMRSCALEVIEWPORTEXT_set(U_POINT16 Denom, U_POINT16 Num);
+char *U_WMRLINETO_set(U_POINT16 coord);
+char *U_WMRMOVETO_set(U_POINT16 coord);
+char *U_WMREXCLUDECLIPRECT_set(U_RECT16 rect);
+char *U_WMRINTERSECTCLIPRECT_set(U_RECT16 rect);
+char *U_WMRARC_set(U_POINT16 StartArc, U_POINT16 EndArc, U_RECT16 rect);
+char *U_WMRELLIPSE_set(U_RECT16 rect);
+char *U_WMRFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord);
+char *U_WMRPIE_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect);
+char *U_WMRRECTANGLE_set(U_RECT16 rect);
+char *U_WMRROUNDRECT_set(int16_t Width, int16_t Height, U_RECT16 rect);
+char *U_WMRPATBLT_set(U_POINT16 Dst, U_POINT16 cwh, uint32_t dwRop3);
+char *U_WMRSAVEDC_set(void);
+char *U_WMRSETPIXEL_set(U_COLORREF Color, U_POINT16 coord);
+char *U_WMROFFSETCLIPRGN_set(U_POINT16 offset);
+char *U_WMRTEXTOUT_set(U_POINT16 Dst, char *string);
+char *U_WMRBITBLT_set(U_POINT16 Dst, U_POINT16 cwh, U_POINT16 Src,
+ uint32_t dwRop3, const U_BITMAP16 *Bm16);
+char *U_WMRSTRETCHBLT_set(U_POINT16 Dst, U_POINT16 cDst, U_POINT16 Src,
+ U_POINT16 cSrc, uint32_t dwRop3, const U_BITMAP16 *Bm16);
+char *U_WMRPOLYGON_set(uint16_t Length, const U_POINT16 * Data);
+char *U_WMRPOLYLINE_set(uint16_t Length, const U_POINT16 * Data);
+char *U_WMRESCAPE_set(uint16_t Escape, uint16_t Length, const void *Data);
+char *U_WMRRESTOREDC_set(int16_t DC);
+char *U_WMRFILLREGION_set(uint16_t Region, uint16_t Brush);
+char *U_WMRFRAMEREGION_set(uint16_t Region, uint16_t Brush, int16_t Height, int16_t Width);
+char *U_WMRINVERTREGION_set(uint16_t Region);
+char *U_WMRPAINTREGION_set(uint16_t Region);
+char *U_WMRSELECTCLIPREGION_set(uint16_t Region);
+char *U_WMRSELECTOBJECT_set(uint16_t object);
+char *U_WMRSETTEXTALIGN_set(uint16_t Mode);
+char *U_WMRDRAWTEXT_set(void); /* in GDI and Wine, not in WMF manual. */
+char *U_WMRCHORD_set(U_POINT16 Radial1, U_POINT16 Radial2, U_RECT16 rect);
+char *U_WMRSETMAPPERFLAGS_set(uint32_t Mode);
+char *U_WMREXTTEXTOUT_set(U_POINT16 Dst, int16_t Length, uint16_t Opts, const char *string, int16_t *dx, U_RECT16 rect);
+char *U_WMRSETDIBTODEV_set(void);
+char *U_WMRSELECTPALETTE_set(uint16_t Palette);
+char *U_WMRREALIZEPALETTE_set(void);
+char *U_WMRANIMATEPALETTE_set(U_PALETTE *Palette);
+char *U_WMRSETPALENTRIES_set(const U_PALETTE *Palette);
+char *U_WMRPOLYPOLYGON_set(const uint16_t, const uint16_t *aPolyCounts, const U_POINT16 * points);
+char *U_WMRRESIZEPALETTE_set(uint16_t Palette);
+char *U_WMR3A_set(void);
+char *U_WMR3B_set(void);
+char *U_WMR3C_set(void);
+char *U_WMR3D_set(void);
+char *U_WMR3E_set(void);
+char *U_WMR3F_set(void);
+char *U_WMRDIBBITBLT_set(U_POINT16 Dst, U_POINT16 cwh, U_POINT16 Src,
+ uint32_t dwRop3, const U_BITMAPINFO * Bmi, uint32_t cbPx, const char *Px);
+char *U_WMRDIBSTRETCHBLT_set(U_POINT16 Dst, U_POINT16 cDst, U_POINT16 Src,
+ U_POINT16 cSrc, uint32_t dwRop3, const U_BITMAPINFO *Bmi, uint32_t cbPx, const char *Px);
+char *U_WMRDIBCREATEPATTERNBRUSH_set(const uint16_t Style, const uint16_t iUsage,
+ const U_BITMAPINFO *Bmi, uint32_t cbPx, const char *Px, const U_BITMAP16 *Bm16);
+char *U_WMRSTRETCHDIB_set(U_POINT16 Dest, U_POINT16 cDest, U_POINT16 Src, U_POINT16 cSrc,
+ const uint16_t cUsage, uint32_t dwRop3, const U_BITMAPINFO *Bmi, uint32_t cbPx, const char *Px);
+char *U_WMR44_set(void);
+char *U_WMR45_set(void);
+char *U_WMR46_set(void);
+char *U_WMR47_set(void);
+char *U_WMREXTFLOODFILL_set(uint16_t Mode, U_COLORREF Color, U_POINT16 coord);
+char *U_WMR49_set(void);
+char *U_WMR4A_set(void);
+char *U_WMR4B_set(void);
+char *U_WMR4C_set(void);
+char *U_WMR4D_set(void);
+char *U_WMR4E_set(void);
+char *U_WMR4F_set(void);
+char *U_WMR50_set(void);
+char *U_WMR51_set(void);
+char *U_WMRABORTDOC_set(void);
+char *U_WMR53_set(void);
+char *U_WMR54_set(void);
+char *U_WMR55_set(void);
+char *U_WMR56_set(void);
+char *U_WMR57_set(void);
+char *U_WMR58_set(void);
+char *U_WMR59_set(void);
+char *U_WMR5A_set(void);
+char *U_WMR5B_set(void);
+char *U_WMR5C_set(void);
+char *U_WMR5D_set(void);
+char *U_WMR5E_set(void);
+char *U_WMR5F_set(void);
+char *U_WMR60_set(void);
+char *U_WMR61_set(void);
+char *U_WMR62_set(void);
+char *U_WMR63_set(void);
+char *U_WMR64_set(void);
+char *U_WMR65_set(void);
+char *U_WMR66_set(void);
+char *U_WMR67_set(void);
+char *U_WMR68_set(void);
+char *U_WMR69_set(void);
+char *U_WMR6A_set(void);
+char *U_WMR6B_set(void);
+char *U_WMR6C_set(void);
+char *U_WMR6D_set(void);
+char *U_WMR6E_set(void);
+char *U_WMR6F_set(void);
+char *U_WMR70_set(void);
+char *U_WMR71_set(void);
+char *U_WMR72_set(void);
+char *U_WMR73_set(void);
+char *U_WMR74_set(void);
+char *U_WMR75_set(void);
+char *U_WMR76_set(void);
+char *U_WMR77_set(void);
+char *U_WMR78_set(void);
+char *U_WMR79_set(void);
+char *U_WMR7A_set(void);
+char *U_WMR7B_set(void);
+char *U_WMR7C_set(void);
+char *U_WMR7D_set(void);
+char *U_WMR7E_set(void);
+char *U_WMR7F_set(void);
+char *U_WMR80_set(void);
+char *U_WMR81_set(void);
+char *U_WMR82_set(void);
+char *U_WMR83_set(void);
+char *U_WMR84_set(void);
+char *U_WMR85_set(void);
+char *U_WMR86_set(void);
+char *U_WMR87_set(void);
+char *U_WMR88_set(void);
+char *U_WMR89_set(void);
+char *U_WMR8A_set(void);
+char *U_WMR8B_set(void);
+char *U_WMR8C_set(void);
+char *U_WMR8D_set(void);
+char *U_WMR8E_set(void);
+char *U_WMR8F_set(void);
+char *U_WMR90_set(void);
+char *U_WMR91_set(void);
+char *U_WMR92_set(void);
+char *U_WMR93_set(void);
+char *U_WMR94_set(void);
+char *U_WMR95_set(void);
+char *U_WMR96_set(void);
+char *U_WMR97_set(void);
+char *U_WMR98_set(void);
+char *U_WMR99_set(void);
+char *U_WMR9A_set(void);
+char *U_WMR9B_set(void);
+char *U_WMR9C_set(void);
+char *U_WMR9D_set(void);
+char *U_WMR9E_set(void);
+char *U_WMR9F_set(void);
+char *U_WMRA0_set(void);
+char *U_WMRA1_set(void);
+char *U_WMRA2_set(void);
+char *U_WMRA3_set(void);
+char *U_WMRA4_set(void);
+char *U_WMRA5_set(void);
+char *U_WMRA6_set(void);
+char *U_WMRA7_set(void);
+char *U_WMRA8_set(void);
+char *U_WMRA9_set(void);
+char *U_WMRAA_set(void);
+char *U_WMRAB_set(void);
+char *U_WMRAC_set(void);
+char *U_WMRAD_set(void);
+char *U_WMRAE_set(void);
+char *U_WMRAF_set(void);
+char *U_WMRB0_set(void);
+char *U_WMRB1_set(void);
+char *U_WMRB2_set(void);
+char *U_WMRB3_set(void);
+char *U_WMRB4_set(void);
+char *U_WMRB5_set(void);
+char *U_WMRB6_set(void);
+char *U_WMRB7_set(void);
+char *U_WMRB8_set(void);
+char *U_WMRB9_set(void);
+char *U_WMRBA_set(void);
+char *U_WMRBB_set(void);
+char *U_WMRBC_set(void);
+char *U_WMRBD_set(void);
+char *U_WMRBE_set(void);
+char *U_WMRBF_set(void);
+char *U_WMRC0_set(void);
+char *U_WMRC1_set(void);
+char *U_WMRC2_set(void);
+char *U_WMRC3_set(void);
+char *U_WMRC4_set(void);
+char *U_WMRC5_set(void);
+char *U_WMRC6_set(void);
+char *U_WMRC7_set(void);
+char *U_WMRC8_set(void);
+char *U_WMRC9_set(void);
+char *U_WMRCA_set(void);
+char *U_WMRCB_set(void);
+char *U_WMRCC_set(void);
+char *U_WMRCD_set(void);
+char *U_WMRCE_set(void);
+char *U_WMRCF_set(void);
+char *U_WMRD0_set(void);
+char *U_WMRD1_set(void);
+char *U_WMRD2_set(void);
+char *U_WMRD3_set(void);
+char *U_WMRD4_set(void);
+char *U_WMRD5_set(void);
+char *U_WMRD6_set(void);
+char *U_WMRD7_set(void);
+char *U_WMRD8_set(void);
+char *U_WMRD9_set(void);
+char *U_WMRDA_set(void);
+char *U_WMRDB_set(void);
+char *U_WMRDC_set(void);
+char *U_WMRDD_set(void);
+char *U_WMRDE_set(void);
+char *U_WMRDF_set(void);
+char *U_WMRE0_set(void);
+char *U_WMRE1_set(void);
+char *U_WMRE2_set(void);
+char *U_WMRE3_set(void);
+char *U_WMRE4_set(void);
+char *U_WMRE5_set(void);
+char *U_WMRE6_set(void);
+char *U_WMRE7_set(void);
+char *U_WMRE8_set(void);
+char *U_WMRE9_set(void);
+char *U_WMREA_set(void);
+char *U_WMREB_set(void);
+char *U_WMREC_set(void);
+char *U_WMRED_set(void);
+char *U_WMREE_set(void);
+char *U_WMREF_set(void);
+char *U_WMRDELETEOBJECT_set(uint16_t object);
+char *U_WMRF1_set(void);
+char *U_WMRF2_set(void);
+char *U_WMRF3_set(void);
+char *U_WMRF4_set(void);
+char *U_WMRF5_set(void);
+char *U_WMRF6_set(void);
+char *U_WMRCREATEPALETTE_set(U_PALETTE *Palette);
+char *U_WMRF8_set(void);
+char *U_WMRCREATEPATTERNBRUSH_set(U_BITMAP16 *Bm16, char *Pattern);
+char *U_WMRCREATEPENINDIRECT_set(U_PEN pen);
+char *U_WMRCREATEFONTINDIRECT_set(U_FONT *font);
+char *U_WMRCREATEBRUSHINDIRECT_set(U_WLOGBRUSH brush);
+char *U_WMRCREATEBITMAPINDIRECT_set(void); /* in GDI and Wine, not in WMF manual. */
+char *U_WMRCREATEBITMAP_set(void); /* in GDI and Wine, not in WMF manual. */
+char *U_WMRCREATEREGION_set(const U_REGION *region);
+
+int16_t *dx16_get( int32_t height, uint32_t weight, uint32_t members);
+size_t U_WMRRECSAFE_get(const char *contents, const char *blimit);
+int wmfheader_get(const char *contents, const char *blimit, U_WMRPLACEABLE *Placeable, U_WMRHEADER *Header);
+int wmr_arc_points(U_RECT16 rclBox, U_POINT16 ArcStart, U_POINT16 ArcEnd,
+ int *f1, int f2, U_PAIRF *center, U_PAIRF *start, U_PAIRF *end, U_PAIRF *size );
+void U_BITMAPINFOHEADER_get(const char *Bmih, uint32_t *Size, int32_t *Width, int32_t *Height,
+ uint32_t *Planes, uint32_t *BitCount, uint32_t *Compression, uint32_t *SizeImage,
+ int32_t *XPelsPerMeter, int32_t *YPelsPerMeter, uint32_t *ClrUsed, uint32_t *ClrImportant);
+void U_BITMAPCOREHEADER_get(const char *BmiCh, uint32_t *Size, int32_t *Width, int32_t *Height, int32_t *BitCount);
+int wget_DIB_params(const char *dib, const char **px, const U_RGBQUAD **ct, uint32_t *numCt,
+ int32_t *width, int32_t *height, int32_t *colortype, int32_t *invert);
+int U_WMREOF_get(const char *contents);
+int U_WMRSETBKCOLOR_get(const char *contents, U_COLORREF *Color);
+int U_WMRSETBKMODE_get(const char *contents, uint16_t *Mode);
+int U_WMRSETMAPMODE_get(const char *contents, uint16_t *Mode);
+int U_WMRSETROP2_get(const char *contents, uint16_t *Mode);
+int U_WMRSETRELABS_get(const char *contents);
+int U_WMRSETPOLYFILLMODE_get(const char *contents, uint16_t *Mode);
+int U_WMRSETSTRETCHBLTMODE_get(const char *contents, uint16_t *Mode);
+int U_WMRSETTEXTCHAREXTRA_get(const char *contents, uint16_t *Mode);
+int U_WMRSETTEXTCOLOR_get(const char *contents, U_COLORREF *Color);
+int U_WMRSETTEXTJUSTIFICATION_get(const char *contents, uint16_t *Count, uint16_t *Extra);
+int U_WMRSETWINDOWORG_get(const char *contents, U_POINT16 * coord);
+int U_WMRSETWINDOWEXT_get(const char *contents, U_POINT16 * extent);
+int U_WMRSETVIEWPORTORG_get(const char *contents, U_POINT16 * coord);
+int U_WMRSETVIEWPORTEXT_get(const char *contents, U_POINT16 * extent);
+int U_WMROFFSETWINDOWORG_get(const char *contents, U_POINT16 * offset);
+int U_WMRSCALEWINDOWEXT_get(const char *contents, U_POINT16 * Denom, U_POINT16 * Num);
+int U_WMROFFSETVIEWPORTORG_get(const char *contents, U_POINT16 * offset);
+int U_WMRSCALEVIEWPORTEXT_get(const char *contents, U_POINT16 * Denom, U_POINT16 * Num);
+int U_WMRLINETO_get(const char *contents, U_POINT16 * coord);
+int U_WMRMOVETO_get(const char *contents, U_POINT16 * coord);
+int U_WMREXCLUDECLIPRECT_get(const char *contents, U_RECT16 * rect);
+int U_WMRINTERSECTCLIPRECT_get(const char *contents, U_RECT16 * rect);
+int U_WMRARC_get(const char *contents, U_POINT16 * StartArc, U_POINT16 * EndArc, U_RECT16 * rect);
+int U_WMRELLIPSE_get(const char *contents, U_RECT16 * rect);
+int U_WMRFLOODFILL_get(const char *contents, uint16_t *Mode, U_COLORREF *Color, U_POINT16 * coord);
+int U_WMRPIE_get(const char *contents, U_POINT16 * Radial1, U_POINT16 * Radial2, U_RECT16 * rect);
+int U_WMRRECTANGLE_get(const char *contents, U_RECT16 * rect);
+int U_WMRROUNDRECT_get(const char *contents, int16_t *Width, int16_t *Height, U_RECT16 * rect);
+int U_WMRPATBLT_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cwh, uint32_t *dwRop3);
+int U_WMRSAVEDC_get(const char *contents);
+int U_WMRSETPIXEL_get(const char *contents, U_COLORREF *Color, U_POINT16 * coord);
+int U_WMROFFSETCLIPRGN_get(const char *contents, U_POINT16 * offset);
+int U_WMRTEXTOUT_get(const char *contents, U_POINT16 * Dst, int16_t *Length, const char **string);
+int U_WMRBITBLT_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cwh, U_POINT16 * Src, uint32_t *dwRop3, U_BITMAP16 *Bm16, const char **px);
+int U_WMRSTRETCHBLT_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cDst, U_POINT16 * Src, U_POINT16 * cSrc, uint32_t *dwRop3, U_BITMAP16 *Bm16, const char **px);
+int U_WMRPOLYGON_get(const char *contents, uint16_t *Length, const char **Data);
+int U_WMRPOLYLINE_get(const char *contents, uint16_t *Length, const char **Data);
+int U_WMRESCAPE_get(const char *contents, uint16_t *Escape, uint16_t *Length, const char **Data);
+int U_WMRRESTOREDC_get(const char *contents, int16_t *DC);
+int U_WMRFILLREGION_get(const char *contents, uint16_t *Region, uint16_t *Brush);
+int U_WMRFRAMEREGION_get(const char *contents, uint16_t *Region, uint16_t *Brush, int16_t *Height, int16_t *Width);
+int U_WMRINVERTREGION_get(const char *contents, uint16_t *Region);
+int U_WMRPAINTREGION_get(const char *contents, uint16_t *Region);
+int U_WMRSELECTCLIPREGION_get(const char *contents, uint16_t *Region);
+int U_WMRSELECTOBJECT_get(const char *contents, uint16_t *Object);
+int U_WMRSETTEXTALIGN_get(const char *contents, uint16_t *Mode);
+int U_WMRDRAWTEXT_get(void); /* in GDI and Wine, not in WMF manual. */
+int U_WMRCHORD_get(const char *contents, U_POINT16 * Radial1, U_POINT16 * Radial2, U_RECT16 * rect);
+int U_WMRSETMAPPERFLAGS_get(const char *contents, uint32_t *Mode);
+int U_WMREXTTEXTOUT_get(const char *contents, U_POINT16 * Dst, int16_t *Length, uint16_t *Opts, const char **string, const int16_t **dx, U_RECT16 * rect);
+int U_WMRSETDIBTODEV_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cwh, U_POINT16 * Src, uint16_t *cUsage, uint16_t *ScanCount, uint16_t *StartScan, const char **dib);
+int U_WMRSELECTPALETTE_get(const char *contents, uint16_t *Palette);
+int U_WMRREALIZEPALETTE_get(const char *contents);
+int U_WMRANIMATEPALETTE_get(const char *contents, U_PALETTE *Palette, const char **PalEntries);
+int U_WMRSETPALENTRIES_get(const char *contents, U_PALETTE *Palette, const char **PalEntries);
+int U_WMRPOLYPOLYGON_get(const char *contents, uint16_t *nPolys, const uint16_t **aPolyCounts, const char **Points);
+int U_WMRRESIZEPALETTE_get(const char *contents, uint16_t *Palette);
+int U_WMR3A_get(void);
+int U_WMR3B_get(void);
+int U_WMR3C_get(void);
+int U_WMR3D_get(void);
+int U_WMR3E_get(void);
+int U_WMR3F_get(void);
+int U_WMRDIBBITBLT_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cwh, U_POINT16 * Src, uint32_t *dwRop3, const char **dib);
+int U_WMRDIBSTRETCHBLT_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cDst, U_POINT16 * Src, U_POINT16 * cSrc, uint32_t *dwRop3, const char **dib);
+int U_WMRDIBCREATEPATTERNBRUSH_get(const char *contents, uint16_t *Style, uint16_t *cUsage, const char **Bm16, const char **dib);
+int U_WMRSTRETCHDIB_get(const char *contents, U_POINT16 * Dst, U_POINT16 * cDst, U_POINT16 * Src, U_POINT16 * cSrc, uint16_t *cUsage, uint32_t *dwRop3, const char **dib);
+int U_WMR44_get(void);
+int U_WMR45_get(void);
+int U_WMR46_get(void);
+int U_WMR47_get(void);
+int U_WMREXTFLOODFILL_get(const char *contents, uint16_t *Mode, U_COLORREF *Color, U_POINT16 * coord);
+int U_WMR49_get(void);
+int U_WMR4A_get(void);
+int U_WMR4B_get(void);
+int U_WMR4C_get(void);
+int U_WMR4D_get(void);
+int U_WMR4E_get(void);
+int U_WMR4F_get(void);
+int U_WMR50_get(void);
+int U_WMR51_get(void);
+int U_WMRABORTDOC_get(void);
+int U_WMR53_get(void);
+int U_WMR54_get(void);
+int U_WMR55_get(void);
+int U_WMR56_get(void);
+int U_WMR57_get(void);
+int U_WMR58_get(void);
+int U_WMR59_get(void);
+int U_WMR5A_get(void);
+int U_WMR5B_get(void);
+int U_WMR5C_get(void);
+int U_WMR5D_get(void);
+int U_WMR5E_get(void);
+int U_WMR5F_get(void);
+int U_WMR60_get(void);
+int U_WMR61_get(void);
+int U_WMR62_get(void);
+int U_WMR63_get(void);
+int U_WMR64_get(void);
+int U_WMR65_get(void);
+int U_WMR66_get(void);
+int U_WMR67_get(void);
+int U_WMR68_get(void);
+int U_WMR69_get(void);
+int U_WMR6A_get(void);
+int U_WMR6B_get(void);
+int U_WMR6C_get(void);
+int U_WMR6D_get(void);
+int U_WMR6E_get(void);
+int U_WMR6F_get(void);
+int U_WMR70_get(void);
+int U_WMR71_get(void);
+int U_WMR72_get(void);
+int U_WMR73_get(void);
+int U_WMR74_get(void);
+int U_WMR75_get(void);
+int U_WMR76_get(void);
+int U_WMR77_get(void);
+int U_WMR78_get(void);
+int U_WMR79_get(void);
+int U_WMR7A_get(void);
+int U_WMR7B_get(void);
+int U_WMR7C_get(void);
+int U_WMR7D_get(void);
+int U_WMR7E_get(void);
+int U_WMR7F_get(void);
+int U_WMR80_get(void);
+int U_WMR81_get(void);
+int U_WMR82_get(void);
+int U_WMR83_get(void);
+int U_WMR84_get(void);
+int U_WMR85_get(void);
+int U_WMR86_get(void);
+int U_WMR87_get(void);
+int U_WMR88_get(void);
+int U_WMR89_get(void);
+int U_WMR8A_get(void);
+int U_WMR8B_get(void);
+int U_WMR8C_get(void);
+int U_WMR8D_get(void);
+int U_WMR8E_get(void);
+int U_WMR8F_get(void);
+int U_WMR90_get(void);
+int U_WMR91_get(void);
+int U_WMR92_get(void);
+int U_WMR93_get(void);
+int U_WMR94_get(void);
+int U_WMR95_get(void);
+int U_WMR96_get(void);
+int U_WMR97_get(void);
+int U_WMR98_get(void);
+int U_WMR99_get(void);
+int U_WMR9A_get(void);
+int U_WMR9B_get(void);
+int U_WMR9C_get(void);
+int U_WMR9D_get(void);
+int U_WMR9E_get(void);
+int U_WMR9F_get(void);
+int U_WMRA0_get(void);
+int U_WMRA1_get(void);
+int U_WMRA2_get(void);
+int U_WMRA3_get(void);
+int U_WMRA4_get(void);
+int U_WMRA5_get(void);
+int U_WMRA6_get(void);
+int U_WMRA7_get(void);
+int U_WMRA8_get(void);
+int U_WMRA9_get(void);
+int U_WMRAA_get(void);
+int U_WMRAB_get(void);
+int U_WMRAC_get(void);
+int U_WMRAD_get(void);
+int U_WMRAE_get(void);
+int U_WMRAF_get(void);
+int U_WMRB0_get(void);
+int U_WMRB1_get(void);
+int U_WMRB2_get(void);
+int U_WMRB3_get(void);
+int U_WMRB4_get(void);
+int U_WMRB5_get(void);
+int U_WMRB6_get(void);
+int U_WMRB7_get(void);
+int U_WMRB8_get(void);
+int U_WMRB9_get(void);
+int U_WMRBA_get(void);
+int U_WMRBB_get(void);
+int U_WMRBC_get(void);
+int U_WMRBD_get(void);
+int U_WMRBE_get(void);
+int U_WMRBF_get(void);
+int U_WMRC0_get(void);
+int U_WMRC1_get(void);
+int U_WMRC2_get(void);
+int U_WMRC3_get(void);
+int U_WMRC4_get(void);
+int U_WMRC5_get(void);
+int U_WMRC6_get(void);
+int U_WMRC7_get(void);
+int U_WMRC8_get(void);
+int U_WMRC9_get(void);
+int U_WMRCA_get(void);
+int U_WMRCB_get(void);
+int U_WMRCC_get(void);
+int U_WMRCD_get(void);
+int U_WMRCE_get(void);
+int U_WMRCF_get(void);
+int U_WMRD0_get(void);
+int U_WMRD1_get(void);
+int U_WMRD2_get(void);
+int U_WMRD3_get(void);
+int U_WMRD4_get(void);
+int U_WMRD5_get(void);
+int U_WMRD6_get(void);
+int U_WMRD7_get(void);
+int U_WMRD8_get(void);
+int U_WMRD9_get(void);
+int U_WMRDA_get(void);
+int U_WMRDB_get(void);
+int U_WMRDC_get(void);
+int U_WMRDD_get(void);
+int U_WMRDE_get(void);
+int U_WMRDF_get(void);
+int U_WMRE0_get(void);
+int U_WMRE1_get(void);
+int U_WMRE2_get(void);
+int U_WMRE3_get(void);
+int U_WMRE4_get(void);
+int U_WMRE5_get(void);
+int U_WMRE6_get(void);
+int U_WMRE7_get(void);
+int U_WMRE8_get(void);
+int U_WMRE9_get(void);
+int U_WMREA_get(void);
+int U_WMREB_get(void);
+int U_WMREC_get(void);
+int U_WMRED_get(void);
+int U_WMREE_get(void);
+int U_WMREF_get(void);
+int U_WMRDELETEOBJECT_get(const char *contents, uint16_t *Object);
+int U_WMRF1_get(void);
+int U_WMRF2_get(void);
+int U_WMRF3_get(void);
+int U_WMRF4_get(void);
+int U_WMRF5_get(void);
+int U_WMRF6_get(void);
+int U_WMRCREATEPALETTE_get(const char *contents, U_PALETTE *Palette, const char **PalEntries);
+int U_WMRF8_get(void);
+int U_WMRCREATEPATTERNBRUSH_get(const char *contents, U_BITMAP16 *Bm16, int *pasize, const char **Pattern);
+int U_WMRCREATEPENINDIRECT_get(const char *contents, U_PEN *pen);
+int U_WMRCREATEFONTINDIRECT_get(const char *contents, const char **font);
+int U_WMRCREATEBRUSHINDIRECT_get(const char *contents, const char **brush);
+int U_WMRCREATEBITMAPINDIRECT_get(void);
+int U_WMRCREATEBITMAP_get(void);
+int U_WMRCREATEREGION_get(const char *contents, const char **Region);
+//! \endcond
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UWMF_ */
diff --git a/src/3rdparty/libuemf/uwmf_endian.c b/src/3rdparty/libuemf/uwmf_endian.c
new file mode 100644
index 000000000..7a047c2a5
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf_endian.c
@@ -0,0 +1,1774 @@
+/**
+ @file uwmf_endian.c
+
+ @brief Functions for converting WMF records between Big Endian and Little Endian byte orders.
+*/
+
+/*
+File: uwmf_endian.c
+Version: 0.1.5
+Date: 28-MAY-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h> /* for offsetof() */
+#include <string.h>
+#include "uwmf.h"
+#include "uwmf_endian.h"
+
+// hide almost everything in this file from Doxygen
+//! \cond
+/* Prototypes for functions used here and defined in uemf_endian.c, but which are not supposed
+to be used in end user code. */
+
+void U_swap2(void *ul, unsigned int count);
+void U_swap4(void *ul, unsigned int count);
+void bitmapinfo_swap(char *Bmi);
+
+/* **********************************************************************************************
+ These functions Swap standard objects used in the WMR records.
+ The low level ones do not append EOL.
+*********************************************************************************************** */
+
+/**
+ \brief Swap U_BITMAP16 object
+ \param b U_BITMAP16 object
+*/
+void bitmap16_swap(
+ char *b
+ ){
+ U_swap2(b,4); /* Type, Width, Height, WidthBytes */
+ /* Planes and BitsPixel are bytes, so no swap needed */
+ /* Bits[] pixel data should already be in order */
+}
+
+/**
+ \brief Swap a U_BRUSH object.
+ \param b U_BRUSH object.
+ style bColor bHatch
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored Bitmap16 object holding patern
+ U_BS_DIBPATTERNPT ColorUsage Enum DIB object
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+void brush_swap(
+ char *b,
+ int torev
+ ){
+ int Style;
+ if(torev){ Style = *(uint16_t *)(b + offsetof(U_BRUSH,Style)); }
+ U_swap2(b + offsetof(U_BRUSH,Style),1);
+ if(!torev){ Style = *(uint16_t *)(b + offsetof(U_BRUSH,Style)); }
+ /* Color is already in the right order */
+ switch(Style){
+ case U_BS_SOLID:
+ /* no/ignored data field */
+ break;
+ case U_BS_NULL:
+ /* no/ignored data field */
+ break;
+ case U_BS_PATTERN:
+ bitmap16_swap(b + offsetof(U_BRUSH,Data));
+ break;
+ case U_BS_DIBPATTERNPT:
+ bitmapinfo_swap(b + offsetof(U_BRUSH,Data));
+ break;
+ case U_BS_HATCHED:
+ /* no/ignored data field */
+ break;
+ }
+}
+
+/**
+ \brief Swap a U_FONT object from pointer.
+ \param lf U_FONT object
+*/
+void font_swap(
+ char *f
+ ){
+ U_swap2(f + offsetof(U_FONT,Height),5); /*Height, Width, Escapement, Orientation, Weight */
+ /* Other fields are single bytes */
+}
+
+/**
+ \brief Swap a pointer to a U_PALETTE object.
+ \param lp Pointer to a U_PALETTE object.
+*/
+void palette_swap(
+ char *p
+ ){
+ U_swap2(p + offsetof(U_PALETTE,Start),2); /* Start, NumEntries*/
+ /* PalEntries[1] is byte ordered, so no need to swap */
+}
+
+/**
+ \brief Swap a U_PEN object.
+ \param p U_PEN object
+*/
+void pen_swap(
+ char *p
+ ){
+ U_swap2(p + offsetof(U_PEN,Style),3); /* Style,Widthw[0],Widthw[1] */
+ /* Color already in order */
+}
+
+/* there are no
+ void rect16_ltrb_swap()
+ void rect16_brtl_swap()
+because rectangles are swapped using U_swap2 as an array of 4 int16 values.
+*/
+
+
+/**
+ \brief Swap U_REGION object
+ \param rect U_REGION object
+ \param torev
+ PARTIAL IMPLEMENTATION
+*/
+void region_swap(
+ char *reg,
+ int torev
+ ){
+ int Size;
+ if(torev){ Size = *(int16_t *)(reg + offsetof(U_REGION,Size)); }
+ U_swap2(reg,10); /* ignore1 through sRrect*/
+ if(!torev){ Size = *(int16_t *)(reg + offsetof(U_REGION,Size)); }
+ U_swap2(reg + U_SIZE_REGION, (Size - U_SIZE_REGION)/2); /* aScans */
+}
+
+
+/**
+ \brief Swap U_BITMAPCOREHEADER object
+ \param ch U_BITMAPCOREHEADER object
+*/
+void bitmapcoreheader_swap(
+ char *ch
+ ){
+ U_swap4(ch + offsetof(U_BITMAPCOREHEADER,Size_4), 1); /* Size_4, may not be aligned */
+ U_swap2(ch + offsetof(U_BITMAPCOREHEADER,Width),4); /* Width, Height, Planes, BitCount, */
+}
+
+/** LogBrushW Object WMF PDF 2.2.2.10
+ \brief Swap a U_WLOGBRUSH object.
+ \param lb U_WLOGBRUSH object.
+
+ style Color Hatch
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined)
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+void wlogbrush_swap(
+ char *lb
+ ){
+ U_swap2(lb + offsetof(U_WLOGBRUSH,Style),1);
+ /* Color is already in order */
+ U_swap2(lb + offsetof(U_WLOGBRUSH,Hatch),1);
+}
+
+/**
+ \brief Swap U_POLYPOLY object from pointer
+ \param pp PU_POLYPOLY object
+*/
+void polypolygon_swap(
+ char *pp,
+ int torev
+ ){
+ int i,totPoints;
+ uint16_t nPolys;
+ uint16_t *aPolyCounts;
+ if(torev){ nPolys = *(uint16_t *)(pp + offsetof(U_POLYPOLYGON, nPolys)); }
+ U_swap2(pp + offsetof(U_POLYPOLYGON, nPolys),1);
+ if(!torev){ nPolys = *(uint16_t *)(pp + offsetof(U_POLYPOLYGON, nPolys)); }
+ aPolyCounts = (uint16_t *)(pp + offsetof(U_POLYPOLYGON, aPolyCounts));
+ if(torev){
+ for(totPoints=0,i=0;i<nPolys; i++){ totPoints += aPolyCounts[i]; }
+ }
+ U_swap2(aPolyCounts,nPolys);
+ if(!torev){
+ for(totPoints=0,i=0;i<nPolys; i++){ totPoints += aPolyCounts[i]; }
+ }
+ U_swap2(&(aPolyCounts[nPolys]),2*totPoints); /* 2 coords/ point */
+}
+
+/**
+ \brief Swap U_SCAN object
+ \param pp U_SCAN object
+*/
+void scan_swap(
+ char *sc,
+ int torev
+ ){
+ int count;
+ if(torev){ count = *(uint16_t *)sc; }
+ U_swap2(sc,3); /*count, top, bottom */
+ if(!torev){ count = *(uint16_t *)sc; }
+ U_swap2(sc + offsetof(U_SCAN,ScanLines),count);
+}
+
+/**
+ \brief Swap a summary of a DIB header
+ A DIB header in an WMF may be either a BitmapCoreHeader or BitmapInfoHeader.
+ \param dh void pointer to DIB header
+*/
+void dibheader_swap(
+ char *dh,
+ int torev
+ ){
+ int Size;
+ memcpy(&Size, dh, 4); /* may not be aligned */
+ if(!torev)U_swap4(&Size,1);
+ if(Size == 0xC){
+ bitmapcoreheader_swap(dh);
+ }
+ else {
+ bitmapinfo_swap(dh);
+ }
+}
+
+/**
+ \brief Swap WMF header object
+ \param head uint8_t pointer to header
+ \returns size of entire header structure
+
+ If the header is preceded by a placeable struture, Swap that as well.
+*/
+int wmfheader_swap(
+ char *contents,
+ int torev
+ ){
+ uint32_t Key,Size16w;
+ int size=0;
+ Key=*(uint32_t *)(contents + offsetof(U_WMRPLACEABLE,Key));
+ if(!torev)U_swap4(&Key,1);
+ if(Key == 0x9AC6CDD7){
+ U_swap4(contents + offsetof(U_WMRPLACEABLE,Key ),1);
+ U_swap2(contents + offsetof(U_WMRPLACEABLE,HWmf ),1);
+ U_swap2(contents + offsetof(U_WMRPLACEABLE,Dst ),4);
+ U_swap2(contents + offsetof(U_WMRPLACEABLE,Inch ),1);
+ U_swap4(contents + offsetof(U_WMRPLACEABLE,Reserved),1);
+ U_swap2(contents + offsetof(U_WMRPLACEABLE,Checksum),1);
+ contents += U_SIZE_WMRPLACEABLE;
+ size += U_SIZE_WMRPLACEABLE;
+ }
+ if(torev){ Size16w = *(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)); }
+ U_swap2(contents + offsetof(U_WMRHEADER,Size16w),2);/* Size16w, Version */
+ if(!torev){ Size16w = *(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w)); }
+ U_swap4(contents + offsetof(U_WMRHEADER,Sizew ),1);/* Sizew */
+ U_swap2(contents + offsetof(U_WMRHEADER,nObjects),1);/* nObjects */
+ U_swap4(contents + offsetof(U_WMRHEADER,maxSize ),1);/* maxSize */
+ U_swap2(contents + offsetof(U_WMRHEADER,nMembers),1);/* nMembers */
+ size += 2*Size16w;
+ return(size);
+}
+
+
+
+/* **********************************************************************************************
+These functions contain shared code used by various U_WMR*_Swap functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+*********************************************************************************************** */
+
+/* Size16 EVERY record type should call this, directly or indirectly*/
+void U_WMRCORE_SIZE16_swap(char *record, int torev){
+ UNUSED_PARAMETER(torev);
+ U_swap4(record, 1); /* Size16_4 is at offset 0 in U_METARECORD */
+}
+
+
+/* Size16, move to data, Single 32bit followed by array of N16 U_POINT16 */
+void U_WMRCORE_U32_N16_swap(char *record, int N16, int torev){
+ int off=U_SIZE_METARECORD;
+ U_WMRCORE_SIZE16_swap(record, torev);
+ U_swap4(record + off, 1); off+=4;
+ U_swap2(record + off, N16);
+}
+
+/* Single 16bit nPoints followed by array of nPoints U_POINT16 */
+void U_WMRCORE_U16_N16_swap(char *record, int torev){
+ int nPoints;
+ U_WMRCORE_SIZE16_swap(record, torev);
+ if(torev){ nPoints = *(uint16_t *)(record + offsetof(U_WMRPOLYGON,nPoints)); }
+ U_swap2(record + offsetof(U_WMRPOLYGON,nPoints), 1);
+ if(!torev){ nPoints = *(uint16_t *)(record + offsetof(U_WMRPOLYGON,nPoints)); }
+ U_swap2(record + offsetof(U_WMRPOLYGON,aPoints), 2*nPoints);
+}
+
+/* all records that specify palette objects */
+void U_WMRCORE_PALETTE_swap(char *record, int torev){
+ UNUSED_PARAMETER(torev);
+ U_WMRCORE_SIZE16_swap(record, torev);
+ palette_swap(record + offsetof(U_WMRANIMATEPALETTE,Palette));
+}
+
+/* all records that have N int16 values, unconditionally swapped */
+void U_WMRCORE_N16_swap(char *record, int N16, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ U_swap2(record+U_SIZE_METARECORD, N16);
+}
+
+
+/* like floodfill */
+void U_WMRCORE_U16_CR_2U16_swap(char *record, int torev){
+ int off = U_SIZE_METARECORD;
+ U_WMRCORE_SIZE16_swap(record, torev);
+ U_swap2(record+off, 1); off += 2 + sizeof(U_COLORREF);
+ U_swap2(record+off, 2);
+}
+
+/* **********************************************************************************************
+These are the core WMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_EMR_* index number.
+*********************************************************************************************** */
+
+/**
+ \brief Swap a pointer to a U_WMR_whatever record which has not been implemented.
+ \param name name of this type of record
+ \param contents pointer to a buffer holding all EMR records
+ \param recnum number of this record in contents
+ \param off offset to this record in contents
+*/
+void U_WMRNOTIMPLEMENTED_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMREOF_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRSETBKCOLOR_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRSETBKMODE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETMAPMODE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETROP2_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETRELABS_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRSETPOLYFILLMODE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETSTRETCHBLTMODE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETTEXTCHAREXTRA_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETTEXTCOLOR_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRSETTEXTJUSTIFICATION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSETWINDOWORG_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSETWINDOWEXT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSETVIEWPORTORG_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSETVIEWPORTEXT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMROFFSETWINDOWORG_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSCALEWINDOWEXT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMROFFSETVIEWPORTORG_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRSCALEVIEWPORTEXT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRLINETO_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRMOVETO_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMREXCLUDECLIPRECT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRINTERSECTCLIPRECT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRARC_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record, 8, torev);
+}
+
+void U_WMRELLIPSE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRFLOODFILL_swap(char *record, int torev){
+ U_WMRCORE_U16_CR_2U16_swap(record, torev);
+}
+
+void U_WMRPIE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record, 8, torev);
+}
+
+void U_WMRRECTANGLE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRROUNDRECT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,6,torev);
+}
+
+void U_WMRPATBLT_swap(char *record, int torev){
+ U_WMRCORE_U32_N16_swap(record,4,torev);
+}
+
+void U_WMRSAVEDC_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRSETPIXEL_swap(char *record, int torev){
+ int off = U_SIZE_METARECORD + sizeof(U_COLORREF);
+ U_WMRCORE_SIZE16_swap(record, torev);
+ U_swap2(record+off, 2);
+}
+
+void U_WMROFFSETCLIPRGN_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRTEXTOUT_swap(char *record, int torev){
+ int L2;
+ if(torev){ L2 = *(int16_t *)(record + U_SIZE_METARECORD); } /* Length field */
+ U_WMRCORE_N16_swap(record,1,torev); /* Length */
+ if(!torev){ L2 = *(int16_t *)(record + U_SIZE_METARECORD); } /* Length field */
+ /* string is in bytes, do not swap that */
+ U_swap2(record + U_SIZE_WMRTEXTOUT + L2, 2); /* y,x */
+}
+
+void U_WMRBITBLT_swap(char *record, int torev){
+ uint32_t Size16;
+ uint8_t xb;
+ memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4);
+ if(!torev)U_swap4(&Size16,1);
+ xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb));
+ if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */
+ U_WMRCORE_U32_N16_swap(record,7,torev);
+ }
+ else { /* yes bitmap */
+ U_WMRCORE_U32_N16_swap(record,6,torev);
+ bitmap16_swap(record + offsetof(U_WMRBITBLT_PX,bitmap));
+ }
+}
+
+void U_WMRSTRETCHBLT_swap(char *record, int torev){
+ uint32_t Size16;
+ uint8_t xb;
+ memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4);
+ if(!torev)U_swap4(&Size16,1);
+ xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb));
+ if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */
+ U_WMRCORE_U32_N16_swap(record,9,torev);
+ }
+ else { /* yes bitmap */
+ U_WMRCORE_U32_N16_swap(record,8,torev);
+ bitmap16_swap(record + offsetof(U_WMRSTRETCHBLT_PX,bitmap));
+ }
+}
+
+void U_WMRPOLYGON_swap(char *record, int torev){
+ U_WMRCORE_U16_N16_swap(record, torev);
+}
+
+void U_WMRPOLYLINE_swap(char *record, int torev){
+ U_WMRCORE_U16_N16_swap(record, torev);
+}
+
+void U_WMRESCAPE_swap(char *record, int torev){
+ uint16_t eFunc;
+
+ if(torev){ eFunc = *(uint16_t *)(record + offsetof(U_WMRESCAPE,eFunc)); }
+ U_WMRCORE_N16_swap(record,2,torev);
+ if(!torev){ eFunc = *(uint16_t *)(record + offsetof(U_WMRESCAPE,eFunc)); }
+ /* Handle data swapping for three types only, anything else end user code must handle */
+ if((eFunc == U_MFE_SETLINECAP) || (eFunc == U_MFE_SETLINEJOIN) || (eFunc == U_MFE_SETMITERLIMIT)){
+ U_swap4(record + offsetof(U_WMRESCAPE, Data),1);
+ }
+}
+
+void U_WMRRESTOREDC_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRFILLREGION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,2,torev);
+}
+
+void U_WMRFRAMEREGION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,4,torev);
+}
+
+void U_WMRINVERTREGION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRPAINTREGION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSELECTCLIPREGION_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSELECTOBJECT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRSETTEXTALIGN_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRDRAWTEXT_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCHORD_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record, 8, torev);
+}
+
+void U_WMRSETMAPPERFLAGS_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMREXTTEXTOUT_swap(char *record, int torev){
+ int off,Length,Len2,Opts;
+ U_swap4(record + offsetof(U_WMREXTTEXTOUT,Size16_4),1);
+ if(torev){
+ Length = *(int16_t *)( record + offsetof(U_WMREXTTEXTOUT,Length));
+ Opts = *(uint16_t *)(record + offsetof(U_WMREXTTEXTOUT,Opts));
+ }
+ U_swap2(record + offsetof(U_WMREXTTEXTOUT,y), 4); /* y,x,Length,Opts*/
+ if(!torev){
+ Length = *(int16_t *)( record + offsetof(U_WMREXTTEXTOUT,Length));
+ Opts = *(uint16_t *)(record + offsetof(U_WMREXTTEXTOUT,Opts));
+ }
+ off = U_SIZE_WMREXTTEXTOUT;
+ if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){
+ U_swap2(record + off,4); off += 8;
+ }
+ Len2 = (Length & 1 ? Length + 1 : Length);
+ off += Len2; /* no need to swap string, it is a byte array */
+ U_swap2(record+off,Length); /* swap the dx array */
+}
+
+void U_WMRSETDIBTODEV_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record, 9, torev);
+ dibheader_swap(record + offsetof(U_WMRSETDIBTODEV,dib), torev);
+}
+
+void U_WMRSELECTPALETTE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRREALIZEPALETTE_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+}
+
+void U_WMRANIMATEPALETTE_swap(char *record, int torev){
+ U_WMRCORE_PALETTE_swap(record, torev);
+}
+
+void U_WMRSETPALENTRIES_swap(char *record, int torev){
+ U_WMRCORE_PALETTE_swap(record, torev);
+}
+
+void U_WMRPOLYPOLYGON_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ polypolygon_swap(record + offsetof(U_WMRPOLYPOLYGON,PPolygon), torev);
+}
+
+void U_WMRRESIZEPALETTE_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMR3A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR3B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR3C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR3D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR3E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR3F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDIBBITBLT_swap(char *record, int torev){
+ uint32_t Size16;
+ uint8_t xb;
+ memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4);
+ if(!torev)U_swap4(&Size16,1);
+ xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb));
+ if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */
+ U_WMRCORE_U32_N16_swap(record,7,torev);
+ }
+ else { /* yes bitmap */
+ U_WMRCORE_U32_N16_swap(record,6,torev);
+ dibheader_swap(record + offsetof(U_WMRDIBBITBLT_PX,dib), torev);
+ }
+}
+
+void U_WMRDIBSTRETCHBLT_swap(char *record, int torev){
+ uint32_t Size16;
+ uint8_t xb;
+ memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4);
+ if(!torev)U_swap4(&Size16,1);
+ xb = *(uint8_t *)(record + offsetof(U_METARECORD,xb));
+ if(U_TEST_NOPX2(Size16,xb)){ /* no bitmap */
+ U_WMRCORE_U32_N16_swap(record,9,torev);
+ }
+ else { /* yes bitmap */
+ U_WMRCORE_U32_N16_swap(record,8,torev);
+ dibheader_swap(record + offsetof(U_WMRDIBSTRETCHBLT_PX,dib), torev);
+ }
+}
+
+void U_WMRDIBCREATEPATTERNBRUSH_swap(char *record, int torev){
+ int Style;
+ if(torev){ Style = *(uint16_t *)(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Style)); }
+ U_WMRCORE_N16_swap(record,2,torev); /* Style and cUsage */
+ if(!torev){ Style = *(uint16_t *)(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Style)); }
+ if(Style == U_BS_PATTERN){
+ bitmap16_swap(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Src));
+ }
+ else {
+ dibheader_swap(record + offsetof(U_WMRDIBCREATEPATTERNBRUSH,Src), torev);
+ }
+}
+
+void U_WMRSTRETCHDIB_swap(char *record, int torev){
+ UNUSED_PARAMETER(torev);
+ U_WMRCORE_U32_N16_swap(record,9,torev);
+ dibheader_swap(record + offsetof(U_WMRSTRETCHDIB,dib), torev);
+}
+
+void U_WMR44_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR45_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR46_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR47_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREXTFLOODFILL_swap(char *record, int torev){
+ U_WMRCORE_U16_CR_2U16_swap(record, torev);
+}
+
+void U_WMR49_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR4F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR50_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR51_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR52_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR53_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR54_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR55_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR56_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR57_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR58_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR59_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR5F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR60_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR61_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR62_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR63_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR64_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR65_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR66_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR67_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR68_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR69_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR6F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR70_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR71_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR72_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR73_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR74_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR75_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR76_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR77_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR78_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR79_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR7F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR80_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR81_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR82_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR83_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR84_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR85_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR86_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR87_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR88_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR89_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR8F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR90_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR91_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR92_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR93_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR94_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR95_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR96_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR97_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR98_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR99_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9A_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9B_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9C_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9D_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9E_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMR9F_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA0_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA7_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRA9_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAA_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAB_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAC_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAD_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAE_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRAF_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB0_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB7_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRB9_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBA_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBB_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBC_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBD_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBE_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRBF_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC0_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC7_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRC9_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCA_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCB_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCC_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCD_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCE_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCF_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD0_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD7_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRD9_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDA_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDB_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDC_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDD_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDE_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDF_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE0_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE7_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRE9_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREA_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREB_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREC_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRED_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREE_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMREF_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRDELETEOBJECT_swap(char *record, int torev){
+ U_WMRCORE_N16_swap(record,1,torev);
+}
+
+void U_WMRF1_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRF2_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRF3_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRF4_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRF5_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRF6_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCREATEPALETTE_swap(char *record, int torev){
+ U_WMRCORE_PALETTE_swap(record, torev);
+}
+
+void U_WMRF8_swap(char *record, int torev){
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCREATEPATTERNBRUSH_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ bitmap16_swap(record + U_SIZE_METARECORD);
+ /* pattern array byte order already correct? */
+}
+
+void U_WMRCREATEPENINDIRECT_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ pen_swap(record + offsetof(U_WMRCREATEPENINDIRECT,pen));
+}
+
+void U_WMRCREATEFONTINDIRECT_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ font_swap(record + offsetof(U_WMRCREATEFONTINDIRECT,font));
+}
+
+void U_WMRCREATEBRUSHINDIRECT_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ wlogbrush_swap(record + offsetof(U_WMRCREATEBRUSHINDIRECT,brush));
+}
+
+void U_WMRCREATEBITMAPINDIRECT_swap(char *record, int torev){ /* in Wine, not in WMF PDF */
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCREATEBITMAP_swap(char *record, int torev){ /* in Wine, not in WMF PDF */
+ U_WMRNOTIMPLEMENTED_swap(record, torev);
+}
+
+void U_WMRCREATEREGION_swap(char *record, int torev){
+ U_WMRCORE_SIZE16_swap(record, torev);
+ region_swap(record + offsetof(U_WMRCREATEREGION,region), torev);
+}
+//! \endcond
+
+/**
+ \brief Convert an entire WMF in memory from Big Endian to Little Endian (or vice versa).
+ \return 0 on failure, 1 on success
+ \param contents pointer to the buffer holding the entire EMF in memory
+ \param length number of bytes in the buffer
+ \param torev 1 for native to reversed, 0 for reversed to native
+ \param onerec 1 if this is operating on a single record instead of an entire file
+
+ Normally this would be called immediately before writing the data to a file
+ or immediately after reading the data from a file.
+*/
+int U_wmf_endian(char *contents, size_t length, int torev, int onerec){
+ size_t off=0;
+ uint32_t OK, Size16;
+ uint8_t iType;
+ char *record;
+ int recnum;
+ int offset=0;
+
+ record = contents;
+ if(!onerec){
+ off = wmfheader_swap(record,torev); fflush(stdout); /* WMF header is not a normal record, handle it separately */
+ record += off;
+ offset = off;
+ }
+ OK = 1;
+ recnum = 1; /* used when debugging */
+
+ while(OK){
+ if(record > contents + length){ return(0); } // this is most likely a corrupt WMF
+
+ memcpy(&Size16, record + offsetof(U_METARECORD,Size16_4), 4); /* This may not be aligned */
+ if(!torev){ U_swap4(&Size16,1); }
+ iType = *(uint8_t *)(record + offsetof(U_METARECORD,iType));
+
+//printf("DEBUG U_wmf_endian before switch record:%d offset:%d type:%d name:%s Size16:%d\n",recnum,offset,iType,U_wmr_names(iType),Size16);fflush(stdout);
+ switch (iType)
+ {
+ case U_WMR_EOF: U_WMREOF_swap(record, torev); OK=0; break;
+ case U_WMR_SETBKCOLOR: U_WMRSETBKCOLOR_swap(record, torev); break;
+ case U_WMR_SETBKMODE: U_WMRSETBKMODE_swap(record, torev); break;
+ case U_WMR_SETMAPMODE: U_WMRSETMAPMODE_swap(record, torev); break;
+ case U_WMR_SETROP2: U_WMRSETROP2_swap(record, torev); break;
+ case U_WMR_SETRELABS: U_WMRSETRELABS_swap(record, torev); break;
+ case U_WMR_SETPOLYFILLMODE: U_WMRSETPOLYFILLMODE_swap(record, torev); break;
+ case U_WMR_SETSTRETCHBLTMODE: U_WMRSETSTRETCHBLTMODE_swap(record, torev); break;
+ case U_WMR_SETTEXTCHAREXTRA: U_WMRSETTEXTCHAREXTRA_swap(record, torev); break;
+ case U_WMR_SETTEXTCOLOR: U_WMRSETTEXTCOLOR_swap(record, torev); break;
+ case U_WMR_SETTEXTJUSTIFICATION: U_WMRSETTEXTJUSTIFICATION_swap(record, torev); break;
+ case U_WMR_SETWINDOWORG: U_WMRSETWINDOWORG_swap(record, torev); break;
+ case U_WMR_SETWINDOWEXT: U_WMRSETWINDOWEXT_swap(record, torev); break;
+ case U_WMR_SETVIEWPORTORG: U_WMRSETVIEWPORTORG_swap(record, torev); break;
+ case U_WMR_SETVIEWPORTEXT: U_WMRSETVIEWPORTEXT_swap(record, torev); break;
+ case U_WMR_OFFSETWINDOWORG: U_WMROFFSETWINDOWORG_swap(record, torev); break;
+ case U_WMR_SCALEWINDOWEXT: U_WMRSCALEWINDOWEXT_swap(record, torev); break;
+ case U_WMR_OFFSETVIEWPORTORG: U_WMROFFSETVIEWPORTORG_swap(record, torev); break;
+ case U_WMR_SCALEVIEWPORTEXT: U_WMRSCALEVIEWPORTEXT_swap(record, torev); break;
+ case U_WMR_LINETO: U_WMRLINETO_swap(record, torev); break;
+ case U_WMR_MOVETO: U_WMRMOVETO_swap(record, torev); break;
+ case U_WMR_EXCLUDECLIPRECT: U_WMREXCLUDECLIPRECT_swap(record, torev); break;
+ case U_WMR_INTERSECTCLIPRECT: U_WMRINTERSECTCLIPRECT_swap(record, torev); break;
+ case U_WMR_ARC: U_WMRARC_swap(record, torev); break;
+ case U_WMR_ELLIPSE: U_WMRELLIPSE_swap(record, torev); break;
+ case U_WMR_FLOODFILL: U_WMRFLOODFILL_swap(record, torev); break;
+ case U_WMR_PIE: U_WMRPIE_swap(record, torev); break;
+ case U_WMR_RECTANGLE: U_WMRRECTANGLE_swap(record, torev); break;
+ case U_WMR_ROUNDRECT: U_WMRROUNDRECT_swap(record, torev); break;
+ case U_WMR_PATBLT: U_WMRPATBLT_swap(record, torev); break;
+ case U_WMR_SAVEDC: U_WMRSAVEDC_swap(record, torev); break;
+ case U_WMR_SETPIXEL: U_WMRSETPIXEL_swap(record, torev); break;
+ case U_WMR_OFFSETCLIPRGN: U_WMROFFSETCLIPRGN_swap(record, torev); break;
+ case U_WMR_TEXTOUT: U_WMRTEXTOUT_swap(record, torev); break;
+ case U_WMR_BITBLT: U_WMRBITBLT_swap(record, torev); break;
+ case U_WMR_STRETCHBLT: U_WMRSTRETCHBLT_swap(record, torev); break;
+ case U_WMR_POLYGON: U_WMRPOLYGON_swap(record, torev); break;
+ case U_WMR_POLYLINE: U_WMRPOLYLINE_swap(record, torev); break;
+ case U_WMR_ESCAPE: U_WMRESCAPE_swap(record, torev); break;
+ case U_WMR_RESTOREDC: U_WMRRESTOREDC_swap(record, torev); break;
+ case U_WMR_FILLREGION: U_WMRFILLREGION_swap(record, torev); break;
+ case U_WMR_FRAMEREGION: U_WMRFRAMEREGION_swap(record, torev); break;
+ case U_WMR_INVERTREGION: U_WMRINVERTREGION_swap(record, torev); break;
+ case U_WMR_PAINTREGION: U_WMRPAINTREGION_swap(record, torev); break;
+ case U_WMR_SELECTCLIPREGION: U_WMRSELECTCLIPREGION_swap(record, torev); break;
+ case U_WMR_SELECTOBJECT: U_WMRSELECTOBJECT_swap(record, torev); break;
+ case U_WMR_SETTEXTALIGN: U_WMRSETTEXTALIGN_swap(record, torev); break;
+ case U_WMR_DRAWTEXT: U_WMRDRAWTEXT_swap(record, torev); break;
+ case U_WMR_CHORD: U_WMRCHORD_swap(record, torev); break;
+ case U_WMR_SETMAPPERFLAGS: U_WMRSETMAPPERFLAGS_swap(record, torev); break;
+ case U_WMR_EXTTEXTOUT: U_WMREXTTEXTOUT_swap(record, torev); break;
+ case U_WMR_SETDIBTODEV: U_WMRSETDIBTODEV_swap(record, torev); break;
+ case U_WMR_SELECTPALETTE: U_WMRSELECTPALETTE_swap(record, torev); break;
+ case U_WMR_REALIZEPALETTE: U_WMRREALIZEPALETTE_swap(record, torev); break;
+ case U_WMR_ANIMATEPALETTE: U_WMRANIMATEPALETTE_swap(record, torev); break;
+ case U_WMR_SETPALENTRIES: U_WMRSETPALENTRIES_swap(record, torev); break;
+ case U_WMR_POLYPOLYGON: U_WMRPOLYPOLYGON_swap(record, torev); break;
+ case U_WMR_RESIZEPALETTE: U_WMRRESIZEPALETTE_swap(record, torev); break;
+ case U_WMR_3A: U_WMR3A_swap(record, torev); break;
+ case U_WMR_3B: U_WMR3B_swap(record, torev); break;
+ case U_WMR_3C: U_WMR3C_swap(record, torev); break;
+ case U_WMR_3D: U_WMR3D_swap(record, torev); break;
+ case U_WMR_3E: U_WMR3E_swap(record, torev); break;
+ case U_WMR_3F: U_WMR3F_swap(record, torev); break;
+ case U_WMR_DIBBITBLT: U_WMRDIBBITBLT_swap(record, torev); break;
+ case U_WMR_DIBSTRETCHBLT: U_WMRDIBSTRETCHBLT_swap(record, torev); break;
+ case U_WMR_DIBCREATEPATTERNBRUSH: U_WMRDIBCREATEPATTERNBRUSH_swap(record, torev); break;
+ case U_WMR_STRETCHDIB: U_WMRSTRETCHDIB_swap(record, torev); break;
+ case U_WMR_44: U_WMR44_swap(record, torev); break;
+ case U_WMR_45: U_WMR45_swap(record, torev); break;
+ case U_WMR_46: U_WMR46_swap(record, torev); break;
+ case U_WMR_47: U_WMR47_swap(record, torev); break;
+ case U_WMR_EXTFLOODFILL: U_WMREXTFLOODFILL_swap(record, torev); break;
+ case U_WMR_49: U_WMR49_swap(record, torev); break;
+ case U_WMR_4A: U_WMR4A_swap(record, torev); break;
+ case U_WMR_4B: U_WMR4B_swap(record, torev); break;
+ case U_WMR_4C: U_WMR4C_swap(record, torev); break;
+ case U_WMR_4D: U_WMR4D_swap(record, torev); break;
+ case U_WMR_4E: U_WMR4E_swap(record, torev); break;
+ case U_WMR_4F: U_WMR4F_swap(record, torev); break;
+ case U_WMR_50: U_WMR50_swap(record, torev); break;
+ case U_WMR_51: U_WMR51_swap(record, torev); break;
+ case U_WMR_52: U_WMR52_swap(record, torev); break;
+ case U_WMR_53: U_WMR53_swap(record, torev); break;
+ case U_WMR_54: U_WMR54_swap(record, torev); break;
+ case U_WMR_55: U_WMR55_swap(record, torev); break;
+ case U_WMR_56: U_WMR56_swap(record, torev); break;
+ case U_WMR_57: U_WMR57_swap(record, torev); break;
+ case U_WMR_58: U_WMR58_swap(record, torev); break;
+ case U_WMR_59: U_WMR59_swap(record, torev); break;
+ case U_WMR_5A: U_WMR5A_swap(record, torev); break;
+ case U_WMR_5B: U_WMR5B_swap(record, torev); break;
+ case U_WMR_5C: U_WMR5C_swap(record, torev); break;
+ case U_WMR_5D: U_WMR5D_swap(record, torev); break;
+ case U_WMR_5E: U_WMR5E_swap(record, torev); break;
+ case U_WMR_5F: U_WMR5F_swap(record, torev); break;
+ case U_WMR_60: U_WMR60_swap(record, torev); break;
+ case U_WMR_61: U_WMR61_swap(record, torev); break;
+ case U_WMR_62: U_WMR62_swap(record, torev); break;
+ case U_WMR_63: U_WMR63_swap(record, torev); break;
+ case U_WMR_64: U_WMR64_swap(record, torev); break;
+ case U_WMR_65: U_WMR65_swap(record, torev); break;
+ case U_WMR_66: U_WMR66_swap(record, torev); break;
+ case U_WMR_67: U_WMR67_swap(record, torev); break;
+ case U_WMR_68: U_WMR68_swap(record, torev); break;
+ case U_WMR_69: U_WMR69_swap(record, torev); break;
+ case U_WMR_6A: U_WMR6A_swap(record, torev); break;
+ case U_WMR_6B: U_WMR6B_swap(record, torev); break;
+ case U_WMR_6C: U_WMR6C_swap(record, torev); break;
+ case U_WMR_6D: U_WMR6D_swap(record, torev); break;
+ case U_WMR_6E: U_WMR6E_swap(record, torev); break;
+ case U_WMR_6F: U_WMR6F_swap(record, torev); break;
+ case U_WMR_70: U_WMR70_swap(record, torev); break;
+ case U_WMR_71: U_WMR71_swap(record, torev); break;
+ case U_WMR_72: U_WMR72_swap(record, torev); break;
+ case U_WMR_73: U_WMR73_swap(record, torev); break;
+ case U_WMR_74: U_WMR74_swap(record, torev); break;
+ case U_WMR_75: U_WMR75_swap(record, torev); break;
+ case U_WMR_76: U_WMR76_swap(record, torev); break;
+ case U_WMR_77: U_WMR77_swap(record, torev); break;
+ case U_WMR_78: U_WMR78_swap(record, torev); break;
+ case U_WMR_79: U_WMR79_swap(record, torev); break;
+ case U_WMR_7A: U_WMR7A_swap(record, torev); break;
+ case U_WMR_7B: U_WMR7B_swap(record, torev); break;
+ case U_WMR_7C: U_WMR7C_swap(record, torev); break;
+ case U_WMR_7D: U_WMR7D_swap(record, torev); break;
+ case U_WMR_7E: U_WMR7E_swap(record, torev); break;
+ case U_WMR_7F: U_WMR7F_swap(record, torev); break;
+ case U_WMR_80: U_WMR80_swap(record, torev); break;
+ case U_WMR_81: U_WMR81_swap(record, torev); break;
+ case U_WMR_82: U_WMR82_swap(record, torev); break;
+ case U_WMR_83: U_WMR83_swap(record, torev); break;
+ case U_WMR_84: U_WMR84_swap(record, torev); break;
+ case U_WMR_85: U_WMR85_swap(record, torev); break;
+ case U_WMR_86: U_WMR86_swap(record, torev); break;
+ case U_WMR_87: U_WMR87_swap(record, torev); break;
+ case U_WMR_88: U_WMR88_swap(record, torev); break;
+ case U_WMR_89: U_WMR89_swap(record, torev); break;
+ case U_WMR_8A: U_WMR8A_swap(record, torev); break;
+ case U_WMR_8B: U_WMR8B_swap(record, torev); break;
+ case U_WMR_8C: U_WMR8C_swap(record, torev); break;
+ case U_WMR_8D: U_WMR8D_swap(record, torev); break;
+ case U_WMR_8E: U_WMR8E_swap(record, torev); break;
+ case U_WMR_8F: U_WMR8F_swap(record, torev); break;
+ case U_WMR_90: U_WMR90_swap(record, torev); break;
+ case U_WMR_91: U_WMR91_swap(record, torev); break;
+ case U_WMR_92: U_WMR92_swap(record, torev); break;
+ case U_WMR_93: U_WMR93_swap(record, torev); break;
+ case U_WMR_94: U_WMR94_swap(record, torev); break;
+ case U_WMR_95: U_WMR95_swap(record, torev); break;
+ case U_WMR_96: U_WMR96_swap(record, torev); break;
+ case U_WMR_97: U_WMR97_swap(record, torev); break;
+ case U_WMR_98: U_WMR98_swap(record, torev); break;
+ case U_WMR_99: U_WMR99_swap(record, torev); break;
+ case U_WMR_9A: U_WMR9A_swap(record, torev); break;
+ case U_WMR_9B: U_WMR9B_swap(record, torev); break;
+ case U_WMR_9C: U_WMR9C_swap(record, torev); break;
+ case U_WMR_9D: U_WMR9D_swap(record, torev); break;
+ case U_WMR_9E: U_WMR9E_swap(record, torev); break;
+ case U_WMR_9F: U_WMR9F_swap(record, torev); break;
+ case U_WMR_A0: U_WMRA0_swap(record, torev); break;
+ case U_WMR_A1: U_WMRA1_swap(record, torev); break;
+ case U_WMR_A2: U_WMRA2_swap(record, torev); break;
+ case U_WMR_A3: U_WMRA3_swap(record, torev); break;
+ case U_WMR_A4: U_WMRA4_swap(record, torev); break;
+ case U_WMR_A5: U_WMRA5_swap(record, torev); break;
+ case U_WMR_A6: U_WMRA6_swap(record, torev); break;
+ case U_WMR_A7: U_WMRA7_swap(record, torev); break;
+ case U_WMR_A8: U_WMRA8_swap(record, torev); break;
+ case U_WMR_A9: U_WMRA9_swap(record, torev); break;
+ case U_WMR_AA: U_WMRAA_swap(record, torev); break;
+ case U_WMR_AB: U_WMRAB_swap(record, torev); break;
+ case U_WMR_AC: U_WMRAC_swap(record, torev); break;
+ case U_WMR_AD: U_WMRAD_swap(record, torev); break;
+ case U_WMR_AE: U_WMRAE_swap(record, torev); break;
+ case U_WMR_AF: U_WMRAF_swap(record, torev); break;
+ case U_WMR_B0: U_WMRB0_swap(record, torev); break;
+ case U_WMR_B1: U_WMRB1_swap(record, torev); break;
+ case U_WMR_B2: U_WMRB2_swap(record, torev); break;
+ case U_WMR_B3: U_WMRB3_swap(record, torev); break;
+ case U_WMR_B4: U_WMRB4_swap(record, torev); break;
+ case U_WMR_B5: U_WMRB5_swap(record, torev); break;
+ case U_WMR_B6: U_WMRB6_swap(record, torev); break;
+ case U_WMR_B7: U_WMRB7_swap(record, torev); break;
+ case U_WMR_B8: U_WMRB8_swap(record, torev); break;
+ case U_WMR_B9: U_WMRB9_swap(record, torev); break;
+ case U_WMR_BA: U_WMRBA_swap(record, torev); break;
+ case U_WMR_BB: U_WMRBB_swap(record, torev); break;
+ case U_WMR_BC: U_WMRBC_swap(record, torev); break;
+ case U_WMR_BD: U_WMRBD_swap(record, torev); break;
+ case U_WMR_BE: U_WMRBE_swap(record, torev); break;
+ case U_WMR_BF: U_WMRBF_swap(record, torev); break;
+ case U_WMR_C0: U_WMRC0_swap(record, torev); break;
+ case U_WMR_C1: U_WMRC1_swap(record, torev); break;
+ case U_WMR_C2: U_WMRC2_swap(record, torev); break;
+ case U_WMR_C3: U_WMRC3_swap(record, torev); break;
+ case U_WMR_C4: U_WMRC4_swap(record, torev); break;
+ case U_WMR_C5: U_WMRC5_swap(record, torev); break;
+ case U_WMR_C6: U_WMRC6_swap(record, torev); break;
+ case U_WMR_C7: U_WMRC7_swap(record, torev); break;
+ case U_WMR_C8: U_WMRC8_swap(record, torev); break;
+ case U_WMR_C9: U_WMRC9_swap(record, torev); break;
+ case U_WMR_CA: U_WMRCA_swap(record, torev); break;
+ case U_WMR_CB: U_WMRCB_swap(record, torev); break;
+ case U_WMR_CC: U_WMRCC_swap(record, torev); break;
+ case U_WMR_CD: U_WMRCD_swap(record, torev); break;
+ case U_WMR_CE: U_WMRCE_swap(record, torev); break;
+ case U_WMR_CF: U_WMRCF_swap(record, torev); break;
+ case U_WMR_D0: U_WMRD0_swap(record, torev); break;
+ case U_WMR_D1: U_WMRD1_swap(record, torev); break;
+ case U_WMR_D2: U_WMRD2_swap(record, torev); break;
+ case U_WMR_D3: U_WMRD3_swap(record, torev); break;
+ case U_WMR_D4: U_WMRD4_swap(record, torev); break;
+ case U_WMR_D5: U_WMRD5_swap(record, torev); break;
+ case U_WMR_D6: U_WMRD6_swap(record, torev); break;
+ case U_WMR_D7: U_WMRD7_swap(record, torev); break;
+ case U_WMR_D8: U_WMRD8_swap(record, torev); break;
+ case U_WMR_D9: U_WMRD9_swap(record, torev); break;
+ case U_WMR_DA: U_WMRDA_swap(record, torev); break;
+ case U_WMR_DB: U_WMRDB_swap(record, torev); break;
+ case U_WMR_DC: U_WMRDC_swap(record, torev); break;
+ case U_WMR_DD: U_WMRDD_swap(record, torev); break;
+ case U_WMR_DE: U_WMRDE_swap(record, torev); break;
+ case U_WMR_DF: U_WMRDF_swap(record, torev); break;
+ case U_WMR_E0: U_WMRE0_swap(record, torev); break;
+ case U_WMR_E1: U_WMRE1_swap(record, torev); break;
+ case U_WMR_E2: U_WMRE2_swap(record, torev); break;
+ case U_WMR_E3: U_WMRE3_swap(record, torev); break;
+ case U_WMR_E4: U_WMRE4_swap(record, torev); break;
+ case U_WMR_E5: U_WMRE5_swap(record, torev); break;
+ case U_WMR_E6: U_WMRE6_swap(record, torev); break;
+ case U_WMR_E7: U_WMRE7_swap(record, torev); break;
+ case U_WMR_E8: U_WMRE8_swap(record, torev); break;
+ case U_WMR_E9: U_WMRE9_swap(record, torev); break;
+ case U_WMR_EA: U_WMREA_swap(record, torev); break;
+ case U_WMR_EB: U_WMREB_swap(record, torev); break;
+ case U_WMR_EC: U_WMREC_swap(record, torev); break;
+ case U_WMR_ED: U_WMRED_swap(record, torev); break;
+ case U_WMR_EE: U_WMREE_swap(record, torev); break;
+ case U_WMR_EF: U_WMREF_swap(record, torev); break;
+ case U_WMR_DELETEOBJECT: U_WMRDELETEOBJECT_swap(record, torev); break;
+ case U_WMR_F1: U_WMRF1_swap(record, torev); break;
+ case U_WMR_F2: U_WMRF2_swap(record, torev); break;
+ case U_WMR_F3: U_WMRF3_swap(record, torev); break;
+ case U_WMR_F4: U_WMRF4_swap(record, torev); break;
+ case U_WMR_F5: U_WMRF5_swap(record, torev); break;
+ case U_WMR_F6: U_WMRF6_swap(record, torev); break;
+ case U_WMR_CREATEPALETTE: U_WMRCREATEPALETTE_swap(record, torev); break;
+ case U_WMR_F8: U_WMRF8_swap(record, torev); break;
+ case U_WMR_CREATEPATTERNBRUSH: U_WMRCREATEPATTERNBRUSH_swap(record, torev); break;
+ case U_WMR_CREATEPENINDIRECT: U_WMRCREATEPENINDIRECT_swap(record, torev); break;
+ case U_WMR_CREATEFONTINDIRECT: U_WMRCREATEFONTINDIRECT_swap(record, torev); break;
+ case U_WMR_CREATEBRUSHINDIRECT: U_WMRCREATEBRUSHINDIRECT_swap(record, torev); break;
+ case U_WMR_CREATEBITMAPINDIRECT: U_WMRCREATEBITMAPINDIRECT_swap(record, torev); break;
+ case U_WMR_CREATEBITMAP: U_WMRCREATEBITMAP_swap(record, torev); break;
+ case U_WMR_CREATEREGION: U_WMRCREATEREGION_swap(record, torev); break;
+ default: U_WMRNOTIMPLEMENTED_swap(record, torev); break;
+ } //end of switch
+ if(onerec)break;
+ record += 2*Size16;
+ offset += 2*Size16;
+ recnum++;
+ } //end of while
+ return(1);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uwmf_endian.h b/src/3rdparty/libuemf/uwmf_endian.h
new file mode 100644
index 000000000..6ce7f1984
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf_endian.h
@@ -0,0 +1,34 @@
+/**
+ @file uwmf_endian.h
+
+ @brief Prototypes for functions for converting WMF records between Big Endian and Little Endian
+*/
+
+/*
+File: uwmf_endian.h
+Version: 0.0.3
+Date: 28-APR-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UWMF_ENDIAN_
+#define _UWMF_ENDIAN_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "uemf_endian.h"
+
+//! \cond
+// prototypes
+int U_wmf_endian(char *contents, size_t length, int torev, int onerec);
+//! \endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UWMF_ENDIAN_ */
diff --git a/src/3rdparty/libuemf/uwmf_print.c b/src/3rdparty/libuemf/uwmf_print.c
new file mode 100644
index 000000000..d6d1b584e
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf_print.c
@@ -0,0 +1,1635 @@
+/**
+ @file uwmf_print.c
+
+ @brief Functions for printing WMF records
+*/
+
+/*
+File: uwmf_print.c
+Version: 0.0.6
+Date: 21-MAY-2015
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h> /* for offsetof() macro */
+#include <string.h>
+#include "uwmf_print.h"
+
+//! \cond
+
+#define UNUSED(x) (void)(x)
+
+/* **********************************************************************************************
+ These functions print standard objects used in the WMR records.
+ The low level ones do not append EOL.
+*********************************************************************************************** */
+
+/* many of these are implemented in uemf_print.c and not replicated here */
+
+
+
+/**
+ \brief Print a U_BRUSH object.
+ \param b U_BRUSH object.
+ style bColor bHatch
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored Bitmap16 object holding patern
+ U_BS_DIBPATTERNPT ColorUsage Enum DIB object
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+void brush_print(
+ U_BRUSH b
+ ){
+ uint16_t hatch;
+ U_COLORREF Color;
+ switch(b.Style){
+ case U_BS_SOLID:
+ memcpy(&Color, &b.Color, sizeof(U_COLORREF));
+ printf("Color:"); colorref_print(Color);
+ break;
+ case U_BS_NULL:
+ printf("Null");
+ break;
+ case U_BS_PATTERN:
+ printf("Pattern:(not shown)");
+ break;
+ case U_BS_DIBPATTERNPT:
+ printf("DIBPattern:(not shown)");
+ break;
+ case U_BS_HATCHED:
+ memcpy(&hatch, b.Data, 2);
+ printf("Hatch:0x%4.4X ", hatch);
+ break;
+ }
+}
+
+/**
+ \brief Print a U_FONT object from a char *pointer.
+ The U_FONT struct object may not be properly aligned, but all of the fields within it will
+ OK for alignment.
+ \param font U_FONT object (as a char * pointer)
+*/
+void font_print(
+ const char *font
+ ){
+ printf("Height:%d ", *(int16_t *)(font + offsetof(U_FONT,Height )));
+ printf("Width:%d ", *(int16_t *)(font + offsetof(U_FONT,Width )));
+ printf("Escapement:%d ", *(int16_t *)(font + offsetof(U_FONT,Escapement )));
+ printf("Orientation:%d ", *(int16_t *)(font + offsetof(U_FONT,Orientation )));
+ printf("Weight:%d ", *(int16_t *)(font + offsetof(U_FONT,Weight )));
+ printf("Italic:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Italic )));
+ printf("Underline:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Underline )));
+ printf("StrikeOut:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,StrikeOut )));
+ printf("CharSet:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,CharSet )));
+ printf("OutPrecision:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,OutPrecision )));
+ printf("ClipPrecision:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,ClipPrecision )));
+ printf("Quality:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,Quality )));
+ printf("PitchAndFamily:0x%2.2X ", *(uint8_t *)(font + offsetof(U_FONT,PitchAndFamily)));
+ printf("FaceName:%s ", (font + offsetof(U_FONT,FaceName )));
+}
+
+
+/**
+ \brief Print a U_PLTNTRY object.
+ \param pny U_PLTNTRY object.
+*/
+void pltntry_print(
+ U_PLTNTRY pny
+ ){
+ printf("Value:%u ", pny.Value);
+ printf("Red:%u ", pny.Red );
+ printf("Green:%u ", pny.Green);
+ printf("Blue:%u ", pny.Blue );
+}
+
+
+/**
+ \brief Print a pointer to a U_PALETTE object.
+ \param p Pointer to a U_PALETTE object
+ \param PalEntries Array of Palette Entries
+*/
+void palette_print(
+ const U_PALETTE *p,
+ const char *PalEntries
+ ){
+ int i;
+ U_PLTNTRY pny;
+
+ printf("Start:%X ", p->Start );
+ printf("NumEntries:%u ",p->NumEntries );
+ if(p->NumEntries && PalEntries){
+ for(i=0; i < p->NumEntries; i++, PalEntries += sizeof(U_PLTNTRY)){
+ memcpy(&pny, PalEntries, sizeof(U_PLTNTRY));
+ printf("%d:",i); pltntry_print(pny);
+ }
+ }
+}
+
+/**
+ \brief Print a U_PEN object.
+ \param p U_PEN object
+ uint16_t Style; //!< PenStyle Enumeration
+ uint16_t Width; //!< Pen Width in object dimensions
+ uint16_t unused; //!< unused
+ union {
+ U_COLORREF Color; //!< Pen color (NOT aligned on 4n byte boundary!)
+ uint16_t Colorw[2]; //!< reassemble/store the Color value using these, NOT Color.
+ };
+*/
+void pen_print(
+ U_PEN p
+ ){
+ U_COLORREF Color;
+ printf("Style:0x%8.8X " ,p.Style );
+ printf("Width:%u " ,p.Widthw[0] );
+ memcpy(&Color, &p.Color, sizeof(U_COLORREF));
+ printf("Color"); colorref_print(Color);
+}
+
+/**
+ \brief Print U_RECT16 object
+ Prints in order left, top, right, bottom
+ \param rect U_RECT16 object
+*/
+void rect16_ltrb_print(
+ U_RECT16 rect
+ ){
+ printf("LTRB{%d,%d,%d,%d} ",rect.left,rect.top,rect.right,rect.bottom);
+}
+
+/**
+ \brief Print U_RECT16 object
+ Some WMF rects use the order bottom, right, top, left. These are passed in using
+ the same structure as for a normal U_RECT16 so:
+ position holds
+ left bottom
+ top right
+ right top
+ bottom left
+ This is used by WMR_RECTANGLE and many others.
+ \param rect U_RECT16 object
+*/
+void rect16_brtl_print(
+ U_RECT16 rect
+ ){
+ printf("BRTL{%d,%d,%d,%d} ",rect.bottom,rect.right,rect.top,rect.left);
+}
+
+
+
+/**
+ \brief Print U_REGION object from a char * pointer.
+ \param region U_REGION object
+*/
+void region_print(
+ const char *region
+ ){
+ U_RECT16 rect16;
+ printf("Type:%d ", *(uint16_t *)(region + offsetof(U_REGION,Type )));
+ printf("Size:%d ", *( int16_t *)(region + offsetof(U_REGION,Size )));
+ printf("sCount:%d ",*( int16_t *)(region + offsetof(U_REGION,sCount)));
+ printf("sMax:%d ", *( int16_t *)(region + offsetof(U_REGION,sMax )));
+ memcpy(&rect16, (region + offsetof(U_REGION,sRect )), sizeof(U_RECT16));
+ printf("sRect: "); rect16_ltrb_print(rect16);
+}
+
+
+/**
+ \brief Print U_BITMAP16 object
+ \param b U_BITMAP16 object
+*/
+void bitmap16_print(
+ U_BITMAP16 b
+ ){
+ printf("Type:%d ", b.Type );
+ printf("Width:%d ", b.Width );
+ printf("Height:%d ", b.Height );
+ printf("WidthBytes:%d ", b.WidthBytes);
+ printf("Planes:%d ", b.Planes );
+ printf("BitsPixel:%d ", b.BitsPixel );
+ printf("BitsBytes:%d ", (((b.Width * b.BitsPixel + 15) >> 4) << 1) * b.Height );
+}
+
+/**
+ \brief Print U_BITMAPCOREHEADER object
+ \param ch U_BITMAPCOREHEADER object
+*/
+void bitmapcoreheader_print(
+ U_BITMAPCOREHEADER ch
+ ){
+ uint32_t Size;
+ memcpy(&Size, &(ch.Size_4), 4); /* will be aligned, but is in two pieces */
+ printf("Size:%d ", Size);
+ printf("Width:%d ", ch.Width);
+ printf("Height:%d ", ch.Height);
+ printf("Planes:%d ", ch.Planes);
+ printf("BitCount:%d ", ch.BitCount);
+}
+
+/** LogBrushW Object WMF PDF 2.2.2.10
+ \brief Print a U_LOGBRUSHW object.
+ \param lb U_LOGBRUSHW object.
+
+ style Color Hatch
+ U_BS_SOLID ColorRef Object Not used (bytes present???)
+ U_BS_NULL ignored ignored (bytes present???).
+ U_BS_PATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERN ignored not used (Action is not strictly defined)
+ U_BS_DIBPATTERNPT ignored not used (Action is not strictly defined)
+ U_BS_HATCHED ColorRef Object HatchStyle Enumeration
+*/
+void wlogbrush_print(
+ const char *lb
+ ){
+ U_COLORREF Color;
+ uint16_t Style = *(uint16_t *)(lb + offsetof(U_WLOGBRUSH,Style));
+ uint16_t Hatch = *(uint16_t *)(lb + offsetof(U_WLOGBRUSH,Hatch));
+ memcpy(&Color, lb + offsetof(U_WLOGBRUSH,Color), sizeof(U_COLORREF));
+ printf("Style:0x%4.4X ",Style);
+ switch(Style){
+ case U_BS_SOLID:
+ printf("Color:"); colorref_print(Color);
+ break;
+ case U_BS_NULL:
+ printf("Null");
+ break;
+ case U_BS_PATTERN:
+ printf("Pattern:(not implemented)");
+ break;
+ case U_BS_DIBPATTERN:
+ printf("DIBPattern:(not implemented)");
+ break;
+ case U_BS_DIBPATTERNPT:
+ printf("DIBPatternPt:(not implemented)");
+ break;
+ case U_BS_HATCHED:
+ printf("Color:"); colorref_print(Color);
+ printf("Hatch:0x%4.4X ", Hatch);
+ break;
+ }
+}
+
+
+/**
+ \brief Print U_POLYPOLY object from pointer
+ \param nPolys Number of elements in aPolyCounts
+ \param aPolyCounts Number of points in each poly (sequential)
+ \param Points pointer to array of U_POINT16 in memory. Probably not aligned.
+*/
+void polypolygon_print(
+ uint16_t nPolys,
+ const uint16_t *aPolyCounts,
+ const char *Points
+ ){
+ int i,j;
+ U_POINT16 pt;
+ for(i=0; i<nPolys; i++, aPolyCounts++){
+ printf(" Polygon[%d]: ",i);
+ for(j=0; j < *aPolyCounts; j++, Points += sizeof(U_POINT16)){
+ memcpy(&pt, Points, sizeof(U_POINT16)); /* may not be aligned */
+ point16_print(pt);
+ }
+ }
+}
+
+/**
+ \brief Print U_SCAN object
+ \param sc U_SCAN object
+*/
+void scan_print(
+ U_SCAN sc
+ ){
+ printf("Count:%d ", sc.count);
+ printf("Top:%d ", sc.top);
+ printf("Bottom:%d ", sc.bottom);
+ printf("data:(not shown)");
+}
+
+/**
+ \brief Print a summary of a DIB header
+ \param dh void pointer to DIB header
+ A DIB header in an WMF may be either a BitmapCoreHeader or BitmapInfoHeader.
+*/
+void dibheader_print(const char *dh, const char *blimit){
+ uint32_t Size;
+ memcpy(&Size, dh, 4); /* may not be aligned */
+ if(Size == 0xC ){
+ printf("(BitmapCoreHeader) ");
+ U_BITMAPCOREHEADER bmch;
+ memcpy(&bmch, dh, sizeof(U_BITMAPCOREHEADER)); /* may not be aligned */
+ bitmapcoreheader_print(bmch);
+ }
+ else {
+ printf(" (BitmapInfoHeader) ");
+ bitmapinfo_print(dh, blimit); /* may not be aligned, called routine must handle it */
+ }
+}
+
+/**
+ \brief Print WMF header object
+ \returns size of entire header structure
+ \param contents pointer to the first byte in the buffer holding the entire WMF file in memory
+ \param blimit pointer to the byte after the last byte in contents
+
+ If the header is preceded by a placeable struture, print that as well.
+*/
+int wmfheader_print(
+ const char *contents,
+ const char *blimit
+ ){
+ U_WMRPLACEABLE Placeable;
+ U_WMRHEADER Header;
+ int size = wmfheader_get(contents, blimit, &Placeable, &Header);
+ uint32_t utmp4;
+ U_RECT16 rect16;
+ uint32_t Key;
+ memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4);
+ if(Placeable.Key == 0x9AC6CDD7){
+ printf("WMF, Placeable: ");
+ printf("HWmf:%u ", Placeable.HWmf);
+ memcpy(&rect16, &(Placeable.Dst), sizeof(U_RECT16));
+ printf("Box:"); rect16_ltrb_print(rect16);
+ printf("Inch:%u ", Placeable.Inch);
+ printf("Checksum:%d ", Placeable.Checksum);
+ printf("Calculated_Checksum:%d\n",U_16_checksum((int16_t *)contents,10));
+ }
+ else {
+ printf("WMF, Not Placeable\n");
+ }
+ printf(" RecType:%d\n", Header.iType);
+ printf(" 16bit words in record:%d\n", Header.Size16w);
+ printf(" Version:%d\n", Header.version);
+ memcpy(&utmp4, &(Header.Sizew),4);
+ printf(" 16bit words in file:%d\n",utmp4);
+ printf(" Objects:%d\n", Header.nObjects);
+ memcpy(&utmp4, &(Header.maxSize),4);
+ printf(" Largest Record:%d\n", utmp4);
+ printf(" nMembers:%d\n", Header.nMembers);
+
+ return(size);
+}
+
+
+
+/* **********************************************************************************************
+These functions contain shared code used by various U_WMR*_print functions. These should NEVER be called
+by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
+*********************************************************************************************** */
+
+
+void wcore_points_print(uint16_t nPoints, const char *aPoints){
+ int i;
+ U_POINT16 pt;
+ printf(" Points: ");
+ for(i=0;i<nPoints; i++){
+ memcpy(&pt, aPoints + i*4, sizeof(U_POINT16)); /* aPoints U_POINT16 structure may not be aligned, so copy it out */
+ printf("[%d]:",i); point16_print(pt);
+ }
+ printf("\n");
+}
+
+
+
+/* **********************************************************************************************
+These are the core WMR functions, each creates a particular type of record.
+All return these records via a char* pointer, which is NULL if the call failed.
+They are listed in order by the corresponding U_WMR_* index number.
+*********************************************************************************************** */
+
+/**
+ \brief Print a pointer to a U_WMR_whatever record which has not been implemented.
+ \param contents pointer to a buffer holding a WMR record
+*/
+void U_WMRNOTIMPLEMENTED_print(const char *contents){
+ UNUSED(contents);
+ printf(" Not Implemented!\n");
+}
+
+void U_WMREOF_print(const char *contents){
+ UNUSED(contents);
+}
+
+void U_WMRSETBKCOLOR_print(const char *contents){
+ U_COLORREF Color;
+ int size = U_WMRSETBKCOLOR_get(contents, &Color);
+ if(size>0){
+ printf(" %-15s ","Color:"); colorref_print(Color); printf("\n");
+ }
+}
+
+void U_WMRSETBKMODE_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETBKMODE_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETMAPMODE_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETMAPMODE_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETROP2_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETROP2_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETRELABS_print(const char *contents){
+ UNUSED(contents);
+ /* This record type has only the common 6 bytes, so nothing (else) to print */
+}
+
+void U_WMRSETPOLYFILLMODE_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETPOLYFILLMODE_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETSTRETCHBLTMODE_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETSTRETCHBLTMODE_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETTEXTCHAREXTRA_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETTEXTCHAREXTRA_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+void U_WMRSETTEXTCOLOR_print(const char *contents){
+ U_COLORREF Color;
+ int size = U_WMRSETTEXTCOLOR_get(contents, &Color);
+ if(size>0){
+ printf(" %-15s ","Color:"); colorref_print(Color); printf("\n");
+ }
+}
+
+void U_WMRSETTEXTJUSTIFICATION_print(const char *contents){
+ uint16_t Count;
+ uint16_t Extra;
+ int size = U_WMRSETTEXTJUSTIFICATION_get(contents, &Count, &Extra);
+ if(size){
+ printf(" %-15s %d\n","Count", Count);
+ printf(" %-15s %d\n","Extra", Extra);
+ }
+}
+
+void U_WMRSETWINDOWORG_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRSETWINDOWORG_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRSETWINDOWEXT_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRSETWINDOWEXT_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","W,H",coord.x, coord.y);
+ }
+}
+
+void U_WMRSETVIEWPORTORG_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRSETVIEWPORTORG_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRSETVIEWPORTEXT_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRSETVIEWPORTEXT_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","W,H",coord.x, coord.y);
+ }
+}
+
+void U_WMROFFSETWINDOWORG_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMROFFSETWINDOWORG_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRSCALEWINDOWEXT_print(const char *contents){
+ U_POINT16 Denom, Num;
+ int size = U_WMRSCALEWINDOWEXT_get(contents, &Denom, &Num);
+ if(size > 0){
+ printf(" yDenom:%d\n", Denom.y);
+ printf(" yNum:%d\n", Num.y );
+ printf(" xDenom:%d\n", Denom.x);
+ printf(" xNum:%d\n", Num.x );
+ }
+}
+
+void U_WMROFFSETVIEWPORTORG_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMROFFSETVIEWPORTORG_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRSCALEVIEWPORTEXT_print(const char *contents){
+ U_POINT16 Denom, Num;
+ int size = U_WMRSCALEVIEWPORTEXT_get(contents, &Denom, &Num);
+ if(size > 0){
+ printf(" yDenom:%d\n", Denom.y);
+ printf(" yNum:%d\n", Num.y );
+ printf(" xDenom:%d\n", Denom.x);
+ printf(" xNum:%d\n", Num.x );
+ }
+}
+
+void U_WMRLINETO_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRLINETO_get(contents, &coord);
+ if(size){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRMOVETO_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMRMOVETO_get(contents, &coord);
+ if(size > 0){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMREXCLUDECLIPRECT_print(const char *contents){
+ U_RECT16 rect16;
+ int size = U_WMREXCLUDECLIPRECT_get(contents, &rect16);
+ if(size > 0){
+ printf(" Rect:");
+ rect16_ltrb_print(rect16);
+ printf("\n");
+ }
+}
+
+void U_WMRINTERSECTCLIPRECT_print(const char *contents){
+ U_RECT16 rect16;
+ int size = U_WMRINTERSECTCLIPRECT_get(contents, &rect16);
+ if(size > 0){
+ printf(" Rect:");
+ rect16_ltrb_print(rect16);
+ printf("\n");
+ }
+}
+
+void U_WMRARC_print(const char *contents){
+ U_POINT16 StartArc, EndArc;
+ U_RECT16 rect16;
+ int size = U_WMRARC_get(contents, &StartArc, &EndArc, &rect16);
+ if(size > 0){
+ printf(" yRadial2:%d\n", EndArc.y);
+ printf(" xRadial2:%d\n", EndArc.x);
+ printf(" yRadial1:%d\n", StartArc.y);
+ printf(" xRadial1:%d\n", StartArc.x);
+ printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n");
+ }
+}
+
+void U_WMRELLIPSE_print(const char *contents){
+ U_RECT16 rect16;
+ int size = U_WMRELLIPSE_get(contents, &rect16);
+ if(size > 0){
+ printf(" Rect:");
+ rect16_ltrb_print(rect16);
+ printf("\n");
+ }
+}
+
+void U_WMRFLOODFILL_print(const char *contents){
+ uint16_t Mode;
+ U_COLORREF Color;
+ U_POINT16 coord;
+ int size = U_WMRFLOODFILL_get(contents, &Mode, &Color, &coord);
+ if(size > 0){
+ printf(" Mode 0x%4.4X\n", Mode);
+ printf(" Color:"); colorref_print(Color); printf("\n");
+ printf(" X,Y {%d,%d}\n", coord.x, coord.y);
+ }
+}
+
+void U_WMRPIE_print(const char *contents){
+ U_POINT16 StartArc, EndArc;
+ U_RECT16 rect16;
+ int size = U_WMRPIE_get(contents, &StartArc, &EndArc, &rect16);
+ if(size > 0){
+ printf(" yRadial2:%d\n", EndArc.y);
+ printf(" xRadial2:%d\n", EndArc.x);
+ printf(" yRadial1:%d\n", StartArc.y);
+ printf(" xRadial1:%d\n", StartArc.x);
+ printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n");
+ }
+}
+
+void U_WMRRECTANGLE_print(const char *contents){
+ U_RECT16 rect16;
+ int size = U_WMRRECTANGLE_get(contents, &rect16);
+ if(size > 0){
+ printf(" Rect:");
+ rect16_ltrb_print(rect16);
+ printf("\n");
+ }
+}
+
+void U_WMRROUNDRECT_print(const char *contents){
+ int16_t Height, Width;
+ U_RECT16 rect16;
+ int size = U_WMRROUNDRECT_get(contents, &Width, &Height, &rect16);
+ if(size > 0){
+ printf(" Width:%d\n", Width);
+ printf(" Height:%d\n", Height);
+ printf(" Rect:");
+ rect16_ltrb_print(rect16);
+ printf("\n");
+ }
+}
+
+void U_WMRPATBLT_print(const char *contents){
+ uint32_t dwRop3;
+ U_POINT16 Dst;
+ U_POINT16 cwh;
+ int size = U_WMRPATBLT_get(contents, &Dst, &cwh, &dwRop3);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" W,H:%d,%d\n", cwh.x, cwh.y );
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ }
+}
+
+void U_WMRSAVEDC_print(const char *contents){
+ UNUSED(contents);
+ /* This record type has only the common 6 bytes, so nothing (else) to print */
+}
+
+void U_WMRSETPIXEL_print(const char *contents){
+ U_COLORREF Color;
+ U_POINT16 coord;
+ int size = U_WMRSETPIXEL_get(contents, &Color, &coord);
+ if(size > 0){
+ printf(" Color:"); colorref_print(Color); printf("\n");
+ printf(" X,Y {%d,%d}\n", coord.x, coord.y);
+ }
+}
+
+void U_WMROFFSETCLIPRGN_print(const char *contents){
+ U_POINT16 coord;
+ int size = U_WMROFFSETCLIPRGN_get(contents, &coord);
+ if(size > 0){
+ printf(" %-15s {%d,%d}\n","X,Y",coord.x, coord.y);
+ }
+}
+
+void U_WMRTEXTOUT_print(const char *contents){
+ int16_t Length;
+ const char *string;
+ U_POINT16 Dst;
+ int size = U_WMRTEXTOUT_get(contents, &Dst, &Length, &string);
+ if(size > 0){
+ printf(" X,Y:{%d,%d}\n", Dst.x,Dst.y);
+ printf(" Length:%d\n", Length);
+ printf(" String:<%.*s>\n", Length, string); /* May not be null terminated */
+ }
+}
+
+void U_WMRBITBLT_print(const char *contents){
+ uint32_t dwRop3;
+ U_POINT16 Dst, Src, cwh;
+ U_BITMAP16 Bm16;
+ const char *px;
+ int size = U_WMRBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &Bm16, &px);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y);
+ printf(" W,H:%d,%d\n", cwh.x, cwh.y);
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y);
+ if(px){ printf(" Bitmap16:"); bitmap16_print(Bm16); printf("\n"); }
+ else { printf(" Bitmap16: none\n"); }
+ }
+}
+
+void U_WMRSTRETCHBLT_print(const char *contents){
+ uint32_t dwRop3;
+ U_POINT16 Dst, Src, cDst, cSrc;
+ U_BITMAP16 Bm16;
+ const char *px;
+ int size = U_WMRSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &Bm16, &px);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y);
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y );
+ printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y);
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ if(px){ printf(" Bitmap16:"); bitmap16_print(Bm16); printf("\n"); }
+ else { printf(" Bitmap16: none\n"); }
+ }
+}
+
+void U_WMRPOLYGON_print(const char *contents){
+ uint16_t Length;
+ const char *Data;
+ int size = U_WMRPOLYGON_get(contents, &Length, &Data);
+ if(size > 0){
+ wcore_points_print(Length, Data);
+ }
+}
+
+void U_WMRPOLYLINE_print(const char *contents){
+ uint16_t Length;
+ const char *Data;
+ int size = U_WMRPOLYLINE_get(contents, &Length, &Data);
+ if(size > 0){
+ wcore_points_print(Length, Data);
+ }
+}
+
+void U_WMRESCAPE_print(const char *contents){
+ uint32_t utmp4;
+ uint16_t Escape;
+ uint16_t Length;
+ const char *Data;
+ int size = U_WMRESCAPE_get(contents, &Escape, &Length, &Data);
+ if(size > 0){
+ printf(" EscType:%s\n",U_wmr_escnames(Escape));
+ printf(" nBytes:%d\n",Length);
+ if((Escape == U_MFE_SETLINECAP) || (Escape == U_MFE_SETLINEJOIN) || (Escape == U_MFE_SETMITERLIMIT)){
+ memcpy(&utmp4, Data ,4);
+ printf(" Data:%d\n", utmp4);
+ }
+ else {
+ printf(" Data: (not shown)\n");
+ }
+ }
+}
+
+void U_WMRRESTOREDC_print(const char *contents){
+ UNUSED(contents);
+ /* This record type has only the common 6 bytes, so nothing (else) to print */
+}
+
+void U_WMRFILLREGION_print(const char *contents){
+ uint16_t Region;
+ uint16_t Brush;
+ int size = U_WMRFILLREGION_get(contents, &Region, &Brush);
+ if(size > 0){
+ printf(" %-15s %d\n","Region", Region);
+ printf(" %-15s %d\n","Brush", Brush);
+ }
+}
+
+void U_WMRFRAMEREGION_print(const char *contents){
+ uint16_t Region;
+ uint16_t Brush;
+ int16_t Height;
+ int16_t Width;
+ int size = U_WMRFRAMEREGION_get(contents, &Region, &Brush, &Height, &Width);
+ if(size > 0){
+ printf(" Region:%d\n",Region);
+ printf(" Brush:%d\n", Brush );
+ printf(" Height:%d\n",Height);
+ printf(" Width:%d\n", Width );
+ }
+}
+
+void U_WMRINVERTREGION_print(const char *contents){
+ uint16_t Region;
+ int size = U_WMRSETTEXTALIGN_get(contents, &Region);
+ if(size > 0){
+ printf(" %-15s %d\n","Region:", Region);
+ }
+}
+
+void U_WMRPAINTREGION_print(const char *contents){
+ uint16_t Region;
+ int size = U_WMRPAINTREGION_get(contents, &Region);
+ if(size>0){
+ printf(" %-15s %d\n","Region:", Region);
+ }
+}
+
+void U_WMRSELECTCLIPREGION_print(const char *contents){
+ uint16_t Region;
+ int size = U_WMRSELECTCLIPREGION_get(contents, &Region);
+ if(size>0){
+ printf(" %-15s %d\n","Region:", Region);
+ }
+}
+
+void U_WMRSELECTOBJECT_print(const char *contents){
+ uint16_t Object;
+ int size = U_WMRSELECTOBJECT_get(contents, &Object);
+ if(size>0){
+ printf(" %-15s %d\n","Object:", Object);
+ }
+}
+
+void U_WMRSETTEXTALIGN_print(const char *contents){
+ uint16_t iMode;
+ int size = U_WMRSETTEXTALIGN_get(contents, &iMode);
+ if(size>0){
+ printf(" %-15s 0x%4.4X\n","iMode:", iMode);
+ }
+}
+
+#define U_WMRDRAWTEXT_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMRCHORD_print(const char *contents){
+ U_POINT16 StartArc, EndArc;
+ U_RECT16 rect16;
+ int size = U_WMRCHORD_get(contents, &StartArc, &EndArc, &rect16);
+ if(size > 0){
+ printf(" yRadial2:%d\n", EndArc.y);
+ printf(" xRadial2:%d\n", EndArc.x);
+ printf(" yRadial1:%d\n", StartArc.y);
+ printf(" xRadial1:%d\n", StartArc.x);
+ printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n");
+ }
+}
+
+void U_WMRSETMAPPERFLAGS_print(const char *contents){
+ uint32_t Flags4;
+ int size = U_WMRSETMAPPERFLAGS_get(contents, &Flags4);
+ if(size > 0){
+ printf(" %-15s 0x%8.8X\n","Flags4:", Flags4);
+ }
+}
+
+void U_WMREXTTEXTOUT_print(const char *contents){
+ U_RECT16 rect16;
+ U_POINT16 Dst;
+ int16_t Length;
+ uint16_t Opts;
+ const int16_t *dx;
+ const char *string;
+ int i;
+ int size = U_WMREXTTEXTOUT_get(contents, &Dst, &Length, &Opts, &string, &dx, &rect16);
+ if(size > 0){
+ printf(" X,Y:{%d,%d}\n", Dst.x, Dst.y);
+ printf(" Length:%d\n", Length );
+ printf(" Opts:%4.4X\n", Opts );
+ if(Opts & (U_ETO_OPAQUE | U_ETO_CLIPPED)){
+ printf(" Rect:"); rect16_ltrb_print(rect16); printf("\n");
+ }
+ printf(" String:<%.*s>\n",Length, string);
+ printf(" Dx:");
+ for(i=0; i<Length; i++,dx++){ printf("%d:", *dx ); }
+ printf("\n");
+ }
+}
+
+void U_WMRSETDIBTODEV_print(const char *contents){
+ uint16_t cUsage;
+ uint16_t ScanCount;
+ uint16_t StartScan;
+ U_POINT16 Dst;
+ U_POINT16 cwh;
+ U_POINT16 Src;
+ const char *dib;
+ int size = U_WMRSETDIBTODEV_get(contents, &Dst, &cwh, &Src, &cUsage, &ScanCount, &StartScan, &dib);
+ if(size > 0){
+ printf(" cUsage:%d\n", cUsage );
+ printf(" ScanCount:%d\n", ScanCount );
+ printf(" StartScan:%d\n", StartScan );
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y );
+ printf(" W,H:%d,%d\n", cwh.x, cwh.y );
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n");
+ }
+}
+
+void U_WMRSELECTPALETTE_print(const char *contents){
+ uint16_t Palette;
+ int size = U_WMRSELECTPALETTE_get(contents, &Palette);
+ if(size > 0){
+ printf(" %-15s %d\n","Palette:", Palette);
+ }
+}
+
+void U_WMRREALIZEPALETTE_print(const char *contents){
+ UNUSED(contents);
+ /* This record type has only the common 6 bytes, so nothing (else) to print */
+}
+
+void U_WMRANIMATEPALETTE_print(const char *contents){
+ U_PALETTE Palette;
+ const char *PalEntries;
+ int size = U_WMRANIMATEPALETTE_get(contents, &Palette, &PalEntries);
+ if(size > 0){
+ printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n");
+
+ }
+}
+
+void U_WMRSETPALENTRIES_print(const char *contents){
+ U_PALETTE Palette;
+ const char *PalEntries;
+ int size = U_WMRSETPALENTRIES_get(contents, &Palette, &PalEntries);
+ if(size > 0){
+ printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n");
+ }
+}
+
+void U_WMRPOLYPOLYGON_print(const char *contents){
+ uint16_t nPolys;
+ const uint16_t *aPolyCounts;
+ const char *Points;
+ int size = U_WMRPOLYPOLYGON_get(contents, &nPolys, &aPolyCounts, &Points);
+ if(size > 0){
+ printf(" Polygons:"); polypolygon_print(nPolys, aPolyCounts, Points); printf("\n");
+ }
+}
+
+void U_WMRRESIZEPALETTE_print(const char *contents){
+ uint16_t Palette;
+ int size = U_WMRSELECTCLIPREGION_get(contents, &Palette);
+ if(size>0){
+ printf(" %-15s %d\n","Palette:", Palette);
+ }
+}
+
+#define U_WMR3A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR3B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR3C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR3D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR3E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR3F_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMRDIBBITBLT_print(const char *contents){
+ U_POINT16 Dst, cwh, Src;
+ uint32_t dwRop3;
+ const char *dib;
+ int size = U_WMRDIBBITBLT_get(contents, &Dst, &cwh, &Src, &dwRop3, &dib);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x );
+ printf(" W,H:%d,%d\n", cwh.x, cwh.y );
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); }
+ else { printf(" DIB: none\n"); }
+ }
+}
+
+void U_WMRDIBSTRETCHBLT_print(const char *contents){
+ U_POINT16 Dst, cDst, Src, cSrc;
+ uint32_t dwRop3;
+ const char *dib;
+ int size = U_WMRDIBSTRETCHBLT_get(contents, &Dst, &cDst, &Src, &cSrc, &dwRop3, &dib);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y );
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x );
+ printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y );
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); }
+ else { printf(" DIB: none\n"); }
+ }
+}
+
+void U_WMRDIBCREATEPATTERNBRUSH_print(const char *contents){
+ uint16_t Style, cUsage;
+ const char *TBm16;
+ const char *dib;
+ int size = U_WMRDIBCREATEPATTERNBRUSH_get(contents, &Style, &cUsage, &TBm16, &dib);
+ if(size > 0){
+ U_BITMAP16 Bm16;
+ printf(" Style:%d\n", Style );
+ printf(" cUsage:%d\n", cUsage);
+ if(TBm16){
+ memcpy(&Bm16, TBm16, U_SIZE_BITMAP16);
+ printf(" Src:Bitmap16:"); bitmap16_print(Bm16); printf("\n");
+ }
+ else { /* from DIB */
+ printf(" Src:DIB:"); dibheader_print(dib, dib+size); printf("\n");
+ }
+ }
+}
+
+void U_WMRSTRETCHDIB_print(const char *contents){
+ U_POINT16 Dst, cDst, Src, cSrc;
+ uint32_t dwRop3;
+ uint16_t cUsage;
+ const char *dib;
+ int size = U_WMRSTRETCHDIB_get(contents, &Dst, &cDst, &Src, &cSrc, &cUsage, &dwRop3, &dib);
+ if(size > 0){
+ printf(" Rop3:%8.8X\n", dwRop3 );
+ printf(" cUsage:%d\n", cUsage );
+ printf(" Src W,H:%d,%d\n", cSrc.x, cSrc.y );
+ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x );
+ printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y );
+ printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y );
+ if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); }
+ else { printf(" DIB: none\n"); }
+ }
+}
+
+#define U_WMR44_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR45_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR46_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR47_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMREXTFLOODFILL_print(const char *contents){
+ uint16_t Mode;
+ U_COLORREF Color;
+ U_POINT16 coord;
+ int size = U_WMREXTFLOODFILL_get(contents, &Mode, &Color, &coord);
+ if(size > 0){
+ printf(" Mode 0x%4.4X\n", Mode);
+ printf(" Color:"); colorref_print(Color); printf("\n");
+ printf(" X,Y {%d,%d}\n", coord.x, coord.y);
+ }
+}
+
+#define U_WMR49_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR4F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR50_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR51_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR52_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR53_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR54_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR55_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR56_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR57_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR58_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR59_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR5F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR60_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR61_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR62_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR63_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR64_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR65_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR66_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR67_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR68_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR69_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR6F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR70_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR71_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR72_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR73_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR74_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR75_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR76_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR77_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR78_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR79_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR7F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR80_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR81_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR82_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR83_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR84_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR85_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR86_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR87_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR88_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR89_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR8F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR90_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR91_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR92_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR93_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR94_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR95_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR96_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR97_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR98_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR99_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9A_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9B_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9C_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9D_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9E_print U_WMRNOTIMPLEMENTED_print
+#define U_WMR9F_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA0_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA6_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA7_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA8_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRA9_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAA_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAB_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAC_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAD_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAE_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRAF_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB0_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB6_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB7_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB8_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRB9_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBA_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBB_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBC_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBD_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBE_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRBF_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC0_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC6_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC7_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC8_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRC9_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCA_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCB_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCC_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCD_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCE_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRCF_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD0_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD6_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD7_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD8_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRD9_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDA_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDB_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDC_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDD_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDE_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRDF_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE0_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE6_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE7_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE8_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRE9_print U_WMRNOTIMPLEMENTED_print
+#define U_WMREA_print U_WMRNOTIMPLEMENTED_print
+#define U_WMREB_print U_WMRNOTIMPLEMENTED_print
+#define U_WMREC_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRED_print U_WMRNOTIMPLEMENTED_print
+#define U_WMREE_print U_WMRNOTIMPLEMENTED_print
+#define U_WMREF_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMRDELETEOBJECT_print(const char *contents){
+ uint16_t Object;
+ int size = U_WMRDELETEOBJECT_get(contents, &Object);
+ if(size>0){
+ printf(" %-15s %d\n","Object:", Object);
+ }
+}
+
+#define U_WMRF1_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRF2_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRF3_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRF4_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRF5_print U_WMRNOTIMPLEMENTED_print
+#define U_WMRF6_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMRCREATEPALETTE_print(const char *contents){
+ U_PALETTE Palette;
+ const char *PalEntries;
+ int size = U_WMRCREATEPALETTE_get(contents, &Palette, &PalEntries);
+ if(size > 0){
+ printf(" Palette:"); palette_print(&Palette, PalEntries); printf("\n");
+
+ }
+}
+
+#define U_WMRF8_print U_WMRNOTIMPLEMENTED_print
+
+void U_WMRCREATEPATTERNBRUSH_print(const char *contents){
+ U_BITMAP16 Bm16;
+ int pasize;
+ int i;
+ const char *Pattern;
+
+ int size = U_WMRCREATEPATTERNBRUSH_get(contents, &Bm16, &pasize, &Pattern);
+ if(size > 0){
+ /* BM16 is truncated, but bitmap16_print does not get into the part that was omitted */
+ printf(" BitMap16: "); bitmap16_print(Bm16); printf("\n");
+ printf(" Pattern: ");
+ for(i=0;i<pasize;i++){
+ printf("%2.2X ",Pattern[i]);
+ }
+ printf("\n");
+ }
+}
+
+void U_WMRCREATEPENINDIRECT_print(const char *contents){
+ U_PEN pen;
+ int size = U_WMRCREATEPENINDIRECT_get(contents, &pen);
+ if(size > 0){
+ printf(" Pen:"); pen_print(pen); printf("\n");
+ }
+}
+
+void U_WMRCREATEFONTINDIRECT_print(const char *contents){
+ const char *font; /* Note, because of possible struct alignment issue have to use char * to reference the data */
+ int size = U_WMRCREATEFONTINDIRECT_get(contents, &font);
+ if(size > 0){
+ printf(" Font:");
+ font_print(font);
+ printf("\n");
+ }
+}
+
+void U_WMRCREATEBRUSHINDIRECT_print(const char *contents){
+ const char *brush; /* Note, because of possible struct alignment issue have to use char * to reference the data */
+ int size = U_WMRCREATEBRUSHINDIRECT_get(contents, &brush);
+ if(size > 0){
+ printf(" Brush:");
+ wlogbrush_print(brush);
+ printf("\n");
+ }
+}
+
+void U_WMRCREATEBITMAPINDIRECT_print(const char *contents){ /* in Wine, not in WMF PDF */
+ U_WMRNOTIMPLEMENTED_print(contents);
+}
+
+void U_WMRCREATEBITMAP_print(const char *contents){ /* in Wine, not in WMF PDF */
+ U_WMRNOTIMPLEMENTED_print(contents);
+}
+
+void U_WMRCREATEREGION_print(const char *contents){
+ const char *region; /* Note, because of possible struct alignment issue have to use char * to reference the data */
+ int size = U_WMRCREATEBRUSHINDIRECT_get(contents, &region);
+ if(size > 0){
+ printf(" Brush:");
+ printf(" Region: "); region_print(region); printf("\n");
+ }
+}
+
+//! \endcond
+
+/**
+ \brief Print any record in a wmf
+ \returns record length for a normal record, 0 for WMREOF, -1 for a bad record
+ \param contents pointer to a buffer holding all WMR records
+ \param blimit one byte past the last WMF record in memory.
+ \param recnum number of this record in contents
+ \param off offset to this record in contents
+*/
+int U_wmf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){
+
+
+ uint8_t iType;
+ size_t size;
+
+ contents += off;
+
+ /* Check that the record size is OK, abort if not.
+ Pointer math might wrap, so check both sides of the range */
+ size = U_WMRRECSAFE_get(contents, blimit);
+ if(!size)return(-1);
+
+ iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) );
+
+ uint32_t crc;
+#if U_BYTE_SWAP
+ //This is a Big Endian machine, WMF crc values must be calculated on Little Endian form
+ char *swapbuf=malloc(size);
+ if(!swapbuf)return(-1);
+ memcpy(swapbuf,contents,size);
+ U_wmf_endian(swapbuf,size,1,1); // BE to LE
+ crc=lu_crc32(swapbuf,size);
+ free(swapbuf);
+#else
+ crc=lu_crc32(contents,size);
+#endif
+ printf("%-30srecord:%5d type:%-4u offset:%8d rsize:%8u crc32:%8.8X\n",
+ U_wmr_names(iType), recnum, iType, (int) off, (int) size, crc);
+
+ switch (iType)
+ {
+ case U_WMR_EOF: U_WMREOF_print(contents); size=0; break;
+ case U_WMR_SETBKCOLOR: U_WMRSETBKCOLOR_print(contents); break;
+ case U_WMR_SETBKMODE: U_WMRSETBKMODE_print(contents); break;
+ case U_WMR_SETMAPMODE: U_WMRSETMAPMODE_print(contents); break;
+ case U_WMR_SETROP2: U_WMRSETROP2_print(contents); break;
+ case U_WMR_SETRELABS: U_WMRSETRELABS_print(contents); break;
+ case U_WMR_SETPOLYFILLMODE: U_WMRSETPOLYFILLMODE_print(contents); break;
+ case U_WMR_SETSTRETCHBLTMODE: U_WMRSETSTRETCHBLTMODE_print(contents); break;
+ case U_WMR_SETTEXTCHAREXTRA: U_WMRSETTEXTCHAREXTRA_print(contents); break;
+ case U_WMR_SETTEXTCOLOR: U_WMRSETTEXTCOLOR_print(contents); break;
+ case U_WMR_SETTEXTJUSTIFICATION: U_WMRSETTEXTJUSTIFICATION_print(contents); break;
+ case U_WMR_SETWINDOWORG: U_WMRSETWINDOWORG_print(contents); break;
+ case U_WMR_SETWINDOWEXT: U_WMRSETWINDOWEXT_print(contents); break;
+ case U_WMR_SETVIEWPORTORG: U_WMRSETVIEWPORTORG_print(contents); break;
+ case U_WMR_SETVIEWPORTEXT: U_WMRSETVIEWPORTEXT_print(contents); break;
+ case U_WMR_OFFSETWINDOWORG: U_WMROFFSETWINDOWORG_print(contents); break;
+ case U_WMR_SCALEWINDOWEXT: U_WMRSCALEWINDOWEXT_print(contents); break;
+ case U_WMR_OFFSETVIEWPORTORG: U_WMROFFSETVIEWPORTORG_print(contents); break;
+ case U_WMR_SCALEVIEWPORTEXT: U_WMRSCALEVIEWPORTEXT_print(contents); break;
+ case U_WMR_LINETO: U_WMRLINETO_print(contents); break;
+ case U_WMR_MOVETO: U_WMRMOVETO_print(contents); break;
+ case U_WMR_EXCLUDECLIPRECT: U_WMREXCLUDECLIPRECT_print(contents); break;
+ case U_WMR_INTERSECTCLIPRECT: U_WMRINTERSECTCLIPRECT_print(contents); break;
+ case U_WMR_ARC: U_WMRARC_print(contents); break;
+ case U_WMR_ELLIPSE: U_WMRELLIPSE_print(contents); break;
+ case U_WMR_FLOODFILL: U_WMRFLOODFILL_print(contents); break;
+ case U_WMR_PIE: U_WMRPIE_print(contents); break;
+ case U_WMR_RECTANGLE: U_WMRRECTANGLE_print(contents); break;
+ case U_WMR_ROUNDRECT: U_WMRROUNDRECT_print(contents); break;
+ case U_WMR_PATBLT: U_WMRPATBLT_print(contents); break;
+ case U_WMR_SAVEDC: U_WMRSAVEDC_print(contents); break;
+ case U_WMR_SETPIXEL: U_WMRSETPIXEL_print(contents); break;
+ case U_WMR_OFFSETCLIPRGN: U_WMROFFSETCLIPRGN_print(contents); break;
+ case U_WMR_TEXTOUT: U_WMRTEXTOUT_print(contents); break;
+ case U_WMR_BITBLT: U_WMRBITBLT_print(contents); break;
+ case U_WMR_STRETCHBLT: U_WMRSTRETCHBLT_print(contents); break;
+ case U_WMR_POLYGON: U_WMRPOLYGON_print(contents); break;
+ case U_WMR_POLYLINE: U_WMRPOLYLINE_print(contents); break;
+ case U_WMR_ESCAPE: U_WMRESCAPE_print(contents); break;
+ case U_WMR_RESTOREDC: U_WMRRESTOREDC_print(contents); break;
+ case U_WMR_FILLREGION: U_WMRFILLREGION_print(contents); break;
+ case U_WMR_FRAMEREGION: U_WMRFRAMEREGION_print(contents); break;
+ case U_WMR_INVERTREGION: U_WMRINVERTREGION_print(contents); break;
+ case U_WMR_PAINTREGION: U_WMRPAINTREGION_print(contents); break;
+ case U_WMR_SELECTCLIPREGION: U_WMRSELECTCLIPREGION_print(contents); break;
+ case U_WMR_SELECTOBJECT: U_WMRSELECTOBJECT_print(contents); break;
+ case U_WMR_SETTEXTALIGN: U_WMRSETTEXTALIGN_print(contents); break;
+ case U_WMR_DRAWTEXT: U_WMRDRAWTEXT_print(contents); break;
+ case U_WMR_CHORD: U_WMRCHORD_print(contents); break;
+ case U_WMR_SETMAPPERFLAGS: U_WMRSETMAPPERFLAGS_print(contents); break;
+ case U_WMR_EXTTEXTOUT: U_WMREXTTEXTOUT_print(contents); break;
+ case U_WMR_SETDIBTODEV: U_WMRSETDIBTODEV_print(contents); break;
+ case U_WMR_SELECTPALETTE: U_WMRSELECTPALETTE_print(contents); break;
+ case U_WMR_REALIZEPALETTE: U_WMRREALIZEPALETTE_print(contents); break;
+ case U_WMR_ANIMATEPALETTE: U_WMRANIMATEPALETTE_print(contents); break;
+ case U_WMR_SETPALENTRIES: U_WMRSETPALENTRIES_print(contents); break;
+ case U_WMR_POLYPOLYGON: U_WMRPOLYPOLYGON_print(contents); break;
+ case U_WMR_RESIZEPALETTE: U_WMRRESIZEPALETTE_print(contents); break;
+ case U_WMR_3A: U_WMR3A_print(contents); break;
+ case U_WMR_3B: U_WMR3B_print(contents); break;
+ case U_WMR_3C: U_WMR3C_print(contents); break;
+ case U_WMR_3D: U_WMR3D_print(contents); break;
+ case U_WMR_3E: U_WMR3E_print(contents); break;
+ case U_WMR_3F: U_WMR3F_print(contents); break;
+ case U_WMR_DIBBITBLT: U_WMRDIBBITBLT_print(contents); break;
+ case U_WMR_DIBSTRETCHBLT: U_WMRDIBSTRETCHBLT_print(contents); break;
+ case U_WMR_DIBCREATEPATTERNBRUSH: U_WMRDIBCREATEPATTERNBRUSH_print(contents); break;
+ case U_WMR_STRETCHDIB: U_WMRSTRETCHDIB_print(contents); break;
+ case U_WMR_44: U_WMR44_print(contents); break;
+ case U_WMR_45: U_WMR45_print(contents); break;
+ case U_WMR_46: U_WMR46_print(contents); break;
+ case U_WMR_47: U_WMR47_print(contents); break;
+ case U_WMR_EXTFLOODFILL: U_WMREXTFLOODFILL_print(contents); break;
+ case U_WMR_49: U_WMR49_print(contents); break;
+ case U_WMR_4A: U_WMR4A_print(contents); break;
+ case U_WMR_4B: U_WMR4B_print(contents); break;
+ case U_WMR_4C: U_WMR4C_print(contents); break;
+ case U_WMR_4D: U_WMR4D_print(contents); break;
+ case U_WMR_4E: U_WMR4E_print(contents); break;
+ case U_WMR_4F: U_WMR4F_print(contents); break;
+ case U_WMR_50: U_WMR50_print(contents); break;
+ case U_WMR_51: U_WMR51_print(contents); break;
+ case U_WMR_52: U_WMR52_print(contents); break;
+ case U_WMR_53: U_WMR53_print(contents); break;
+ case U_WMR_54: U_WMR54_print(contents); break;
+ case U_WMR_55: U_WMR55_print(contents); break;
+ case U_WMR_56: U_WMR56_print(contents); break;
+ case U_WMR_57: U_WMR57_print(contents); break;
+ case U_WMR_58: U_WMR58_print(contents); break;
+ case U_WMR_59: U_WMR59_print(contents); break;
+ case U_WMR_5A: U_WMR5A_print(contents); break;
+ case U_WMR_5B: U_WMR5B_print(contents); break;
+ case U_WMR_5C: U_WMR5C_print(contents); break;
+ case U_WMR_5D: U_WMR5D_print(contents); break;
+ case U_WMR_5E: U_WMR5E_print(contents); break;
+ case U_WMR_5F: U_WMR5F_print(contents); break;
+ case U_WMR_60: U_WMR60_print(contents); break;
+ case U_WMR_61: U_WMR61_print(contents); break;
+ case U_WMR_62: U_WMR62_print(contents); break;
+ case U_WMR_63: U_WMR63_print(contents); break;
+ case U_WMR_64: U_WMR64_print(contents); break;
+ case U_WMR_65: U_WMR65_print(contents); break;
+ case U_WMR_66: U_WMR66_print(contents); break;
+ case U_WMR_67: U_WMR67_print(contents); break;
+ case U_WMR_68: U_WMR68_print(contents); break;
+ case U_WMR_69: U_WMR69_print(contents); break;
+ case U_WMR_6A: U_WMR6A_print(contents); break;
+ case U_WMR_6B: U_WMR6B_print(contents); break;
+ case U_WMR_6C: U_WMR6C_print(contents); break;
+ case U_WMR_6D: U_WMR6D_print(contents); break;
+ case U_WMR_6E: U_WMR6E_print(contents); break;
+ case U_WMR_6F: U_WMR6F_print(contents); break;
+ case U_WMR_70: U_WMR70_print(contents); break;
+ case U_WMR_71: U_WMR71_print(contents); break;
+ case U_WMR_72: U_WMR72_print(contents); break;
+ case U_WMR_73: U_WMR73_print(contents); break;
+ case U_WMR_74: U_WMR74_print(contents); break;
+ case U_WMR_75: U_WMR75_print(contents); break;
+ case U_WMR_76: U_WMR76_print(contents); break;
+ case U_WMR_77: U_WMR77_print(contents); break;
+ case U_WMR_78: U_WMR78_print(contents); break;
+ case U_WMR_79: U_WMR79_print(contents); break;
+ case U_WMR_7A: U_WMR7A_print(contents); break;
+ case U_WMR_7B: U_WMR7B_print(contents); break;
+ case U_WMR_7C: U_WMR7C_print(contents); break;
+ case U_WMR_7D: U_WMR7D_print(contents); break;
+ case U_WMR_7E: U_WMR7E_print(contents); break;
+ case U_WMR_7F: U_WMR7F_print(contents); break;
+ case U_WMR_80: U_WMR80_print(contents); break;
+ case U_WMR_81: U_WMR81_print(contents); break;
+ case U_WMR_82: U_WMR82_print(contents); break;
+ case U_WMR_83: U_WMR83_print(contents); break;
+ case U_WMR_84: U_WMR84_print(contents); break;
+ case U_WMR_85: U_WMR85_print(contents); break;
+ case U_WMR_86: U_WMR86_print(contents); break;
+ case U_WMR_87: U_WMR87_print(contents); break;
+ case U_WMR_88: U_WMR88_print(contents); break;
+ case U_WMR_89: U_WMR89_print(contents); break;
+ case U_WMR_8A: U_WMR8A_print(contents); break;
+ case U_WMR_8B: U_WMR8B_print(contents); break;
+ case U_WMR_8C: U_WMR8C_print(contents); break;
+ case U_WMR_8D: U_WMR8D_print(contents); break;
+ case U_WMR_8E: U_WMR8E_print(contents); break;
+ case U_WMR_8F: U_WMR8F_print(contents); break;
+ case U_WMR_90: U_WMR90_print(contents); break;
+ case U_WMR_91: U_WMR91_print(contents); break;
+ case U_WMR_92: U_WMR92_print(contents); break;
+ case U_WMR_93: U_WMR93_print(contents); break;
+ case U_WMR_94: U_WMR94_print(contents); break;
+ case U_WMR_95: U_WMR95_print(contents); break;
+ case U_WMR_96: U_WMR96_print(contents); break;
+ case U_WMR_97: U_WMR97_print(contents); break;
+ case U_WMR_98: U_WMR98_print(contents); break;
+ case U_WMR_99: U_WMR99_print(contents); break;
+ case U_WMR_9A: U_WMR9A_print(contents); break;
+ case U_WMR_9B: U_WMR9B_print(contents); break;
+ case U_WMR_9C: U_WMR9C_print(contents); break;
+ case U_WMR_9D: U_WMR9D_print(contents); break;
+ case U_WMR_9E: U_WMR9E_print(contents); break;
+ case U_WMR_9F: U_WMR9F_print(contents); break;
+ case U_WMR_A0: U_WMRA0_print(contents); break;
+ case U_WMR_A1: U_WMRA1_print(contents); break;
+ case U_WMR_A2: U_WMRA2_print(contents); break;
+ case U_WMR_A3: U_WMRA3_print(contents); break;
+ case U_WMR_A4: U_WMRA4_print(contents); break;
+ case U_WMR_A5: U_WMRA5_print(contents); break;
+ case U_WMR_A6: U_WMRA6_print(contents); break;
+ case U_WMR_A7: U_WMRA7_print(contents); break;
+ case U_WMR_A8: U_WMRA8_print(contents); break;
+ case U_WMR_A9: U_WMRA9_print(contents); break;
+ case U_WMR_AA: U_WMRAA_print(contents); break;
+ case U_WMR_AB: U_WMRAB_print(contents); break;
+ case U_WMR_AC: U_WMRAC_print(contents); break;
+ case U_WMR_AD: U_WMRAD_print(contents); break;
+ case U_WMR_AE: U_WMRAE_print(contents); break;
+ case U_WMR_AF: U_WMRAF_print(contents); break;
+ case U_WMR_B0: U_WMRB0_print(contents); break;
+ case U_WMR_B1: U_WMRB1_print(contents); break;
+ case U_WMR_B2: U_WMRB2_print(contents); break;
+ case U_WMR_B3: U_WMRB3_print(contents); break;
+ case U_WMR_B4: U_WMRB4_print(contents); break;
+ case U_WMR_B5: U_WMRB5_print(contents); break;
+ case U_WMR_B6: U_WMRB6_print(contents); break;
+ case U_WMR_B7: U_WMRB7_print(contents); break;
+ case U_WMR_B8: U_WMRB8_print(contents); break;
+ case U_WMR_B9: U_WMRB9_print(contents); break;
+ case U_WMR_BA: U_WMRBA_print(contents); break;
+ case U_WMR_BB: U_WMRBB_print(contents); break;
+ case U_WMR_BC: U_WMRBC_print(contents); break;
+ case U_WMR_BD: U_WMRBD_print(contents); break;
+ case U_WMR_BE: U_WMRBE_print(contents); break;
+ case U_WMR_BF: U_WMRBF_print(contents); break;
+ case U_WMR_C0: U_WMRC0_print(contents); break;
+ case U_WMR_C1: U_WMRC1_print(contents); break;
+ case U_WMR_C2: U_WMRC2_print(contents); break;
+ case U_WMR_C3: U_WMRC3_print(contents); break;
+ case U_WMR_C4: U_WMRC4_print(contents); break;
+ case U_WMR_C5: U_WMRC5_print(contents); break;
+ case U_WMR_C6: U_WMRC6_print(contents); break;
+ case U_WMR_C7: U_WMRC7_print(contents); break;
+ case U_WMR_C8: U_WMRC8_print(contents); break;
+ case U_WMR_C9: U_WMRC9_print(contents); break;
+ case U_WMR_CA: U_WMRCA_print(contents); break;
+ case U_WMR_CB: U_WMRCB_print(contents); break;
+ case U_WMR_CC: U_WMRCC_print(contents); break;
+ case U_WMR_CD: U_WMRCD_print(contents); break;
+ case U_WMR_CE: U_WMRCE_print(contents); break;
+ case U_WMR_CF: U_WMRCF_print(contents); break;
+ case U_WMR_D0: U_WMRD0_print(contents); break;
+ case U_WMR_D1: U_WMRD1_print(contents); break;
+ case U_WMR_D2: U_WMRD2_print(contents); break;
+ case U_WMR_D3: U_WMRD3_print(contents); break;
+ case U_WMR_D4: U_WMRD4_print(contents); break;
+ case U_WMR_D5: U_WMRD5_print(contents); break;
+ case U_WMR_D6: U_WMRD6_print(contents); break;
+ case U_WMR_D7: U_WMRD7_print(contents); break;
+ case U_WMR_D8: U_WMRD8_print(contents); break;
+ case U_WMR_D9: U_WMRD9_print(contents); break;
+ case U_WMR_DA: U_WMRDA_print(contents); break;
+ case U_WMR_DB: U_WMRDB_print(contents); break;
+ case U_WMR_DC: U_WMRDC_print(contents); break;
+ case U_WMR_DD: U_WMRDD_print(contents); break;
+ case U_WMR_DE: U_WMRDE_print(contents); break;
+ case U_WMR_DF: U_WMRDF_print(contents); break;
+ case U_WMR_E0: U_WMRE0_print(contents); break;
+ case U_WMR_E1: U_WMRE1_print(contents); break;
+ case U_WMR_E2: U_WMRE2_print(contents); break;
+ case U_WMR_E3: U_WMRE3_print(contents); break;
+ case U_WMR_E4: U_WMRE4_print(contents); break;
+ case U_WMR_E5: U_WMRE5_print(contents); break;
+ case U_WMR_E6: U_WMRE6_print(contents); break;
+ case U_WMR_E7: U_WMRE7_print(contents); break;
+ case U_WMR_E8: U_WMRE8_print(contents); break;
+ case U_WMR_E9: U_WMRE9_print(contents); break;
+ case U_WMR_EA: U_WMREA_print(contents); break;
+ case U_WMR_EB: U_WMREB_print(contents); break;
+ case U_WMR_EC: U_WMREC_print(contents); break;
+ case U_WMR_ED: U_WMRED_print(contents); break;
+ case U_WMR_EE: U_WMREE_print(contents); break;
+ case U_WMR_EF: U_WMREF_print(contents); break;
+ case U_WMR_DELETEOBJECT: U_WMRDELETEOBJECT_print(contents); break;
+ case U_WMR_F1: U_WMRF1_print(contents); break;
+ case U_WMR_F2: U_WMRF2_print(contents); break;
+ case U_WMR_F3: U_WMRF3_print(contents); break;
+ case U_WMR_F4: U_WMRF4_print(contents); break;
+ case U_WMR_F5: U_WMRF5_print(contents); break;
+ case U_WMR_F6: U_WMRF6_print(contents); break;
+ case U_WMR_CREATEPALETTE: U_WMRCREATEPALETTE_print(contents); break;
+ case U_WMR_F8: U_WMRF8_print(contents); break;
+ case U_WMR_CREATEPATTERNBRUSH: U_WMRCREATEPATTERNBRUSH_print(contents); break;
+ case U_WMR_CREATEPENINDIRECT: U_WMRCREATEPENINDIRECT_print(contents); break;
+ case U_WMR_CREATEFONTINDIRECT: U_WMRCREATEFONTINDIRECT_print(contents); break;
+ case U_WMR_CREATEBRUSHINDIRECT: U_WMRCREATEBRUSHINDIRECT_print(contents); break;
+ case U_WMR_CREATEBITMAPINDIRECT: U_WMRCREATEBITMAPINDIRECT_print(contents); break;
+ case U_WMR_CREATEBITMAP: U_WMRCREATEBITMAP_print(contents); break;
+ case U_WMR_CREATEREGION: U_WMRCREATEREGION_print(contents); break;
+ default: U_WMRNOTIMPLEMENTED_print(contents); break;
+ } //end of switch
+ return(size);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/3rdparty/libuemf/uwmf_print.h b/src/3rdparty/libuemf/uwmf_print.h
new file mode 100644
index 000000000..54dfe9c9c
--- /dev/null
+++ b/src/3rdparty/libuemf/uwmf_print.h
@@ -0,0 +1,52 @@
+/**
+ @file uwmf_print.h
+
+ @brief Prototypes for functions for printing records from WMF files.
+*/
+
+/*
+File: uwmf_print.h
+Version: 0.0.2
+Date: 14-FEB-2013
+Author: David Mathog, Biology Division, Caltech
+email: mathog@caltech.edu
+Copyright: 2012 David Mathog and California Institute of Technology (Caltech)
+*/
+
+#ifndef _UWMF_PRINT_
+#define _UWMF_PRINT_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "uwmf.h"
+#include "uemf_print.h"
+
+//! \cond
+/* prototypes for objects used in WMR records (other than those defined in uemf_print.h) */
+void brush_print(U_BRUSH b);
+void font_print(const char *font);
+void pltntry_print(U_PLTNTRY pny);
+void palette_print(const U_PALETTE *p, const char *PalEntries);
+void pen_print(U_PEN p);
+void rect16_ltrb_print(U_RECT16 rect);
+void rect16_brtl_print(U_RECT16 rect);
+void region_print(const char *region);
+void bitmap16_print(U_BITMAP16 b);
+void bitmapcoreheader_print(U_BITMAPCOREHEADER ch);
+void logbrushw_print(U_WLOGBRUSH lb);
+void polypolygon_print(uint16_t nPolys, const uint16_t *aPolyCounts, const char *Points);
+void scan_print(U_SCAN sc);
+void dibheader_print(const char *dh, const char *blimit);
+
+/* prototypes for WMF records */
+int wmfheader_print(const char *contents, const char *blimit);
+void U_WMRNOTIMPLEMENTED_print(const char *contents);
+int U_wmf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off);
+//! \endcond
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UWMF_PRINT_ */