The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Xml.vala in libbirdxml

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdxml/Xml.vala.
Report error if malloc fails
1 /* 2 Copyright (C) 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 /** 16 * Tools originally written for the BirdFont project. 17 */ 18 namespace Bird { 19 20 /** Log levels */ 21 internal const int NONE = 0; 22 internal const int WARNINGS = 1; 23 24 /** 25 * XML parser 26 * 27 * A tiny XML parser written in Vala. 28 * 29 * Example: 30 * {{{ 31 * 32 * // Print all tags and attributes in an XML document. 33 * // Expected output: 34 * // tag1 35 * // tag2 36 * // attribute1 37 * public static int main (string[] arg) { 38 * Tag root; 39 * XmlParser parser; 40 * 41 * parser = new XmlParser ("""<tag1><tag2 attribute1=""/></tag1>"""); 42 * 43 * if (parser.validate ()) { 44 * root = parser.get_root_tag (); 45 * print_tags (root); 46 * } 47 * } 48 * 49 * 50 * void print_tags (Tag tag) { 51 * print (tag.get_name ()); 52 * print ("\n"); 53 * print_attributes (tag); 54 * 55 * foreach (Tag t in tag) { 56 * print_tags (t); 57 * } 58 * } 59 * 60 * void print_attributes (Tag tag) { 61 * Attributes attributes = tag.get_attributes (); 62 * foreach (Attribute attribute in attributes) { 63 * print (attribute.get_name ()); 64 * print ("\n"); 65 * } 66 * } 67 * 68 * }}} 69 * 70 */ 71 public class XmlParser : GLib.Object { 72 Tag root; 73 XmlData data; 74 string input; 75 bool error; 76 77 /** 78 * Create a new xml parser. 79 * @param data valid xml data 80 */ 81 public XmlParser (string data) { 82 this.input = data; 83 this.data = new XmlData (data, data.length); 84 reparse (NONE); 85 } 86 87 /** 88 * Determine if the document can be parsed. 89 * @return true if the xml document is valid xml. 90 */ 91 public bool validate () { 92 if (this.data.error) { 93 error = true; 94 return false; 95 } 96 97 reparse (NONE); 98 99 if (error) { 100 return false; 101 } 102 103 validate_tags (root); 104 105 reparse (NONE); 106 return !error; 107 } 108 109 void validate_tags (Tag tag) { 110 Attributes attributes = tag.get_attributes (); 111 112 foreach (Attribute a in attributes) { 113 if (tag.has_failed () || a.name.length == 0) { 114 error = true; 115 return; 116 } 117 } 118 119 foreach (Tag t in tag) { 120 if (tag.has_failed ()) { 121 error = true; 122 return; 123 } 124 125 validate_tags (t); 126 } 127 } 128 129 /** 130 * Obtain the root tag. 131 * @return the root tag. 132 */ 133 public Tag get_root_tag () { 134 reparse (WARNINGS); 135 return root; 136 } 137 138 /** 139 * Reset the parser and start from the beginning of the XML document. 140 */ 141 internal void reparse (int log_level) { 142 int root_index; 143 Tag container; 144 XmlString content; 145 XmlString empty; 146 147 error = false; 148 empty = new XmlString ("", 0); 149 150 root_index = find_root_tag (); 151 if (root_index == -1) { 152 if (log_level == WARNINGS) { 153 XmlParser.warning ("No root tag found."); 154 } 155 error = true; 156 root = new Tag.empty (); 157 } else { 158 content = data.substring (root_index); 159 container = new Tag (empty, empty, content, log_level, data); 160 root = container.get_next_tag (); 161 } 162 } 163 164 int find_root_tag () { 165 int index = 0; 166 int prev_index = 0; 167 int modifier = 0; 168 unichar c; 169 170 while (true) { 171 prev_index = index; 172 if (!data.get_next_ascii_char (ref index, out c)) { 173 break; 174 } 175 176 if (c == '<') { 177 modifier = index; 178 data.get_next_ascii_char (ref modifier, out c); 179 if (c != '?' && c != '[' && c != '!') { 180 return prev_index; 181 } 182 } 183 } 184 185 return -1; 186 } 187 188 /** Print a warning message. */ 189 public static void warning (string message) { 190 print ("XML error: "); 191 print (message); 192 print ("\n"); 193 } 194 195 /** Replace escaped character with plain text characters. 196 * &amp; will be replaced with & etc. 197 */ 198 public static string decode (string s) { 199 string t; 200 t = s.replace ("&quot;", "\""); 201 t = t.replace ("&apos;", "'"); 202 t = t.replace ("&lt;", "<"); 203 t = t.replace ("&gt;", ">"); 204 t = t.replace ("&amp;", "&"); 205 return t; 206 } 207 208 public static string encode (string s) { 209 string t; 210 t = s.replace ("\"", "&quot;"); 211 t = t.replace ("'", "&apos;"); 212 t = t.replace ("<", "&lt;"); 213 t = t.replace (">", "&gt;"); 214 t = t.replace ("&", "&amp;"); 215 return t; 216 } 217 218 } 219 220 } 221