--- /dev/null
+/* m17n-flt-xml.c -- XML Font Layout Table sub-module.
+ Copyright (C) 2009
+ National Institute of Advanced Industrial Science and Technology (AIST)
+ Registration Number H15PRO112
+
+ This file is part of the m17n library.
+
+ The m17n 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.
+
+ The m17n 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the m17n library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ 02111-1307, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+
+#include "/usr/local/work/m17n-lib-xml/src/config.h"
+#include <m17n.h>
+#include <m17n-misc.h>
+#include "/usr/local/work/m17n-lib-xml/src/internal.h"
+#include "/usr/local/work/m17n-lib-xml/src/database.h"
+
+#define STRCAT(dest, src) \
+ do { \
+ dest = realloc (dest, strlen (dest) + strlen ((char *) src) + 1); \
+ strcat (dest, (char *) src); \
+ } while (0)
+
+
+static void
+decode_otf_specification (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ xmlNodePtr cur0;
+ xmlChar *ptr;
+ char *p = malloc (6);
+
+ sprintf (p, ":otf=");
+
+ ptr = xmlGetProp (cur, (xmlChar *) "script");
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "langsys")))
+ {
+ STRCAT(p, "/");
+ STRCAT(p, ptr);
+ xmlFree (ptr);
+ }
+
+ cur = cur->xmlChildrenNode;
+
+ if (cur && xmlStrEqual (cur->name, (xmlChar *) "gsub-features"))
+ {
+ cur0 = cur->xmlChildrenNode;
+ if (xmlStrEqual (cur0->name, (xmlChar *) "positive-list"))
+ {
+ STRCAT(p, "=");
+ for (cur0 = cur0->xmlChildrenNode; cur0; cur0 = cur0->next)
+ {
+ if (p[strlen (p) - 1] != '=')
+ STRCAT (p, ",");
+ ptr = xmlNodeListGetString (doc, cur0->xmlChildrenNode, 1);
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+ }
+ }
+ else if (cur0->xmlChildrenNode) /* at least one negative element */
+ {
+ STRCAT(p, "=");
+ for (cur0 = cur0->xmlChildrenNode; cur0; cur0 = cur0->next)
+ {
+ if (p[strlen (p) - 1] != '=')
+ STRCAT (p, ",");
+ STRCAT (p, "~");
+ ptr = xmlNodeListGetString (doc, cur0->xmlChildrenNode, 1);
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+ }
+ STRCAT(p, ",*");
+ }
+ cur = cur->next;
+ }
+
+ if (cur && xmlStrEqual (cur->name, (xmlChar *) "gpos-features"))
+ {
+ cur0 = cur->xmlChildrenNode;
+ if (xmlStrEqual (cur0->name, (xmlChar *) "positive-list"))
+ {
+ STRCAT(p, "+");
+ for (cur0 = cur0->xmlChildrenNode; cur0; cur0 = cur0->next)
+ {
+ if (p[strlen (p) - 1] != '+')
+ STRCAT (p, ",");
+ ptr = xmlNodeListGetString (doc, cur0->xmlChildrenNode, 1);
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+ }
+ }
+ else if (cur0->xmlChildrenNode) /* at least one negative element */
+ {
+ STRCAT(p, "+");
+ for (cur0 = cur0->xmlChildrenNode; cur0; cur0 = cur0->next)
+ {
+ if (p[strlen (p) - 1] != '+')
+ STRCAT (p, ",");
+ STRCAT (p, "~");
+ ptr = xmlNodeListGetString (doc, cur0->xmlChildrenNode, 1);
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+ }
+ STRCAT(p, ",*");
+ }
+ }
+
+ mplist_add (parent, Msymbol, msymbol (p));
+ free (p);
+}
+
+static void
+decode_lang_specification (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ xmlChar *ptr;
+ char *p = malloc (7);
+
+ sprintf (p, ":lang=");
+
+ while (cur)
+ {
+ if (p[strlen (p) - 1] != '=')
+ STRCAT (p, ",");
+ ptr = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
+ STRCAT (p, ptr);
+ xmlFree (ptr);
+ cur = cur->next;
+ }
+
+ mplist_add (parent, Msymbol, msymbol (p));
+ free (p);
+}
+
+static void
+decode_font (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ xmlChar *ptr;
+
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "foundry")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ ptr = xmlGetProp (cur, (xmlChar *) "family");
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "weight")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "style")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "stretch")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "adstyle")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ }
+ }
+ }
+ }
+ }
+
+ if ((ptr = xmlGetProp (cur, (xmlChar *) "registry")))
+ {
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ }
+
+ cur = cur->xmlChildrenNode;
+
+ if (cur && xmlStrEqual (cur->name, (xmlChar *) "otf-specification"))
+ {
+ decode_otf_specification (doc, cur, parent);
+ cur = cur->next;
+ }
+
+ if (cur)
+ decode_lang_specification (doc, cur, parent);
+}
+
+static xmlChar *
+decode_glyph_code (xmlChar *ptr, MPlist *parent)
+{
+ if (xmlStrlen (ptr) >= 3
+ && (ptr[0] == '0' || ptr[0] == '#')
+ && ptr[1] == 'x')
+ {
+ int val;
+
+ sscanf ((char *) ptr + 2, "%x", &val);
+ mplist_add (parent, Minteger, (void *) val);
+ while (*ptr && ! isspace (*ptr))
+ ptr++;
+ while (*ptr && isspace (*ptr))
+ ptr++;
+ return (ptr);
+ }
+ else if (ptr[0] == '?')
+ {
+ int val, len = 4;
+
+ val = xmlGetUTF8Char (ptr + 1, &len);
+ mplist_add (parent, Minteger, (void *) val);
+ return (ptr + 1 + len);
+ }
+ else
+ {
+ mplist_add (parent, Minteger, (void *) atoi ((char *) ptr));
+ while (*ptr && ! isspace (*ptr))
+ ptr++;
+ while (*ptr && isspace (*ptr))
+ ptr++;
+ return (ptr);
+ }
+}
+
+static void
+decode_category_table (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ MPlist *plist = mplist ();
+
+ mplist_add (plist, Msymbol, msymbol ("category"));
+
+ for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
+ {
+ xmlChar *ptr;
+ MPlist *plist0 = mplist ();
+
+ ptr = xmlGetProp (cur, (xmlChar *) "code");
+ if (ptr)
+ {
+ decode_glyph_code (ptr, plist0);
+ xmlFree (ptr);
+ }
+ else
+ {
+ ptr = xmlGetProp (cur, (xmlChar *) "from-code");
+ decode_glyph_code (ptr, plist0);
+ xmlFree (ptr);
+ ptr = xmlGetProp (cur, (xmlChar *) "to-code");
+ decode_glyph_code (ptr, plist0);
+ xmlFree (ptr);
+ }
+ ptr = xmlGetProp (cur, (xmlChar *) "category-value");
+ mplist_add (plist0, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+
+ mplist_add (plist, Mplist, plist0);
+ M17N_OBJECT_UNREF (plist0);
+ }
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+}
+
+static void
+decode_action (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ xmlChar *ptr;
+
+ if (xmlStrEqual (cur->name, (xmlChar *) "direct-code"))
+ {
+ ptr = xmlGetProp (cur, (xmlChar *) "glyph-code");
+ decode_glyph_code (ptr, parent);
+ xmlFree (ptr);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "copy-glyph"))
+ mplist_add (parent, Msymbol, msymbol ("="));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "repeat"))
+ mplist_add (parent, Msymbol, msymbol ("*"));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "start-cluster"))
+ mplist_add (parent, Msymbol, msymbol ("<"));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "end-cluster"))
+ mplist_add (parent, Msymbol, msymbol (">"));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "left-padding-flag"))
+ mplist_add (parent, Msymbol, msymbol ("["));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "right-padding-flag"))
+ mplist_add (parent, Msymbol, msymbol ("]"));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "separator"))
+ mplist_add (parent, Msymbol, msymbol ("|"));
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "regexp-block"))
+ {
+ MPlist *plist = mplist ();
+
+ ptr = xmlGetProp (cur, (xmlChar *) "regexp");
+ mplist_add (plist, Mtext,
+ mtext_from_data (ptr, xmlStrlen (ptr), MTEXT_FORMAT_UTF_8));
+
+ for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
+ decode_action (doc, cur, plist);
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "match-block"))
+ {
+ MPlist *plist = mplist ();
+
+ ptr = xmlGetProp (cur, (xmlChar *) "match-index");
+ mplist_add (plist, Minteger, (void *) atoi ((char *) ptr));
+ xmlFree (ptr);
+
+ for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
+ decode_action (doc, cur, plist);
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "subst-block"))
+ {
+ MPlist *plist = mplist (), *plist0 = mplist ();
+
+ cur = cur->xmlChildrenNode;
+ if (xmlStrEqual (cur->name, (xmlChar *) "source-pattern"))
+ {
+ xmlChar *start = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
+
+ for (ptr = start; *ptr; ptr = decode_glyph_code (ptr, plist0));
+ xmlFree (start);
+ }
+ else /* code-range */
+ {
+ mplist_add (plist0, Msymbol, msymbol ("range"));
+ ptr = xmlGetProp (cur, (xmlChar *) "from-code");
+ decode_glyph_code (ptr, plist0);
+ xmlFree (ptr);
+ ptr = xmlGetProp (cur, (xmlChar *) "to-code");
+ decode_glyph_code (ptr, plist0);
+ xmlFree (ptr);
+ }
+ mplist_add (plist, Mplist, plist0);
+ M17N_OBJECT_UNREF (plist0);
+
+ for (cur = cur->next; cur; cur = cur->next)
+ decode_action (doc, cur, plist);
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "cond-block"))
+ {
+ MPlist *plist = mplist ();
+
+ mplist_add (plist, Msymbol, msymbol ("cond"));
+
+ for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
+ decode_action (doc, cur, plist);
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "font-facility-block"))
+ {
+ MPlist *plist = mplist (), *plist0 = mplist ();
+
+ mplist_add (plist0, Msymbol, msymbol ("font-facility"));
+
+ cur = cur->xmlChildrenNode;
+ if (xmlStrEqual (cur->name, (xmlChar *) "font"))
+ decode_font (doc, cur, plist0);
+ else /* characters */
+ {
+ xmlChar *start = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
+
+ for (ptr = start; *ptr; ptr = decode_glyph_code (ptr, plist0));
+ xmlFree (start);
+ }
+ mplist_add (plist, Mplist, plist0);
+
+ for (cur = cur->next; cur; cur = cur->next)
+ decode_action (doc, cur, plist);
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "otf-specification"))
+ decode_otf_specification (doc, cur, parent);
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "combining-specification"))
+ {
+ char *v_pos1, *h_pos1, *v_pos2, *h_pos2;
+ char *x_direction, *x_amount, *y_direction, *y_amount;
+ char *combining_name;
+ int len = 6;
+
+ v_pos1 = (char *) xmlGetProp (cur, (xmlChar *) "v-pos1");
+ h_pos1 = (char *) xmlGetProp (cur, (xmlChar *) "h-pos1");
+ v_pos2 = (char *) xmlGetProp (cur, (xmlChar *) "v-pos2");
+ h_pos2 = (char *) xmlGetProp (cur, (xmlChar *) "h-pos2");
+ x_direction = (char *) xmlGetProp (cur, (xmlChar *) "x-direction");
+ x_amount = (char *) xmlGetProp (cur, (xmlChar *) "x-amount");
+ y_direction = (char *) xmlGetProp (cur, (xmlChar *) "y-direction");
+ y_amount = (char *) xmlGetProp (cur, (xmlChar *) "y-amount");
+
+ if (! x_direction && !y_direction)
+ {
+ combining_name = malloc (len);
+ sprintf (combining_name, "%c%c.%c%c",
+ *v_pos1, *h_pos1, *v_pos2, *h_pos2);
+ }
+ else
+ {
+ if (x_direction)
+ len++;
+ if (x_amount)
+ len += strlen (x_amount);
+ if (y_direction)
+ len++;
+ if (y_amount)
+ len += strlen (y_amount);
+ combining_name = malloc (len);
+ sprintf (combining_name, "%c%c%s%s%s%s%c%c",
+ *v_pos1, *h_pos1,
+ ! y_direction ? "" :
+ (! strcmp (y_direction, "up") ? "+" : "-"),
+ y_amount ? y_amount : "",
+ ! x_direction ? "" :
+ (! strcmp (x_direction, "left") ? ">" : "<"),
+ x_amount ? x_amount : "",
+ *v_pos2, *h_pos2);
+ }
+ mplist_add (parent, Msymbol, msymbol (combining_name));
+
+ xmlFree (v_pos1);
+ xmlFree (h_pos1);
+ xmlFree (v_pos2);
+ xmlFree (h_pos2);
+ if (x_direction)
+ xmlFree (x_direction);
+ if (x_amount)
+ xmlFree (x_amount);
+ if (y_direction)
+ xmlFree (y_direction);
+ if (y_amount)
+ xmlFree (y_amount);
+ free (combining_name);
+ }
+
+ else if (xmlStrEqual (cur->name, (xmlChar *) "macro-reference"))
+ {
+ ptr = xmlGetProp (cur, (xmlChar *) "macro-ID");
+ mplist_add (parent, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ }
+
+ else
+ {
+ ptr = cur->name;
+ }
+}
+
+static void
+decode_generator (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ MPlist *plist = mplist ();
+
+ mplist_add (plist, Msymbol, msymbol ("generator"));
+
+ cur = cur->xmlChildrenNode;
+ decode_action (doc, cur, plist);
+
+ /* macro-definition */
+ for (cur = cur->next; cur; cur = cur->next)
+ {
+ xmlNodePtr cur0;
+ xmlChar *ptr;
+ MPlist *plist0 = mplist ();
+
+ ptr = xmlGetProp (cur, (xmlChar *) "macro-ID");
+ mplist_add (plist0, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+ for (cur0 = cur->xmlChildrenNode; cur0; cur0 = cur0->next)
+ decode_action (doc, cur0, plist0);
+ mplist_add (plist, Mplist, plist0);
+ M17N_OBJECT_UNREF (plist0);
+ }
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+}
+
+static void
+decode_first_stage (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ cur = cur->xmlChildrenNode;
+ decode_category_table (doc, cur, parent);
+
+ cur = cur->next;
+ decode_generator (doc, cur, parent);
+}
+
+static void
+decode_stage (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ cur = cur->xmlChildrenNode;
+
+ if (xmlStrEqual (cur->name, (xmlChar *) "category-table"))
+ {
+ decode_category_table (doc, cur, parent);
+ cur = cur->next;
+ }
+
+ decode_generator (doc, cur, parent);
+}
+
+static void
+decode_font_layouter (xmlDocPtr doc, xmlNodePtr cur, MPlist *parent)
+{
+ xmlChar *ptr;
+ MPlist *plist = mplist ();
+ MSymbol Mfont = msymbol ("font");
+
+ mplist_add (plist, Msymbol, Mfont);
+ mplist_add (plist, Msymbol, msymbol ("layouter"));
+
+ ptr = xmlGetProp (cur, (xmlChar *) "key0");
+ mplist_add (plist, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+
+ ptr = xmlGetProp (cur, (xmlChar *) "key1");
+ mplist_add (plist, Msymbol, msymbol ((char *) ptr));
+ xmlFree (ptr);
+
+ cur = xmlDocGetRootElement (doc)->xmlChildrenNode;
+
+ if (xmlStrEqual (cur->name, (xmlChar *) "font"))
+ {
+ MPlist *plist0 = mplist (), *plist1 = mplist ();
+
+ mplist_add (plist0, Msymbol, Mfont);
+ decode_font (doc, cur, plist1);
+ mplist_add (plist0, Mplist, plist1);
+ mplist_add (plist, Mplist, plist0);
+ M17N_OBJECT_UNREF (plist0);
+ M17N_OBJECT_UNREF (plist1);
+ cur = cur->next;
+ }
+
+ mplist_add (parent, Mplist, plist);
+ M17N_OBJECT_UNREF (plist);
+
+ decode_first_stage (doc, cur, parent);
+
+ for (cur = cur->next; cur; cur = cur->next)
+ decode_stage (doc, cur, parent);
+}
+
+MPlist *
+mflt__load_xml (MDatabaseInfo *db_info, char *filename)
+{
+ xmlDocPtr doc;
+ xmlNodePtr cur;
+ MPlist *xml = mplist ();
+
+ doc = xmlReadFile (filename, NULL, XML_PARSE_NOENT | XML_PARSE_NOBLANKS);
+ if (! doc)
+ return NULL;
+
+ cur = xmlDocGetRootElement (doc);
+ if (! cur)
+ {
+ xmlFreeDoc (doc);
+ return NULL;
+ }
+
+ if (xmlStrcmp (cur->name, (xmlChar *) "font-layouter"))
+ {
+ xmlFreeDoc (doc);
+ return NULL;
+ }
+
+ if (! mdatabase__validate (doc, db_info))
+ {
+ xmlFreeDoc (doc);
+ MERROR (MERROR_IM, NULL);
+ }
+
+ decode_font_layouter (doc, cur, xml);
+
+ xmlFreeDoc (doc);
+ return xml;
+}