forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
329
Kha/Tools/linux_x64/std/haxe/xml/Check.hx
Normal file
329
Kha/Tools/linux_x64/std/haxe/xml/Check.hx
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package haxe.xml;
|
||||
|
||||
enum Filter {
|
||||
FInt;
|
||||
FBool;
|
||||
FEnum(values:Array<String>);
|
||||
FReg(matcher:EReg);
|
||||
}
|
||||
|
||||
enum Attrib {
|
||||
Att(name:String, ?filter:Filter, ?defvalue:String);
|
||||
}
|
||||
|
||||
enum Rule {
|
||||
RNode(name:String, ?attribs:Array<Attrib>, ?childs:Rule);
|
||||
RData(?filter:Filter);
|
||||
RMulti(rule:Rule, ?atLeastOne:Bool);
|
||||
RList(rules:Array<Rule>, ?ordered:Bool);
|
||||
RChoice(choices:Array<Rule>);
|
||||
ROptional(rule:Rule);
|
||||
}
|
||||
|
||||
private enum CheckResult {
|
||||
CMatch;
|
||||
CMissing(r:Rule);
|
||||
CExtra(x:Xml);
|
||||
CElementExpected(name:String, x:Xml);
|
||||
CDataExpected(x:Xml);
|
||||
CExtraAttrib(att:String, x:Xml);
|
||||
CMissingAttrib(att:String, x:Xml);
|
||||
CInvalidAttrib(att:String, x:Xml, f:Filter);
|
||||
CInvalidData(x:Xml, f:Filter);
|
||||
CInElement(x:Xml, r:CheckResult);
|
||||
}
|
||||
|
||||
class Check {
|
||||
static var blanks = ~/^[ \r\n\t]*$/;
|
||||
|
||||
static function isBlank(x:Xml) {
|
||||
return (x.nodeType == Xml.PCData && blanks.match(x.nodeValue)) || x.nodeType == Xml.Comment;
|
||||
}
|
||||
|
||||
static function filterMatch(s:String, f:Filter) {
|
||||
switch (f) {
|
||||
case FInt:
|
||||
return filterMatch(s, FReg(~/[0-9]+/));
|
||||
case FBool:
|
||||
return filterMatch(s, FEnum(["true", "false", "0", "1"]));
|
||||
case FEnum(values):
|
||||
for (v in values)
|
||||
if (s == v)
|
||||
return true;
|
||||
return false;
|
||||
case FReg(r):
|
||||
return r.match(s);
|
||||
}
|
||||
}
|
||||
|
||||
static function isNullable(r:Rule) {
|
||||
switch (r) {
|
||||
case RMulti(r, one):
|
||||
return (one != true || isNullable(r));
|
||||
case RList(rl, _):
|
||||
for (r in rl)
|
||||
if (!isNullable(r))
|
||||
return false;
|
||||
return true;
|
||||
case RChoice(rl):
|
||||
for (r in rl)
|
||||
if (isNullable(r))
|
||||
return true;
|
||||
return false;
|
||||
case RData(_):
|
||||
return false;
|
||||
case RNode(_, _, _):
|
||||
return false;
|
||||
case ROptional(_):
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static function check(x:Xml, r:Rule) {
|
||||
switch (r) {
|
||||
// check the node validity
|
||||
case RNode(name, attribs, childs):
|
||||
if (x.nodeType != Xml.Element || x.nodeName != name)
|
||||
return CElementExpected(name, x);
|
||||
var attribs = if (attribs == null) new Array() else attribs.copy();
|
||||
// check defined attributes
|
||||
for (xatt in x.attributes()) {
|
||||
var found = false;
|
||||
for (att in attribs)
|
||||
switch (att) {
|
||||
case Att(name, filter, _):
|
||||
if (xatt != name)
|
||||
continue;
|
||||
if (filter != null && !filterMatch(x.get(xatt), filter))
|
||||
return CInvalidAttrib(name, x, filter);
|
||||
attribs.remove(att);
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
return CExtraAttrib(xatt, x);
|
||||
}
|
||||
// check remaining unchecked attributes
|
||||
for (att in attribs)
|
||||
switch (att) {
|
||||
case Att(name, _, defvalue):
|
||||
if (defvalue == null)
|
||||
return CMissingAttrib(name, x);
|
||||
}
|
||||
// check childs
|
||||
if (childs == null)
|
||||
childs = RList([]);
|
||||
var m = checkList(x.iterator(), childs);
|
||||
if (m != CMatch)
|
||||
return CInElement(x, m);
|
||||
// set default attribs values
|
||||
for (att in attribs)
|
||||
switch (att) {
|
||||
case Att(name, _, defvalue):
|
||||
x.set(name, defvalue);
|
||||
}
|
||||
return CMatch;
|
||||
// check the data validity
|
||||
case RData(filter):
|
||||
if (x.nodeType != Xml.PCData && x.nodeType != Xml.CData)
|
||||
return CDataExpected(x);
|
||||
if (filter != null && !filterMatch(x.nodeValue, filter))
|
||||
return CInvalidData(x, filter);
|
||||
return CMatch;
|
||||
// several choices
|
||||
case RChoice(choices):
|
||||
if (choices.length == 0)
|
||||
throw "No choice possible";
|
||||
for (c in choices)
|
||||
if (check(x, c) == CMatch)
|
||||
return CMatch;
|
||||
return check(x, choices[0]);
|
||||
case ROptional(r):
|
||||
return check(x, r);
|
||||
default:
|
||||
throw "Unexpected " + Std.string(r);
|
||||
}
|
||||
}
|
||||
|
||||
static function checkList(it:Iterator<Xml>, r:Rule) {
|
||||
switch (r) {
|
||||
case RList(rules, ordered):
|
||||
var rules = rules.copy();
|
||||
for (x in it) {
|
||||
if (isBlank(x))
|
||||
continue;
|
||||
var found = false;
|
||||
for (r in rules) {
|
||||
var m = checkList([x].iterator(), r);
|
||||
if (m == CMatch) {
|
||||
found = true;
|
||||
switch (r) {
|
||||
case RMulti(rsub, one):
|
||||
if (one) {
|
||||
var i;
|
||||
for (i in 0...rules.length)
|
||||
if (rules[i] == r)
|
||||
rules[i] = RMulti(rsub);
|
||||
}
|
||||
default:
|
||||
rules.remove(r);
|
||||
}
|
||||
break;
|
||||
} else if (ordered && !isNullable(r))
|
||||
return m;
|
||||
}
|
||||
if (!found)
|
||||
return CExtra(x);
|
||||
}
|
||||
for (r in rules)
|
||||
if (!isNullable(r))
|
||||
return CMissing(r);
|
||||
return CMatch;
|
||||
case RMulti(r, one):
|
||||
var found = false;
|
||||
for (x in it) {
|
||||
if (isBlank(x))
|
||||
continue;
|
||||
var m = checkList([x].iterator(), r);
|
||||
if (m != CMatch)
|
||||
return m;
|
||||
found = true;
|
||||
}
|
||||
if (one && !found)
|
||||
return CMissing(r);
|
||||
return CMatch;
|
||||
default:
|
||||
var found = false;
|
||||
for (x in it) {
|
||||
if (isBlank(x))
|
||||
continue;
|
||||
var m = check(x, r);
|
||||
if (m != CMatch)
|
||||
return m;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
switch (r) {
|
||||
case ROptional(_):
|
||||
default: return CMissing(r);
|
||||
}
|
||||
}
|
||||
for (x in it) {
|
||||
if (isBlank(x))
|
||||
continue;
|
||||
return CExtra(x);
|
||||
}
|
||||
return CMatch;
|
||||
}
|
||||
}
|
||||
|
||||
static function makeWhere(path:Array<Xml>) {
|
||||
if (path.length == 0)
|
||||
return "";
|
||||
var s = "In ";
|
||||
var first = true;
|
||||
for (x in path) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
s += ".";
|
||||
s += x.nodeName;
|
||||
}
|
||||
return s + ": ";
|
||||
}
|
||||
|
||||
static function makeString(x:Xml) {
|
||||
if (x.nodeType == Xml.Element)
|
||||
return "element " + x.nodeName;
|
||||
var s = x.nodeValue.split("\r").join("\\r").split("\n").join("\\n").split("\t").join("\\t");
|
||||
if (s.length > 20)
|
||||
return s.substr(0, 17) + "...";
|
||||
return s;
|
||||
}
|
||||
|
||||
static function makeRule(r:Rule) {
|
||||
switch (r) {
|
||||
case RNode(name, _, _):
|
||||
return "element " + name;
|
||||
case RData(_):
|
||||
return "data";
|
||||
case RMulti(r, _):
|
||||
return makeRule(r);
|
||||
case RList(rules, _):
|
||||
return makeRule(rules[0]);
|
||||
case RChoice(choices):
|
||||
return makeRule(choices[0]);
|
||||
case ROptional(r):
|
||||
return makeRule(r);
|
||||
}
|
||||
}
|
||||
|
||||
static function makeError(m, ?path) {
|
||||
if (path == null)
|
||||
path = new Array();
|
||||
switch (m) {
|
||||
case CMatch:
|
||||
throw "assert";
|
||||
case CMissing(r):
|
||||
return makeWhere(path) + "Missing " + makeRule(r);
|
||||
case CExtra(x):
|
||||
return makeWhere(path) + "Unexpected " + makeString(x);
|
||||
case CElementExpected(name, x):
|
||||
return makeWhere(path) + makeString(x) + " while expected element " + name;
|
||||
case CDataExpected(x):
|
||||
return makeWhere(path) + makeString(x) + " while data expected";
|
||||
case CExtraAttrib(att, x):
|
||||
path.push(x);
|
||||
return makeWhere(path) + "unexpected attribute " + att;
|
||||
case CMissingAttrib(att, x):
|
||||
path.push(x);
|
||||
return makeWhere(path) + "missing required attribute " + att;
|
||||
case CInvalidAttrib(att, x, _):
|
||||
path.push(x);
|
||||
return makeWhere(path) + "invalid attribute value for " + att;
|
||||
case CInvalidData(x, _):
|
||||
return makeWhere(path) + "invalid data format for " + makeString(x);
|
||||
case CInElement(x, m):
|
||||
path.push(x);
|
||||
return makeError(m, path);
|
||||
}
|
||||
}
|
||||
|
||||
public static function checkNode(x:Xml, r:Rule) {
|
||||
var m = checkList([x].iterator(), r);
|
||||
if (m == CMatch)
|
||||
return;
|
||||
throw makeError(m);
|
||||
}
|
||||
|
||||
public static function checkDocument(x:Xml, r:Rule) {
|
||||
if (x.nodeType != Xml.Document)
|
||||
throw "Document expected";
|
||||
var m = checkList(x.iterator(), r);
|
||||
if (m == CMatch)
|
||||
return;
|
||||
throw makeError(m);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user