diff --git a/go/ql/test/query-tests/Security/CWE-643/go.mod b/go/ql/test/query-tests/Security/CWE-643/go.mod
index 8f574e90cf50..242de16029a4 100644
--- a/go/ql/test/query-tests/Security/CWE-643/go.mod
+++ b/go/ql/test/query-tests/Security/CWE-643/go.mod
@@ -1,13 +1,13 @@
module main
-go 1.21
+go 1.25.0
require (
github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d
github.com/antchfx/htmlquery v1.2.2
github.com/antchfx/jsonquery v1.1.2
github.com/antchfx/xmlquery v1.2.3
- github.com/antchfx/xpath v1.1.5
+ github.com/antchfx/xpath v1.3.6
github.com/go-xmlpath/xmlpath v0.0.0-20150820204837-860cbeca3ebc
github.com/jbowtie/gokogiri v0.0.0-20190301021639-37f655d3078f
github.com/lestrrat-go/libxml2 v0.0.0-20231124114421-99c71026c2f5
@@ -15,14 +15,10 @@ require (
)
require (
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/pkg/errors v0.9.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/stretchr/testify v1.8.4 // indirect
+ golang.org/x/net v0.52.0 // indirect
+ golang.org/x/text v0.35.0 // indirect
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect
- gopkg.in/xmlpath.v1 v1.0.0-20140413065638-a146725ea6e7 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
- launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
- launchpad.net/xmlpath v0.0.0-20130614043138-000000000004 // indirect
+ gopkg.in/xmlpath.v2 v2.0.0-20150820204837-860cbeca3ebc // indirect
)
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml
new file mode 100644
index 000000000000..53c84e840de3
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+
+go:
+ - 1.6
+
+before_install:
+ - go get -u github.com/ChrisTrenkamp/goxpath
+ - go get -u github.com/ChrisTrenkamp/goxpath/cmd/goxpath
+ - go get -u github.com/wadey/gocovmerge
+
+script:
+ - go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {}
+ - gocovmerge `ls *.coverprofile` > coverage.txt
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md
new file mode 100644
index 000000000000..deb49624a385
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md
@@ -0,0 +1,2 @@
+# goxpath [](https://godoc.org/github.com/ChrisTrenkamp/goxpath) [](https://travis-ci.org/ChrisTrenkamp/goxpath) [](https://codecov.io/github/ChrisTrenkamp/goxpath?branch=master) [](https://goreportcard.com/report/github.com/ChrisTrenkamp/goxpath)
+An XPath 1.0 implementation written in Go. See the [wiki](https://github.com/ChrisTrenkamp/goxpath/wiki) for more information.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh
new file mode 100644
index 000000000000..0e35d7de7512
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+go get github.com/ChrisTrenkamp/goxpath/cmd/goxpath
+if [ $? != 0 ]; then
+ exit 1
+fi
+go test >/dev/null 2>&1
+if [ $? != 0 ]; then
+ go test
+ exit 1
+fi
+gometalinter --deadline=1m ./...
+go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}} >/dev/null' ./... | xargs -I {} bash -c {} 2>/dev/null
+gocovmerge `ls *.coverprofile` > coverage.txt
+go tool cover -html=coverage.txt -o coverage.html
+firefox coverage.html
+rm coverage.html coverage.txt *.coverprofile
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go
new file mode 100644
index 000000000000..189ebb9c2faf
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go
@@ -0,0 +1,117 @@
+package goxpath
+
+import (
+ "encoding/xml"
+ "fmt"
+
+ "github.com/ChrisTrenkamp/goxpath/internal/execxp"
+ "github.com/ChrisTrenkamp/goxpath/parser"
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+//Opts defines namespace mappings and custom functions for XPath expressions.
+type Opts struct {
+ NS map[string]string
+ Funcs map[xml.Name]tree.Wrap
+ Vars map[string]tree.Result
+}
+
+//FuncOpts is a function wrapper for Opts.
+type FuncOpts func(*Opts)
+
+//XPathExec is the XPath executor, compiled from an XPath string
+type XPathExec struct {
+ n *parser.Node
+}
+
+//Parse parses the XPath expression, xp, returning an XPath executor.
+func Parse(xp string) (XPathExec, error) {
+ n, err := parser.Parse(xp)
+ return XPathExec{n: n}, err
+}
+
+//MustParse is like Parse, but panics instead of returning an error.
+func MustParse(xp string) XPathExec {
+ ret, err := Parse(xp)
+ if err != nil {
+ panic(err)
+ }
+ return ret
+}
+
+//Exec executes the XPath expression, xp, against the tree, t, with the
+//namespace mappings, ns, and returns the result as a stringer.
+func (xp XPathExec) Exec(t tree.Node, opts ...FuncOpts) (tree.Result, error) {
+ o := &Opts{
+ NS: make(map[string]string),
+ Funcs: make(map[xml.Name]tree.Wrap),
+ Vars: make(map[string]tree.Result),
+ }
+ for _, i := range opts {
+ i(o)
+ }
+ return execxp.Exec(xp.n, t, o.NS, o.Funcs, o.Vars)
+}
+
+//ExecBool is like Exec, except it will attempt to convert the result to its boolean value.
+func (xp XPathExec) ExecBool(t tree.Node, opts ...FuncOpts) (bool, error) {
+ res, err := xp.Exec(t, opts...)
+ if err != nil {
+ return false, err
+ }
+
+ b, ok := res.(tree.IsBool)
+ if !ok {
+ return false, fmt.Errorf("Cannot convert result to a boolean")
+ }
+
+ return bool(b.Bool()), nil
+}
+
+//ExecNum is like Exec, except it will attempt to convert the result to its number value.
+func (xp XPathExec) ExecNum(t tree.Node, opts ...FuncOpts) (float64, error) {
+ res, err := xp.Exec(t, opts...)
+ if err != nil {
+ return 0, err
+ }
+
+ n, ok := res.(tree.IsNum)
+ if !ok {
+ return 0, fmt.Errorf("Cannot convert result to a number")
+ }
+
+ return float64(n.Num()), nil
+}
+
+//ExecNode is like Exec, except it will attempt to return the result as a node-set.
+func (xp XPathExec) ExecNode(t tree.Node, opts ...FuncOpts) (tree.NodeSet, error) {
+ res, err := xp.Exec(t, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ n, ok := res.(tree.NodeSet)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert result to a node-set")
+ }
+
+ return n, nil
+}
+
+//MustExec is like Exec, but panics instead of returning an error.
+func (xp XPathExec) MustExec(t tree.Node, opts ...FuncOpts) tree.Result {
+ res, err := xp.Exec(t, opts...)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+//ParseExec parses the XPath string, xpstr, and runs Exec.
+func ParseExec(xpstr string, t tree.Node, opts ...FuncOpts) (tree.Result, error) {
+ xp, err := Parse(xpstr)
+ if err != nil {
+ return nil, err
+ }
+ return xp.Exec(t, opts...)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go
new file mode 100644
index 000000000000..7b32515683e8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go
@@ -0,0 +1,27 @@
+package execxp
+
+import (
+ "encoding/xml"
+
+ "github.com/ChrisTrenkamp/goxpath/parser"
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+//Exec executes the XPath expression, xp, against the tree, t, with the
+//namespace mappings, ns.
+func Exec(n *parser.Node, t tree.Node, ns map[string]string, fns map[xml.Name]tree.Wrap, v map[string]tree.Result) (tree.Result, error) {
+ f := xpFilt{
+ t: t,
+ ns: ns,
+ ctx: tree.NodeSet{t},
+ fns: fns,
+ variables: v,
+ }
+
+ return exec(&f, n)
+}
+
+func exec(f *xpFilt, n *parser.Node) (tree.Result, error) {
+ err := xfExec(f, n)
+ return f.ctx, err
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go
new file mode 100644
index 000000000000..058f79a0bd68
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go
@@ -0,0 +1,307 @@
+package findutil
+
+import (
+ "encoding/xml"
+
+ "github.com/ChrisTrenkamp/goxpath/parser/pathexpr"
+ "github.com/ChrisTrenkamp/goxpath/tree"
+ "github.com/ChrisTrenkamp/goxpath/xconst"
+)
+
+const (
+ wildcard = "*"
+)
+
+type findFunc func(tree.Node, *pathexpr.PathExpr, *[]tree.Node)
+
+var findMap = map[string]findFunc{
+ xconst.AxisAncestor: findAncestor,
+ xconst.AxisAncestorOrSelf: findAncestorOrSelf,
+ xconst.AxisAttribute: findAttribute,
+ xconst.AxisChild: findChild,
+ xconst.AxisDescendent: findDescendent,
+ xconst.AxisDescendentOrSelf: findDescendentOrSelf,
+ xconst.AxisFollowing: findFollowing,
+ xconst.AxisFollowingSibling: findFollowingSibling,
+ xconst.AxisNamespace: findNamespace,
+ xconst.AxisParent: findParent,
+ xconst.AxisPreceding: findPreceding,
+ xconst.AxisPrecedingSibling: findPrecedingSibling,
+ xconst.AxisSelf: findSelf,
+}
+
+//Find finds nodes based on the pathexpr.PathExpr
+func Find(x tree.Node, p pathexpr.PathExpr) []tree.Node {
+ ret := []tree.Node{}
+
+ if p.Axis == "" {
+ findChild(x, &p, &ret)
+ return ret
+ }
+
+ f := findMap[p.Axis]
+ f(x, &p, &ret)
+
+ return ret
+}
+
+func findAncestor(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() == tree.NtRoot {
+ return
+ }
+
+ addNode(x.GetParent(), p, ret)
+ findAncestor(x.GetParent(), p, ret)
+}
+
+func findAncestorOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ findSelf(x, p, ret)
+ findAncestor(x, p, ret)
+}
+
+func findAttribute(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if ele, ok := x.(tree.Elem); ok {
+ for _, i := range ele.GetAttrs() {
+ addNode(i, p, ret)
+ }
+ }
+}
+
+func findChild(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if ele, ok := x.(tree.Elem); ok {
+ ch := ele.GetChildren()
+ for i := range ch {
+ addNode(ch[i], p, ret)
+ }
+ }
+}
+
+func findDescendent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if ele, ok := x.(tree.Elem); ok {
+ ch := ele.GetChildren()
+ for i := range ch {
+ addNode(ch[i], p, ret)
+ findDescendent(ch[i], p, ret)
+ }
+ }
+}
+
+func findDescendentOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ findSelf(x, p, ret)
+ findDescendent(x, p, ret)
+}
+
+func findFollowing(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() == tree.NtRoot {
+ return
+ }
+ par := x.GetParent()
+ ch := par.GetChildren()
+ i := 0
+ for x != ch[i] {
+ i++
+ }
+ i++
+ for i < len(ch) {
+ findDescendentOrSelf(ch[i], p, ret)
+ i++
+ }
+ findFollowing(par, p, ret)
+}
+
+func findFollowingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() == tree.NtRoot {
+ return
+ }
+ par := x.GetParent()
+ ch := par.GetChildren()
+ i := 0
+ for x != ch[i] {
+ i++
+ }
+ i++
+ for i < len(ch) {
+ findSelf(ch[i], p, ret)
+ i++
+ }
+}
+
+func findNamespace(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if ele, ok := x.(tree.NSElem); ok {
+ ns := tree.BuildNS(ele)
+ for _, i := range ns {
+ addNode(i, p, ret)
+ }
+ }
+}
+
+func findParent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() != tree.NtRoot {
+ addNode(x.GetParent(), p, ret)
+ }
+}
+
+func findPreceding(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() == tree.NtRoot {
+ return
+ }
+ par := x.GetParent()
+ ch := par.GetChildren()
+ i := len(ch) - 1
+ for x != ch[i] {
+ i--
+ }
+ i--
+ for i >= 0 {
+ findDescendentOrSelf(ch[i], p, ret)
+ i--
+ }
+ findPreceding(par, p, ret)
+}
+
+func findPrecedingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ if x.GetNodeType() == tree.NtRoot {
+ return
+ }
+ par := x.GetParent()
+ ch := par.GetChildren()
+ i := len(ch) - 1
+ for x != ch[i] {
+ i--
+ }
+ i--
+ for i >= 0 {
+ findSelf(ch[i], p, ret)
+ i--
+ }
+}
+
+func findSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ addNode(x, p, ret)
+}
+
+func addNode(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
+ add := false
+ tok := x.GetToken()
+
+ switch x.GetNodeType() {
+ case tree.NtAttr:
+ add = evalAttr(p, tok.(xml.Attr))
+ case tree.NtChd:
+ add = evalChd(p)
+ case tree.NtComm:
+ add = evalComm(p)
+ case tree.NtElem, tree.NtRoot:
+ add = evalEle(p, tok.(xml.StartElement))
+ case tree.NtNs:
+ add = evalNS(p, tok.(xml.Attr))
+ case tree.NtPi:
+ add = evalPI(p)
+ }
+
+ if add {
+ *ret = append(*ret, x)
+ }
+}
+
+func evalAttr(p *pathexpr.PathExpr, a xml.Attr) bool {
+ if p.NodeType == "" {
+ if p.Name.Space != wildcard {
+ if a.Name.Space != p.NS[p.Name.Space] {
+ return false
+ }
+ }
+
+ if p.Name.Local == wildcard && p.Axis == xconst.AxisAttribute {
+ return true
+ }
+
+ if p.Name.Local == a.Name.Local {
+ return true
+ }
+ } else {
+ if p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+ }
+
+ return false
+}
+
+func evalChd(p *pathexpr.PathExpr) bool {
+ if p.NodeType == xconst.NodeTypeText || p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+
+ return false
+}
+
+func evalComm(p *pathexpr.PathExpr) bool {
+ if p.NodeType == xconst.NodeTypeComment || p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+
+ return false
+}
+
+func evalEle(p *pathexpr.PathExpr, ele xml.StartElement) bool {
+ if p.NodeType == "" {
+ return checkNameAndSpace(p, ele)
+ }
+
+ if p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+
+ return false
+}
+
+func checkNameAndSpace(p *pathexpr.PathExpr, ele xml.StartElement) bool {
+ if p.Name.Local == wildcard && p.Name.Space == "" {
+ return true
+ }
+
+ if p.Name.Space != wildcard && ele.Name.Space != p.NS[p.Name.Space] {
+ return false
+ }
+
+ if p.Name.Local == wildcard && p.Axis != xconst.AxisAttribute && p.Axis != xconst.AxisNamespace {
+ return true
+ }
+
+ if p.Name.Local == ele.Name.Local {
+ return true
+ }
+
+ return false
+}
+
+func evalNS(p *pathexpr.PathExpr, ns xml.Attr) bool {
+ if p.NodeType == "" {
+ if p.Name.Space != "" && p.Name.Space != wildcard {
+ return false
+ }
+
+ if p.Name.Local == wildcard && p.Axis == xconst.AxisNamespace {
+ return true
+ }
+
+ if p.Name.Local == ns.Name.Local {
+ return true
+ }
+ } else {
+ if p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+ }
+
+ return false
+}
+
+func evalPI(p *pathexpr.PathExpr) bool {
+ if p.NodeType == xconst.NodeTypeProcInst || p.NodeType == xconst.NodeTypeNode {
+ return true
+ }
+
+ return false
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go
new file mode 100644
index 000000000000..5480ebcc4e9e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go
@@ -0,0 +1,74 @@
+package intfns
+
+import (
+ "fmt"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+ "golang.org/x/text/language"
+)
+
+func boolean(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ if b, ok := args[0].(tree.IsBool); ok {
+ return b.Bool(), nil
+ }
+
+ return nil, fmt.Errorf("Cannot convert object to a boolean")
+}
+
+func not(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ b, ok := args[0].(tree.IsBool)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a boolean")
+ }
+ return !b.Bool(), nil
+}
+
+func _true(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Bool(true), nil
+}
+
+func _false(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Bool(false), nil
+}
+
+func lang(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ lStr := args[0].String()
+
+ var n tree.Elem
+
+ for _, i := range c.NodeSet {
+ if i.GetNodeType() == tree.NtElem {
+ n = i.(tree.Elem)
+ } else {
+ n = i.GetParent()
+ }
+
+ for n.GetNodeType() != tree.NtRoot {
+ if attr, ok := tree.GetAttribute(n, "lang", tree.XMLSpace); ok {
+ return checkLang(lStr, attr.Value), nil
+ }
+ n = n.GetParent()
+ }
+ }
+
+ return tree.Bool(false), nil
+}
+
+func checkLang(srcStr, targStr string) tree.Bool {
+ srcLang := language.Make(srcStr)
+ srcRegion, srcRegionConf := srcLang.Region()
+
+ targLang := language.Make(targStr)
+ targRegion, targRegionConf := targLang.Region()
+
+ if srcRegionConf == language.Exact && targRegionConf != language.Exact {
+ return tree.Bool(false)
+ }
+
+ if srcRegion != targRegion && srcRegionConf == language.Exact && targRegionConf == language.Exact {
+ return tree.Bool(false)
+ }
+
+ _, _, conf := language.NewMatcher([]language.Tag{srcLang}).Match(targLang)
+ return tree.Bool(conf >= language.High)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go
new file mode 100644
index 000000000000..8b09fa99f5ad
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go
@@ -0,0 +1,41 @@
+package intfns
+
+import (
+ "encoding/xml"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+//BuiltIn contains the list of built-in XPath functions
+var BuiltIn = map[xml.Name]tree.Wrap{
+ //String functions
+ {Local: "string"}: {Fn: _string, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "concat"}: {Fn: concat, NArgs: 3, LastArgOpt: tree.Variadic},
+ {Local: "starts-with"}: {Fn: startsWith, NArgs: 2},
+ {Local: "contains"}: {Fn: contains, NArgs: 2},
+ {Local: "substring-before"}: {Fn: substringBefore, NArgs: 2},
+ {Local: "substring-after"}: {Fn: substringAfter, NArgs: 2},
+ {Local: "substring"}: {Fn: substring, NArgs: 3, LastArgOpt: tree.Optional},
+ {Local: "string-length"}: {Fn: stringLength, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "normalize-space"}: {Fn: normalizeSpace, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "translate"}: {Fn: translate, NArgs: 3},
+ //Node set functions
+ {Local: "last"}: {Fn: last},
+ {Local: "position"}: {Fn: position},
+ {Local: "count"}: {Fn: count, NArgs: 1},
+ {Local: "local-name"}: {Fn: localName, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "namespace-uri"}: {Fn: namespaceURI, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "name"}: {Fn: name, NArgs: 1, LastArgOpt: tree.Optional},
+ //boolean functions
+ {Local: "boolean"}: {Fn: boolean, NArgs: 1},
+ {Local: "not"}: {Fn: not, NArgs: 1},
+ {Local: "true"}: {Fn: _true},
+ {Local: "false"}: {Fn: _false},
+ {Local: "lang"}: {Fn: lang, NArgs: 1},
+ //number functions
+ {Local: "number"}: {Fn: number, NArgs: 1, LastArgOpt: tree.Optional},
+ {Local: "sum"}: {Fn: sum, NArgs: 1},
+ {Local: "floor"}: {Fn: floor, NArgs: 1},
+ {Local: "ceiling"}: {Fn: ceiling, NArgs: 1},
+ {Local: "round"}: {Fn: round, NArgs: 1},
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go
new file mode 100644
index 000000000000..7286a304259c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go
@@ -0,0 +1,131 @@
+package intfns
+
+import (
+ "encoding/xml"
+ "fmt"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+func last(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Num(c.Size), nil
+}
+
+func position(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Num(c.Pos), nil
+}
+
+func count(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ n, ok := args[0].(tree.NodeSet)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a node-set")
+ }
+
+ return tree.Num(len(n)), nil
+}
+
+func localName(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ var n tree.NodeSet
+ ok := true
+ if len(args) == 1 {
+ n, ok = args[0].(tree.NodeSet)
+ } else {
+ n = c.NodeSet
+ }
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a node-set")
+ }
+
+ ret := ""
+ if len(n) == 0 {
+ return tree.String(ret), nil
+ }
+ node := n[0]
+
+ tok := node.GetToken()
+
+ switch node.GetNodeType() {
+ case tree.NtElem:
+ ret = tok.(xml.StartElement).Name.Local
+ case tree.NtAttr:
+ ret = tok.(xml.Attr).Name.Local
+ case tree.NtPi:
+ ret = tok.(xml.ProcInst).Target
+ }
+
+ return tree.String(ret), nil
+}
+
+func namespaceURI(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ var n tree.NodeSet
+ ok := true
+ if len(args) == 1 {
+ n, ok = args[0].(tree.NodeSet)
+ } else {
+ n = c.NodeSet
+ }
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a node-set")
+ }
+
+ ret := ""
+ if len(n) == 0 {
+ return tree.String(ret), nil
+ }
+ node := n[0]
+
+ tok := node.GetToken()
+
+ switch node.GetNodeType() {
+ case tree.NtElem:
+ ret = tok.(xml.StartElement).Name.Space
+ case tree.NtAttr:
+ ret = tok.(xml.Attr).Name.Space
+ }
+
+ return tree.String(ret), nil
+}
+
+func name(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ var n tree.NodeSet
+ ok := true
+ if len(args) == 1 {
+ n, ok = args[0].(tree.NodeSet)
+ } else {
+ n = c.NodeSet
+ }
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a node-set")
+ }
+
+ ret := ""
+ if len(n) == 0 {
+ return tree.String(ret), nil
+ }
+ node := n[0]
+
+ switch node.GetNodeType() {
+ case tree.NtElem:
+ t := node.GetToken().(xml.StartElement)
+ space := ""
+
+ if t.Name.Space != "" {
+ space = fmt.Sprintf("{%s}", t.Name.Space)
+ }
+
+ ret = fmt.Sprintf("%s%s", space, t.Name.Local)
+ case tree.NtAttr:
+ t := node.GetToken().(xml.Attr)
+ space := ""
+
+ if t.Name.Space != "" {
+ space = fmt.Sprintf("{%s}", t.Name.Space)
+ }
+
+ ret = fmt.Sprintf("%s%s", space, t.Name.Local)
+ case tree.NtPi:
+ ret = fmt.Sprintf("%s", node.GetToken().(xml.ProcInst).Target)
+ }
+
+ return tree.String(ret), nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go
new file mode 100644
index 000000000000..464403f96b97
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go
@@ -0,0 +1,71 @@
+package intfns
+
+import (
+ "fmt"
+ "math"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+func number(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ if b, ok := args[0].(tree.IsNum); ok {
+ return b.Num(), nil
+ }
+
+ return nil, fmt.Errorf("Cannot convert object to a number")
+}
+
+func sum(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ n, ok := args[0].(tree.NodeSet)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a node-set")
+ }
+
+ ret := 0.0
+ for _, i := range n {
+ ret += float64(tree.GetNodeNum(i))
+ }
+
+ return tree.Num(ret), nil
+}
+
+func floor(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ n, ok := args[0].(tree.IsNum)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a number")
+ }
+
+ return tree.Num(math.Floor(float64(n.Num()))), nil
+}
+
+func ceiling(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ n, ok := args[0].(tree.IsNum)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a number")
+ }
+
+ return tree.Num(math.Ceil(float64(n.Num()))), nil
+}
+
+func round(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ isn, ok := args[0].(tree.IsNum)
+ if !ok {
+ return nil, fmt.Errorf("Cannot convert object to a number")
+ }
+
+ n := isn.Num()
+
+ if math.IsNaN(float64(n)) || math.IsInf(float64(n), 0) {
+ return n, nil
+ }
+
+ if n < -0.5 {
+ n = tree.Num(int(n - 0.5))
+ } else if n > 0.5 {
+ n = tree.Num(int(n + 0.5))
+ } else {
+ n = 0
+ }
+
+ return n, nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go
new file mode 100644
index 000000000000..4e6a73a09984
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go
@@ -0,0 +1,141 @@
+package intfns
+
+import (
+ "math"
+ "regexp"
+ "strings"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+func _string(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ if len(args) == 1 {
+ return tree.String(args[0].String()), nil
+ }
+
+ return tree.String(c.NodeSet.String()), nil
+}
+
+func concat(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ ret := ""
+
+ for _, i := range args {
+ ret += i.String()
+ }
+
+ return tree.String(ret), nil
+}
+
+func startsWith(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Bool(strings.Index(args[0].String(), args[1].String()) == 0), nil
+}
+
+func contains(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ return tree.Bool(strings.Contains(args[0].String(), args[1].String())), nil
+}
+
+func substringBefore(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ ind := strings.Index(args[0].String(), args[1].String())
+ if ind == -1 {
+ return tree.String(""), nil
+ }
+
+ return tree.String(args[0].String()[:ind]), nil
+}
+
+func substringAfter(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ ind := strings.Index(args[0].String(), args[1].String())
+ if ind == -1 {
+ return tree.String(""), nil
+ }
+
+ return tree.String(args[0].String()[ind+len(args[1].String()):]), nil
+}
+
+func substring(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ str := args[0].String()
+
+ bNum, bErr := round(c, args[1])
+ if bErr != nil {
+ return nil, bErr
+ }
+
+ b := bNum.(tree.Num).Num()
+
+ if float64(b-1) >= float64(len(str)) || math.IsNaN(float64(b)) {
+ return tree.String(""), nil
+ }
+
+ if len(args) == 2 {
+ if b <= 1 {
+ b = 1
+ }
+
+ return tree.String(str[int(b)-1:]), nil
+ }
+
+ eNum, eErr := round(c, args[2])
+ if eErr != nil {
+ return nil, eErr
+ }
+
+ e := eNum.(tree.Num).Num()
+
+ if e <= 0 || math.IsNaN(float64(e)) || (math.IsInf(float64(b), 0) && math.IsInf(float64(e), 0)) {
+ return tree.String(""), nil
+ }
+
+ if b <= 1 {
+ e = b + e - 1
+ b = 1
+ }
+
+ if float64(b+e-1) >= float64(len(str)) {
+ e = tree.Num(len(str)) - b + 1
+ }
+
+ return tree.String(str[int(b)-1 : int(b+e)-1]), nil
+}
+
+func stringLength(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ var str string
+ if len(args) == 1 {
+ str = args[0].String()
+ } else {
+ str = c.NodeSet.String()
+ }
+
+ return tree.Num(len(str)), nil
+}
+
+var spaceTrim = regexp.MustCompile(`\s+`)
+
+func normalizeSpace(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ var str string
+ if len(args) == 1 {
+ str = args[0].String()
+ } else {
+ str = c.NodeSet.String()
+ }
+
+ str = strings.TrimSpace(str)
+
+ return tree.String(spaceTrim.ReplaceAllString(str, " ")), nil
+}
+
+func translate(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
+ ret := args[0].String()
+ src := args[1].String()
+ repl := args[2].String()
+
+ for i := range src {
+ r := ""
+ if i < len(repl) {
+ r = string(repl[i])
+ }
+
+ ret = strings.Replace(ret, string(src[i]), r, -1)
+ }
+
+ return tree.String(ret), nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go
new file mode 100644
index 000000000000..d41ba7fcc7b1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go
@@ -0,0 +1,212 @@
+package execxp
+
+import (
+ "fmt"
+ "math"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+func bothNodeOperator(left tree.NodeSet, right tree.NodeSet, f *xpFilt, op string) error {
+ var err error
+ for _, l := range left {
+ for _, r := range right {
+ lStr := l.ResValue()
+ rStr := r.ResValue()
+
+ if eqOps[op] {
+ err = equalsOperator(tree.String(lStr), tree.String(rStr), f, op)
+ if err == nil && f.ctx.String() == tree.True {
+ return nil
+ }
+ } else {
+ err = numberOperator(tree.String(lStr), tree.String(rStr), f, op)
+ if err == nil && f.ctx.String() == tree.True {
+ return nil
+ }
+ }
+ }
+ }
+
+ f.ctx = tree.Bool(false)
+
+ return nil
+}
+
+func leftNodeOperator(left tree.NodeSet, right tree.Result, f *xpFilt, op string) error {
+ var err error
+ for _, l := range left {
+ lStr := l.ResValue()
+
+ if eqOps[op] {
+ err = equalsOperator(tree.String(lStr), right, f, op)
+ if err == nil && f.ctx.String() == tree.True {
+ return nil
+ }
+ } else {
+ err = numberOperator(tree.String(lStr), right, f, op)
+ if err == nil && f.ctx.String() == tree.True {
+ return nil
+ }
+ }
+ }
+
+ f.ctx = tree.Bool(false)
+
+ return nil
+}
+
+func rightNodeOperator(left tree.Result, right tree.NodeSet, f *xpFilt, op string) error {
+ var err error
+ for _, r := range right {
+ rStr := r.ResValue()
+
+ if eqOps[op] {
+ err = equalsOperator(left, tree.String(rStr), f, op)
+ if err == nil && f.ctx.String() == "true" {
+ return nil
+ }
+ } else {
+ err = numberOperator(left, tree.String(rStr), f, op)
+ if err == nil && f.ctx.String() == "true" {
+ return nil
+ }
+ }
+ }
+
+ f.ctx = tree.Bool(false)
+
+ return nil
+}
+
+func equalsOperator(left, right tree.Result, f *xpFilt, op string) error {
+ _, lOK := left.(tree.Bool)
+ _, rOK := right.(tree.Bool)
+
+ if lOK || rOK {
+ lTest, lt := left.(tree.IsBool)
+ rTest, rt := right.(tree.IsBool)
+ if !lt || !rt {
+ return fmt.Errorf("Cannot convert argument to boolean")
+ }
+
+ if op == "=" {
+ f.ctx = tree.Bool(lTest.Bool() == rTest.Bool())
+ } else {
+ f.ctx = tree.Bool(lTest.Bool() != rTest.Bool())
+ }
+
+ return nil
+ }
+
+ _, lOK = left.(tree.Num)
+ _, rOK = right.(tree.Num)
+ if lOK || rOK {
+ return numberOperator(left, right, f, op)
+ }
+
+ lStr := left.String()
+ rStr := right.String()
+
+ if op == "=" {
+ f.ctx = tree.Bool(lStr == rStr)
+ } else {
+ f.ctx = tree.Bool(lStr != rStr)
+ }
+
+ return nil
+}
+
+func numberOperator(left, right tree.Result, f *xpFilt, op string) error {
+ lt, lOK := left.(tree.IsNum)
+ rt, rOK := right.(tree.IsNum)
+ if !lOK || !rOK {
+ return fmt.Errorf("Cannot convert data type to number")
+ }
+
+ ln, rn := lt.Num(), rt.Num()
+
+ switch op {
+ case "*":
+ f.ctx = ln * rn
+ case "div":
+ if rn != 0 {
+ f.ctx = ln / rn
+ } else {
+ if ln == 0 {
+ f.ctx = tree.Num(math.NaN())
+ } else {
+ if math.Signbit(float64(ln)) == math.Signbit(float64(rn)) {
+ f.ctx = tree.Num(math.Inf(1))
+ } else {
+ f.ctx = tree.Num(math.Inf(-1))
+ }
+ }
+ }
+ case "mod":
+ f.ctx = tree.Num(int(ln) % int(rn))
+ case "+":
+ f.ctx = ln + rn
+ case "-":
+ f.ctx = ln - rn
+ case "=":
+ f.ctx = tree.Bool(ln == rn)
+ case "!=":
+ f.ctx = tree.Bool(ln != rn)
+ case "<":
+ f.ctx = tree.Bool(ln < rn)
+ case "<=":
+ f.ctx = tree.Bool(ln <= rn)
+ case ">":
+ f.ctx = tree.Bool(ln > rn)
+ case ">=":
+ f.ctx = tree.Bool(ln >= rn)
+ }
+
+ return nil
+}
+
+func andOrOperator(left, right tree.Result, f *xpFilt, op string) error {
+ lt, lOK := left.(tree.IsBool)
+ rt, rOK := right.(tree.IsBool)
+
+ if !lOK || !rOK {
+ return fmt.Errorf("Cannot convert argument to boolean")
+ }
+
+ l, r := lt.Bool(), rt.Bool()
+
+ if op == "and" {
+ f.ctx = l && r
+ } else {
+ f.ctx = l || r
+ }
+
+ return nil
+}
+
+func unionOperator(left, right tree.Result, f *xpFilt, op string) error {
+ lNode, lOK := left.(tree.NodeSet)
+ rNode, rOK := right.(tree.NodeSet)
+
+ if !lOK || !rOK {
+ return fmt.Errorf("Cannot convert data type to node-set")
+ }
+
+ uniq := make(map[int]tree.Node)
+ for _, i := range lNode {
+ uniq[i.Pos()] = i
+ }
+ for _, i := range rNode {
+ uniq[i.Pos()] = i
+ }
+
+ res := make(tree.NodeSet, 0, len(uniq))
+ for _, v := range uniq {
+ res = append(res, v)
+ }
+
+ f.ctx = res
+
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go
new file mode 100644
index 000000000000..5a78138eef49
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go
@@ -0,0 +1,396 @@
+package execxp
+
+import (
+ "encoding/xml"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil"
+ "github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns"
+ "github.com/ChrisTrenkamp/goxpath/internal/xsort"
+ "github.com/ChrisTrenkamp/goxpath/lexer"
+ "github.com/ChrisTrenkamp/goxpath/parser"
+ "github.com/ChrisTrenkamp/goxpath/parser/pathexpr"
+ "github.com/ChrisTrenkamp/goxpath/tree"
+ "github.com/ChrisTrenkamp/goxpath/xconst"
+)
+
+type xpFilt struct {
+ t tree.Node
+ ctx tree.Result
+ expr pathexpr.PathExpr
+ ns map[string]string
+ ctxPos int
+ ctxSize int
+ proxPos map[int]int
+ fns map[xml.Name]tree.Wrap
+ variables map[string]tree.Result
+}
+
+type xpExecFn func(*xpFilt, string)
+
+var xpFns = map[lexer.XItemType]xpExecFn{
+ lexer.XItemAbsLocPath: xfAbsLocPath,
+ lexer.XItemAbbrAbsLocPath: xfAbbrAbsLocPath,
+ lexer.XItemRelLocPath: xfRelLocPath,
+ lexer.XItemAbbrRelLocPath: xfAbbrRelLocPath,
+ lexer.XItemAxis: xfAxis,
+ lexer.XItemAbbrAxis: xfAbbrAxis,
+ lexer.XItemNCName: xfNCName,
+ lexer.XItemQName: xfQName,
+ lexer.XItemNodeType: xfNodeType,
+ lexer.XItemProcLit: xfProcInstLit,
+ lexer.XItemStrLit: xfStrLit,
+ lexer.XItemNumLit: xfNumLit,
+}
+
+func xfExec(f *xpFilt, n *parser.Node) (err error) {
+ for n != nil {
+ if fn, ok := xpFns[n.Val.Typ]; ok {
+ fn(f, n.Val.Val)
+ n = n.Left
+ } else if n.Val.Typ == lexer.XItemPredicate {
+ if err = xfPredicate(f, n.Left); err != nil {
+ return
+ }
+
+ n = n.Right
+ } else if n.Val.Typ == lexer.XItemFunction {
+ if err = xfFunction(f, n); err != nil {
+ return
+ }
+
+ n = n.Right
+ } else if n.Val.Typ == lexer.XItemOperator {
+ lf := xpFilt{
+ t: f.t,
+ ns: f.ns,
+ ctx: f.ctx,
+ ctxPos: f.ctxPos,
+ ctxSize: f.ctxSize,
+ proxPos: f.proxPos,
+ fns: f.fns,
+ variables: f.variables,
+ }
+ left, err := exec(&lf, n.Left)
+ if err != nil {
+ return err
+ }
+
+ rf := xpFilt{
+ t: f.t,
+ ns: f.ns,
+ ctx: f.ctx,
+ fns: f.fns,
+ variables: f.variables,
+ }
+ right, err := exec(&rf, n.Right)
+ if err != nil {
+ return err
+ }
+
+ return xfOperator(left, right, f, n.Val.Val)
+ } else if n.Val.Typ == lexer.XItemVariable {
+ if res, ok := f.variables[n.Val.Val]; ok {
+ f.ctx = res
+ return nil
+ }
+ return fmt.Errorf("Invalid variable '%s'", n.Val.Val)
+ } else if string(n.Val.Typ) == "" {
+ n = n.Left
+ //} else {
+ // return fmt.Errorf("Cannot process " + string(n.Val.Typ))
+ }
+ }
+
+ return
+}
+
+func xfPredicate(f *xpFilt, n *parser.Node) (err error) {
+ res := f.ctx.(tree.NodeSet)
+ newRes := make(tree.NodeSet, 0, len(res))
+
+ for i := range res {
+ pf := xpFilt{
+ t: f.t,
+ ns: f.ns,
+ ctxPos: i,
+ ctxSize: f.ctxSize,
+ ctx: tree.NodeSet{res[i]},
+ fns: f.fns,
+ variables: f.variables,
+ }
+
+ predRes, err := exec(&pf, n)
+ if err != nil {
+ return err
+ }
+
+ ok, err := checkPredRes(predRes, f, res[i])
+ if err != nil {
+ return err
+ }
+
+ if ok {
+ newRes = append(newRes, res[i])
+ }
+ }
+
+ f.proxPos = make(map[int]int)
+ for pos, j := range newRes {
+ f.proxPos[j.Pos()] = pos + 1
+ }
+
+ f.ctx = newRes
+ f.ctxSize = len(newRes)
+
+ return
+}
+
+func checkPredRes(ret tree.Result, f *xpFilt, node tree.Node) (bool, error) {
+ if num, ok := ret.(tree.Num); ok {
+ if float64(f.proxPos[node.Pos()]) == float64(num) {
+ return true, nil
+ }
+ return false, nil
+ }
+
+ if b, ok := ret.(tree.IsBool); ok {
+ return bool(b.Bool()), nil
+ }
+
+ return false, fmt.Errorf("Cannot convert argument to boolean")
+}
+
+func xfFunction(f *xpFilt, n *parser.Node) error {
+ spl := strings.Split(n.Val.Val, ":")
+ var name xml.Name
+ if len(spl) == 1 {
+ name.Local = spl[0]
+ } else {
+ name.Space = f.ns[spl[0]]
+ name.Local = spl[1]
+ }
+ fn, ok := intfns.BuiltIn[name]
+ if !ok {
+ fn, ok = f.fns[name]
+ }
+
+ if ok {
+ args := []tree.Result{}
+ param := n.Left
+
+ for param != nil {
+ pf := xpFilt{
+ t: f.t,
+ ctx: f.ctx,
+ ns: f.ns,
+ ctxPos: f.ctxPos,
+ ctxSize: f.ctxSize,
+ fns: f.fns,
+ variables: f.variables,
+ }
+ res, err := exec(&pf, param.Left)
+ if err != nil {
+ return err
+ }
+
+ args = append(args, res)
+ param = param.Right
+ }
+
+ filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...)
+ f.ctx = filt
+ return err
+ }
+
+ return fmt.Errorf("Unknown function: %s", n.Val.Val)
+}
+
+var eqOps = map[string]bool{
+ "=": true,
+ "!=": true,
+}
+
+var booleanOps = map[string]bool{
+ "=": true,
+ "!=": true,
+ "<": true,
+ "<=": true,
+ ">": true,
+ ">=": true,
+}
+
+var numOps = map[string]bool{
+ "*": true,
+ "div": true,
+ "mod": true,
+ "+": true,
+ "-": true,
+ "=": true,
+ "!=": true,
+ "<": true,
+ "<=": true,
+ ">": true,
+ ">=": true,
+}
+
+var andOrOps = map[string]bool{
+ "and": true,
+ "or": true,
+}
+
+func xfOperator(left, right tree.Result, f *xpFilt, op string) error {
+ if booleanOps[op] {
+ lNode, lOK := left.(tree.NodeSet)
+ rNode, rOK := right.(tree.NodeSet)
+ if lOK && rOK {
+ return bothNodeOperator(lNode, rNode, f, op)
+ }
+
+ if lOK {
+ return leftNodeOperator(lNode, right, f, op)
+ }
+
+ if rOK {
+ return rightNodeOperator(left, rNode, f, op)
+ }
+
+ if eqOps[op] {
+ return equalsOperator(left, right, f, op)
+ }
+ }
+
+ if numOps[op] {
+ return numberOperator(left, right, f, op)
+ }
+
+ if andOrOps[op] {
+ return andOrOperator(left, right, f, op)
+ }
+
+ //if op == "|" {
+ return unionOperator(left, right, f, op)
+ //}
+
+ //return fmt.Errorf("Unknown operator " + op)
+}
+
+func xfAbsLocPath(f *xpFilt, val string) {
+ i := f.t
+ for i.GetNodeType() != tree.NtRoot {
+ i = i.GetParent()
+ }
+ f.ctx = tree.NodeSet{i}
+}
+
+func xfAbbrAbsLocPath(f *xpFilt, val string) {
+ i := f.t
+ for i.GetNodeType() != tree.NtRoot {
+ i = i.GetParent()
+ }
+ f.ctx = tree.NodeSet{i}
+ f.expr = abbrPathExpr()
+ find(f)
+}
+
+func xfRelLocPath(f *xpFilt, val string) {
+}
+
+func xfAbbrRelLocPath(f *xpFilt, val string) {
+ f.expr = abbrPathExpr()
+ find(f)
+}
+
+func xfAxis(f *xpFilt, val string) {
+ f.expr.Axis = val
+}
+
+func xfAbbrAxis(f *xpFilt, val string) {
+ f.expr.Axis = xconst.AxisAttribute
+}
+
+func xfNCName(f *xpFilt, val string) {
+ f.expr.Name.Space = val
+}
+
+func xfQName(f *xpFilt, val string) {
+ f.expr.Name.Local = val
+ find(f)
+}
+
+func xfNodeType(f *xpFilt, val string) {
+ f.expr.NodeType = val
+ find(f)
+}
+
+func xfProcInstLit(f *xpFilt, val string) {
+ filt := tree.NodeSet{}
+ for _, i := range f.ctx.(tree.NodeSet) {
+ if i.GetToken().(xml.ProcInst).Target == val {
+ filt = append(filt, i)
+ }
+ }
+ f.ctx = filt
+}
+
+func xfStrLit(f *xpFilt, val string) {
+ f.ctx = tree.String(val)
+}
+
+func xfNumLit(f *xpFilt, val string) {
+ num, _ := strconv.ParseFloat(val, 64)
+ f.ctx = tree.Num(num)
+}
+
+func abbrPathExpr() pathexpr.PathExpr {
+ return pathexpr.PathExpr{
+ Name: xml.Name{},
+ Axis: xconst.AxisDescendentOrSelf,
+ NodeType: xconst.NodeTypeNode,
+ }
+}
+
+func find(f *xpFilt) {
+ dupFilt := make(map[int]tree.Node)
+ f.proxPos = make(map[int]int)
+
+ if f.expr.Axis == "" && f.expr.NodeType == "" && f.expr.Name.Space == "" {
+ if f.expr.Name.Local == "." {
+ f.expr = pathexpr.PathExpr{
+ Name: xml.Name{},
+ Axis: xconst.AxisSelf,
+ NodeType: xconst.NodeTypeNode,
+ }
+ }
+
+ if f.expr.Name.Local == ".." {
+ f.expr = pathexpr.PathExpr{
+ Name: xml.Name{},
+ Axis: xconst.AxisParent,
+ NodeType: xconst.NodeTypeNode,
+ }
+ }
+ }
+
+ f.expr.NS = f.ns
+
+ for _, i := range f.ctx.(tree.NodeSet) {
+ for pos, j := range findutil.Find(i, f.expr) {
+ dupFilt[j.Pos()] = j
+ f.proxPos[j.Pos()] = pos + 1
+ }
+ }
+
+ res := make(tree.NodeSet, 0, len(dupFilt))
+ for _, i := range dupFilt {
+ res = append(res, i)
+ }
+
+ xsort.SortNodes(res)
+
+ f.expr = pathexpr.PathExpr{}
+ f.ctxSize = len(res)
+ f.ctx = res
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go
new file mode 100644
index 000000000000..95f57c24950b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go
@@ -0,0 +1,20 @@
+package xsort
+
+import (
+ "sort"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+type nodeSort []tree.Node
+
+func (ns nodeSort) Len() int { return len(ns) }
+func (ns nodeSort) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
+func (ns nodeSort) Less(i, j int) bool {
+ return ns[i].Pos() < ns[j].Pos()
+}
+
+//SortNodes sorts the array by the node document order
+func SortNodes(res []tree.Node) {
+ sort.Sort(nodeSort(res))
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go
new file mode 100644
index 000000000000..29f53c42abb8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go
@@ -0,0 +1,419 @@
+package lexer
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+const (
+ //XItemError is an error with the parser input
+ XItemError XItemType = "Error"
+ //XItemAbsLocPath is an absolute path
+ XItemAbsLocPath = "Absolute path"
+ //XItemAbbrAbsLocPath represents an abbreviated absolute path
+ XItemAbbrAbsLocPath = "Abbreviated absolute path"
+ //XItemAbbrRelLocPath marks the start of a path expression
+ XItemAbbrRelLocPath = "Abbreviated relative path"
+ //XItemRelLocPath represents a relative location path
+ XItemRelLocPath = "Relative path"
+ //XItemEndPath marks the end of a path
+ XItemEndPath = "End path instruction"
+ //XItemAxis marks an axis specifier of a path
+ XItemAxis = "Axis"
+ //XItemAbbrAxis marks an abbreviated axis specifier (just @ at this point)
+ XItemAbbrAxis = "Abbreviated attribute axis"
+ //XItemNCName marks a namespace name in a node test
+ XItemNCName = "Namespace"
+ //XItemQName marks the local name in an a node test
+ XItemQName = "Local name"
+ //XItemNodeType marks a node type in a node test
+ XItemNodeType = "Node type"
+ //XItemProcLit marks a processing-instruction literal
+ XItemProcLit = "processing-instruction"
+ //XItemFunction marks a function call
+ XItemFunction = "function"
+ //XItemArgument marks a function argument
+ XItemArgument = "function argument"
+ //XItemEndFunction marks the end of a function
+ XItemEndFunction = "end of function"
+ //XItemPredicate marks a predicate in an axis
+ XItemPredicate = "predicate"
+ //XItemEndPredicate marks a predicate in an axis
+ XItemEndPredicate = "end of predicate"
+ //XItemStrLit marks a string literal
+ XItemStrLit = "string literal"
+ //XItemNumLit marks a numeric literal
+ XItemNumLit = "numeric literal"
+ //XItemOperator marks an operator
+ XItemOperator = "operator"
+ //XItemVariable marks a variable reference
+ XItemVariable = "variable"
+)
+
+const (
+ eof = -(iota + 1)
+)
+
+//XItemType is the parser token types
+type XItemType string
+
+//XItem is the token emitted from the parser
+type XItem struct {
+ Typ XItemType
+ Val string
+}
+
+type stateFn func(*Lexer) stateFn
+
+//Lexer lexes out XPath expressions
+type Lexer struct {
+ input string
+ start int
+ pos int
+ width int
+ items chan XItem
+}
+
+//Lex an XPath expresion on the io.Reader
+func Lex(xpath string) chan XItem {
+ l := &Lexer{
+ input: xpath,
+ items: make(chan XItem),
+ }
+ go l.run()
+ return l.items
+}
+
+func (l *Lexer) run() {
+ for state := startState; state != nil; {
+ state = state(l)
+ }
+
+ if l.peek() != eof {
+ l.errorf("Malformed XPath expression")
+ }
+
+ close(l.items)
+}
+
+func (l *Lexer) emit(t XItemType) {
+ l.items <- XItem{t, l.input[l.start:l.pos]}
+ l.start = l.pos
+}
+
+func (l *Lexer) emitVal(t XItemType, val string) {
+ l.items <- XItem{t, val}
+ l.start = l.pos
+}
+
+func (l *Lexer) next() (r rune) {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+
+ r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+
+ l.pos += l.width
+
+ return r
+}
+
+func (l *Lexer) ignore() {
+ l.start = l.pos
+}
+
+func (l *Lexer) backup() {
+ l.pos -= l.width
+}
+
+func (l *Lexer) peek() rune {
+ r := l.next()
+
+ l.backup()
+ return r
+}
+
+func (l *Lexer) peekAt(n int) rune {
+ if n <= 1 {
+ return l.peek()
+ }
+
+ width := 0
+ var ret rune
+
+ for count := 0; count < n; count++ {
+ r, s := utf8.DecodeRuneInString(l.input[l.pos+width:])
+ width += s
+
+ if l.pos+width > len(l.input) {
+ return eof
+ }
+
+ ret = r
+ }
+
+ return ret
+}
+
+func (l *Lexer) accept(valid string) bool {
+ if strings.ContainsRune(valid, l.next()) {
+ return true
+ }
+
+ l.backup()
+ return false
+}
+
+func (l *Lexer) acceptRun(valid string) {
+ for strings.ContainsRune(valid, l.next()) {
+ }
+ l.backup()
+}
+
+func (l *Lexer) skip(num int) {
+ for i := 0; i < num; i++ {
+ l.next()
+ }
+ l.ignore()
+}
+
+func (l *Lexer) skipWS(ig bool) {
+ for {
+ n := l.next()
+
+ if n == eof || !unicode.IsSpace(n) {
+ break
+ }
+ }
+
+ l.backup()
+
+ if ig {
+ l.ignore()
+ }
+}
+
+func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- XItem{
+ XItemError,
+ fmt.Sprintf(format, args...),
+ }
+
+ return nil
+}
+
+func isElemChar(r rune) bool {
+ return string(r) != ":" && string(r) != "/" &&
+ (unicode.Is(first, r) || unicode.Is(second, r) || string(r) == "*") &&
+ r != eof
+}
+
+func startState(l *Lexer) stateFn {
+ l.skipWS(true)
+
+ if string(l.peek()) == "/" {
+ l.next()
+ l.ignore()
+
+ if string(l.next()) == "/" {
+ l.ignore()
+ return abbrAbsLocPathState
+ }
+
+ l.backup()
+ return absLocPathState
+ } else if string(l.peek()) == `'` || string(l.peek()) == `"` {
+ if err := getStrLit(l, XItemStrLit); err != nil {
+ return l.errorf(err.Error())
+ }
+
+ if l.peek() != eof {
+ return startState
+ }
+ } else if getNumLit(l) {
+ l.skipWS(true)
+ if l.peek() != eof {
+ return startState
+ }
+ } else if string(l.peek()) == "$" {
+ l.next()
+ l.ignore()
+ r := l.peek()
+ for unicode.Is(first, r) || unicode.Is(second, r) {
+ l.next()
+ r = l.peek()
+ }
+ tok := l.input[l.start:l.pos]
+ if len(tok) == 0 {
+ return l.errorf("Empty variable name")
+ }
+ l.emit(XItemVariable)
+ l.skipWS(true)
+ if l.peek() != eof {
+ return startState
+ }
+ } else if st := findOperatorState(l); st != nil {
+ return st
+ } else {
+ if isElemChar(l.peek()) {
+ colons := 0
+
+ for {
+ if isElemChar(l.peek()) {
+ l.next()
+ } else if string(l.peek()) == ":" {
+ l.next()
+ colons++
+ } else {
+ break
+ }
+ }
+
+ if string(l.peek()) == "(" && colons <= 1 {
+ tok := l.input[l.start:l.pos]
+ err := procFunc(l, tok)
+ if err != nil {
+ return l.errorf(err.Error())
+ }
+
+ l.skipWS(true)
+
+ if string(l.peek()) == "/" {
+ l.next()
+ l.ignore()
+
+ if string(l.next()) == "/" {
+ l.ignore()
+ return abbrRelLocPathState
+ }
+
+ l.backup()
+ return relLocPathState
+ }
+
+ return startState
+ }
+
+ l.pos = l.start
+ return relLocPathState
+ } else if string(l.peek()) == "@" {
+ return relLocPathState
+ }
+ }
+
+ return nil
+}
+
+func strPeek(str string, l *Lexer) bool {
+ for i := 0; i < len(str); i++ {
+ if string(l.peekAt(i+1)) != string(str[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func findOperatorState(l *Lexer) stateFn {
+ l.skipWS(true)
+
+ switch string(l.peek()) {
+ case ">", "<", "!":
+ l.next()
+ if string(l.peek()) == "=" {
+ l.next()
+ }
+ l.emit(XItemOperator)
+ return startState
+ case "|", "+", "-", "*", "=":
+ l.next()
+ l.emit(XItemOperator)
+ return startState
+ case "(":
+ l.next()
+ l.emit(XItemOperator)
+ for state := startState; state != nil; {
+ state = state(l)
+ }
+ l.skipWS(true)
+ if string(l.next()) != ")" {
+ return l.errorf("Missing end )")
+ }
+ l.emit(XItemOperator)
+ return startState
+ }
+
+ if strPeek("and", l) {
+ l.next()
+ l.next()
+ l.next()
+ l.emit(XItemOperator)
+ return startState
+ }
+
+ if strPeek("or", l) {
+ l.next()
+ l.next()
+ l.emit(XItemOperator)
+ return startState
+ }
+
+ if strPeek("mod", l) {
+ l.next()
+ l.next()
+ l.next()
+ l.emit(XItemOperator)
+ return startState
+ }
+
+ if strPeek("div", l) {
+ l.next()
+ l.next()
+ l.next()
+ l.emit(XItemOperator)
+ return startState
+ }
+
+ return nil
+}
+
+func getStrLit(l *Lexer, tok XItemType) error {
+ q := l.next()
+ var r rune
+
+ l.ignore()
+
+ for r != q {
+ r = l.next()
+ if r == eof {
+ return fmt.Errorf("Unexpected end of string literal.")
+ }
+ }
+
+ l.backup()
+ l.emit(tok)
+ l.next()
+ l.ignore()
+
+ return nil
+}
+
+func getNumLit(l *Lexer) bool {
+ const dig = "0123456789"
+ l.accept("-")
+ start := l.pos
+ l.acceptRun(dig)
+
+ if l.pos == start {
+ return false
+ }
+
+ if l.accept(".") {
+ l.acceptRun(dig)
+ }
+
+ l.emit(XItemNumLit)
+ return true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go
new file mode 100644
index 000000000000..dac30d6b6534
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go
@@ -0,0 +1,219 @@
+package lexer
+
+import (
+ "fmt"
+
+ "github.com/ChrisTrenkamp/goxpath/xconst"
+)
+
+func absLocPathState(l *Lexer) stateFn {
+ l.emit(XItemAbsLocPath)
+ return stepState
+}
+
+func abbrAbsLocPathState(l *Lexer) stateFn {
+ l.emit(XItemAbbrAbsLocPath)
+ return stepState
+}
+
+func relLocPathState(l *Lexer) stateFn {
+ l.emit(XItemRelLocPath)
+ return stepState
+}
+
+func abbrRelLocPathState(l *Lexer) stateFn {
+ l.emit(XItemAbbrRelLocPath)
+ return stepState
+}
+
+func stepState(l *Lexer) stateFn {
+ l.skipWS(true)
+ r := l.next()
+
+ for isElemChar(r) {
+ r = l.next()
+ }
+
+ l.backup()
+ tok := l.input[l.start:l.pos]
+
+ state, err := parseSeparators(l, tok)
+ if err != nil {
+ return l.errorf(err.Error())
+ }
+
+ return getNextPathState(l, state)
+}
+
+func parseSeparators(l *Lexer, tok string) (XItemType, error) {
+ l.skipWS(false)
+ state := XItemType(XItemQName)
+ r := l.peek()
+
+ if string(r) == ":" && string(l.peekAt(2)) == ":" {
+ var err error
+ if state, err = getAxis(l, tok); err != nil {
+ return state, fmt.Errorf(err.Error())
+ }
+ } else if string(r) == ":" {
+ state = XItemNCName
+ l.emitVal(state, tok)
+ l.skip(1)
+ l.skipWS(true)
+ } else if string(r) == "@" {
+ state = XItemAbbrAxis
+ l.emitVal(state, tok)
+ l.skip(1)
+ l.skipWS(true)
+ } else if string(r) == "(" {
+ var err error
+ if state, err = getNT(l, tok); err != nil {
+ return state, fmt.Errorf(err.Error())
+ }
+ } else if len(tok) > 0 {
+ l.emitVal(state, tok)
+ }
+
+ return state, nil
+}
+
+func getAxis(l *Lexer, tok string) (XItemType, error) {
+ var state XItemType
+ for i := range xconst.AxisNames {
+ if tok == xconst.AxisNames[i] {
+ state = XItemAxis
+ }
+ }
+ if state != XItemAxis {
+ return state, fmt.Errorf("Invalid Axis specifier, %s", tok)
+ }
+ l.emitVal(state, tok)
+ l.skip(2)
+ l.skipWS(true)
+ return state, nil
+}
+
+func getNT(l *Lexer, tok string) (XItemType, error) {
+ isNT := false
+ for _, i := range xconst.NodeTypes {
+ if tok == i {
+ isNT = true
+ break
+ }
+ }
+
+ if isNT {
+ return procNT(l, tok)
+ }
+
+ return XItemError, fmt.Errorf("Invalid node-type " + tok)
+}
+
+func procNT(l *Lexer, tok string) (XItemType, error) {
+ state := XItemType(XItemNodeType)
+ l.emitVal(state, tok)
+ l.skip(1)
+ l.skipWS(true)
+ n := l.peek()
+ if tok == xconst.NodeTypeProcInst && (string(n) == `"` || string(n) == `'`) {
+ if err := getStrLit(l, XItemProcLit); err != nil {
+ return state, fmt.Errorf(err.Error())
+ }
+ l.skipWS(true)
+ n = l.next()
+ }
+
+ if string(n) != ")" {
+ return state, fmt.Errorf("Missing ) at end of NodeType declaration.")
+ }
+
+ l.skip(1)
+ return state, nil
+}
+
+func procFunc(l *Lexer, tok string) error {
+ state := XItemType(XItemFunction)
+ l.emitVal(state, tok)
+ l.skip(1)
+ l.skipWS(true)
+ if string(l.peek()) != ")" {
+ l.emit(XItemArgument)
+ for {
+ for state := startState; state != nil; {
+ state = state(l)
+ }
+ l.skipWS(true)
+
+ if string(l.peek()) == "," {
+ l.emit(XItemArgument)
+ l.skip(1)
+ } else if string(l.peek()) == ")" {
+ l.emit(XItemEndFunction)
+ l.skip(1)
+ break
+ } else if l.peek() == eof {
+ return fmt.Errorf("Missing ) at end of function declaration.")
+ }
+ }
+ } else {
+ l.emit(XItemEndFunction)
+ l.skip(1)
+ }
+
+ return nil
+}
+
+func getNextPathState(l *Lexer, state XItemType) stateFn {
+ isMultiPart := state == XItemAxis || state == XItemAbbrAxis || state == XItemNCName
+
+ l.skipWS(true)
+
+ for string(l.peek()) == "[" {
+ if err := getPred(l); err != nil {
+ return l.errorf(err.Error())
+ }
+ }
+
+ if string(l.peek()) == "/" && !isMultiPart {
+ l.skip(1)
+ if string(l.peek()) == "/" {
+ l.skip(1)
+ return abbrRelLocPathState
+ }
+ l.skipWS(true)
+ return relLocPathState
+ } else if isMultiPart && isElemChar(l.peek()) {
+ return stepState
+ }
+
+ if isMultiPart {
+ return l.errorf("Step is not complete")
+ }
+
+ l.emit(XItemEndPath)
+ return findOperatorState
+}
+
+func getPred(l *Lexer) error {
+ l.emit(XItemPredicate)
+ l.skip(1)
+ l.skipWS(true)
+
+ if string(l.peek()) == "]" {
+ return fmt.Errorf("Missing content in predicate.")
+ }
+
+ for state := startState; state != nil; {
+ state = state(l)
+ }
+
+ l.skipWS(true)
+ if string(l.peek()) != "]" {
+ return fmt.Errorf("Missing ] at end of predicate.")
+ }
+ l.skip(1)
+ l.emit(XItemEndPredicate)
+ l.skipWS(true)
+
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go
new file mode 100644
index 000000000000..4e6bc8f6790f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go
@@ -0,0 +1,316 @@
+package lexer
+
+import "unicode"
+
+//first and second was copied from src/encoding/xml/xml.go
+var first = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x003A, 0x003A, 1},
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
+ },
+}
+
+var second = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
+ },
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go
new file mode 100644
index 000000000000..e1045f20eed9
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go
@@ -0,0 +1,105 @@
+package goxpath
+
+import (
+ "bytes"
+ "encoding/xml"
+ "io"
+
+ "github.com/ChrisTrenkamp/goxpath/tree"
+)
+
+//Marshal prints the result tree, r, in XML form to w.
+func Marshal(n tree.Node, w io.Writer) error {
+ return marshal(n, w)
+}
+
+//MarshalStr is like Marhal, but returns a string.
+func MarshalStr(n tree.Node) (string, error) {
+ ret := bytes.NewBufferString("")
+ err := marshal(n, ret)
+
+ return ret.String(), err
+}
+
+func marshal(n tree.Node, w io.Writer) error {
+ e := xml.NewEncoder(w)
+ err := encTok(n, e)
+ if err != nil {
+ return err
+ }
+
+ return e.Flush()
+}
+
+func encTok(n tree.Node, e *xml.Encoder) error {
+ switch n.GetNodeType() {
+ case tree.NtAttr:
+ return encAttr(n.GetToken().(xml.Attr), e)
+ case tree.NtElem:
+ return encEle(n.(tree.Elem), e)
+ case tree.NtNs:
+ return encNS(n.GetToken().(xml.Attr), e)
+ case tree.NtRoot:
+ for _, i := range n.(tree.Elem).GetChildren() {
+ err := encTok(i, e)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ //case tree.NtChd, tree.NtComm, tree.NtPi:
+ return e.EncodeToken(n.GetToken())
+}
+
+func encAttr(a xml.Attr, e *xml.Encoder) error {
+ str := a.Name.Local + `="` + a.Value + `"`
+
+ if a.Name.Space != "" {
+ str += ` xmlns="` + a.Name.Space + `"`
+ }
+
+ pi := xml.ProcInst{
+ Target: "attribute",
+ Inst: ([]byte)(str),
+ }
+
+ return e.EncodeToken(pi)
+}
+
+func encNS(ns xml.Attr, e *xml.Encoder) error {
+ pi := xml.ProcInst{
+ Target: "namespace",
+ Inst: ([]byte)(ns.Value),
+ }
+ return e.EncodeToken(pi)
+}
+
+func encEle(n tree.Elem, e *xml.Encoder) error {
+ ele := xml.StartElement{
+ Name: n.GetToken().(xml.StartElement).Name,
+ }
+
+ attrs := n.GetAttrs()
+ ele.Attr = make([]xml.Attr, len(attrs))
+ for i := range attrs {
+ ele.Attr[i] = attrs[i].GetToken().(xml.Attr)
+ }
+
+ err := e.EncodeToken(ele)
+ if err != nil {
+ return err
+ }
+
+ if x, ok := n.(tree.Elem); ok {
+ for _, i := range x.GetChildren() {
+ err := encTok(i, e)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return e.EncodeToken(ele.End())
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go
new file mode 100644
index 000000000000..08196c62eeef
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go
@@ -0,0 +1,113 @@
+package parser
+
+import "github.com/ChrisTrenkamp/goxpath/lexer"
+
+//NodeType enumerations
+const (
+ Empty lexer.XItemType = ""
+)
+
+//Node builds an AST tree for operating on XPath expressions
+type Node struct {
+ Val lexer.XItem
+ Left *Node
+ Right *Node
+ Parent *Node
+ next *Node
+}
+
+var beginPathType = map[lexer.XItemType]bool{
+ lexer.XItemAbsLocPath: true,
+ lexer.XItemAbbrAbsLocPath: true,
+ lexer.XItemAbbrRelLocPath: true,
+ lexer.XItemRelLocPath: true,
+ lexer.XItemFunction: true,
+}
+
+func (n *Node) add(i lexer.XItem) {
+ if n.Val.Typ == Empty {
+ n.Val = i
+ } else if n.Left == nil && n.Right == nil {
+ n.Left = &Node{Val: n.Val, Parent: n}
+ n.Val = i
+ } else if beginPathType[n.Val.Typ] {
+ next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n}
+ n.Left, n.Right = next, nil
+ n.Val = i
+ } else if n.Right == nil {
+ n.Right = &Node{Val: i, Parent: n}
+ } else {
+ next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n}
+ n.Left, n.Right = next, nil
+ n.Val = i
+ }
+ n.next = n
+}
+
+func (n *Node) push(i lexer.XItem) {
+ if n.Left == nil {
+ n.Left = &Node{Val: i, Parent: n}
+ n.next = n.Left
+ } else if n.Right == nil {
+ n.Right = &Node{Val: i, Parent: n}
+ n.next = n.Right
+ } else {
+ next := &Node{Val: i, Left: n.Right, Parent: n}
+ n.Right = next
+ n.next = n.Right
+ }
+}
+
+func (n *Node) pushNotEmpty(i lexer.XItem) {
+ if n.Val.Typ == Empty {
+ n.add(i)
+ } else {
+ n.push(i)
+ }
+}
+
+/*
+func (n *Node) prettyPrint(depth, width int) {
+ nodes := []*Node{}
+ n.getLine(depth, &nodes)
+ fmt.Printf("%*s", (width-depth)*2, "")
+ toggle := true
+ if len(nodes) > 1 {
+ for _, i := range nodes {
+ if i != nil {
+ if toggle {
+ fmt.Print("/ ")
+ } else {
+ fmt.Print("\\ ")
+ }
+ }
+ toggle = !toggle
+ }
+ fmt.Println()
+ fmt.Printf("%*s", (width-depth)*2, "")
+ }
+ for _, i := range nodes {
+ if i != nil {
+ fmt.Print(i.Val.Val, " ")
+ }
+ }
+ fmt.Println()
+}
+
+func (n *Node) getLine(depth int, ret *[]*Node) {
+ if depth <= 0 && n != nil {
+ *ret = append(*ret, n)
+ return
+ }
+ if n.Left != nil {
+ n.Left.getLine(depth-1, ret)
+ } else if depth-1 <= 0 {
+ *ret = append(*ret, nil)
+ }
+ if n.Right != nil {
+ n.Right.getLine(depth-1, ret)
+ } else if depth-1 <= 0 {
+ *ret = append(*ret, nil)
+ }
+}
+*/
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go
new file mode 100644
index 000000000000..e5ce8222fbc2
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go
@@ -0,0 +1,200 @@
+package parser
+
+import (
+ "fmt"
+
+ "github.com/ChrisTrenkamp/goxpath/lexer"
+)
+
+type stateType int
+
+const (
+ defState stateType = iota
+ xpathState
+ funcState
+ paramState
+ predState
+ parenState
+)
+
+type parseStack struct {
+ stack []*Node
+ stateTypes []stateType
+ cur *Node
+}
+
+func (p *parseStack) push(t stateType) {
+ p.stack = append(p.stack, p.cur)
+ p.stateTypes = append(p.stateTypes, t)
+}
+
+func (p *parseStack) pop() {
+ stackPos := len(p.stack) - 1
+
+ p.cur = p.stack[stackPos]
+ p.stack = p.stack[:stackPos]
+ p.stateTypes = p.stateTypes[:stackPos]
+}
+
+func (p *parseStack) curState() stateType {
+ if len(p.stateTypes) == 0 {
+ return defState
+ }
+ return p.stateTypes[len(p.stateTypes)-1]
+}
+
+type lexFn func(*parseStack, lexer.XItem)
+
+var parseMap = map[lexer.XItemType]lexFn{
+ lexer.XItemAbsLocPath: xiXPath,
+ lexer.XItemAbbrAbsLocPath: xiXPath,
+ lexer.XItemAbbrRelLocPath: xiXPath,
+ lexer.XItemRelLocPath: xiXPath,
+ lexer.XItemEndPath: xiEndPath,
+ lexer.XItemAxis: xiXPath,
+ lexer.XItemAbbrAxis: xiXPath,
+ lexer.XItemNCName: xiXPath,
+ lexer.XItemQName: xiXPath,
+ lexer.XItemNodeType: xiXPath,
+ lexer.XItemProcLit: xiXPath,
+ lexer.XItemFunction: xiFunc,
+ lexer.XItemArgument: xiFuncArg,
+ lexer.XItemEndFunction: xiEndFunc,
+ lexer.XItemPredicate: xiPred,
+ lexer.XItemEndPredicate: xiEndPred,
+ lexer.XItemStrLit: xiValue,
+ lexer.XItemNumLit: xiValue,
+ lexer.XItemOperator: xiOp,
+ lexer.XItemVariable: xiValue,
+}
+
+var opPrecedence = map[string]int{
+ "|": 1,
+ "*": 2,
+ "div": 2,
+ "mod": 2,
+ "+": 3,
+ "-": 3,
+ "=": 4,
+ "!=": 4,
+ "<": 4,
+ "<=": 4,
+ ">": 4,
+ ">=": 4,
+ "and": 5,
+ "or": 6,
+}
+
+//Parse creates an AST tree for XPath expressions.
+func Parse(xp string) (*Node, error) {
+ var err error
+ c := lexer.Lex(xp)
+ n := &Node{}
+ p := &parseStack{cur: n}
+
+ for next := range c {
+ if next.Typ != lexer.XItemError {
+ parseMap[next.Typ](p, next)
+ } else if err == nil {
+ err = fmt.Errorf(next.Val)
+ }
+ }
+
+ return n, err
+}
+
+func xiXPath(p *parseStack, i lexer.XItem) {
+ if p.curState() == xpathState {
+ p.cur.push(i)
+ p.cur = p.cur.next
+ return
+ }
+
+ if p.cur.Val.Typ == lexer.XItemFunction {
+ p.cur.Right = &Node{Val: i, Parent: p.cur}
+ p.cur.next = p.cur.Right
+ p.push(xpathState)
+ p.cur = p.cur.next
+ return
+ }
+
+ p.cur.pushNotEmpty(i)
+ p.push(xpathState)
+ p.cur = p.cur.next
+}
+
+func xiEndPath(p *parseStack, i lexer.XItem) {
+ p.pop()
+}
+
+func xiFunc(p *parseStack, i lexer.XItem) {
+ if p.cur.Val.Typ == Empty {
+ p.cur.pushNotEmpty(i)
+ p.push(funcState)
+ p.cur = p.cur.next
+ return
+ }
+ p.cur.push(i)
+ p.cur = p.cur.next
+ p.push(funcState)
+}
+
+func xiFuncArg(p *parseStack, i lexer.XItem) {
+ if p.curState() != funcState {
+ p.pop()
+ }
+
+ p.cur.push(i)
+ p.cur = p.cur.next
+ p.push(paramState)
+ p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
+ p.cur = p.cur.next
+}
+
+func xiEndFunc(p *parseStack, i lexer.XItem) {
+ if p.curState() == paramState {
+ p.pop()
+ }
+ p.pop()
+}
+
+func xiPred(p *parseStack, i lexer.XItem) {
+ p.cur.push(i)
+ p.cur = p.cur.next
+ p.push(predState)
+ p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
+ p.cur = p.cur.next
+}
+
+func xiEndPred(p *parseStack, i lexer.XItem) {
+ p.pop()
+}
+
+func xiValue(p *parseStack, i lexer.XItem) {
+ p.cur.add(i)
+}
+
+func xiOp(p *parseStack, i lexer.XItem) {
+ if i.Val == "(" {
+ p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
+ p.push(parenState)
+ p.cur = p.cur.next
+ return
+ }
+
+ if i.Val == ")" {
+ p.pop()
+ return
+ }
+
+ if p.cur.Val.Typ == lexer.XItemOperator {
+ if opPrecedence[p.cur.Val.Val] <= opPrecedence[i.Val] {
+ p.cur.add(i)
+ } else {
+ p.cur.push(i)
+ }
+ } else {
+ p.cur.add(i)
+ }
+ p.cur = p.cur.next
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go
new file mode 100644
index 000000000000..7fe69eb4ae32
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go
@@ -0,0 +1,11 @@
+package pathexpr
+
+import "encoding/xml"
+
+//PathExpr represents XPath step's. xmltree.XMLTree uses it to find nodes.
+type PathExpr struct {
+ Name xml.Name
+ Axis string
+ NodeType string
+ NS map[string]string
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go
deleted file mode 100644
index 4b1e74cc1921..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go
+++ /dev/null
@@ -1,54 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/ChrisTrenkamp/goxpath, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/ChrisTrenkamp/goxpath (exports: Opts,FuncOpts,XPathExec; functions: Parse,MustParse,ParseExec)
-
-// Package goxpath is a stub of github.com/ChrisTrenkamp/goxpath, generated by depstubber.
-package goxpath
-
-import (
- xml "encoding/xml"
-)
-
-type FuncOpts func(*Opts)
-
-func MustParse(_ string) XPathExec {
- return XPathExec{}
-}
-
-type Opts struct {
- NS map[string]string
- Funcs map[xml.Name]interface{}
- Vars map[string]interface{}
-}
-
-func Parse(_ string) (XPathExec, error) {
- return XPathExec{}, nil
-}
-
-func ParseExec(_ string, _ interface{}, _ ...FuncOpts) (interface{}, error) {
- return nil, nil
-}
-
-type XPathExec struct{}
-
-func (_ XPathExec) Exec(_ interface{}, _ ...FuncOpts) (interface{}, error) {
- return nil, nil
-}
-
-func (_ XPathExec) ExecBool(_ interface{}, _ ...FuncOpts) (bool, error) {
- return false, nil
-}
-
-func (_ XPathExec) ExecNode(_ interface{}, _ ...FuncOpts) (interface{}, error) {
- return nil, nil
-}
-
-func (_ XPathExec) ExecNum(_ interface{}, _ ...FuncOpts) (float64, error) {
- return 0, nil
-}
-
-func (_ XPathExec) MustExec(_ interface{}, _ ...FuncOpts) interface{} {
- return nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go
new file mode 100644
index 000000000000..a6e64257338d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go
@@ -0,0 +1,18 @@
+package tree
+
+import "fmt"
+
+//Result is used for all data types.
+type Result interface {
+ fmt.Stringer
+}
+
+//IsBool is used for the XPath boolean function. It turns the data type to a bool.
+type IsBool interface {
+ Bool() Bool
+}
+
+//IsNum is used for the XPath number function. It turns the data type to a number.
+type IsNum interface {
+ Num() Num
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go
deleted file mode 100644
index 7cc3b01c6268..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/ChrisTrenkamp/goxpath/tree, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/ChrisTrenkamp/goxpath/tree (exports: Node,String; functions: )
-
-// Package tree is a stub of github.com/ChrisTrenkamp/goxpath/tree, generated by depstubber.
-package tree
-
-import (
- xml "encoding/xml"
-)
-
-type Bool bool
-
-func (_ Bool) Bool() Bool {
- return false
-}
-
-func (_ Bool) Num() Num {
- return 0
-}
-
-func (_ Bool) String() string {
- return ""
-}
-
-type Elem interface {
- GetAttrs() []Node
- GetChildren() []Node
- GetNodeType() NodeType
- GetParent() Elem
- GetToken() xml.Token
- Pos() int
- ResValue() string
-}
-
-type Node interface {
- GetNodeType() NodeType
- GetParent() Elem
- GetToken() xml.Token
- Pos() int
- ResValue() string
-}
-
-type NodeType int
-
-func (_ NodeType) GetNodeType() NodeType {
- return 0
-}
-
-type Num float64
-
-func (_ Num) Bool() Bool {
- return false
-}
-
-func (_ Num) Num() Num {
- return 0
-}
-
-func (_ Num) String() string {
- return ""
-}
-
-type String string
-
-func (_ String) Bool() Bool {
- return false
-}
-
-func (_ String) Num() Num {
- return 0
-}
-
-func (_ String) String() string {
- return ""
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go
new file mode 100644
index 000000000000..c5d6333d71df
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go
@@ -0,0 +1,221 @@
+package tree
+
+import (
+ "encoding/xml"
+ "sort"
+)
+
+//XMLSpace is the W3C XML namespace
+const XMLSpace = "http://www.w3.org/XML/1998/namespace"
+
+//NodePos is a helper for representing the node's document order
+type NodePos int
+
+//Pos returns the node's document order position
+func (n NodePos) Pos() int {
+ return int(n)
+}
+
+//NodeType is a safer way to determine a node's type than type assertions.
+type NodeType int
+
+//GetNodeType returns the node's type.
+func (t NodeType) GetNodeType() NodeType {
+ return t
+}
+
+//These are all the possible node types
+const (
+ NtAttr NodeType = iota
+ NtChd
+ NtComm
+ NtElem
+ NtNs
+ NtRoot
+ NtPi
+)
+
+//Node is a XPath result that is a node except elements
+type Node interface {
+ //ResValue prints the node's string value
+ ResValue() string
+ //Pos returns the node's position in the document order
+ Pos() int
+ //GetToken returns the xml.Token representation of the node
+ GetToken() xml.Token
+ //GetParent returns the parent node, which will always be an XML element
+ GetParent() Elem
+ //GetNodeType returns the node's type
+ GetNodeType() NodeType
+}
+
+//Elem is a XPath result that is an element node
+type Elem interface {
+ Node
+ //GetChildren returns the elements children.
+ GetChildren() []Node
+ //GetAttrs returns the attributes of the element
+ GetAttrs() []Node
+}
+
+//NSElem is a node that keeps track of namespaces.
+type NSElem interface {
+ Elem
+ GetNS() map[xml.Name]string
+}
+
+//NSBuilder is a helper-struct for satisfying the NSElem interface
+type NSBuilder struct {
+ NS map[xml.Name]string
+}
+
+//GetNS returns the namespaces found on the current element. It should not be
+//confused with BuildNS, which actually resolves the namespace nodes.
+func (ns NSBuilder) GetNS() map[xml.Name]string {
+ return ns.NS
+}
+
+type nsValueSort []NS
+
+func (ns nsValueSort) Len() int { return len(ns) }
+func (ns nsValueSort) Swap(i, j int) {
+ ns[i], ns[j] = ns[j], ns[i]
+}
+func (ns nsValueSort) Less(i, j int) bool {
+ return ns[i].Value < ns[j].Value
+}
+
+//BuildNS resolves all the namespace nodes of the element and returns them
+func BuildNS(t Elem) (ret []NS) {
+ vals := make(map[xml.Name]string)
+
+ if nselem, ok := t.(NSElem); ok {
+ buildNS(nselem, vals)
+
+ ret = make([]NS, 0, len(vals))
+ i := 1
+
+ for k, v := range vals {
+ if !(k.Local == "xmlns" && k.Space == "" && v == "") {
+ ret = append(ret, NS{
+ Attr: xml.Attr{Name: k, Value: v},
+ Parent: t,
+ NodeType: NtNs,
+ })
+ i++
+ }
+ }
+
+ sort.Sort(nsValueSort(ret))
+ for i := range ret {
+ ret[i].NodePos = NodePos(t.Pos() + i + 1)
+ }
+ }
+
+ return ret
+}
+
+func buildNS(x NSElem, ret map[xml.Name]string) {
+ if x.GetNodeType() == NtRoot {
+ return
+ }
+
+ if nselem, ok := x.GetParent().(NSElem); ok {
+ buildNS(nselem, ret)
+ }
+
+ for k, v := range x.GetNS() {
+ ret[k] = v
+ }
+}
+
+//NS is a namespace node.
+type NS struct {
+ xml.Attr
+ Parent Elem
+ NodePos
+ NodeType
+}
+
+//GetToken returns the xml.Token representation of the namespace.
+func (ns NS) GetToken() xml.Token {
+ return ns.Attr
+}
+
+//GetParent returns the parent node of the namespace.
+func (ns NS) GetParent() Elem {
+ return ns.Parent
+}
+
+//ResValue returns the string value of the namespace
+func (ns NS) ResValue() string {
+ return ns.Attr.Value
+}
+
+//GetAttribute is a convenience function for getting the specified attribute from an element.
+//false is returned if the attribute is not found.
+func GetAttribute(n Elem, local, space string) (xml.Attr, bool) {
+ attrs := n.GetAttrs()
+ for _, i := range attrs {
+ attr := i.GetToken().(xml.Attr)
+ if local == attr.Name.Local && space == attr.Name.Space {
+ return attr, true
+ }
+ }
+ return xml.Attr{}, false
+}
+
+//GetAttributeVal is like GetAttribute, except it returns the attribute's value.
+func GetAttributeVal(n Elem, local, space string) (string, bool) {
+ attr, ok := GetAttribute(n, local, space)
+ return attr.Value, ok
+}
+
+//GetAttrValOrEmpty is like GetAttributeVal, except it returns an empty string if
+//the attribute is not found instead of false.
+func GetAttrValOrEmpty(n Elem, local, space string) string {
+ val, ok := GetAttributeVal(n, local, space)
+ if !ok {
+ return ""
+ }
+ return val
+}
+
+//FindNodeByPos finds a node from the given position. Returns nil if the node
+//is not found.
+func FindNodeByPos(n Node, pos int) Node {
+ if n.Pos() == pos {
+ return n
+ }
+
+ if elem, ok := n.(Elem); ok {
+ chldrn := elem.GetChildren()
+ for i := 1; i < len(chldrn); i++ {
+ if chldrn[i-1].Pos() <= pos && chldrn[i].Pos() > pos {
+ return FindNodeByPos(chldrn[i-1], pos)
+ }
+ }
+
+ if len(chldrn) > 0 {
+ if chldrn[len(chldrn)-1].Pos() <= pos {
+ return FindNodeByPos(chldrn[len(chldrn)-1], pos)
+ }
+ }
+
+ attrs := elem.GetAttrs()
+ for _, i := range attrs {
+ if i.Pos() == pos {
+ return i
+ }
+ }
+
+ ns := BuildNS(elem)
+ for _, i := range ns {
+ if i.Pos() == pos {
+ return i
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go
new file mode 100644
index 000000000000..7a940bb3405f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go
@@ -0,0 +1,52 @@
+package tree
+
+import (
+ "fmt"
+)
+
+//Ctx represents the current context position, size, node, and the current filtered result
+type Ctx struct {
+ NodeSet
+ Pos int
+ Size int
+}
+
+//Fn is a XPath function, written in Go
+type Fn func(c Ctx, args ...Result) (Result, error)
+
+//LastArgOpt sets whether the last argument in a function is optional, variadic, or neither
+type LastArgOpt int
+
+//LastArgOpt options
+const (
+ None LastArgOpt = iota
+ Optional
+ Variadic
+)
+
+//Wrap interfaces XPath function calls with Go
+type Wrap struct {
+ Fn Fn
+ //NArgs represents the number of arguments to the XPath function. -1 represents a single optional argument
+ NArgs int
+ LastArgOpt LastArgOpt
+}
+
+//Call checks the arguments and calls Fn if they are valid
+func (w Wrap) Call(c Ctx, args ...Result) (Result, error) {
+ switch w.LastArgOpt {
+ case Optional:
+ if len(args) == w.NArgs || len(args) == w.NArgs-1 {
+ return w.Fn(c, args...)
+ }
+ case Variadic:
+ if len(args) >= w.NArgs-1 {
+ return w.Fn(c, args...)
+ }
+ default:
+ if len(args) == w.NArgs {
+ return w.Fn(c, args...)
+ }
+ }
+ return nil, fmt.Errorf("Invalid number of arguments")
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go
new file mode 100644
index 000000000000..b9704109f965
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go
@@ -0,0 +1,113 @@
+package tree
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+)
+
+//Boolean strings
+const (
+ True = "true"
+ False = "false"
+)
+
+//Bool is a boolean XPath type
+type Bool bool
+
+//ResValue satisfies the Res interface for Bool
+func (b Bool) String() string {
+ if b {
+ return True
+ }
+
+ return False
+}
+
+//Bool satisfies the HasBool interface for Bool's
+func (b Bool) Bool() Bool {
+ return b
+}
+
+//Num satisfies the HasNum interface for Bool's
+func (b Bool) Num() Num {
+ if b {
+ return Num(1)
+ }
+
+ return Num(0)
+}
+
+//Num is a number XPath type
+type Num float64
+
+//ResValue satisfies the Res interface for Num
+func (n Num) String() string {
+ if math.IsInf(float64(n), 0) {
+ if math.IsInf(float64(n), 1) {
+ return "Infinity"
+ }
+ return "-Infinity"
+ }
+ return fmt.Sprintf("%g", float64(n))
+}
+
+//Bool satisfies the HasBool interface for Num's
+func (n Num) Bool() Bool {
+ return n != 0
+}
+
+//Num satisfies the HasNum interface for Num's
+func (n Num) Num() Num {
+ return n
+}
+
+//String is string XPath type
+type String string
+
+//ResValue satisfies the Res interface for String
+func (s String) String() string {
+ return string(s)
+}
+
+//Bool satisfies the HasBool interface for String's
+func (s String) Bool() Bool {
+ return Bool(len(s) > 0)
+}
+
+//Num satisfies the HasNum interface for String's
+func (s String) Num() Num {
+ num, err := strconv.ParseFloat(strings.TrimSpace(string(s)), 64)
+ if err != nil {
+ return Num(math.NaN())
+ }
+ return Num(num)
+}
+
+//NodeSet is a node-set XPath type
+type NodeSet []Node
+
+//GetNodeNum converts the node to a string-value and to a number
+func GetNodeNum(n Node) Num {
+ return String(n.ResValue()).Num()
+}
+
+//String satisfies the Res interface for NodeSet
+func (n NodeSet) String() string {
+ if len(n) == 0 {
+ return ""
+ }
+
+ return n[0].ResValue()
+}
+
+//Bool satisfies the HasBool interface for node-set's
+func (n NodeSet) Bool() Bool {
+ return Bool(len(n) > 0)
+}
+
+//Num satisfies the HasNum interface for NodeSet's
+func (n NodeSet) Num() Num {
+ return String(n.String()).Num()
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go
new file mode 100644
index 000000000000..650991272e44
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go
@@ -0,0 +1,66 @@
+package xconst
+
+const (
+ //AxisAncestor represents the "ancestor" axis
+ AxisAncestor = "ancestor"
+ //AxisAncestorOrSelf represents the "ancestor-or-self" axis
+ AxisAncestorOrSelf = "ancestor-or-self"
+ //AxisAttribute represents the "attribute" axis
+ AxisAttribute = "attribute"
+ //AxisChild represents the "child" axis
+ AxisChild = "child"
+ //AxisDescendent represents the "descendant" axis
+ AxisDescendent = "descendant"
+ //AxisDescendentOrSelf represents the "descendant-or-self" axis
+ AxisDescendentOrSelf = "descendant-or-self"
+ //AxisFollowing represents the "following" axis
+ AxisFollowing = "following"
+ //AxisFollowingSibling represents the "following-sibling" axis
+ AxisFollowingSibling = "following-sibling"
+ //AxisNamespace represents the "namespace" axis
+ AxisNamespace = "namespace"
+ //AxisParent represents the "parent" axis
+ AxisParent = "parent"
+ //AxisPreceding represents the "preceding" axis
+ AxisPreceding = "preceding"
+ //AxisPrecedingSibling represents the "preceding-sibling" axis
+ AxisPrecedingSibling = "preceding-sibling"
+ //AxisSelf represents the "self" axis
+ AxisSelf = "self"
+)
+
+//AxisNames is all the possible Axis identifiers wrapped in an array for convenience
+var AxisNames = []string{
+ AxisAncestor,
+ AxisAncestorOrSelf,
+ AxisAttribute,
+ AxisChild,
+ AxisDescendent,
+ AxisDescendentOrSelf,
+ AxisFollowing,
+ AxisFollowingSibling,
+ AxisNamespace,
+ AxisParent,
+ AxisPreceding,
+ AxisPrecedingSibling,
+ AxisSelf,
+}
+
+const (
+ //NodeTypeComment represents the "comment" node test
+ NodeTypeComment = "comment"
+ //NodeTypeText represents the "text" node test
+ NodeTypeText = "text"
+ //NodeTypeProcInst represents the "processing-instruction" node test
+ NodeTypeProcInst = "processing-instruction"
+ //NodeTypeNode represents the "node" node test
+ NodeTypeNode = "node"
+)
+
+//NodeTypes is all the possible node tests wrapped in an array for convenience
+var NodeTypes = []string{
+ NodeTypeComment,
+ NodeTypeText,
+ NodeTypeProcInst,
+ NodeTypeNode,
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore
new file mode 100644
index 000000000000..4d5d27b1d3a1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore
@@ -0,0 +1,32 @@
+# vscode
+.vscode
+debug
+*.test
+
+./build
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml
new file mode 100644
index 000000000000..384e0307482a
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml
@@ -0,0 +1,18 @@
+language: go
+
+go:
+ - 1.7
+ - 1.8
+ - 1.9.x
+ - 1.12.x
+ - 1.13.x
+
+install:
+ - go get golang.org/x/net/html/charset
+ - go get golang.org/x/net/html
+ - go get github.com/antchfx/xpath
+ - go get github.com/mattn/goveralls
+ - go get github.com/golang/groupcache
+
+script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md
new file mode 100644
index 000000000000..6e7775d573b1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md
@@ -0,0 +1,168 @@
+htmlquery
+====
+[](https://travis-ci.org/antchfx/htmlquery)
+[](https://coveralls.io/github/antchfx/htmlquery?branch=master)
+[](https://godoc.org/github.com/antchfx/htmlquery)
+[](https://goreportcard.com/report/github.com/antchfx/htmlquery)
+
+Overview
+====
+
+`htmlquery` is an XPath query package for HTML, lets you extract data or evaluate from HTML documents by an XPath expression.
+
+`htmlquery` built-in the query object caching feature based on [LRU](https://godoc.org/github.com/golang/groupcache/lru), this feature will caching the recently used XPATH query string. Enable query caching can avoid re-compile XPath expression each query.
+
+Installation
+====
+
+```
+go get github.com/antchfx/htmlquery
+```
+
+Getting Started
+====
+
+#### Query, returns matched elements or error.
+
+```go
+nodes, err := htmlquery.QueryAll(doc, "//a")
+if err != nil {
+ panic(`not a valid XPath expression.`)
+}
+```
+
+#### Load HTML document from URL.
+
+```go
+doc, err := htmlquery.LoadURL("http://example.com/")
+```
+
+#### Load HTML from document.
+
+```go
+filePath := "/home/user/sample.html"
+doc, err := htmlquery.LoadDoc(filePath)
+```
+
+#### Load HTML document from string.
+
+```go
+s := `....`
+doc, err := htmlquery.Parse(strings.NewReader(s))
+```
+
+#### Find all A elements.
+
+```go
+list := htmlquery.Find(doc, "//a")
+```
+
+#### Find all A elements that have `href` attribute.
+
+```go
+list := range htmlquery.Find(doc, "//a[@href]")
+```
+
+#### Find all A elements with `href` attribute and only return `href` value.
+
+```go
+list := range htmlquery.Find(doc, "//a/@href")
+for n := range list{
+ fmt.Println(htmlquery.InnerText(n)) // output @href value without A element.
+}
+```
+
+### Find the third A element.
+
+```go
+a := htmlquery.FindOne(doc, "//a[3]")
+```
+
+#### Evaluate the number of all IMG element.
+
+```go
+expr, _ := xpath.Compile("count(//img)")
+v := expr.Evaluate(htmlquery.CreateXPathNavigator(doc)).(float64)
+fmt.Printf("total count is %f", v)
+```
+
+
+FAQ
+====
+
+#### `Find()` vs `QueryAll()`, which is better?
+
+`Find` and `QueryAll` both do the same things, searches all of matched html nodes.
+The `Find` will panics if you give an error XPath query, but `QueryAll` will return an error for you.
+
+#### Can I save my query expression object for the next query?
+
+Yes, you can. We offer the `QuerySelector` and `QuerySelectorAll` methods, It will accept your query expression object.
+
+Cache a query expression object(or reused) will avoid re-compile XPath query expression, improve your query performance.
+
+#### XPath query object cache performance
+
+```
+goos: windows
+goarch: amd64
+pkg: github.com/antchfx/htmlquery
+BenchmarkSelectorCache-4 20000000 55.2 ns/op
+BenchmarkDisableSelectorCache-4 500000 3162 ns/op
+```
+
+#### How to disable caching?
+
+```
+htmlquery.DisableSelectorCache = true
+```
+
+Changelogs
+===
+
+2019-11-19
+- Add built-in query object cache feature, avoid re-compilation for the same query string. [#16](https://github.com/antchfx/htmlquery/issues/16)
+- Added LoadDoc [18](https://github.com/antchfx/htmlquery/pull/18)
+
+2019-10-05
+- Add new methods that compatible with invalid XPath expression error: `QueryAll` and `Query`.
+- Add `QuerySelector` and `QuerySelectorAll` methods, supported reused your query object.
+
+2019-02-04
+- [#7](https://github.com/antchfx/htmlquery/issues/7) Removed deprecated `FindEach()` and `FindEachWithBreak()` methods.
+
+2018-12-28
+- Avoid adding duplicate elements to list for `Find()` method. [#6](https://github.com/antchfx/htmlquery/issues/6)
+
+Tutorial
+===
+
+```go
+func main() {
+ doc, err := htmlquery.LoadURL("https://www.bing.com/search?q=golang")
+ if err != nil {
+ panic(err)
+ }
+ // Find all news item.
+ list, err := htmlquery.QueryAll(doc, "//ol/li")
+ if err != nil {
+ panic(err)
+ }
+ for i, n := range list {
+ a := htmlquery.FindOne(n, "//a")
+ fmt.Printf("%d %s(%s)\n", i, htmlquery.InnerText(a), htmlquery.SelectAttr(a, "href"))
+ }
+}
+```
+
+List of supported XPath query packages
+===
+| Name | Description |
+| ------------------------------------------------- | ----------------------------------------- |
+| [htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document |
+| [xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document |
+| [jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document |
+
+Questions
+===
+Please let me know if you have any questions.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go
new file mode 100644
index 000000000000..e27cd289741b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go
@@ -0,0 +1,42 @@
+package htmlquery
+
+import (
+ "sync"
+
+ "github.com/antchfx/xpath"
+ "github.com/golang/groupcache/lru"
+)
+
+// DisableSelectorCache will disable caching for the query selector if value is true.
+var DisableSelectorCache = false
+
+// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50.
+// Will disable caching if SelectorCacheMaxEntries <= 0.
+var SelectorCacheMaxEntries = 50
+
+var (
+ cacheOnce sync.Once
+ cache *lru.Cache
+ cacheMutex sync.Mutex
+)
+
+func getQuery(expr string) (*xpath.Expr, error) {
+ if DisableSelectorCache || SelectorCacheMaxEntries <= 0 {
+ return xpath.Compile(expr)
+ }
+ cacheOnce.Do(func() {
+ cache = lru.New(SelectorCacheMaxEntries)
+ })
+ cacheMutex.Lock()
+ defer cacheMutex.Unlock()
+ if v, ok := cache.Get(expr); ok {
+ return v.(*xpath.Expr), nil
+ }
+ v, err := xpath.Compile(expr)
+ if err != nil {
+ return nil, err
+ }
+ cache.Add(expr, v)
+ return v, nil
+
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go
new file mode 100644
index 000000000000..db7578202c0f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go
@@ -0,0 +1,338 @@
+/*
+Package htmlquery provides extract data from HTML documents using XPath expression.
+*/
+package htmlquery
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+
+ "github.com/antchfx/xpath"
+ "golang.org/x/net/html"
+ "golang.org/x/net/html/charset"
+)
+
+var _ xpath.NodeNavigator = &NodeNavigator{}
+
+// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
+func CreateXPathNavigator(top *html.Node) *NodeNavigator {
+ return &NodeNavigator{curr: top, root: top, attr: -1}
+}
+
+// Find is like QueryAll but Will panics if the expression `expr` cannot be parsed.
+//
+// See `QueryAll()` function.
+func Find(top *html.Node, expr string) []*html.Node {
+ nodes, err := QueryAll(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return nodes
+}
+
+// FindOne is like Query but will panics if the expression `expr` cannot be parsed.
+// See `Query()` function.
+func FindOne(top *html.Node, expr string) *html.Node {
+ node, err := Query(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return node
+}
+
+// QueryAll searches the html.Node that matches by the specified XPath expr.
+// Return an error if the expression `expr` cannot be parsed.
+func QueryAll(top *html.Node, expr string) ([]*html.Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ nodes := QuerySelectorAll(top, exp)
+ return nodes, nil
+}
+
+// Query searches the html.Node that matches by the specified XPath expr,
+// and return the first element of matched html.Node.
+//
+// Return an error if the expression `expr` cannot be parsed.
+func Query(top *html.Node, expr string) (*html.Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ return QuerySelector(top, exp), nil
+}
+
+// QuerySelector returns the first matched html.Node by the specified XPath selector.
+func QuerySelector(top *html.Node, selector *xpath.Expr) *html.Node {
+ t := selector.Select(CreateXPathNavigator(top))
+ if t.MoveNext() {
+ return getCurrentNode(t.Current().(*NodeNavigator))
+ }
+ return nil
+}
+
+// QuerySelectorAll searches all of the html.Node that matches the specified XPath selectors.
+func QuerySelectorAll(top *html.Node, selector *xpath.Expr) []*html.Node {
+ var elems []*html.Node
+ t := selector.Select(CreateXPathNavigator(top))
+ for t.MoveNext() {
+ nav := t.Current().(*NodeNavigator)
+ n := getCurrentNode(nav)
+ // avoid adding duplicate nodes.
+ if len(elems) > 0 && (elems[0] == n || (nav.NodeType() == xpath.AttributeNode &&
+ nav.LocalName() == elems[0].Data && nav.Value() == InnerText(elems[0]))) {
+ continue
+ }
+ elems = append(elems, n)
+ }
+ return elems
+}
+
+// LoadURL loads the HTML document from the specified URL.
+func LoadURL(url string) (*html.Node, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ r, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type"))
+ if err != nil {
+ return nil, err
+ }
+ return html.Parse(r)
+}
+
+// LoadDoc loads the HTML document from the specified file path.
+func LoadDoc(path string) (*html.Node, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return html.Parse(bufio.NewReader(f))
+}
+
+func getCurrentNode(n *NodeNavigator) *html.Node {
+ if n.NodeType() == xpath.AttributeNode {
+ childNode := &html.Node{
+ Type: html.TextNode,
+ Data: n.Value(),
+ }
+ return &html.Node{
+ Type: html.ElementNode,
+ Data: n.LocalName(),
+ FirstChild: childNode,
+ LastChild: childNode,
+ }
+
+ }
+ return n.curr
+}
+
+// Parse returns the parse tree for the HTML from the given Reader.
+func Parse(r io.Reader) (*html.Node, error) {
+ return html.Parse(r)
+}
+
+// InnerText returns the text between the start and end tags of the object.
+func InnerText(n *html.Node) string {
+ var output func(*bytes.Buffer, *html.Node)
+ output = func(buf *bytes.Buffer, n *html.Node) {
+ switch n.Type {
+ case html.TextNode:
+ buf.WriteString(n.Data)
+ return
+ case html.CommentNode:
+ return
+ }
+ for child := n.FirstChild; child != nil; child = child.NextSibling {
+ output(buf, child)
+ }
+ }
+
+ var buf bytes.Buffer
+ output(&buf, n)
+ return buf.String()
+}
+
+// SelectAttr returns the attribute value with the specified name.
+func SelectAttr(n *html.Node, name string) (val string) {
+ if n == nil {
+ return
+ }
+ if n.Type == html.ElementNode && n.Parent == nil && name == n.Data {
+ return InnerText(n)
+ }
+ for _, attr := range n.Attr {
+ if attr.Key == name {
+ val = attr.Val
+ break
+ }
+ }
+ return
+}
+
+// OutputHTML returns the text including tags name.
+func OutputHTML(n *html.Node, self bool) string {
+ var buf bytes.Buffer
+ if self {
+ html.Render(&buf, n)
+ } else {
+ for n := n.FirstChild; n != nil; n = n.NextSibling {
+ html.Render(&buf, n)
+ }
+ }
+ return buf.String()
+}
+
+type NodeNavigator struct {
+ root, curr *html.Node
+ attr int
+}
+
+func (h *NodeNavigator) Current() *html.Node {
+ return h.curr
+}
+
+func (h *NodeNavigator) NodeType() xpath.NodeType {
+ switch h.curr.Type {
+ case html.CommentNode:
+ return xpath.CommentNode
+ case html.TextNode:
+ return xpath.TextNode
+ case html.DocumentNode:
+ return xpath.RootNode
+ case html.ElementNode:
+ if h.attr != -1 {
+ return xpath.AttributeNode
+ }
+ return xpath.ElementNode
+ case html.DoctypeNode:
+ // ignored declare and as Root-Node type.
+ return xpath.RootNode
+ }
+ panic(fmt.Sprintf("unknown HTML node type: %v", h.curr.Type))
+}
+
+func (h *NodeNavigator) LocalName() string {
+ if h.attr != -1 {
+ return h.curr.Attr[h.attr].Key
+ }
+ return h.curr.Data
+}
+
+func (*NodeNavigator) Prefix() string {
+ return ""
+}
+
+func (h *NodeNavigator) Value() string {
+ switch h.curr.Type {
+ case html.CommentNode:
+ return h.curr.Data
+ case html.ElementNode:
+ if h.attr != -1 {
+ return h.curr.Attr[h.attr].Val
+ }
+ return InnerText(h.curr)
+ case html.TextNode:
+ return h.curr.Data
+ }
+ return ""
+}
+
+func (h *NodeNavigator) Copy() xpath.NodeNavigator {
+ n := *h
+ return &n
+}
+
+func (h *NodeNavigator) MoveToRoot() {
+ h.curr = h.root
+}
+
+func (h *NodeNavigator) MoveToParent() bool {
+ if h.attr != -1 {
+ h.attr = -1
+ return true
+ } else if node := h.curr.Parent; node != nil {
+ h.curr = node
+ return true
+ }
+ return false
+}
+
+func (h *NodeNavigator) MoveToNextAttribute() bool {
+ if h.attr >= len(h.curr.Attr)-1 {
+ return false
+ }
+ h.attr++
+ return true
+}
+
+func (h *NodeNavigator) MoveToChild() bool {
+ if h.attr != -1 {
+ return false
+ }
+ if node := h.curr.FirstChild; node != nil {
+ h.curr = node
+ return true
+ }
+ return false
+}
+
+func (h *NodeNavigator) MoveToFirst() bool {
+ if h.attr != -1 || h.curr.PrevSibling == nil {
+ return false
+ }
+ for {
+ node := h.curr.PrevSibling
+ if node == nil {
+ break
+ }
+ h.curr = node
+ }
+ return true
+}
+
+func (h *NodeNavigator) String() string {
+ return h.Value()
+}
+
+func (h *NodeNavigator) MoveToNext() bool {
+ if h.attr != -1 {
+ return false
+ }
+ if node := h.curr.NextSibling; node != nil {
+ h.curr = node
+ return true
+ }
+ return false
+}
+
+func (h *NodeNavigator) MoveToPrevious() bool {
+ if h.attr != -1 {
+ return false
+ }
+ if node := h.curr.PrevSibling; node != nil {
+ h.curr = node
+ return true
+ }
+ return false
+}
+
+func (h *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
+ node, ok := other.(*NodeNavigator)
+ if !ok || node.root != h.root {
+ return false
+ }
+
+ h.curr = node.curr
+ h.attr = node.attr
+ return true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go
deleted file mode 100644
index 7a41d8f98837..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/antchfx/htmlquery, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/antchfx/htmlquery (exports: ; functions: Find,FindOne,QueryAll,Query)
-
-// Package htmlquery is a stub of github.com/antchfx/htmlquery, generated by depstubber.
-package htmlquery
-
-func Find(_ interface{}, _ string) []interface{} {
- return nil
-}
-
-func FindOne(_ interface{}, _ string) interface{} {
- return nil
-}
-
-func Query(_ interface{}, _ string) (interface{}, error) {
- return nil, nil
-}
-
-func QueryAll(_ interface{}, _ string) ([]interface{}, error) {
- return nil, nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore
new file mode 100644
index 000000000000..4d5d27b1d3a1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore
@@ -0,0 +1,32 @@
+# vscode
+.vscode
+debug
+*.test
+
+./build
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml
new file mode 100644
index 000000000000..e4f176de78aa
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+
+go:
+ - 1.7
+ - 1.8
+ - 1.9.x
+ - 1.12.x
+ - 1.13.x
+
+install:
+ - go get github.com/antchfx/xpath
+ - go get github.com/mattn/goveralls
+ - go get github.com/golang/groupcache
+
+script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md
new file mode 100644
index 000000000000..162c289b983e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md
@@ -0,0 +1,175 @@
+jsonquery
+====
+[](https://travis-ci.org/antchfx/jsonquery)
+[](https://coveralls.io/github/antchfx/jsonquery?branch=master)
+[](https://godoc.org/github.com/antchfx/jsonquery)
+[](https://goreportcard.com/report/github.com/antchfx/jsonquery)
+
+Overview
+===
+
+jsonquery is an XPath query package for JSON document, lets you extract data from JSON documents through an XPath expression. Built-in XPath expression cache avoid re-compile XPath expression each query.
+
+Getting Started
+===
+
+### Install Package
+```
+go get github.com/antchfx/jsonquery
+```
+
+#### Load JSON document from URL.
+
+```go
+doc, err := jsonquery.LoadURL("http://www.example.com/feed?json")
+```
+
+#### Load JSON document from string.
+
+```go
+s :=`{
+ "name":"John",
+ "age":31,
+ "city":"New York"
+ }`
+doc, err := jsonquery.Parse(strings.NewReader(s))
+```
+
+#### Load JSON document from io.Reader.
+
+```go
+f, err := os.Open("./books.json")
+doc, err := jsonquery.Parse(f)
+```
+
+#### Find authors of all books in the store.
+```go
+list := jsonquery.Find(doc, "store/book/*/author")
+// or equal to
+list := jsonquery.Find(doc, "//author")
+// or by QueryAll()
+nodes, err := jsonquery.QueryAll(doc, "//a")
+```
+
+#### Find the third book.
+
+```go
+book := jsonquery.Find(doc, "//book/*[3]")
+```
+
+#### Find the last book.
+
+```go
+book := jsonquery.Find(doc, "//book/*[last()]")
+```
+
+#### Find all books with isbn number.
+
+```go
+list := jsonquery.Find(doc, "//book/*[isbn]")
+```
+
+#### Find all books cheapier than 10.
+
+```go
+list := jsonquery.Find(doc, "//book/*[price<10]")
+```
+
+Examples
+===
+
+```go
+func main() {
+ s := `{
+ "name": "John",
+ "age" : 26,
+ "address" : {
+ "streetAddress": "naist street",
+ "city" : "Nara",
+ "postalCode" : "630-0192"
+ },
+ "phoneNumbers": [
+ {
+ "type" : "iPhone",
+ "number": "0123-4567-8888"
+ },
+ {
+ "type" : "home",
+ "number": "0123-4567-8910"
+ }
+ ]
+ }`
+ doc, err := jsonquery.Parse(strings.NewReader(s))
+ if err != nil {
+ panic(err)
+ }
+ name := jsonquery.FindOne(doc, "name")
+ fmt.Printf("name: %s\n", name.InnerText())
+ var a []string
+ for _, n := range jsonquery.Find(doc, "phoneNumbers/*/number") {
+ a = append(a, n.InnerText())
+ }
+ fmt.Printf("phone number: %s\n", strings.Join(a, ","))
+ if n := jsonquery.FindOne(doc, "address/streetAddress"); n != nil {
+ fmt.Printf("address: %s\n", n.InnerText())
+ }
+}
+```
+
+Implement Principle
+===
+If you are familiar with XPath and XML, you can quick start to known how
+write your XPath expression.
+
+```json
+{
+"name":"John",
+"age":30,
+"cars": [
+ { "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
+ { "name":"BMW", "models":[ "320", "X3", "X5" ] },
+ { "name":"Fiat", "models":[ "500", "Panda" ] }
+]
+}
+```
+The above JSON document will be convert to similar to XML document by the *JSONQuery*, like below:
+
+```XML
+John
+30
+
+
+ Ford
+
+ Fiesta
+ Focus
+ Mustang
+
+
+
+ BMW
+
+ 320
+ X3
+ X5
+
+
+
+ Fiat
+
+ 500
+ Panda
+
+
+
+```
+
+Notes: `element` is empty element that have no any name.
+
+List of XPath query packages
+===
+|Name |Description |
+|--------------------------|----------------|
+|[htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document|
+|[xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document|
+|[jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document|
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json
new file mode 100644
index 000000000000..e4bd94628c12
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json
@@ -0,0 +1,36 @@
+{
+ "store": {
+ "book": [
+ {
+ "category": "reference",
+ "author": "Nigel Rees",
+ "title": "Sayings of the Century",
+ "price": 8.95
+ },
+ {
+ "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": 12.99
+ },
+ {
+ "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": 8.99
+ },
+ {
+ "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": 22.99
+ }
+ ],
+ "bicycle": {
+ "color": "red",
+ "price": 19.95
+ }
+ }
+}
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go
new file mode 100644
index 000000000000..27b7a324a0cd
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go
@@ -0,0 +1,43 @@
+package jsonquery
+
+import (
+ "sync"
+
+ "github.com/golang/groupcache/lru"
+
+ "github.com/antchfx/xpath"
+)
+
+// DisableSelectorCache will disable caching for the query selector if value is true.
+var DisableSelectorCache = false
+
+// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50.
+// Will disable caching if SelectorCacheMaxEntries <= 0.
+var SelectorCacheMaxEntries = 50
+
+var (
+ cacheOnce sync.Once
+ cache *lru.Cache
+ cacheMutex sync.Mutex
+)
+
+func getQuery(expr string) (*xpath.Expr, error) {
+ if DisableSelectorCache || SelectorCacheMaxEntries <= 0 {
+ return xpath.Compile(expr)
+ }
+ cacheOnce.Do(func() {
+ cache = lru.New(SelectorCacheMaxEntries)
+ })
+ cacheMutex.Lock()
+ defer cacheMutex.Unlock()
+ if v, ok := cache.Get(expr); ok {
+ return v.(*xpath.Expr), nil
+ }
+ v, err := xpath.Compile(expr)
+ if err != nil {
+ return nil, err
+ }
+ cache.Add(expr, v)
+ return v, nil
+
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go
new file mode 100644
index 000000000000..76032bb2ddee
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go
@@ -0,0 +1,157 @@
+package jsonquery
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "sort"
+ "strconv"
+)
+
+// A NodeType is the type of a Node.
+type NodeType uint
+
+const (
+ // DocumentNode is a document object that, as the root of the document tree,
+ // provides access to the entire XML document.
+ DocumentNode NodeType = iota
+ // ElementNode is an element.
+ ElementNode
+ // TextNode is the text content of a node.
+ TextNode
+)
+
+// A Node consists of a NodeType and some Data (tag name for
+// element nodes, content for text) and are part of a tree of Nodes.
+type Node struct {
+ Parent, PrevSibling, NextSibling, FirstChild, LastChild *Node
+
+ Type NodeType
+ Data string
+
+ level int
+}
+
+// ChildNodes gets all child nodes of the node.
+func (n *Node) ChildNodes() []*Node {
+ var a []*Node
+ for nn := n.FirstChild; nn != nil; nn = nn.NextSibling {
+ a = append(a, nn)
+ }
+ return a
+}
+
+// InnerText gets the value of the node and all its child nodes.
+func (n *Node) InnerText() string {
+ var output func(*bytes.Buffer, *Node)
+ output = func(buf *bytes.Buffer, n *Node) {
+ if n.Type == TextNode {
+ buf.WriteString(n.Data)
+ return
+ }
+ for child := n.FirstChild; child != nil; child = child.NextSibling {
+ output(buf, child)
+ }
+ }
+ var buf bytes.Buffer
+ output(&buf, n)
+ return buf.String()
+}
+
+// SelectElement finds the first of child elements with the
+// specified name.
+func (n *Node) SelectElement(name string) *Node {
+ for nn := n.FirstChild; nn != nil; nn = nn.NextSibling {
+ if nn.Data == name {
+ return nn
+ }
+ }
+ return nil
+}
+
+// LoadURL loads the JSON document from the specified URL.
+func LoadURL(url string) (*Node, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ return Parse(resp.Body)
+}
+
+func parseValue(x interface{}, top *Node, level int) {
+ addNode := func(n *Node) {
+ if n.level == top.level {
+ top.NextSibling = n
+ n.PrevSibling = top
+ n.Parent = top.Parent
+ if top.Parent != nil {
+ top.Parent.LastChild = n
+ }
+ } else if n.level > top.level {
+ n.Parent = top
+ if top.FirstChild == nil {
+ top.FirstChild = n
+ top.LastChild = n
+ } else {
+ t := top.LastChild
+ t.NextSibling = n
+ n.PrevSibling = t
+ top.LastChild = n
+ }
+ }
+ }
+ switch v := x.(type) {
+ case []interface{}:
+ for _, vv := range v {
+ n := &Node{Type: ElementNode, level: level}
+ addNode(n)
+ parseValue(vv, n, level+1)
+ }
+ case map[string]interface{}:
+ // The Go’s map iteration order is random.
+ // (https://blog.golang.org/go-maps-in-action#Iteration-order)
+ var keys []string
+ for key := range v {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ for _, key := range keys {
+ n := &Node{Data: key, Type: ElementNode, level: level}
+ addNode(n)
+ parseValue(v[key], n, level+1)
+ }
+ case string:
+ n := &Node{Data: v, Type: TextNode, level: level}
+ addNode(n)
+ case float64:
+ s := strconv.FormatFloat(v, 'f', -1, 64)
+ n := &Node{Data: s, Type: TextNode, level: level}
+ addNode(n)
+ case bool:
+ s := strconv.FormatBool(v)
+ n := &Node{Data: s, Type: TextNode, level: level}
+ addNode(n)
+ }
+}
+
+func parse(b []byte) (*Node, error) {
+ var v interface{}
+ if err := json.Unmarshal(b, &v); err != nil {
+ return nil, err
+ }
+ doc := &Node{Type: DocumentNode}
+ parseValue(v, doc, 1)
+ return doc, nil
+}
+
+// Parse JSON document.
+func Parse(r io.Reader) (*Node, error) {
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+ return parse(b)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go
new file mode 100644
index 000000000000..6421801638c8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go
@@ -0,0 +1,177 @@
+package jsonquery
+
+import (
+ "fmt"
+
+ "github.com/antchfx/xpath"
+)
+
+var _ xpath.NodeNavigator = &NodeNavigator{}
+
+// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
+func CreateXPathNavigator(top *Node) *NodeNavigator {
+ return &NodeNavigator{cur: top, root: top}
+}
+
+// Find is like QueryAll but will panics if `expr` cannot be parsed.
+func Find(top *Node, expr string) []*Node {
+ nodes, err := QueryAll(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return nodes
+}
+
+// FindOne is like Query but will panics if `expr` cannot be parsed.
+func FindOne(top *Node, expr string) *Node {
+ node, err := Query(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return node
+}
+
+// QueryAll searches the Node that matches by the specified XPath expr.
+// Return an error if the expression `expr` cannot be parsed.
+func QueryAll(top *Node, expr string) ([]*Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ return QuerySelectorAll(top, exp), nil
+}
+
+// Query searches the Node that matches by the specified XPath expr,
+// and returns first element of matched.
+func Query(top *Node, expr string) (*Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ return QuerySelector(top, exp), nil
+}
+
+// QuerySelectorAll searches all of the Node that matches the specified XPath selectors.
+func QuerySelectorAll(top *Node, selector *xpath.Expr) []*Node {
+ t := selector.Select(CreateXPathNavigator(top))
+ var elems []*Node
+ for t.MoveNext() {
+ elems = append(elems, (t.Current().(*NodeNavigator)).cur)
+ }
+ return elems
+}
+
+// QuerySelector returns the first matched XML Node by the specified XPath selector.
+func QuerySelector(top *Node, selector *xpath.Expr) *Node {
+ t := selector.Select(CreateXPathNavigator(top))
+ if t.MoveNext() {
+ return (t.Current().(*NodeNavigator)).cur
+ }
+ return nil
+}
+
+// NodeNavigator is for navigating JSON document.
+type NodeNavigator struct {
+ root, cur *Node
+}
+
+func (a *NodeNavigator) Current() *Node {
+ return a.cur
+}
+
+func (a *NodeNavigator) NodeType() xpath.NodeType {
+ switch a.cur.Type {
+ case TextNode:
+ return xpath.TextNode
+ case DocumentNode:
+ return xpath.RootNode
+ case ElementNode:
+ return xpath.ElementNode
+ default:
+ panic(fmt.Sprintf("unknown node type %v", a.cur.Type))
+ }
+}
+
+func (a *NodeNavigator) LocalName() string {
+ return a.cur.Data
+
+}
+
+func (a *NodeNavigator) Prefix() string {
+ return ""
+}
+
+func (a *NodeNavigator) Value() string {
+ switch a.cur.Type {
+ case ElementNode:
+ return a.cur.InnerText()
+ case TextNode:
+ return a.cur.Data
+ }
+ return ""
+}
+
+func (a *NodeNavigator) Copy() xpath.NodeNavigator {
+ n := *a
+ return &n
+}
+
+func (a *NodeNavigator) MoveToRoot() {
+ a.cur = a.root
+}
+
+func (a *NodeNavigator) MoveToParent() bool {
+ if n := a.cur.Parent; n != nil {
+ a.cur = n
+ return true
+ }
+ return false
+}
+
+func (x *NodeNavigator) MoveToNextAttribute() bool {
+ return false
+}
+
+func (a *NodeNavigator) MoveToChild() bool {
+ if n := a.cur.FirstChild; n != nil {
+ a.cur = n
+ return true
+ }
+ return false
+}
+
+func (a *NodeNavigator) MoveToFirst() bool {
+ for n := a.cur.PrevSibling; n != nil; n = n.PrevSibling {
+ a.cur = n
+ }
+ return true
+}
+
+func (a *NodeNavigator) String() string {
+ return a.Value()
+}
+
+func (a *NodeNavigator) MoveToNext() bool {
+ if n := a.cur.NextSibling; n != nil {
+ a.cur = n
+ return true
+ }
+ return false
+}
+
+func (a *NodeNavigator) MoveToPrevious() bool {
+ if n := a.cur.PrevSibling; n != nil {
+ a.cur = n
+ return true
+ }
+ return false
+}
+
+func (a *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
+ node, ok := other.(*NodeNavigator)
+ if !ok || node.root != a.root {
+ return false
+ }
+ a.cur = node.cur
+ return true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go
deleted file mode 100644
index 4abcf002faa9..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/antchfx/jsonquery, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/antchfx/jsonquery (exports: Node; functions: Find,FindOne,QueryAll,Query)
-
-// Package jsonquery is a stub of github.com/antchfx/jsonquery, generated by depstubber.
-package jsonquery
-
-func Find(_ *Node, _ string) []*Node {
- return nil
-}
-
-func FindOne(_ *Node, _ string) *Node {
- return nil
-}
-
-type Node struct {
- Parent *Node
- PrevSibling *Node
- NextSibling *Node
- FirstChild *Node
- LastChild *Node
- Type NodeType
- Data string
-}
-
-func (_ *Node) ChildNodes() []*Node {
- return nil
-}
-
-func (_ *Node) InnerText() string {
- return ""
-}
-
-func (_ *Node) SelectElement(_ string) *Node {
- return nil
-}
-
-type NodeType uint
-
-func Query(_ *Node, _ string) (*Node, error) {
- return nil, nil
-}
-
-func QueryAll(_ *Node, _ string) ([]*Node, error) {
- return nil, nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore
new file mode 100644
index 000000000000..4d5d27b1d3a1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore
@@ -0,0 +1,32 @@
+# vscode
+.vscode
+debug
+*.test
+
+./build
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml
new file mode 100644
index 000000000000..a2aeb1ca66af
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml
@@ -0,0 +1,17 @@
+language: go
+
+go:
+ - 1.7
+ - 1.8
+ - 1.9.x
+ - 1.12.x
+ - 1.13.x
+
+install:
+ - go get golang.org/x/net/html/charset
+ - go get github.com/antchfx/xpath
+ - go get github.com/mattn/goveralls
+ - go get github.com/golang/groupcache
+
+script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md
new file mode 100644
index 000000000000..8b3c35ee2638
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md
@@ -0,0 +1,221 @@
+xmlquery
+====
+[](https://travis-ci.org/antchfx/xmlquery)
+[](https://coveralls.io/github/antchfx/xmlquery?branch=master)
+[](https://godoc.org/github.com/antchfx/xmlquery)
+[](https://goreportcard.com/report/github.com/antchfx/xmlquery)
+
+Overview
+===
+
+`xmlquery` is an XPath query package for XML document, lets you extract data or evaluate from XML documents by an XPath expression.
+
+`xmlquery` built-in the query object caching feature will caching the recently used XPATH query string. Enable caching can avoid re-compile XPath expression each query.
+
+Change Logs
+===
+
+2019-11-11
+- Add XPath query caching.
+
+2019-10-05
+- Add new methods that compatible with invalid XPath expression error: `QueryAll` and `Query`.
+- Add `QuerySelector` and `QuerySelectorAll` methods, supported reused your query object.
+- PR [#12](https://github.com/antchfx/xmlquery/pull/12) (Thanks @FrancescoIlario)
+- PR [#11](https://github.com/antchfx/xmlquery/pull/11) (Thanks @gjvnq)
+
+2018-12-23
+- added XML output will including comment node. [#9](https://github.com/antchfx/xmlquery/issues/9)
+
+2018-12-03
+- added support attribute name with namespace prefix and XML output. [#6](https://github.com/antchfx/xmlquery/issues/6)
+
+Installation
+====
+```
+ $ go get github.com/antchfx/xmlquery
+```
+
+Getting Started
+===
+
+### Find specified XPath query.
+
+```go
+list, err := xmlquery.QueryAll(doc, "a")
+if err != nil {
+ panic(err)
+}
+```
+
+#### Parse a XML from URL.
+
+```go
+doc, err := xmlquery.LoadURL("http://www.example.com/sitemap.xml")
+```
+
+#### Parse a XML from string.
+
+```go
+s := ``
+doc, err := xmlquery.Parse(strings.NewReader(s))
+```
+
+#### Parse a XML from io.Reader.
+
+```go
+f, err := os.Open("../books.xml")
+doc, err := xmlquery.Parse(f)
+```
+
+#### Find authors of all books in the bookstore.
+
+```go
+list := xmlquery.Find(doc, "//book//author")
+// or
+list := xmlquery.Find(doc, "//author")
+```
+
+#### Find the second book.
+
+```go
+book := xmlquery.FindOne(doc, "//book[2]")
+```
+
+#### Find all book elements and only get `id` attribute self. (New Feature)
+
+```go
+list := xmlquery.Find(doc,"//book/@id")
+```
+
+#### Find all books with id is bk104.
+
+```go
+list := xmlquery.Find(doc, "//book[@id='bk104']")
+```
+
+#### Find all books that price less than 5.
+
+```go
+list := xmlquery.Find(doc, "//book[price<5]")
+```
+
+#### Evaluate the total price of all books.
+
+```go
+expr, err := xpath.Compile("sum(//book/price)")
+price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
+fmt.Printf("total price: %f\n", price)
+```
+
+#### Evaluate the number of all books element.
+
+```go
+expr, err := xpath.Compile("count(//book)")
+price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64)
+```
+
+FAQ
+====
+
+#### `Find()` vs `QueryAll()`, which is better?
+
+`Find` and `QueryAll` both do the same things, searches all of matched html nodes.
+The `Find` will panics if you give an error XPath query, but `QueryAll` will return an error for you.
+
+#### Can I save my query expression object for the next query?
+
+Yes, you can. We offer the `QuerySelector` and `QuerySelectorAll` methods, It will accept your query expression object.
+
+Cache a query expression object(or reused) will avoid re-compile XPath query expression, improve your query performance.
+
+#### Create XML document.
+
+```go
+doc := &xmlquery.Node{
+ Type: xmlquery.DeclarationNode,
+ Data: "xml",
+ Attr: []xml.Attr{
+ xml.Attr{Name: xml.Name{Local: "version"}, Value: "1.0"},
+ },
+}
+root := &xmlquery.Node{
+ Data: "rss",
+ Type: xmlquery.ElementNode,
+}
+doc.FirstChild = root
+channel := &xmlquery.Node{
+ Data: "channel",
+ Type: xmlquery.ElementNode,
+}
+root.FirstChild = channel
+title := &xmlquery.Node{
+ Data: "title",
+ Type: xmlquery.ElementNode,
+}
+title_text := &xmlquery.Node{
+ Data: "W3Schools Home Page",
+ Type: xmlquery.TextNode,
+}
+title.FirstChild = title_text
+channel.FirstChild = title
+fmt.Println(doc.OutputXML(true))
+// W3Schools Home Page
+```
+
+Quick Tutorial
+===
+
+```go
+import (
+ "github.com/antchfx/xmlquery"
+)
+
+func main(){
+ s := `
+
+
+ W3Schools Home Page
+ https://www.w3schools.com
+ Free web building tutorials
+
+ RSS Tutorial
+ https://www.w3schools.com/xml/xml_rss.asp
+ New RSS tutorial on W3Schools
+
+
+ XML Tutorial
+ https://www.w3schools.com/xml
+ New XML tutorial on W3Schools
+
+
+`
+
+ doc, err := xmlquery.Parse(strings.NewReader(s))
+ if err != nil {
+ panic(err)
+ }
+ channel := xmlquery.FindOne(doc, "//channel")
+ if n := channel.SelectElement("title"); n != nil {
+ fmt.Printf("title: %s\n", n.InnerText())
+ }
+ if n := channel.SelectElement("link"); n != nil {
+ fmt.Printf("link: %s\n", n.InnerText())
+ }
+ for i, n := range xmlquery.Find(doc, "//item/title") {
+ fmt.Printf("#%d %s\n", i, n.InnerText())
+ }
+}
+```
+
+List of supported XPath query packages
+===
+|Name |Description |
+|--------------------------|----------------|
+|[htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document|
+|[xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document|
+|[jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document|
+
+ Questions
+===
+Please let me know if you have any questions
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml
new file mode 100644
index 000000000000..85a74b588d98
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml
@@ -0,0 +1,121 @@
+
+
+
+
+ Gambardella, Matthew
+ XML Developer's Guide
+ Computer
+ 44.95
+ 2000-10-01
+ An in-depth look at creating applications
+ with XML.
+
+
+ Ralls, Kim
+ Midnight Rain
+ Fantasy
+ 5.95
+ 2000-12-16
+ A former architect battles corporate zombies,
+ an evil sorceress, and her own childhood to become queen
+ of the world.
+
+
+ Corets, Eva
+ Maeve Ascendant
+ Fantasy
+ 5.95
+ 2000-11-17
+ After the collapse of a nanotechnology
+ society in England, the young survivors lay the
+ foundation for a new society.
+
+
+ Corets, Eva
+ Oberon's Legacy
+ Fantasy
+ 5.95
+ 2001-03-10
+ In post-apocalypse England, the mysterious
+ agent known only as Oberon helps to create a new life
+ for the inhabitants of London. Sequel to Maeve
+ Ascendant.
+
+
+ Corets, Eva
+ The Sundered Grail
+ Fantasy
+ 5.95
+ 2001-09-10
+ The two daughters of Maeve, half-sisters,
+ battle one another for control of England. Sequel to
+ Oberon's Legacy.
+
+
+ Randall, Cynthia
+ Lover Birds
+ Romance
+ 4.95
+ 2000-09-02
+ When Carla meets Paul at an ornithology
+ conference, tempers fly as feathers get ruffled.
+
+
+ Thurman, Paula
+ Splish Splash
+ Romance
+ 4.95
+ 2000-11-02
+ A deep sea diver finds true love twenty
+ thousand leagues beneath the sea.
+
+
+ Knorr, Stefan
+ Creepy Crawlies
+ Horror
+ 4.95
+ 2000-12-06
+ An anthology of horror stories about roaches,
+ centipedes, scorpions and other insects.
+
+
+ Kress, Peter
+ Paradox Lost
+ Science Fiction
+ 6.95
+ 2000-11-02
+ After an inadvertant trip through a Heisenberg
+ Uncertainty Device, James Salway discovers the problems
+ of being quantum.
+
+
+ O'Brien, Tim
+ Microsoft .NET: The Programming Bible
+ Computer
+ 36.95
+ 2000-12-09
+ Microsoft's .NET initiative is explored in
+ detail in this deep programmer's reference.
+
+
+ O'Brien, Tim
+ MSXML3: A Comprehensive Guide
+ Computer
+ 36.95
+ 2000-12-01
+ The Microsoft MSXML3 parser is covered in
+ detail, with attention to XML DOM interfaces, XSLT processing,
+ SAX and more.
+
+
+ Galos, Mike
+ Visual Studio 7: A Comprehensive Guide
+ Computer
+ 49.95
+ 2001-04-16
+ Microsoft Visual Studio 7 is explored in depth,
+ looking at how Visual Basic, Visual C++, C#, and ASP+ are
+ integrated into a comprehensive development
+ environment.
+
+
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go
new file mode 100644
index 000000000000..3abffcdc57c2
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go
@@ -0,0 +1,43 @@
+package xmlquery
+
+import (
+ "sync"
+
+ "github.com/golang/groupcache/lru"
+
+ "github.com/antchfx/xpath"
+)
+
+// DisableSelectorCache will disable caching for the query selector if value is true.
+var DisableSelectorCache = false
+
+// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50.
+// Will disable caching if SelectorCacheMaxEntries <= 0.
+var SelectorCacheMaxEntries = 50
+
+var (
+ cacheOnce sync.Once
+ cache *lru.Cache
+ cacheMutex sync.Mutex
+)
+
+func getQuery(expr string) (*xpath.Expr, error) {
+ if DisableSelectorCache || SelectorCacheMaxEntries <= 0 {
+ return xpath.Compile(expr)
+ }
+ cacheOnce.Do(func() {
+ cache = lru.New(SelectorCacheMaxEntries)
+ })
+ cacheMutex.Lock()
+ defer cacheMutex.Unlock()
+ if v, ok := cache.Get(expr); ok {
+ return v.(*xpath.Expr), nil
+ }
+ v, err := xpath.Compile(expr)
+ if err != nil {
+ return nil, err
+ }
+ cache.Add(expr, v)
+ return v, nil
+
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go
new file mode 100644
index 000000000000..e86c0c3fe62d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go
@@ -0,0 +1,327 @@
+package xmlquery
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "golang.org/x/net/html/charset"
+)
+
+// A NodeType is the type of a Node.
+type NodeType uint
+
+const (
+ // DocumentNode is a document object that, as the root of the document tree,
+ // provides access to the entire XML document.
+ DocumentNode NodeType = iota
+ // DeclarationNode is the document type declaration, indicated by the following
+ // tag (for example, ).
+ DeclarationNode
+ // ElementNode is an element (for example, ).
+ ElementNode
+ // TextNode is the text content of a node.
+ TextNode
+ // CommentNode a comment (for example, ).
+ CommentNode
+ // AttributeNode is an attribute of element.
+ AttributeNode
+)
+
+// A Node consists of a NodeType and some Data (tag name for
+// element nodes, content for text) and are part of a tree of Nodes.
+type Node struct {
+ Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node
+
+ Type NodeType
+ Data string
+ Prefix string
+ NamespaceURI string
+ Attr []xml.Attr
+
+ level int // node level in the tree
+}
+
+// InnerText returns the text between the start and end tags of the object.
+func (n *Node) InnerText() string {
+ var output func(*bytes.Buffer, *Node)
+ output = func(buf *bytes.Buffer, n *Node) {
+ switch n.Type {
+ case TextNode:
+ buf.WriteString(n.Data)
+ return
+ case CommentNode:
+ return
+ }
+ for child := n.FirstChild; child != nil; child = child.NextSibling {
+ output(buf, child)
+ }
+ }
+
+ var buf bytes.Buffer
+ output(&buf, n)
+ return buf.String()
+}
+
+func (n *Node) sanitizedData(preserveSpaces bool) string {
+ if preserveSpaces {
+ return strings.Trim(n.Data, "\n\t")
+ }
+ return strings.TrimSpace(n.Data)
+}
+
+func calculatePreserveSpaces(n *Node, pastValue bool) bool {
+ if attr := n.SelectAttr("xml:space"); attr == "preserve" {
+ return true
+ } else if attr == "default" {
+ return false
+ }
+ return pastValue
+}
+
+func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) {
+ preserveSpaces = calculatePreserveSpaces(n, preserveSpaces)
+ if n.Type == TextNode {
+ xml.EscapeText(buf, []byte(n.sanitizedData(preserveSpaces)))
+ return
+ }
+ if n.Type == CommentNode {
+ buf.WriteString("")
+ return
+ }
+ if n.Type == DeclarationNode {
+ buf.WriteString("" + n.Data)
+ } else {
+ if n.Prefix == "" {
+ buf.WriteString("<" + n.Data)
+ } else {
+ buf.WriteString("<" + n.Prefix + ":" + n.Data)
+ }
+ }
+
+ for _, attr := range n.Attr {
+ if attr.Name.Space != "" {
+ buf.WriteString(fmt.Sprintf(` %s:%s=`, attr.Name.Space, attr.Name.Local))
+ } else {
+ buf.WriteString(fmt.Sprintf(` %s=`, attr.Name.Local))
+ }
+ buf.WriteByte(34) // "
+ xml.EscapeText(buf, []byte(attr.Value))
+ buf.WriteByte(34)
+ }
+ if n.Type == DeclarationNode {
+ buf.WriteString("?>")
+ } else {
+ buf.WriteString(">")
+ }
+ for child := n.FirstChild; child != nil; child = child.NextSibling {
+ outputXML(buf, child, preserveSpaces)
+ }
+ if n.Type != DeclarationNode {
+ if n.Prefix == "" {
+ buf.WriteString(fmt.Sprintf("%s>", n.Data))
+ } else {
+ buf.WriteString(fmt.Sprintf("%s:%s>", n.Prefix, n.Data))
+ }
+ }
+}
+
+// OutputXML returns the text that including tags name.
+func (n *Node) OutputXML(self bool) string {
+ var buf bytes.Buffer
+ if self {
+ outputXML(&buf, n, false)
+ } else {
+ for n := n.FirstChild; n != nil; n = n.NextSibling {
+ outputXML(&buf, n, false)
+ }
+ }
+
+ return buf.String()
+}
+
+func addAttr(n *Node, key, val string) {
+ var attr xml.Attr
+ if i := strings.Index(key, ":"); i > 0 {
+ attr = xml.Attr{
+ Name: xml.Name{Space: key[:i], Local: key[i+1:]},
+ Value: val,
+ }
+ } else {
+ attr = xml.Attr{
+ Name: xml.Name{Local: key},
+ Value: val,
+ }
+ }
+
+ n.Attr = append(n.Attr, attr)
+}
+
+func addChild(parent, n *Node) {
+ n.Parent = parent
+ if parent.FirstChild == nil {
+ parent.FirstChild = n
+ } else {
+ parent.LastChild.NextSibling = n
+ n.PrevSibling = parent.LastChild
+ }
+
+ parent.LastChild = n
+}
+
+func addSibling(sibling, n *Node) {
+ for t := sibling.NextSibling; t != nil; t = t.NextSibling {
+ sibling = t
+ }
+ n.Parent = sibling.Parent
+ sibling.NextSibling = n
+ n.PrevSibling = sibling
+ if sibling.Parent != nil {
+ sibling.Parent.LastChild = n
+ }
+}
+
+// LoadURL loads the XML document from the specified URL.
+func LoadURL(url string) (*Node, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ return parse(resp.Body)
+}
+
+func parse(r io.Reader) (*Node, error) {
+ var (
+ decoder = xml.NewDecoder(r)
+ doc = &Node{Type: DocumentNode}
+ space2prefix = make(map[string]string)
+ level = 0
+ )
+ // http://www.w3.org/XML/1998/namespace is bound by definition to the prefix xml.
+ space2prefix["http://www.w3.org/XML/1998/namespace"] = "xml"
+ decoder.CharsetReader = charset.NewReaderLabel
+ prev := doc
+ for {
+ tok, err := decoder.Token()
+ switch {
+ case err == io.EOF:
+ goto quit
+ case err != nil:
+ return nil, err
+ }
+
+ switch tok := tok.(type) {
+ case xml.StartElement:
+ if level == 0 {
+ // mising XML declaration
+ node := &Node{Type: DeclarationNode, Data: "xml", level: 1}
+ addChild(prev, node)
+ level = 1
+ prev = node
+ }
+ // https://www.w3.org/TR/xml-names/#scoping-defaulting
+ for _, att := range tok.Attr {
+ if att.Name.Local == "xmlns" {
+ space2prefix[att.Value] = ""
+ } else if att.Name.Space == "xmlns" {
+ space2prefix[att.Value] = att.Name.Local
+ }
+ }
+
+ if tok.Name.Space != "" {
+ if _, found := space2prefix[tok.Name.Space]; !found {
+ return nil, errors.New("xmlquery: invalid XML document, namespace is missing")
+ }
+ }
+
+ for i := 0; i < len(tok.Attr); i++ {
+ att := &tok.Attr[i]
+ if prefix, ok := space2prefix[att.Name.Space]; ok {
+ att.Name.Space = prefix
+ }
+ }
+
+ node := &Node{
+ Type: ElementNode,
+ Data: tok.Name.Local,
+ Prefix: space2prefix[tok.Name.Space],
+ NamespaceURI: tok.Name.Space,
+ Attr: tok.Attr,
+ level: level,
+ }
+ //fmt.Println(fmt.Sprintf("start > %s : %d", node.Data, level))
+ if level == prev.level {
+ addSibling(prev, node)
+ } else if level > prev.level {
+ addChild(prev, node)
+ } else if level < prev.level {
+ for i := prev.level - level; i > 1; i-- {
+ prev = prev.Parent
+ }
+ addSibling(prev.Parent, node)
+ }
+ prev = node
+ level++
+ case xml.EndElement:
+ level--
+ case xml.CharData:
+ node := &Node{Type: TextNode, Data: string(tok), level: level}
+ if level == prev.level {
+ addSibling(prev, node)
+ } else if level > prev.level {
+ addChild(prev, node)
+ } else if level < prev.level {
+ for i := prev.level - level; i > 1; i-- {
+ prev = prev.Parent
+ }
+ addSibling(prev.Parent, node)
+ }
+ case xml.Comment:
+ node := &Node{Type: CommentNode, Data: string(tok), level: level}
+ if level == prev.level {
+ addSibling(prev, node)
+ } else if level > prev.level {
+ addChild(prev, node)
+ } else if level < prev.level {
+ for i := prev.level - level; i > 1; i-- {
+ prev = prev.Parent
+ }
+ addSibling(prev.Parent, node)
+ }
+ case xml.ProcInst: // Processing Instruction
+ if prev.Type != DeclarationNode {
+ level++
+ }
+ node := &Node{Type: DeclarationNode, Data: tok.Target, level: level}
+ pairs := strings.Split(string(tok.Inst), " ")
+ for _, pair := range pairs {
+ pair = strings.TrimSpace(pair)
+ if i := strings.Index(pair, "="); i > 0 {
+ addAttr(node, pair[:i], strings.Trim(pair[i+1:], `"`))
+ }
+ }
+ if level == prev.level {
+ addSibling(prev, node)
+ } else if level > prev.level {
+ addChild(prev, node)
+ }
+ prev = node
+ case xml.Directive:
+ }
+
+ }
+quit:
+ return doc, nil
+}
+
+// Parse returns the parse tree for the XML from the given Reader.
+func Parse(r io.Reader) (*Node, error) {
+ return parse(r)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go
new file mode 100644
index 000000000000..1da9e816983c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go
@@ -0,0 +1,299 @@
+/*
+Package xmlquery provides extract data from XML documents using XPath expression.
+*/
+package xmlquery
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/antchfx/xpath"
+)
+
+// SelectElements finds child elements with the specified name.
+func (n *Node) SelectElements(name string) []*Node {
+ return Find(n, name)
+}
+
+// SelectElement finds child elements with the specified name.
+func (n *Node) SelectElement(name string) *Node {
+ return FindOne(n, name)
+}
+
+// SelectAttr returns the attribute value with the specified name.
+func (n *Node) SelectAttr(name string) string {
+ if n.Type == AttributeNode {
+ if n.Data == name {
+ return n.InnerText()
+ }
+ return ""
+ }
+ var local, space string
+ local = name
+ if i := strings.Index(name, ":"); i > 0 {
+ space = name[:i]
+ local = name[i+1:]
+ }
+ for _, attr := range n.Attr {
+ if attr.Name.Local == local && attr.Name.Space == space {
+ return attr.Value
+ }
+ }
+ return ""
+}
+
+var _ xpath.NodeNavigator = &NodeNavigator{}
+
+// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node.
+func CreateXPathNavigator(top *Node) *NodeNavigator {
+ return &NodeNavigator{curr: top, root: top, attr: -1}
+}
+
+func getCurrentNode(it *xpath.NodeIterator) *Node {
+ n := it.Current().(*NodeNavigator)
+ if n.NodeType() == xpath.AttributeNode {
+ childNode := &Node{
+ Type: TextNode,
+ Data: n.Value(),
+ }
+ return &Node{
+ Parent: n.curr,
+ Type: AttributeNode,
+ Data: n.LocalName(),
+ FirstChild: childNode,
+ LastChild: childNode,
+ }
+ }
+ return n.curr
+}
+
+// Find is like QueryAll but it will panics if the `expr` is not a
+// valid XPath expression. See `QueryAll()` function.
+func Find(top *Node, expr string) []*Node {
+ nodes, err := QueryAll(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return nodes
+}
+
+// FindOne is like Query but it will panics if the `expr` is not a
+// valid XPath expression. See `Query()` function.
+func FindOne(top *Node, expr string) *Node {
+ node, err := Query(top, expr)
+ if err != nil {
+ panic(err)
+ }
+ return node
+}
+
+// QueryAll searches the XML Node that matches by the specified XPath expr.
+// Return an error if the expression `expr` cannot be parsed.
+func QueryAll(top *Node, expr string) ([]*Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ return QuerySelectorAll(top, exp), nil
+}
+
+// Query searches the XML Node that matches by the specified XPath expr,
+// and returns first element of matched.
+func Query(top *Node, expr string) (*Node, error) {
+ exp, err := getQuery(expr)
+ if err != nil {
+ return nil, err
+ }
+ return QuerySelector(top, exp), nil
+}
+
+// QuerySelectorAll searches all of the XML Node that matches the specified XPath selectors.
+func QuerySelectorAll(top *Node, selector *xpath.Expr) []*Node {
+ t := selector.Select(CreateXPathNavigator(top))
+ var elems []*Node
+ for t.MoveNext() {
+ elems = append(elems, getCurrentNode(t))
+ }
+ return elems
+}
+
+// QuerySelector returns the first matched XML Node by the specified XPath selector.
+func QuerySelector(top *Node, selector *xpath.Expr) *Node {
+ t := selector.Select(CreateXPathNavigator(top))
+ if t.MoveNext() {
+ return getCurrentNode(t)
+ }
+ return nil
+}
+
+// FindEach searches the html.Node and calls functions cb.
+// Important: this method has deprecated, recommend use for .. = range Find(){}.
+func FindEach(top *Node, expr string, cb func(int, *Node)) {
+ for i, n := range Find(top, expr) {
+ cb(i, n)
+ }
+}
+
+// FindEachWithBreak functions the same as FindEach but allows you
+// to break the loop by returning false from your callback function, cb.
+// Important: this method has deprecated, recommend use for .. = range Find(){}.
+func FindEachWithBreak(top *Node, expr string, cb func(int, *Node) bool) {
+ for i, n := range Find(top, expr) {
+ if !cb(i, n) {
+ break
+ }
+ }
+}
+
+type NodeNavigator struct {
+ root, curr *Node
+ attr int
+}
+
+func (x *NodeNavigator) Current() *Node {
+ return x.curr
+}
+
+func (x *NodeNavigator) NodeType() xpath.NodeType {
+ switch x.curr.Type {
+ case CommentNode:
+ return xpath.CommentNode
+ case TextNode:
+ return xpath.TextNode
+ case DeclarationNode, DocumentNode:
+ return xpath.RootNode
+ case ElementNode:
+ if x.attr != -1 {
+ return xpath.AttributeNode
+ }
+ return xpath.ElementNode
+ }
+ panic(fmt.Sprintf("unknown XML node type: %v", x.curr.Type))
+}
+
+func (x *NodeNavigator) LocalName() string {
+ if x.attr != -1 {
+ return x.curr.Attr[x.attr].Name.Local
+ }
+ return x.curr.Data
+
+}
+
+func (x *NodeNavigator) Prefix() string {
+ if x.NodeType() == xpath.AttributeNode {
+ if x.attr != -1 {
+ return x.curr.Attr[x.attr].Name.Space
+ }
+ return ""
+ }
+ return x.curr.Prefix
+}
+
+func (x *NodeNavigator) NamespaceURL() string {
+ return x.curr.NamespaceURI
+}
+
+func (x *NodeNavigator) Value() string {
+ switch x.curr.Type {
+ case CommentNode:
+ return x.curr.Data
+ case ElementNode:
+ if x.attr != -1 {
+ return x.curr.Attr[x.attr].Value
+ }
+ return x.curr.InnerText()
+ case TextNode:
+ return x.curr.Data
+ }
+ return ""
+}
+
+func (x *NodeNavigator) Copy() xpath.NodeNavigator {
+ n := *x
+ return &n
+}
+
+func (x *NodeNavigator) MoveToRoot() {
+ x.curr = x.root
+}
+
+func (x *NodeNavigator) MoveToParent() bool {
+ if x.attr != -1 {
+ x.attr = -1
+ return true
+ } else if node := x.curr.Parent; node != nil {
+ x.curr = node
+ return true
+ }
+ return false
+}
+
+func (x *NodeNavigator) MoveToNextAttribute() bool {
+ if x.attr >= len(x.curr.Attr)-1 {
+ return false
+ }
+ x.attr++
+ return true
+}
+
+func (x *NodeNavigator) MoveToChild() bool {
+ if x.attr != -1 {
+ return false
+ }
+ if node := x.curr.FirstChild; node != nil {
+ x.curr = node
+ return true
+ }
+ return false
+}
+
+func (x *NodeNavigator) MoveToFirst() bool {
+ if x.attr != -1 || x.curr.PrevSibling == nil {
+ return false
+ }
+ for {
+ node := x.curr.PrevSibling
+ if node == nil {
+ break
+ }
+ x.curr = node
+ }
+ return true
+}
+
+func (x *NodeNavigator) String() string {
+ return x.Value()
+}
+
+func (x *NodeNavigator) MoveToNext() bool {
+ if x.attr != -1 {
+ return false
+ }
+ if node := x.curr.NextSibling; node != nil {
+ x.curr = node
+ return true
+ }
+ return false
+}
+
+func (x *NodeNavigator) MoveToPrevious() bool {
+ if x.attr != -1 {
+ return false
+ }
+ if node := x.curr.PrevSibling; node != nil {
+ x.curr = node
+ return true
+ }
+ return false
+}
+
+func (x *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool {
+ node, ok := other.(*NodeNavigator)
+ if !ok || node.root != x.root {
+ return false
+ }
+
+ x.curr = node.curr
+ x.attr = node.attr
+ return true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go
deleted file mode 100644
index a4c5d8cc806e..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/antchfx/xmlquery, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/antchfx/xmlquery (exports: Node; functions: Find,FindOne,FindEach,FindEachWithBreak,QueryAll,Query)
-
-// Package xmlquery is a stub of github.com/antchfx/xmlquery, generated by depstubber.
-package xmlquery
-
-import (
- xml "encoding/xml"
-)
-
-func Find(_ *Node, _ string) []*Node {
- return nil
-}
-
-func FindEach(_ *Node, _ string, _ func(int, *Node)) {}
-
-func FindEachWithBreak(_ *Node, _ string, _ func(int, *Node) bool) {}
-
-func FindOne(_ *Node, _ string) *Node {
- return nil
-}
-
-type Node struct {
- Parent *Node
- FirstChild *Node
- LastChild *Node
- PrevSibling *Node
- NextSibling *Node
- Type NodeType
- Data string
- Prefix string
- NamespaceURI string
- Attr []xml.Attr
-}
-
-func (_ *Node) InnerText() string {
- return ""
-}
-
-func (_ *Node) OutputXML(_ bool) string {
- return ""
-}
-
-func (_ *Node) SelectAttr(_ string) string {
- return ""
-}
-
-func (_ *Node) SelectElement(_ string) *Node {
- return nil
-}
-
-func (_ *Node) SelectElements(_ string) []*Node {
- return nil
-}
-
-type NodeType uint
-
-func Query(_ *Node, _ string) (*Node, error) {
- return nil, nil
-}
-
-func QueryAll(_ *Node, _ string) ([]*Node, error) {
- return nil, nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore
new file mode 100644
index 000000000000..4d5d27b1d3a1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore
@@ -0,0 +1,32 @@
+# vscode
+.vscode
+debug
+*.test
+
+./build
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
\ No newline at end of file
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md
new file mode 100644
index 000000000000..733c4c8727e0
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md
@@ -0,0 +1,167 @@
+# XPath
+
+[](https://godoc.org/github.com/antchfx/xpath)
+[](https://coveralls.io/github/antchfx/xpath?branch=master)
+[](https://github.com/antchfx/xpath/actions/workflows/testing.yml)
+[](https://goreportcard.com/report/github.com/antchfx/xpath)
+
+XPath is Go package provides selecting nodes from XML, HTML or other documents using XPath expression.
+
+# Implementation
+
+- [htmlquery](https://github.com/antchfx/htmlquery) - an XPath query package for HTML document
+
+- [xmlquery](https://github.com/antchfx/xmlquery) - an XPath query package for XML document.
+
+- [jsonquery](https://github.com/antchfx/jsonquery) - an XPath query package for JSON document
+
+# Supported Features
+
+#### The basic XPath patterns.
+
+> The basic XPath patterns cover 90% of the cases that most stylesheets will need.
+
+- `node` : Selects all child elements with nodeName of node.
+
+- `*` : Selects all child elements.
+
+- `@attr` : Selects the attribute attr.
+
+- `@*` : Selects all attributes.
+
+- `node()` : Matches an org.w3c.dom.Node.
+
+- `text()` : Matches a org.w3c.dom.Text node.
+
+- `comment()` : Matches a comment.
+
+- `.` : Selects the current node.
+
+- `..` : Selects the parent of current node.
+
+- `/` : Selects the document node.
+
+- `a[expr]` : Select only those nodes matching a which also satisfy the expression expr.
+
+- `a[n]` : Selects the nth matching node matching a When a filter's expression is a number, XPath selects based on position.
+
+- `a/b` : For each node matching a, add the nodes matching b to the result.
+
+- `a//b` : For each node matching a, add the descendant nodes matching b to the result.
+
+- `//b` : Returns elements in the entire document matching b.
+
+- `a|b` : All nodes matching a or b, union operation(not boolean or).
+
+- `(a, b, c)` : Evaluates each of its operands and concatenates the resulting sequences, in order, into a single result sequence
+
+- `(a/b)` : Selects all matches nodes as grouping set.
+
+#### Node Axes
+
+- `child::*` : The child axis selects children of the current node.
+
+ - `child::node()`: Selects all the children of the context node.
+ - `child::text()`: Selects all text node children of the context node.
+
+- `descendant::*` : The descendant axis selects descendants of the current node. It is equivalent to '//'.
+
+- `descendant-or-self::*` : Selects descendants including the current node.
+
+- `attribute::*` : Selects attributes of the current element. It is equivalent to @\*
+
+- `following-sibling::*` : Selects nodes after the current node.
+
+- `preceding-sibling::*` : Selects nodes before the current node.
+
+- `following::*` : Selects the first matching node following in document order, excluding descendants.
+
+- `preceding::*` : Selects the first matching node preceding in document order, excluding ancestors.
+
+- `parent::*` : Selects the parent if it matches. The '..' pattern from the core is equivalent to 'parent::node()'.
+
+- `ancestor::*` : Selects matching ancestors.
+
+- `ancestor-or-self::*` : Selects ancestors including the current node.
+
+- `self::*` : Selects the current node. '.' is equivalent to 'self::node()'.
+
+#### Expressions
+
+The gxpath supported three types: number, boolean, string.
+
+- `path` : Selects nodes based on the path.
+
+- `a = b` : Standard comparisons.
+
+ - `a = b` : True if a equals b.
+ - `a != b` : True if a is not equal to b.
+ - `a < b` : True if a is less than b.
+ - `a <= b` : True if a is less than or equal to b.
+ - `a > b` : True if a is greater than b.
+ - `a >= b` : True if a is greater than or equal to b.
+
+- `a + b` : Arithmetic expressions.
+
+ - `- a` Unary minus
+ - `a + b` : Addition
+ - `a - b` : Subtraction
+ - `a * b` : Multiplication
+ - `a div b` : Division
+ - `a mod b` : Modulus (division remainder)
+
+- `a or b` : Boolean `or` operation.
+
+- `a and b` : Boolean `and` operation.
+
+- `(expr)` : Parenthesized expressions.
+
+- `fun(arg1, ..., argn)` : Function calls:
+
+| Function | Supported |
+| ----------------------- | --------- |
+| `boolean()` | ✓ |
+| `ceiling()` | ✓ |
+| `choose()` | ✗ |
+| `concat()` | ✓ |
+| `contains()` | ✓ |
+| `count()` | ✓ |
+| `current()` | ✗ |
+| `document()` | ✗ |
+| `element-available()` | ✗ |
+| `ends-with()` | ✓ |
+| `false()` | ✓ |
+| `floor()` | ✓ |
+| `format-number()` | ✗ |
+| `function-available()` | ✗ |
+| `generate-id()` | ✗ |
+| `id()` | ✗ |
+| `key()` | ✗ |
+| `lang()` | ✗ |
+| `last()` | ✓ |
+| `local-name()` | ✓ |
+| `lower-case()`[^1] | ✓ |
+| `matches()` | ✓ |
+| `name()` | ✓ |
+| `namespace-uri()` | ✓ |
+| `normalize-space()` | ✓ |
+| `not()` | ✓ |
+| `number()` | ✓ |
+| `position()` | ✓ |
+| `replace()` | ✓ |
+| `reverse()` | ✓ |
+| `round()` | ✓ |
+| `starts-with()` | ✓ |
+| `string()` | ✓ |
+| `string-join()`[^1] | ✓ |
+| `string-length()` | ✓ |
+| `substring()` | ✓ |
+| `substring-after()` | ✓ |
+| `substring-before()` | ✓ |
+| `sum()` | ✓ |
+| `system-property()` | ✗ |
+| `translate()` | ✓ |
+| `true()` | ✓ |
+| `unparsed-entity-url()` | ✗ |
+
+[^1]: XPath-2.0 expression
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go
new file mode 100644
index 000000000000..7172608cd6d1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go
@@ -0,0 +1,718 @@
+package xpath
+
+import (
+ "errors"
+ "fmt"
+)
+
+type flag int
+
+var flagsEnum = struct {
+ None flag
+ SmartDesc flag
+ PosFilter flag
+ Filter flag
+ Condition flag
+}{
+ None: 0,
+ SmartDesc: 1,
+ PosFilter: 2,
+ Filter: 4,
+ Condition: 8,
+}
+
+type builderProp int
+
+var builderProps = struct {
+ None builderProp
+ PosFilter builderProp
+ HasPosition builderProp
+ HasLast builderProp
+ NonFlat builderProp
+}{
+ None: 0,
+ PosFilter: 1,
+ HasPosition: 2,
+ HasLast: 4,
+ NonFlat: 8,
+}
+
+// builder provides building an XPath expressions.
+type builder struct {
+ parseDepth int
+ firstInput query
+}
+
+// axisPredicate creates a predicate to predicating for this axis node.
+func axisPredicate(root *axisNode) func(NodeNavigator) bool {
+ nametest := root.LocalName != "" || root.Prefix != ""
+ predicate := func(n NodeNavigator) bool {
+ if root.typeTest == n.NodeType() || root.typeTest == allNode {
+ if nametest {
+ type namespaceURL interface {
+ NamespaceURL() string
+ }
+ if ns, ok := n.(namespaceURL); ok && root.hasNamespaceURI {
+ return root.LocalName == n.LocalName() && root.namespaceURI == ns.NamespaceURL()
+ }
+ if root.LocalName == n.LocalName() && root.Prefix == n.Prefix() {
+ return true
+ }
+ } else {
+ return true
+ }
+ }
+ return false
+ }
+
+ return predicate
+}
+
+// processAxis processes a query for the XPath axis node.
+func (b *builder) processAxis(root *axisNode, flags flag, props *builderProp) (query, error) {
+ var (
+ err error
+ qyInput query
+ qyOutput query
+ )
+ b.firstInput = nil
+ predicate := axisPredicate(root)
+
+ if root.Input == nil {
+ qyInput = &contextQuery{}
+ *props = builderProps.None
+ } else {
+ inputFlags := flagsEnum.None
+ if (flags & flagsEnum.Filter) == 0 {
+ if root.AxisType == "child" && (root.Input.Type() == nodeAxis) {
+ if input := root.Input.(*axisNode); input.AxisType == "descendant-or-self" {
+ var qyGrandInput query
+ if input.Input != nil {
+ qyGrandInput, err = b.processNode(input.Input, flagsEnum.SmartDesc, props)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ qyGrandInput = &contextQuery{}
+ }
+ qyOutput = &descendantQuery{name: root.LocalName, Input: qyGrandInput, Predicate: predicate, Self: false}
+ *props |= builderProps.NonFlat
+ return qyOutput, nil
+ }
+ }
+ if root.AxisType == "descendant" || root.AxisType == "descendant-or-self" {
+ inputFlags |= flagsEnum.SmartDesc
+ }
+ }
+
+ qyInput, err = b.processNode(root.Input, inputFlags, props)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ switch root.AxisType {
+ case "ancestor":
+ qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
+ *props |= builderProps.NonFlat
+ case "ancestor-or-self":
+ qyOutput = &ancestorQuery{name: root.LocalName, Input: qyInput, Predicate: predicate, Self: true}
+ *props |= builderProps.NonFlat
+ case "attribute":
+ qyOutput = &attributeQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
+ case "child":
+ if (*props & builderProps.NonFlat) == 0 {
+ qyOutput = &childQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
+ } else {
+ qyOutput = &cachedChildQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
+ }
+ case "descendant":
+ if (flags & flagsEnum.SmartDesc) != flagsEnum.None {
+ qyOutput = &descendantOverDescendantQuery{name: root.LocalName, Input: qyInput, MatchSelf: false, Predicate: predicate}
+ } else {
+ qyOutput = &descendantQuery{name: root.LocalName, Input: qyInput, Predicate: predicate}
+ }
+ *props |= builderProps.NonFlat
+ case "descendant-or-self":
+ if (flags & flagsEnum.SmartDesc) != flagsEnum.None {
+ qyOutput = &descendantOverDescendantQuery{name: root.LocalName, Input: qyInput, MatchSelf: true, Predicate: predicate}
+ } else {
+ qyOutput = &descendantQuery{name: root.LocalName, Input: qyInput, Predicate: predicate, Self: true}
+ }
+ *props |= builderProps.NonFlat
+ case "following":
+ qyOutput = &followingQuery{Input: qyInput, Predicate: predicate}
+ *props |= builderProps.NonFlat
+ case "following-sibling":
+ qyOutput = &followingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
+ case "parent":
+ qyOutput = &parentQuery{Input: qyInput, Predicate: predicate}
+ case "preceding":
+ qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate}
+ *props |= builderProps.NonFlat
+ case "preceding-sibling":
+ qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate, Sibling: true}
+ case "self":
+ qyOutput = &selfQuery{Input: qyInput, Predicate: predicate}
+ case "namespace":
+ // haha,what will you do someting??
+ default:
+ err = fmt.Errorf("unknown axe type: %s", root.AxisType)
+ return nil, err
+ }
+ return qyOutput, nil
+}
+
+func canBeNumber(q query) bool {
+ if q.ValueType() != xpathResultType.Any {
+ return q.ValueType() == xpathResultType.Number
+ }
+ return true
+}
+
+// processFilterNode builds query for the XPath filter predicate.
+func (b *builder) processFilter(root *filterNode, flags flag, props *builderProp) (query, error) {
+ first := (flags & flagsEnum.Filter) == 0
+
+ qyInput, err := b.processNode(root.Input, (flags | flagsEnum.Filter), props)
+ if err != nil {
+ return nil, err
+ }
+ firstInput := b.firstInput
+
+ var propsCond builderProp
+ cond, err := b.processNode(root.Condition, flags, &propsCond)
+ if err != nil {
+ return nil, err
+ }
+
+ // Checking whether is number
+ if canBeNumber(cond) || ((propsCond & (builderProps.HasPosition | builderProps.HasLast)) != 0) {
+ propsCond |= builderProps.HasPosition
+ flags |= flagsEnum.PosFilter
+ }
+
+ if root.Input.Type() != nodeFilter {
+ *props &= ^builderProps.PosFilter
+ }
+
+ if (propsCond & builderProps.HasPosition) != 0 {
+ *props |= builderProps.PosFilter
+ }
+
+ if (propsCond & builderProps.HasPosition) != builderProps.None {
+ if (propsCond & builderProps.HasLast) != 0 {
+ // https://github.com/antchfx/xpath/issues/76
+ // https://github.com/antchfx/xpath/issues/78
+ if qyFunc, ok := cond.(*functionQuery); ok {
+ switch qyFunc.Input.(type) {
+ case *filterQuery:
+ cond = &lastFuncQuery{Input: qyFunc.Input}
+ case *groupQuery:
+ cond = &lastFuncQuery{Input: qyFunc.Input}
+ }
+ }
+ }
+ }
+
+ merge := (qyInput.Properties() & queryProps.Merge) != 0
+ if first && firstInput != nil {
+ if merge && ((*props & builderProps.PosFilter) != 0) {
+ var (
+ rootQuery = &contextQuery{}
+ parent query
+ )
+ switch axisQuery := firstInput.(type) {
+ case *ancestorQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *attributeQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *childQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *cachedChildQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *descendantQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *followingQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *precedingQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *parentQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *selfQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *groupQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ case *descendantOverDescendantQuery:
+ if _, ok := axisQuery.Input.(*contextQuery); !ok {
+ parent = axisQuery.Input
+ axisQuery.Input = rootQuery
+ }
+ }
+ b.firstInput = nil
+ child := &filterQuery{Input: qyInput, Predicate: cond, NoPosition: false}
+ if parent != nil {
+ return &mergeQuery{Input: parent, Child: child}, nil
+ }
+ return child, nil
+ }
+ b.firstInput = nil
+ }
+
+ resultQuery := &filterQuery{
+ Input: qyInput,
+ Predicate: cond,
+ NoPosition: (propsCond & builderProps.HasPosition) == 0,
+ }
+ return resultQuery, nil
+}
+
+// processFunctionNode processes query for the XPath function node.
+func (b *builder) processFunction(root *functionNode, props *builderProp) (query, error) {
+ // Reset builder props
+ *props = builderProps.None
+
+ var qyOutput query
+ switch root.FuncName {
+ case "lower-case":
+ arg, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: lowerCaseFunc(arg)}
+ case "starts-with":
+ arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: startwithFunc(arg1, arg2)}
+ case "ends-with":
+ arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: endwithFunc(arg1, arg2)}
+ case "contains":
+ arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ arg2, err := b.processNode(root.Args[1], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: containsFunc(arg1, arg2)}
+ case "matches":
+ //matches(string , pattern)
+ if len(root.Args) != 2 {
+ return nil, errors.New("xpath: matches function must have two parameters")
+ }
+ var (
+ arg1, arg2 query
+ err error
+ )
+ if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ // Issue #92, testing the regular expression before.
+ if q, ok := arg2.(*constantQuery); ok {
+ if _, err = getRegexp(q.Val.(string)); err != nil {
+ return nil, fmt.Errorf("matches() got error. %v", err)
+ }
+ }
+ qyOutput = &functionQuery{Func: matchesFunc(arg1, arg2)}
+ case "substring":
+ //substring( string , start [, length] )
+ if len(root.Args) < 2 {
+ return nil, errors.New("xpath: substring function must have at least two parameter")
+ }
+ var (
+ arg1, arg2, arg3 query
+ err error
+ )
+ if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if len(root.Args) == 3 {
+ if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ }
+ qyOutput = &functionQuery{Func: substringFunc(arg1, arg2, arg3)}
+ case "substring-before", "substring-after":
+ //substring-xxxx( haystack, needle )
+ if len(root.Args) != 2 {
+ return nil, errors.New("xpath: substring-before function must have two parameters")
+ }
+ var (
+ arg1, arg2 query
+ err error
+ )
+ if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{
+ Func: substringIndFunc(arg1, arg2, root.FuncName == "substring-after"),
+ }
+ case "string-length":
+ // string-length( [string] )
+ if len(root.Args) < 1 {
+ return nil, errors.New("xpath: string-length function must have at least one parameter")
+ }
+ arg1, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: stringLengthFunc(arg1)}
+ case "normalize-space":
+ var arg node
+ if len(root.Args) > 0 {
+ arg = root.Args[0]
+ } else {
+ arg = newAxisNode("self", allNode, "", "", "", nil)
+ }
+ arg1, err := b.processNode(arg, flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: normalizespaceFunc(arg1)}
+ case "replace":
+ //replace( string , string, string )
+ if len(root.Args) != 3 {
+ return nil, errors.New("xpath: replace function must have three parameters")
+ }
+ var (
+ arg1, arg2, arg3 query
+ err error
+ )
+ if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: replaceFunc(arg1, arg2, arg3)}
+ case "translate":
+ //translate( string , string, string )
+ if len(root.Args) != 3 {
+ return nil, errors.New("xpath: translate function must have three parameters")
+ }
+ var (
+ arg1, arg2, arg3 query
+ err error
+ )
+ if arg1, err = b.processNode(root.Args[0], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg2, err = b.processNode(root.Args[1], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ if arg3, err = b.processNode(root.Args[2], flagsEnum.None, props); err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: translateFunc(arg1, arg2, arg3)}
+ case "not":
+ if len(root.Args) == 0 {
+ return nil, errors.New("xpath: not function must have at least one parameter")
+ }
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: notFunc(argQuery)}
+ case "name", "local-name", "namespace-uri":
+ if len(root.Args) > 1 {
+ return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName)
+ }
+ var (
+ arg query
+ err error
+ )
+ if len(root.Args) == 1 {
+ arg, err = b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ }
+ switch root.FuncName {
+ case "name":
+ qyOutput = &functionQuery{Func: nameFunc(arg)}
+ case "local-name":
+ qyOutput = &functionQuery{Func: localNameFunc(arg)}
+ case "namespace-uri":
+ qyOutput = &functionQuery{Func: namespaceFunc(arg)}
+ }
+ case "true", "false":
+ val := root.FuncName == "true"
+ qyOutput = &functionQuery{
+ Func: func(_ query, _ iterator) interface{} {
+ return val
+ },
+ }
+ case "last":
+ qyOutput = &functionQuery{Input: b.firstInput, Func: lastFunc()}
+ *props |= builderProps.HasLast
+ case "position":
+ qyOutput = &functionQuery{Input: b.firstInput, Func: positionFunc()}
+ *props |= builderProps.HasPosition
+ case "boolean", "number", "string":
+ var inp query
+ if len(root.Args) > 1 {
+ return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName)
+ }
+ if len(root.Args) == 1 {
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ inp = argQuery
+ }
+ switch root.FuncName {
+ case "boolean":
+ qyOutput = &functionQuery{Func: booleanFunc(inp)}
+ case "string":
+ qyOutput = &functionQuery{Func: stringFunc(inp)}
+ case "number":
+ qyOutput = &functionQuery{Func: numberFunc(inp)}
+ }
+ case "count":
+ if len(root.Args) == 0 {
+ return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets")
+ }
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: countFunc(argQuery)}
+ case "sum":
+ if len(root.Args) == 0 {
+ return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets")
+ }
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: sumFunc(argQuery)}
+ case "ceiling", "floor", "round":
+ if len(root.Args) == 0 {
+ return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets")
+ }
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ switch root.FuncName {
+ case "ceiling":
+ qyOutput = &functionQuery{Func: ceilingFunc(argQuery)}
+ case "floor":
+ qyOutput = &functionQuery{Func: floorFunc(argQuery)}
+ case "round":
+ qyOutput = &functionQuery{Func: roundFunc(argQuery)}
+ }
+ case "concat":
+ if len(root.Args) < 2 {
+ return nil, fmt.Errorf("xpath: concat() must have at least two arguments")
+ }
+ var args []query
+ for _, v := range root.Args {
+ q, err := b.processNode(v, flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ args = append(args, q)
+ }
+ qyOutput = &functionQuery{Func: concatFunc(args...)}
+ case "reverse":
+ if len(root.Args) == 0 {
+ return nil, fmt.Errorf("xpath: reverse(node-sets) function must with have parameters node-sets")
+ }
+ argQuery, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &transformFunctionQuery{Input: argQuery, Func: reverseFunc}
+ case "string-join":
+ if len(root.Args) != 2 {
+ return nil, fmt.Errorf("xpath: string-join(node-sets, separator) function requires node-set and argument")
+ }
+ input, err := b.processNode(root.Args[0], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ arg1, err := b.processNode(root.Args[1], flagsEnum.None, props)
+ if err != nil {
+ return nil, err
+ }
+ qyOutput = &functionQuery{Func: stringJoinFunc(input, arg1)}
+ default:
+ return nil, fmt.Errorf("not yet support this function %s()", root.FuncName)
+ }
+ return qyOutput, nil
+}
+
+func (b *builder) processOperator(root *operatorNode, props *builderProp) (query, error) {
+ var (
+ leftProp builderProp
+ rightProp builderProp
+ )
+
+ left, err := b.processNode(root.Left, flagsEnum.None, &leftProp)
+ if err != nil {
+ return nil, err
+ }
+ right, err := b.processNode(root.Right, flagsEnum.None, &rightProp)
+ if err != nil {
+ return nil, err
+ }
+ *props = leftProp | rightProp
+
+ var qyOutput query
+ switch root.Op {
+ case "+", "-", "*", "div", "mod": // Numeric operator
+ var exprFunc func(iterator, interface{}, interface{}) interface{}
+ switch root.Op {
+ case "+":
+ exprFunc = plusFunc
+ case "-":
+ exprFunc = minusFunc
+ case "*":
+ exprFunc = mulFunc
+ case "div":
+ exprFunc = divFunc
+ case "mod":
+ exprFunc = modFunc
+ }
+ qyOutput = &numericQuery{Left: left, Right: right, Do: exprFunc}
+ case "=", ">", ">=", "<", "<=", "!=":
+ var exprFunc func(iterator, interface{}, interface{}) interface{}
+ switch root.Op {
+ case "=":
+ exprFunc = eqFunc
+ case ">":
+ exprFunc = gtFunc
+ case ">=":
+ exprFunc = geFunc
+ case "<":
+ exprFunc = ltFunc
+ case "<=":
+ exprFunc = leFunc
+ case "!=":
+ exprFunc = neFunc
+ }
+ qyOutput = &logicalQuery{Left: left, Right: right, Do: exprFunc}
+ case "or", "and":
+ isOr := false
+ if root.Op == "or" {
+ isOr = true
+ }
+ qyOutput = &booleanQuery{Left: left, Right: right, IsOr: isOr}
+ case "|":
+ *props |= builderProps.NonFlat
+ qyOutput = &unionQuery{Left: left, Right: right}
+ }
+ return qyOutput, nil
+}
+
+func (b *builder) processNode(root node, flags flag, props *builderProp) (q query, err error) {
+ if b.parseDepth = b.parseDepth + 1; b.parseDepth > 1024 {
+ err = errors.New("the xpath expressions is too complex")
+ return
+ }
+ *props = builderProps.None
+ switch root.Type() {
+ case nodeConstantOperand:
+ n := root.(*operandNode)
+ q = &constantQuery{Val: n.Val}
+ case nodeRoot:
+ q = &absoluteQuery{}
+ case nodeAxis:
+ q, err = b.processAxis(root.(*axisNode), flags, props)
+ b.firstInput = q
+ case nodeFilter:
+ q, err = b.processFilter(root.(*filterNode), flags, props)
+ b.firstInput = q
+ case nodeFunction:
+ q, err = b.processFunction(root.(*functionNode), props)
+ case nodeOperator:
+ q, err = b.processOperator(root.(*operatorNode), props)
+ case nodeGroup:
+ q, err = b.processNode(root.(*groupNode).Input, flagsEnum.None, props)
+ if err != nil {
+ return
+ }
+ q = &groupQuery{Input: q}
+ b.firstInput = q
+ }
+ b.parseDepth--
+ return
+}
+
+// build builds a specified XPath expressions expr.
+func build(expr string, namespaces map[string]string) (q query, err error) {
+ defer func() {
+ if e := recover(); e != nil {
+ switch x := e.(type) {
+ case string:
+ err = errors.New(x)
+ case error:
+ err = x
+ default:
+ err = errors.New("unknown panic")
+ }
+ }
+ }()
+ root := parse(expr, namespaces)
+ b := &builder{}
+ props := builderProps.None
+ return b.processNode(root, flagsEnum.None, &props)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/cache.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/cache.go
new file mode 100644
index 000000000000..31a2b335656b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/cache.go
@@ -0,0 +1,80 @@
+package xpath
+
+import (
+ "regexp"
+ "sync"
+)
+
+type loadFunc func(key interface{}) (interface{}, error)
+
+const (
+ defaultCap = 65536
+)
+
+// The reason we're building a simple capacity-resetting loading cache (when capacity reached) instead of using
+// something like github.com/hashicorp/golang-lru is primarily due to (not wanting to create) external dependency.
+// Currently this library has 0 external dep (other than go sdk), and supports go 1.6, 1.9, and 1.10 (and later).
+// Creating external lib dependencies (plus their transitive dependencies) would make things hard if not impossible.
+// We expect under most circumstances, the defaultCap is big enough for any long running services that use this
+// library if their xpath regexp cardinality is low. However, in extreme cases when the capacity is reached, we
+// simply reset the cache, taking a small subsequent perf hit (next to nothing considering amortization) in trade
+// of more complex and less performant LRU type of construct.
+type loadingCache struct {
+ sync.RWMutex
+ cap int
+ load loadFunc
+ m map[interface{}]interface{}
+ reset int
+}
+
+// NewLoadingCache creates a new instance of a loading cache with capacity. Capacity must be >= 0, or
+// it will panic. Capacity == 0 means the cache growth is unbounded.
+func NewLoadingCache(load loadFunc, capacity int) *loadingCache {
+ if capacity < 0 {
+ panic("capacity must be >= 0")
+ }
+ return &loadingCache{cap: capacity, load: load, m: make(map[interface{}]interface{})}
+}
+
+func (c *loadingCache) get(key interface{}) (interface{}, error) {
+ c.RLock()
+ v, found := c.m[key]
+ c.RUnlock()
+ if found {
+ return v, nil
+ }
+ v, err := c.load(key)
+ if err != nil {
+ return nil, err
+ }
+ c.Lock()
+ if c.cap > 0 && len(c.m) >= c.cap {
+ c.m = map[interface{}]interface{}{key: v}
+ c.reset++
+ } else {
+ c.m[key] = v
+ }
+ c.Unlock()
+ return v, nil
+}
+
+var (
+ // RegexpCache is a loading cache for string -> *regexp.Regexp mapping. It is exported so that in rare cases
+ // client can customize load func and/or capacity.
+ RegexpCache = defaultRegexpCache()
+)
+
+func defaultRegexpCache() *loadingCache {
+ return NewLoadingCache(
+ func(key interface{}) (interface{}, error) {
+ return regexp.Compile(key.(string))
+ }, defaultCap)
+}
+
+func getRegexp(pattern string) (*regexp.Regexp, error) {
+ exp, err := RegexpCache.get(pattern)
+ if err != nil {
+ return nil, err
+ }
+ return exp.(*regexp.Regexp), nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go
new file mode 100644
index 000000000000..ffbee656765e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go
@@ -0,0 +1,708 @@
+package xpath
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode"
+)
+
+// Defined an interface of stringBuilder that compatible with
+// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10)
+type stringBuilder interface {
+ WriteRune(r rune) (n int, err error)
+ WriteString(s string) (int, error)
+ Reset()
+ Grow(n int)
+ String() string
+}
+
+var builderPool = sync.Pool{New: func() interface{} {
+ return newStringBuilder()
+}}
+
+// The XPath function list.
+
+func predicate(q query) func(NodeNavigator) bool {
+ type Predicater interface {
+ Test(NodeNavigator) bool
+ }
+ if p, ok := q.(Predicater); ok {
+ return p.Test
+ }
+ return func(NodeNavigator) bool { return true }
+}
+
+// positionFunc is a XPath Node Set functions position().
+func positionFunc() func(query, iterator) interface{} {
+ return func(q query, t iterator) interface{} {
+ var (
+ count = 1
+ node = t.Current().Copy()
+ )
+ test := predicate(q)
+ for node.MoveToPrevious() {
+ if test(node) {
+ count++
+ }
+ }
+ return float64(count)
+ }
+}
+
+// lastFunc is a XPath Node Set functions last().
+func lastFunc() func(query, iterator) interface{} {
+ return func(q query, t iterator) interface{} {
+ var (
+ count = 0
+ node = t.Current().Copy()
+ )
+ test := predicate(q)
+ node.MoveToFirst()
+ for {
+ if test(node) {
+ count++
+ }
+ if !node.MoveToNext() {
+ break
+ }
+ }
+ return float64(count)
+ }
+}
+
+// countFunc is a XPath Node Set functions count(node-set).
+func countFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var count = 0
+ q := functionArgs(arg)
+ test := predicate(q)
+ switch typ := q.Evaluate(t).(type) {
+ case query:
+ for node := typ.Select(t); node != nil; node = typ.Select(t) {
+ if test(node) {
+ count++
+ }
+ }
+ }
+ return float64(count)
+ }
+}
+
+// sumFunc is a XPath Node Set functions sum(node-set).
+func sumFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var sum float64
+ switch typ := functionArgs(arg).Evaluate(t).(type) {
+ case query:
+ for node := typ.Select(t); node != nil; node = typ.Select(t) {
+ if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
+ sum += v
+ }
+ }
+ case float64:
+ sum = typ
+ case string:
+ v, err := strconv.ParseFloat(typ, 64)
+ if err != nil {
+ panic(errors.New("sum() function argument type must be a node-set or number"))
+ }
+ sum = v
+ }
+ return sum
+ }
+}
+
+func asNumber(t iterator, o interface{}) float64 {
+ switch typ := o.(type) {
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return math.NaN()
+ }
+ if v, err := strconv.ParseFloat(node.Value(), 64); err == nil {
+ return v
+ }
+ case float64:
+ return typ
+ case string:
+ v, err := strconv.ParseFloat(typ, 64)
+ if err == nil {
+ return v
+ }
+ }
+ return math.NaN()
+}
+
+// ceilingFunc is a XPath Node Set functions ceiling(node-set).
+func ceilingFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ val := asNumber(t, functionArgs(arg).Evaluate(t))
+ // if math.IsNaN(val) {
+ // panic(errors.New("ceiling() function argument type must be a valid number"))
+ // }
+ return math.Ceil(val)
+ }
+}
+
+// floorFunc is a XPath Node Set functions floor(node-set).
+func floorFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ val := asNumber(t, functionArgs(arg).Evaluate(t))
+ return math.Floor(val)
+ }
+}
+
+// roundFunc is a XPath Node Set functions round(node-set).
+func roundFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ val := asNumber(t, functionArgs(arg).Evaluate(t))
+ //return math.Round(val)
+ return round(val)
+ }
+}
+
+// nameFunc is a XPath functions name([node-set]).
+func nameFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var v NodeNavigator
+ if arg == nil {
+ v = t.Current()
+ } else {
+ v = arg.Clone().Select(t)
+ if v == nil {
+ return ""
+ }
+ }
+ ns := v.Prefix()
+ if ns == "" {
+ return v.LocalName()
+ }
+ return ns + ":" + v.LocalName()
+ }
+}
+
+// localNameFunc is a XPath functions local-name([node-set]).
+func localNameFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var v NodeNavigator
+ if arg == nil {
+ v = t.Current()
+ } else {
+ v = arg.Clone().Select(t)
+ if v == nil {
+ return ""
+ }
+ }
+ return v.LocalName()
+ }
+}
+
+// namespaceFunc is a XPath functions namespace-uri([node-set]).
+func namespaceFunc(arg query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var v NodeNavigator
+ if arg == nil {
+ v = t.Current()
+ } else {
+ // Get the first node in the node-set if specified.
+ v = arg.Clone().Select(t)
+ if v == nil {
+ return ""
+ }
+ }
+ // fix about namespace-uri() bug: https://github.com/antchfx/xmlquery/issues/22
+ // TODO: In the next version, add NamespaceURL() to the NodeNavigator interface.
+ type namespaceURL interface {
+ NamespaceURL() string
+ }
+ if f, ok := v.(namespaceURL); ok {
+ return f.NamespaceURL()
+ }
+ return v.Prefix()
+ }
+}
+
+func asBool(t iterator, v interface{}) bool {
+ switch v := v.(type) {
+ case nil:
+ return false
+ case *NodeIterator:
+ return v.MoveNext()
+ case bool:
+ return v
+ case float64:
+ return v != 0
+ case string:
+ return v != ""
+ case query:
+ return v.Select(t) != nil
+ default:
+ panic(fmt.Errorf("unexpected type: %T", v))
+ }
+}
+
+func asString(t iterator, v interface{}) string {
+ switch v := v.(type) {
+ case nil:
+ return ""
+ case bool:
+ if v {
+ return "true"
+ }
+ return "false"
+ case float64:
+ return strconv.FormatFloat(v, 'g', -1, 64)
+ case string:
+ return v
+ case query:
+ node := v.Select(t)
+ if node == nil {
+ return ""
+ }
+ return node.Value()
+ default:
+ panic(fmt.Errorf("unexpected type: %T", v))
+ }
+}
+
+// booleanFunc is a XPath functions boolean([node-set]).
+func booleanFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ v := functionArgs(arg1).Evaluate(t)
+ return asBool(t, v)
+ }
+}
+
+// numberFunc is a XPath functions number([node-set]).
+func numberFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ v := functionArgs(arg1).Evaluate(t)
+ return asNumber(t, v)
+ }
+}
+
+// stringFunc is a XPath functions string([node-set]).
+func stringFunc(arg1 query) func(query, iterator) interface{} {
+ return func(q query, t iterator) interface{} {
+ if arg1 == nil {
+ return t.Current().Value()
+ }
+ v := functionArgs(arg1).Evaluate(t)
+ return asString(t, v)
+ }
+}
+
+// startwithFunc is a XPath functions starts-with(string, string).
+func startwithFunc(arg1, arg2 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var (
+ m, n string
+ ok bool
+ )
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ m = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return false
+ }
+ m = node.Value()
+ default:
+ panic(errors.New("starts-with() function argument type must be string"))
+ }
+ n, ok = functionArgs(arg2).Evaluate(t).(string)
+ if !ok {
+ panic(errors.New("starts-with() function argument type must be string"))
+ }
+ return strings.HasPrefix(m, n)
+ }
+}
+
+// endwithFunc is a XPath functions ends-with(string, string).
+func endwithFunc(arg1, arg2 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var (
+ m, n string
+ ok bool
+ )
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ m = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return false
+ }
+ m = node.Value()
+ default:
+ panic(errors.New("ends-with() function argument type must be string"))
+ }
+ n, ok = functionArgs(arg2).Evaluate(t).(string)
+ if !ok {
+ panic(errors.New("ends-with() function argument type must be string"))
+ }
+ return strings.HasSuffix(m, n)
+ }
+}
+
+// containsFunc is a XPath functions contains(string or @attr, string).
+func containsFunc(arg1, arg2 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var (
+ m, n string
+ ok bool
+ )
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ m = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return false
+ }
+ m = node.Value()
+ default:
+ panic(errors.New("contains() function argument type must be string"))
+ }
+
+ n, ok = functionArgs(arg2).Evaluate(t).(string)
+ if !ok {
+ panic(errors.New("contains() function argument type must be string"))
+ }
+
+ return strings.Contains(m, n)
+ }
+}
+
+// matchesFunc is an XPath function that tests a given string against a regexp pattern.
+// Note: does not support https://www.w3.org/TR/xpath-functions-31/#func-matches 3rd optional `flags` argument; if
+// needed, directly put flags in the regexp pattern, such as `(?i)^pattern$` for `i` flag.
+func matchesFunc(arg1, arg2 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var s string
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ s = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return ""
+ }
+ s = node.Value()
+ }
+ var pattern string
+ var ok bool
+ if pattern, ok = functionArgs(arg2).Evaluate(t).(string); !ok {
+ panic(errors.New("matches() function second argument type must be string"))
+ }
+ re, err := getRegexp(pattern)
+ if err != nil {
+ panic(fmt.Errorf("matches() function second argument is not a valid regexp pattern, err: %s", err.Error()))
+ }
+ return re.MatchString(s)
+ }
+}
+
+// normalizespaceFunc is XPath functions normalize-space(string?)
+func normalizespaceFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var m string
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ m = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return ""
+ }
+ m = node.Value()
+ }
+ var b = builderPool.Get().(stringBuilder)
+ b.Grow(len(m))
+
+ runeStr := []rune(strings.TrimSpace(m))
+ l := len(runeStr)
+ for i := range runeStr {
+ r := runeStr[i]
+ isSpace := unicode.IsSpace(r)
+ if !(isSpace && (i+1 < l && unicode.IsSpace(runeStr[i+1]))) {
+ if isSpace {
+ r = ' '
+ }
+ b.WriteRune(r)
+ }
+ }
+ result := b.String()
+ b.Reset()
+ builderPool.Put(b)
+
+ return result
+ }
+}
+
+// substringFunc is XPath functions substring function returns a part of a given string.
+func substringFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var m string
+ switch typ := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ m = typ
+ case query:
+ node := typ.Select(t)
+ if node == nil {
+ return ""
+ }
+ m = node.Value()
+ }
+
+ var start, length float64
+ var ok bool
+ if start, ok = functionArgs(arg2).Evaluate(t).(float64); !ok {
+ panic(errors.New("substring() function first argument type must be number"))
+ }
+ // fix https://github.com/antchfx/xpath/issues/109
+ start = math.Round(start)
+ if start > float64(len(m)) {
+ return ""
+ }
+ if arg3 == nil {
+ if start <= 0 {
+ return m
+ }
+ return m[int(start)-1:]
+ }
+
+ if length, ok = functionArgs(arg3).Evaluate(t).(float64); !ok {
+ panic(errors.New("substring() function second argument type must be number"))
+ }
+ length = math.Round(length)
+ if length <= 0 {
+ return ""
+ }
+ if length > float64(len(m)) {
+ length = float64(len(m))
+ }
+ if start < 0 {
+ length = length - math.Abs(start)
+ if length <= 1 {
+ return ""
+ }
+ return m[:int(length-1)]
+ }
+ if start == 0 {
+ return m[:int(length-1)]
+ }
+ return m[int(start-1):int(length+start-1)]
+ }
+}
+
+// substringIndFunc is XPath functions substring-before/substring-after function returns a part of a given string.
+func substringIndFunc(arg1, arg2 query, after bool) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var str string
+ switch v := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ str = v
+ case query:
+ node := v.Select(t)
+ if node == nil {
+ return ""
+ }
+ str = node.Value()
+ }
+ var word string
+ switch v := functionArgs(arg2).Evaluate(t).(type) {
+ case string:
+ word = v
+ case query:
+ node := v.Select(t)
+ if node == nil {
+ return ""
+ }
+ word = node.Value()
+ }
+ if word == "" {
+ return ""
+ }
+
+ i := strings.Index(str, word)
+ if i < 0 {
+ return ""
+ }
+ if after {
+ return str[i+len(word):]
+ }
+ return str[:i]
+ }
+}
+
+// stringLengthFunc is XPATH string-length( [string] ) function that returns a number
+// equal to the number of characters in a given string.
+func stringLengthFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ switch v := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ return float64(len(v))
+ case query:
+ node := v.Select(t)
+ if node == nil {
+ break
+ }
+ return float64(len(node.Value()))
+ }
+ return float64(0)
+ }
+}
+
+// translateFunc is XPath functions translate() function returns a replaced string.
+func translateFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ str := asString(t, functionArgs(arg1).Evaluate(t))
+ src := asString(t, functionArgs(arg2).Evaluate(t))
+ dst := asString(t, functionArgs(arg3).Evaluate(t))
+
+ replace := make([]string, 0, len(src))
+ for i, s := range src {
+ d := ""
+ if i < len(dst) {
+ d = string(dst[i])
+ }
+ replace = append(replace, string(s), d)
+ }
+ return strings.NewReplacer(replace...).Replace(str)
+ }
+}
+
+// replaceFunc is XPath functions replace() function returns a replaced string.
+func replaceFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ str := asString(t, functionArgs(arg1).Evaluate(t))
+ src := asString(t, functionArgs(arg2).Evaluate(t))
+ dst := asString(t, functionArgs(arg3).Evaluate(t))
+ e, err := getRegexp(src)
+ if err != nil {
+ panic(fmt.Errorf("replace() function second argument is not a valid regexp pattern, err: %s", err.Error()))
+ }
+
+ // replace all $i to ${i} for golang regexp.Expand
+ for idx := e.NumSubexp(); idx > 0; idx-- {
+ dst = strings.ReplaceAll(dst, fmt.Sprintf("$%d", idx), fmt.Sprintf("${%d}", idx))
+ }
+
+ return e.ReplaceAllString(str, dst)
+ }
+}
+
+// notFunc is XPATH functions not(expression) function operation.
+func notFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ switch v := functionArgs(arg1).Evaluate(t).(type) {
+ case bool:
+ return !v
+ case query:
+ node := v.Select(t)
+ return node == nil
+ default:
+ return false
+ }
+ }
+}
+
+// concatFunc is the concat function concatenates two or more
+// strings and returns the resulting string.
+// concat( string1 , string2 [, stringn]* )
+func concatFunc(args ...query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ b := builderPool.Get().(stringBuilder)
+ for _, v := range args {
+ v = functionArgs(v)
+
+ switch v := v.Evaluate(t).(type) {
+ case string:
+ b.WriteString(v)
+ case query:
+ node := v.Select(t)
+ if node != nil {
+ b.WriteString(node.Value())
+ }
+ }
+ }
+ result := b.String()
+ b.Reset()
+ builderPool.Put(b)
+
+ return result
+ }
+}
+
+// https://github.com/antchfx/xpath/issues/43
+func functionArgs(q query) query {
+ if _, ok := q.(*functionQuery); ok {
+ return q
+ }
+ return q.Clone()
+}
+
+func reverseFunc(q query, t iterator) func() NodeNavigator {
+ var list []NodeNavigator
+ for {
+ node := q.Select(t)
+ if node == nil {
+ break
+ }
+ list = append(list, node.Copy())
+ }
+ i := len(list)
+ return func() NodeNavigator {
+ if i <= 0 {
+ return nil
+ }
+ i--
+ node := list[i]
+ return node
+ }
+}
+
+// string-join is a XPath Node Set functions string-join(node-set, separator).
+func stringJoinFunc(q, arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ var separator string
+ switch v := functionArgs(arg1).Evaluate(t).(type) {
+ case string:
+ separator = v
+ case query:
+ node := v.Select(t)
+ if node != nil {
+ separator = node.Value()
+ }
+ }
+
+ q = functionArgs(q)
+ test := predicate(q)
+ var parts []string
+ switch v := q.Evaluate(t).(type) {
+ case string:
+ return v
+ case query:
+ for node := v.Select(t); node != nil; node = v.Select(t) {
+ if test(node) {
+ parts = append(parts, node.Value())
+ }
+ }
+ }
+ return strings.Join(parts, separator)
+ }
+}
+
+// lower-case is XPATH function that converts a string to lower case.
+func lowerCaseFunc(arg1 query) func(query, iterator) interface{} {
+ return func(_ query, t iterator) interface{} {
+ v := functionArgs(arg1).Evaluate(t)
+ return strings.ToLower(asString(t, v))
+ }
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go
new file mode 100644
index 000000000000..d6ca45139311
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go
@@ -0,0 +1,16 @@
+// +build go1.10
+
+package xpath
+
+import (
+ "math"
+ "strings"
+)
+
+func round(f float64) int {
+ return int(math.Round(f))
+}
+
+func newStringBuilder() stringBuilder {
+ return &strings.Builder{}
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go
new file mode 100644
index 000000000000..335141f79f51
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go
@@ -0,0 +1,22 @@
+// +build !go1.10
+
+package xpath
+
+import (
+ "bytes"
+ "math"
+)
+
+// math.Round() is supported by Go 1.10+,
+// This method just compatible for version <1.10.
+// https://github.com/golang/go/issues/20100
+func round(f float64) int {
+ if math.Abs(f) < 0.5 {
+ return 0
+ }
+ return int(f + math.Copysign(0.5, f))
+}
+
+func newStringBuilder() stringBuilder {
+ return &bytes.Buffer{}
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go
new file mode 100644
index 000000000000..2820152b3696
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go
@@ -0,0 +1,288 @@
+package xpath
+
+import (
+ "strconv"
+)
+
+// The XPath number operator function list.
+
+type logical func(iterator, string, interface{}, interface{}) bool
+
+var logicalFuncs = [][]logical{
+ {cmpBooleanBoolean, nil, nil, nil},
+ {nil, cmpNumericNumeric, cmpNumericString, cmpNumericNodeSet},
+ {nil, cmpStringNumeric, cmpStringString, cmpStringNodeSet},
+ {nil, cmpNodeSetNumeric, cmpNodeSetString, cmpNodeSetNodeSet},
+}
+
+// number vs number
+func cmpNumberNumberF(op string, a, b float64) bool {
+ switch op {
+ case "=":
+ return a == b
+ case ">":
+ return a > b
+ case "<":
+ return a < b
+ case ">=":
+ return a >= b
+ case "<=":
+ return a <= b
+ case "!=":
+ return a != b
+ }
+ return false
+}
+
+// string vs string
+func cmpStringStringF(op string, a, b string) bool {
+ switch op {
+ case "=":
+ return a == b
+ case ">":
+ return a > b
+ case "<":
+ return a < b
+ case ">=":
+ return a >= b
+ case "<=":
+ return a <= b
+ case "!=":
+ return a != b
+ }
+ return false
+}
+
+func cmpBooleanBooleanF(op string, a, b bool) bool {
+ switch op {
+ case "or":
+ return a || b
+ case "and":
+ return a && b
+ }
+ return false
+}
+
+func cmpNumericNumeric(t iterator, op string, m, n interface{}) bool {
+ a := m.(float64)
+ b := n.(float64)
+ return cmpNumberNumberF(op, a, b)
+}
+
+func cmpNumericString(t iterator, op string, m, n interface{}) bool {
+ a := m.(float64)
+ b := n.(string)
+ num, err := strconv.ParseFloat(b, 64)
+ if err != nil {
+ panic(err)
+ }
+ return cmpNumberNumberF(op, a, num)
+}
+
+func cmpNumericNodeSet(t iterator, op string, m, n interface{}) bool {
+ a := m.(float64)
+ b := n.(query)
+
+ for {
+ node := b.Select(t)
+ if node == nil {
+ break
+ }
+ num, err := strconv.ParseFloat(node.Value(), 64)
+ if err != nil {
+ panic(err)
+ }
+ if cmpNumberNumberF(op, a, num) {
+ return true
+ }
+ }
+ return false
+}
+
+func cmpNodeSetNumeric(t iterator, op string, m, n interface{}) bool {
+ a := m.(query)
+ b := n.(float64)
+ for {
+ node := a.Select(t)
+ if node == nil {
+ break
+ }
+ num, err := strconv.ParseFloat(node.Value(), 64)
+ if err != nil {
+ panic(err)
+ }
+ if cmpNumberNumberF(op, num, b) {
+ return true
+ }
+ }
+ return false
+}
+
+func cmpNodeSetString(t iterator, op string, m, n interface{}) bool {
+ a := m.(query)
+ b := n.(string)
+ for {
+ node := a.Select(t)
+ if node == nil {
+ break
+ }
+ if cmpStringStringF(op, b, node.Value()) {
+ return true
+ }
+ }
+ return false
+}
+
+func cmpNodeSetNodeSet(t iterator, op string, m, n interface{}) bool {
+ a := m.(query)
+ b := n.(query)
+ for {
+ x := a.Select(t)
+ if x == nil {
+ return false
+ }
+
+ y := b.Select(t)
+ if y == nil {
+ return false
+ }
+
+ for {
+ if cmpStringStringF(op, x.Value(), y.Value()) {
+ return true
+ }
+ if y = b.Select(t); y == nil {
+ break
+ }
+ }
+ // reset
+ b.Evaluate(t)
+ }
+}
+
+func cmpStringNumeric(t iterator, op string, m, n interface{}) bool {
+ a := m.(string)
+ b := n.(float64)
+ num, err := strconv.ParseFloat(a, 64)
+ if err != nil {
+ panic(err)
+ }
+ return cmpNumberNumberF(op, b, num)
+}
+
+func cmpStringString(t iterator, op string, m, n interface{}) bool {
+ a := m.(string)
+ b := n.(string)
+ return cmpStringStringF(op, a, b)
+}
+
+func cmpStringNodeSet(t iterator, op string, m, n interface{}) bool {
+ a := m.(string)
+ b := n.(query)
+ for {
+ node := b.Select(t)
+ if node == nil {
+ break
+ }
+ if cmpStringStringF(op, a, node.Value()) {
+ return true
+ }
+ }
+ return false
+}
+
+func cmpBooleanBoolean(t iterator, op string, m, n interface{}) bool {
+ a := m.(bool)
+ b := n.(bool)
+ return cmpBooleanBooleanF(op, a, b)
+}
+
+// eqFunc is an `=` operator.
+func eqFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, "=", m, n)
+}
+
+// gtFunc is an `>` operator.
+func gtFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, ">", m, n)
+}
+
+// geFunc is an `>=` operator.
+func geFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, ">=", m, n)
+}
+
+// ltFunc is an `<` operator.
+func ltFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, "<", m, n)
+}
+
+// leFunc is an `<=` operator.
+func leFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, "<=", m, n)
+}
+
+// neFunc is an `!=` operator.
+func neFunc(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, "!=", m, n)
+}
+
+// orFunc is an `or` operator.
+var orFunc = func(t iterator, m, n interface{}) interface{} {
+ t1 := getXPathType(m)
+ t2 := getXPathType(n)
+ return logicalFuncs[t1][t2](t, "or", m, n)
+}
+
+func numericExpr(t iterator, m, n interface{}, cb func(float64, float64) float64) float64 {
+ a := asNumber(t, m)
+ b := asNumber(t, n)
+ return cb(a, b)
+}
+
+// plusFunc is an `+` operator.
+var plusFunc = func(t iterator, m, n interface{}) interface{} {
+ return numericExpr(t, m, n, func(a, b float64) float64 {
+ return a + b
+ })
+}
+
+// minusFunc is an `-` operator.
+var minusFunc = func(t iterator, m, n interface{}) interface{} {
+ return numericExpr(t, m, n, func(a, b float64) float64 {
+ return a - b
+ })
+}
+
+// mulFunc is an `*` operator.
+var mulFunc = func(t iterator, m, n interface{}) interface{} {
+ return numericExpr(t, m, n, func(a, b float64) float64 {
+ return a * b
+ })
+}
+
+// divFunc is an `DIV` operator.
+var divFunc = func(t iterator, m, n interface{}) interface{} {
+ return numericExpr(t, m, n, func(a, b float64) float64 {
+ return a / b
+ })
+}
+
+// modFunc is an 'MOD' operator.
+var modFunc = func(t iterator, m, n interface{}) interface{} {
+ return numericExpr(t, m, n, func(a, b float64) float64 {
+ return float64(int(a) % int(b))
+ })
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go
new file mode 100644
index 000000000000..539312591152
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go
@@ -0,0 +1,1254 @@
+package xpath
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "strconv"
+ "unicode"
+ "unicode/utf8"
+)
+
+// A XPath expression token type.
+type itemType int
+
+const (
+ itemComma itemType = iota // ','
+ itemSlash // '/'
+ itemAt // '@'
+ itemDot // '.'
+ itemLParens // '('
+ itemRParens // ')'
+ itemLBracket // '['
+ itemRBracket // ']'
+ itemStar // '*'
+ itemPlus // '+'
+ itemMinus // '-'
+ itemEq // '='
+ itemLt // '<'
+ itemGt // '>'
+ itemBang // '!'
+ itemDollar // '$'
+ itemApos // '\''
+ itemQuote // '"'
+ itemUnion // '|'
+ itemNe // '!='
+ itemLe // '<='
+ itemGe // '>='
+ itemAnd // '&&'
+ itemOr // '||'
+ itemDotDot // '..'
+ itemSlashSlash // '//'
+ itemName // XML Name
+ itemString // Quoted string constant
+ itemNumber // Number constant
+ itemAxe // Axe (like child::)
+ itemEOF // END
+)
+
+// A node is an XPath node in the parse tree.
+type node interface {
+ Type() nodeType
+}
+
+// nodeType identifies the type of a parse tree node.
+type nodeType int
+
+func (t nodeType) Type() nodeType {
+ return t
+}
+
+const (
+ nodeRoot nodeType = iota
+ nodeAxis
+ nodeFilter
+ nodeFunction
+ nodeOperator
+ nodeVariable
+ nodeConstantOperand
+ nodeGroup
+)
+
+type parser struct {
+ r *scanner
+ d int
+ namespaces map[string]string
+}
+
+// newOperatorNode returns new operator node OperatorNode.
+func newOperatorNode(op string, left, right node) node {
+ return &operatorNode{nodeType: nodeOperator, Op: op, Left: left, Right: right}
+}
+
+// newOperand returns new constant operand node OperandNode.
+func newOperandNode(v interface{}) node {
+ return &operandNode{nodeType: nodeConstantOperand, Val: v}
+}
+
+// newAxisNode returns new axis node AxisNode.
+func newAxisNode(axisType string, typeTest NodeType, localName, prefix, prop string, n node, opts ...func(p *axisNode)) node {
+ a := axisNode{
+ nodeType: nodeAxis,
+ typeTest: typeTest,
+ LocalName: localName,
+ Prefix: prefix,
+ AxisType: axisType,
+ Prop: prop,
+ Input: n,
+ }
+ for _, o := range opts {
+ o(&a)
+ }
+ return &a
+}
+
+// newVariableNode returns new variable node VariableNode.
+func newVariableNode(prefix, name string) node {
+ return &variableNode{nodeType: nodeVariable, Name: name, Prefix: prefix}
+}
+
+// newFilterNode returns a new filter node FilterNode.
+func newFilterNode(n, m node) node {
+ return &filterNode{nodeType: nodeFilter, Input: n, Condition: m}
+}
+
+func newGroupNode(n node) node {
+ return &groupNode{nodeType: nodeGroup, Input: n}
+}
+
+// newRootNode returns a root node.
+func newRootNode(s string) node {
+ return &rootNode{nodeType: nodeRoot, slash: s}
+}
+
+// newFunctionNode returns function call node.
+func newFunctionNode(name, prefix string, args []node) node {
+ return &functionNode{nodeType: nodeFunction, Prefix: prefix, FuncName: name, Args: args}
+}
+
+// testOp reports whether current item name is an operand op.
+func testOp(r *scanner, op string) bool {
+ return r.typ == itemName && r.prefix == "" && r.name == op
+}
+
+func isPrimaryExpr(r *scanner) bool {
+ switch r.typ {
+ case itemString, itemNumber, itemDollar, itemLParens:
+ return true
+ case itemName:
+ return r.canBeFunc && !isNodeType(r)
+ }
+ return false
+}
+
+func isNodeType(r *scanner) bool {
+ switch r.name {
+ case "node", "text", "processing-instruction", "comment":
+ return r.prefix == ""
+ }
+ return false
+}
+
+func isStep(item itemType) bool {
+ switch item {
+ case itemDot, itemDotDot, itemAt, itemAxe, itemStar, itemName:
+ return true
+ }
+ return false
+}
+
+func checkItem(r *scanner, typ itemType) {
+ if r.typ != typ {
+ panic(fmt.Sprintf("%s has an invalid token", r.text))
+ }
+}
+
+// parseExpression parsing the expression with input node n.
+func (p *parser) parseExpression(n node) node {
+ if p.d = p.d + 1; p.d > 200 {
+ panic("the xpath query is too complex(depth > 200)")
+ }
+ n = p.parseOrExpr(n)
+ p.d--
+ return n
+}
+
+// next scanning next item on forward.
+func (p *parser) next() bool {
+ return p.r.nextItem()
+}
+
+func (p *parser) skipItem(typ itemType) {
+ checkItem(p.r, typ)
+ p.next()
+}
+
+// OrExpr ::= AndExpr | OrExpr 'or' AndExpr
+func (p *parser) parseOrExpr(n node) node {
+ opnd := p.parseAndExpr(n)
+ for {
+ if !testOp(p.r, "or") {
+ break
+ }
+ p.next()
+ opnd = newOperatorNode("or", opnd, p.parseAndExpr(n))
+ }
+ return opnd
+}
+
+// AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
+func (p *parser) parseAndExpr(n node) node {
+ opnd := p.parseEqualityExpr(n)
+ for {
+ if !testOp(p.r, "and") {
+ break
+ }
+ p.next()
+ opnd = newOperatorNode("and", opnd, p.parseEqualityExpr(n))
+ }
+ return opnd
+}
+
+// EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr | EqualityExpr '!=' RelationalExpr
+func (p *parser) parseEqualityExpr(n node) node {
+ opnd := p.parseRelationalExpr(n)
+Loop:
+ for {
+ var op string
+ switch p.r.typ {
+ case itemEq:
+ op = "="
+ case itemNe:
+ op = "!="
+ default:
+ break Loop
+ }
+ p.next()
+ opnd = newOperatorNode(op, opnd, p.parseRelationalExpr(n))
+ }
+ return opnd
+}
+
+// RelationalExpr ::= AdditiveExpr | RelationalExpr '<' AdditiveExpr | RelationalExpr '>' AdditiveExpr
+//
+// | RelationalExpr '<=' AdditiveExpr
+// | RelationalExpr '>=' AdditiveExpr
+func (p *parser) parseRelationalExpr(n node) node {
+ opnd := p.parseAdditiveExpr(n)
+Loop:
+ for {
+ var op string
+ switch p.r.typ {
+ case itemLt:
+ op = "<"
+ case itemGt:
+ op = ">"
+ case itemLe:
+ op = "<="
+ case itemGe:
+ op = ">="
+ default:
+ break Loop
+ }
+ p.next()
+ opnd = newOperatorNode(op, opnd, p.parseAdditiveExpr(n))
+ }
+ return opnd
+}
+
+// AdditiveExpr ::= MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr | AdditiveExpr '-' MultiplicativeExpr
+func (p *parser) parseAdditiveExpr(n node) node {
+ opnd := p.parseMultiplicativeExpr(n)
+Loop:
+ for {
+ var op string
+ switch p.r.typ {
+ case itemPlus:
+ op = "+"
+ case itemMinus:
+ op = "-"
+ default:
+ break Loop
+ }
+ p.next()
+ opnd = newOperatorNode(op, opnd, p.parseMultiplicativeExpr(n))
+ }
+ return opnd
+}
+
+// MultiplicativeExpr ::= UnaryExpr | MultiplicativeExpr MultiplyOperator(*) UnaryExpr
+//
+// | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr
+func (p *parser) parseMultiplicativeExpr(n node) node {
+ opnd := p.parseUnaryExpr(n)
+Loop:
+ for {
+ var op string
+ if p.r.typ == itemStar {
+ op = "*"
+ } else if testOp(p.r, "div") || testOp(p.r, "mod") {
+ op = p.r.name
+ } else {
+ break Loop
+ }
+ p.next()
+ opnd = newOperatorNode(op, opnd, p.parseUnaryExpr(n))
+ }
+ return opnd
+}
+
+// UnaryExpr ::= UnionExpr | '-' UnaryExpr
+func (p *parser) parseUnaryExpr(n node) node {
+ minus := false
+ // ignore '-' sequence
+ for p.r.typ == itemMinus {
+ p.next()
+ minus = !minus
+ }
+ opnd := p.parseUnionExpr(n)
+ if minus {
+ opnd = newOperatorNode("*", opnd, newOperandNode(float64(-1)))
+ }
+ return opnd
+}
+
+// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
+func (p *parser) parseUnionExpr(n node) node {
+ opnd := p.parsePathExpr(n)
+Loop:
+ for {
+ if p.r.typ != itemUnion {
+ break Loop
+ }
+ p.next()
+ opnd2 := p.parsePathExpr(n)
+ // Checking the node type that must be is node set type?
+ opnd = newOperatorNode("|", opnd, opnd2)
+ }
+ return opnd
+}
+
+// PathExpr ::= LocationPath | FilterExpr | FilterExpr '/' RelativeLocationPath | FilterExpr '//' RelativeLocationPath
+func (p *parser) parsePathExpr(n node) node {
+ var opnd node
+ if isPrimaryExpr(p.r) {
+ opnd = p.parseFilterExpr(n)
+ switch p.r.typ {
+ case itemSlash:
+ p.next()
+ opnd = p.parseRelativeLocationPath(opnd)
+ case itemSlashSlash:
+ p.next()
+ opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", allNode, "", "", "", opnd))
+ }
+ } else {
+ opnd = p.parseLocationPath(nil)
+ }
+ return opnd
+}
+
+// FilterExpr ::= PrimaryExpr | FilterExpr Predicate
+func (p *parser) parseFilterExpr(n node) node {
+ opnd := p.parsePrimaryExpr(n)
+ if p.r.typ == itemLBracket {
+ opnd = newFilterNode(opnd, p.parsePredicate(opnd))
+ }
+ return opnd
+}
+
+// Predicate ::= '[' PredicateExpr ']'
+func (p *parser) parsePredicate(n node) node {
+ p.skipItem(itemLBracket)
+ opnd := p.parseExpression(n)
+ p.skipItem(itemRBracket)
+ return opnd
+}
+
+// LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
+func (p *parser) parseLocationPath(n node) (opnd node) {
+ switch p.r.typ {
+ case itemSlash:
+ p.next()
+ opnd = newRootNode("/")
+ if isStep(p.r.typ) {
+ opnd = p.parseRelativeLocationPath(opnd) // ?? child:: or self ??
+ }
+ case itemSlashSlash:
+ p.next()
+ opnd = newRootNode("//")
+ opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", allNode, "", "", "", opnd))
+ default:
+ opnd = p.parseRelativeLocationPath(n)
+ }
+ return opnd
+}
+
+// RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | AbbreviatedRelativeLocationPath
+func (p *parser) parseRelativeLocationPath(n node) node {
+ opnd := n
+Loop:
+ for {
+ opnd = p.parseStep(opnd)
+ switch p.r.typ {
+ case itemSlashSlash:
+ p.next()
+ opnd = newAxisNode("descendant-or-self", allNode, "", "", "", opnd)
+ case itemSlash:
+ p.next()
+ default:
+ break Loop
+ }
+ }
+ return opnd
+}
+
+// Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
+func (p *parser) parseStep(n node) (opnd node) {
+ if p.r.typ == itemDot || p.r.typ == itemDotDot {
+ if p.r.typ == itemDot {
+ opnd = newAxisNode("self", allNode, "", "", "", n)
+ } else {
+ opnd = newAxisNode("parent", allNode, "", "", "", n)
+ }
+ p.next()
+ if p.r.typ != itemLBracket {
+ return opnd
+ }
+ } else {
+ axisType := "child" // default axes value.
+ switch p.r.typ {
+ case itemAt:
+ axisType = "attribute"
+ p.next()
+ case itemAxe:
+ axisType = p.r.name
+ p.next()
+ case itemLParens:
+ return p.parseSequence(n)
+ }
+ matchType := ElementNode
+ if axisType == "attribute" {
+ matchType = AttributeNode
+ }
+ opnd = p.parseNodeTest(n, axisType, matchType)
+ }
+ for p.r.typ == itemLBracket {
+ opnd = newFilterNode(opnd, p.parsePredicate(opnd))
+ }
+ return opnd
+}
+
+// Expr ::= '(' Step ("," Step)* ')'
+func (p *parser) parseSequence(n node) (opnd node) {
+ p.skipItem(itemLParens)
+ opnd = p.parseStep(n)
+ for {
+ if p.r.typ != itemComma {
+ break
+ }
+ p.next()
+ opnd2 := p.parseStep(n)
+ opnd = newOperatorNode("|", opnd, opnd2)
+ }
+ p.skipItem(itemRParens)
+ return opnd
+}
+
+// NodeTest ::= NameTest | nodeType '(' ')' | 'processing-instruction' '(' Literal ')'
+func (p *parser) parseNodeTest(n node, axeTyp string, matchType NodeType) (opnd node) {
+ switch p.r.typ {
+ case itemName:
+ if p.r.canBeFunc && isNodeType(p.r) {
+ var prop string
+ switch p.r.name {
+ case "comment", "text", "processing-instruction", "node":
+ prop = p.r.name
+ }
+ var name string
+ p.next()
+ p.skipItem(itemLParens)
+ if prop == "processing-instruction" && p.r.typ != itemRParens {
+ checkItem(p.r, itemString)
+ name = p.r.strval
+ p.next()
+ }
+ p.skipItem(itemRParens)
+ switch prop {
+ case "comment":
+ matchType = CommentNode
+ case "text":
+ matchType = TextNode
+ case "processing-instruction":
+ case "node":
+ matchType = allNode
+ default:
+ matchType = RootNode
+ }
+
+ opnd = newAxisNode(axeTyp, matchType, name, "", prop, n)
+ } else {
+ prefix := p.r.prefix
+ name := p.r.name
+ p.next()
+ if p.r.name == "*" {
+ name = ""
+ }
+ opnd = newAxisNode(axeTyp, matchType, name, prefix, "", n, func(a *axisNode) {
+ if prefix != "" && p.namespaces != nil {
+ if ns, ok := p.namespaces[prefix]; ok {
+ a.hasNamespaceURI = true
+ a.namespaceURI = ns
+ } else {
+ panic(fmt.Sprintf("prefix %s not defined.", prefix))
+ }
+ }
+ })
+ }
+ case itemStar:
+ opnd = newAxisNode(axeTyp, matchType, "", "", "", n)
+ p.next()
+ default:
+ panic("expression must evaluate to a node-set")
+ }
+ return opnd
+}
+
+// PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
+func (p *parser) parsePrimaryExpr(n node) (opnd node) {
+ switch p.r.typ {
+ case itemString:
+ opnd = newOperandNode(p.r.strval)
+ p.next()
+ case itemNumber:
+ opnd = newOperandNode(p.r.numval)
+ p.next()
+ case itemDollar:
+ p.next()
+ checkItem(p.r, itemName)
+ opnd = newVariableNode(p.r.prefix, p.r.name)
+ p.next()
+ case itemLParens:
+ p.next()
+ opnd = p.parseExpression(n)
+ if opnd.Type() != nodeConstantOperand {
+ opnd = newGroupNode(opnd)
+ }
+ p.skipItem(itemRParens)
+ case itemName:
+ if p.r.canBeFunc && !isNodeType(p.r) {
+ opnd = p.parseMethod(nil)
+ }
+ }
+ return opnd
+}
+
+// FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
+func (p *parser) parseMethod(n node) node {
+ var args []node
+ name := p.r.name
+ prefix := p.r.prefix
+
+ p.skipItem(itemName)
+ p.skipItem(itemLParens)
+ if p.r.typ != itemRParens {
+ for {
+ args = append(args, p.parseExpression(n))
+ if p.r.typ == itemRParens {
+ break
+ }
+ p.skipItem(itemComma)
+ }
+ }
+ p.skipItem(itemRParens)
+ return newFunctionNode(name, prefix, args)
+}
+
+// Parse parsing the XPath express string expr and returns a tree node.
+func parse(expr string, namespaces map[string]string) node {
+ r := &scanner{text: expr}
+ r.nextChar()
+ r.nextItem()
+ p := &parser{r: r, namespaces: namespaces}
+ return p.parseExpression(nil)
+}
+
+// rootNode holds a top-level node of tree.
+type rootNode struct {
+ nodeType
+ slash string
+}
+
+func (r *rootNode) String() string {
+ return r.slash
+}
+
+// operatorNode holds two Nodes operator.
+type operatorNode struct {
+ nodeType
+ Op string
+ Left, Right node
+}
+
+func (o *operatorNode) String() string {
+ return fmt.Sprintf("%v%s%v", o.Left, o.Op, o.Right)
+}
+
+// axisNode holds a location step.
+type axisNode struct {
+ nodeType
+ Input node
+ Prop string // node-test name.[comment|text|processing-instruction|node]
+ AxisType string // name of the axis.[attribute|ancestor|child|....]
+ LocalName string // local part name of node.
+ Prefix string // prefix name of node.
+ namespaceURI string // namespace URI of node
+ hasNamespaceURI bool // if namespace URI is set (can be "")
+ typeTest NodeType
+}
+
+func (a *axisNode) String() string {
+ var b bytes.Buffer
+ if a.AxisType != "" {
+ b.Write([]byte(a.AxisType + "::"))
+ }
+ if a.Prefix != "" {
+ b.Write([]byte(a.Prefix + ":"))
+ }
+ b.Write([]byte(a.LocalName))
+ if a.Prop != "" {
+ b.Write([]byte("/" + a.Prop + "()"))
+ }
+ return b.String()
+}
+
+// operandNode holds a constant operand.
+type operandNode struct {
+ nodeType
+ Val interface{}
+}
+
+func (o *operandNode) String() string {
+ return fmt.Sprintf("%v", o.Val)
+}
+
+// groupNode holds a set of node expression
+type groupNode struct {
+ nodeType
+ Input node
+}
+
+func (g *groupNode) String() string {
+ return fmt.Sprintf("%s", g.Input)
+}
+
+// filterNode holds a condition filter.
+type filterNode struct {
+ nodeType
+ Input, Condition node
+}
+
+func (f *filterNode) String() string {
+ return fmt.Sprintf("%s[%s]", f.Input, f.Condition)
+}
+
+// variableNode holds a variable.
+type variableNode struct {
+ nodeType
+ Name, Prefix string
+}
+
+func (v *variableNode) String() string {
+ if v.Prefix == "" {
+ return v.Name
+ }
+ return fmt.Sprintf("%s:%s", v.Prefix, v.Name)
+}
+
+// functionNode holds a function call.
+type functionNode struct {
+ nodeType
+ Args []node
+ Prefix string
+ FuncName string // function name
+}
+
+func (f *functionNode) String() string {
+ var b bytes.Buffer
+ // fun(arg1, ..., argn)
+ b.Write([]byte(f.FuncName))
+ b.Write([]byte("("))
+ for i, arg := range f.Args {
+ if i > 0 {
+ b.Write([]byte(","))
+ }
+ b.Write([]byte(fmt.Sprintf("%s", arg)))
+ }
+ b.Write([]byte(")"))
+ return b.String()
+}
+
+type scanner struct {
+ text, name, prefix string
+
+ pos int
+ curr rune
+ currSize int
+ typ itemType
+ strval string // text value at current pos
+ numval float64 // number value at current pos
+ canBeFunc bool
+}
+
+func (s *scanner) nextChar() bool {
+ if s.pos >= len(s.text) {
+ s.curr = rune(0)
+ s.currSize = 1
+ return false
+ }
+
+ r, size := rune(s.text[s.pos]), 1
+ if r >= 0x80 { // handle multi-byte runes
+ r, size = utf8.DecodeRuneInString(s.text[s.pos:])
+ }
+
+ s.curr = r
+ s.currSize = size
+ s.pos += size
+ return true
+}
+
+func (s *scanner) nextItem() bool {
+ s.skipSpace()
+ switch s.curr {
+ case 0:
+ s.typ = itemEOF
+ return false
+ case ',', '@', '(', ')', '|', '*', '[', ']', '+', '-', '=', '#', '$':
+ s.typ = asItemType(s.curr)
+ s.nextChar()
+ case '<':
+ s.typ = itemLt
+ s.nextChar()
+ if s.curr == '=' {
+ s.typ = itemLe
+ s.nextChar()
+ }
+ case '>':
+ s.typ = itemGt
+ s.nextChar()
+ if s.curr == '=' {
+ s.typ = itemGe
+ s.nextChar()
+ }
+ case '!':
+ s.typ = itemBang
+ s.nextChar()
+ if s.curr == '=' {
+ s.typ = itemNe
+ s.nextChar()
+ }
+ case '.':
+ s.typ = itemDot
+ s.nextChar()
+ if s.curr == '.' {
+ s.typ = itemDotDot
+ s.nextChar()
+ } else if isDigit(s.curr) {
+ s.typ = itemNumber
+ s.numval = s.scanFraction()
+ }
+ case '/':
+ s.typ = itemSlash
+ s.nextChar()
+ if s.curr == '/' {
+ s.typ = itemSlashSlash
+ s.nextChar()
+ }
+ case '"', '\'':
+ s.typ = itemString
+ s.strval = s.scanString()
+ default:
+ if isDigit(s.curr) {
+ s.typ = itemNumber
+ s.numval = s.scanNumber()
+ } else if isName(s.curr) {
+ s.typ = itemName
+ s.name = s.scanName()
+ s.prefix = ""
+ // "foo:bar" is one itemem not three because it doesn't allow spaces in between
+ // We should distinct it from "foo::" and need process "foo ::" as well
+ if s.curr == ':' {
+ s.nextChar()
+ // can be "foo:bar" or "foo::"
+ if s.curr == ':' {
+ // "foo::"
+ s.nextChar()
+ s.typ = itemAxe
+ } else { // "foo:*", "foo:bar" or "foo: "
+ s.prefix = s.name
+ if s.curr == '*' {
+ s.nextChar()
+ s.name = "*"
+ } else if isName(s.curr) {
+ s.name = s.scanName()
+ } else {
+ panic(fmt.Sprintf("%s has an invalid qualified name.", s.text))
+ }
+ }
+ } else {
+ s.skipSpace()
+ if s.curr == ':' {
+ s.nextChar()
+ // it can be "foo ::" or just "foo :"
+ if s.curr == ':' {
+ s.nextChar()
+ s.typ = itemAxe
+ } else {
+ panic(fmt.Sprintf("%s has an invalid qualified name.", s.text))
+ }
+ }
+ }
+ s.skipSpace()
+ s.canBeFunc = s.curr == '('
+ } else {
+ panic(fmt.Sprintf("%s has an invalid token.", s.text))
+ }
+ }
+ return true
+}
+
+func (s *scanner) skipSpace() {
+Loop:
+ for {
+ if !unicode.IsSpace(s.curr) || !s.nextChar() {
+ break Loop
+ }
+ }
+}
+
+func (s *scanner) scanFraction() float64 {
+ var (
+ i = s.pos - 2
+ c = 1 // '.'
+ )
+ for isDigit(s.curr) {
+ s.nextChar()
+ c++
+ }
+ v, err := strconv.ParseFloat(s.text[i:i+c], 64)
+ if err != nil {
+ panic(fmt.Errorf("xpath: scanFraction parse float got error: %v", err))
+ }
+ return v
+}
+
+func (s *scanner) scanNumber() float64 {
+ var (
+ c int
+ i = s.pos - 1
+ )
+ for isDigit(s.curr) {
+ s.nextChar()
+ c++
+ }
+ if s.curr == '.' {
+ s.nextChar()
+ c++
+ for isDigit(s.curr) {
+ s.nextChar()
+ c++
+ }
+ }
+ v, err := strconv.ParseFloat(s.text[i:i+c], 64)
+ if err != nil {
+ panic(fmt.Errorf("xpath: scanNumber parse float got error: %v", err))
+ }
+ return v
+}
+
+func (s *scanner) scanString() string {
+ var (
+ end = s.curr
+ )
+ s.nextChar()
+ i := s.pos - s.currSize
+ c := s.currSize
+ for s.curr != end {
+ if !s.nextChar() {
+ panic(errors.New("xpath: scanString got unclosed string"))
+ }
+ c += s.currSize
+ }
+ c -= 1
+ s.nextChar()
+ return s.text[i : i+c]
+}
+
+func (s *scanner) scanName() string {
+ var (
+ c = s.currSize - 1
+ i = s.pos - s.currSize
+ )
+
+ // Detect current rune size
+
+ for isName(s.curr) {
+ if !s.nextChar() {
+ c += s.currSize
+ break
+ }
+ c += s.currSize
+ }
+ return s.text[i : i+c]
+}
+
+func isName(r rune) bool {
+ return string(r) != ":" && string(r) != "/" &&
+ (unicode.Is(first, r) || unicode.Is(second, r) || string(r) == "*")
+}
+
+func isDigit(r rune) bool {
+ return unicode.IsDigit(r)
+}
+
+func asItemType(r rune) itemType {
+ switch r {
+ case ',':
+ return itemComma
+ case '@':
+ return itemAt
+ case '(':
+ return itemLParens
+ case ')':
+ return itemRParens
+ case '|':
+ return itemUnion
+ case '*':
+ return itemStar
+ case '[':
+ return itemLBracket
+ case ']':
+ return itemRBracket
+ case '+':
+ return itemPlus
+ case '-':
+ return itemMinus
+ case '=':
+ return itemEq
+ case '$':
+ return itemDollar
+ }
+ panic(fmt.Errorf("unknown item: %v", r))
+}
+
+var first = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x003A, 0x003A, 1},
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
+ },
+}
+
+var second = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
+ },
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go
new file mode 100644
index 000000000000..8c5535e18274
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go
@@ -0,0 +1,1451 @@
+package xpath
+
+import (
+ "bytes"
+ "fmt"
+ "hash/fnv"
+ "reflect"
+ "strconv"
+)
+
+// The return type of the XPath expression.
+type resultType int
+
+var xpathResultType = struct {
+ Boolean resultType
+ // A numeric value
+ Number resultType
+ String resultType
+ // A node collection.
+ NodeSet resultType
+ // Any of the XPath node types.
+ Any resultType
+}{
+ Boolean: 0,
+ Number: 1,
+ String: 2,
+ NodeSet: 3,
+ Any: 4,
+}
+
+type queryProp int
+
+var queryProps = struct {
+ None queryProp
+ Position queryProp
+ Count queryProp
+ Cached queryProp
+ Reverse queryProp
+ Merge queryProp
+}{
+ None: 0,
+ Position: 1,
+ Count: 2,
+ Cached: 4,
+ Reverse: 8,
+ Merge: 16,
+}
+
+type iterator interface {
+ Current() NodeNavigator
+}
+
+// An XPath query interface.
+type query interface {
+ // Select traversing iterator returns a query matched node NodeNavigator.
+ Select(iterator) NodeNavigator
+
+ // Evaluate evaluates query and returns values of the current query.
+ Evaluate(iterator) interface{}
+
+ Clone() query
+
+ // ValueType returns the value type of the current query.
+ ValueType() resultType
+
+ Properties() queryProp
+}
+
+// nopQuery is an empty query that always return nil for any query.
+type nopQuery struct{}
+
+func (nopQuery) Select(iterator) NodeNavigator { return nil }
+
+func (nopQuery) Evaluate(iterator) interface{} { return nil }
+
+func (nopQuery) Clone() query { return nopQuery{} }
+
+func (nopQuery) ValueType() resultType { return xpathResultType.NodeSet }
+
+func (nopQuery) Properties() queryProp {
+ return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
+}
+
+// contextQuery is returns current node on the iterator object query.
+type contextQuery struct {
+ count int
+}
+
+func (c *contextQuery) Select(t iterator) NodeNavigator {
+ if c.count > 0 {
+ return nil
+ }
+ c.count++
+ return t.Current().Copy()
+}
+
+func (c *contextQuery) Evaluate(iterator) interface{} {
+ c.count = 0
+ return c
+}
+
+func (c *contextQuery) Clone() query {
+ return &contextQuery{}
+}
+
+func (c *contextQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (c *contextQuery) Properties() queryProp {
+ return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
+}
+
+type absoluteQuery struct {
+ count int
+}
+
+func (a *absoluteQuery) Select(t iterator) (n NodeNavigator) {
+ if a.count > 0 {
+ return
+ }
+ a.count++
+ n = t.Current().Copy()
+ n.MoveToRoot()
+ return
+}
+
+func (a *absoluteQuery) Evaluate(t iterator) interface{} {
+ a.count = 0
+ return a
+}
+
+func (a *absoluteQuery) Clone() query {
+ return &absoluteQuery{}
+}
+
+func (a *absoluteQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (a *absoluteQuery) Properties() queryProp {
+ return queryProps.Merge | queryProps.Position | queryProps.Count | queryProps.Cached
+}
+
+// ancestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*)
+type ancestorQuery struct {
+ name string
+ iterator func() NodeNavigator
+ table map[uint64]bool
+ pos int
+
+ Self bool
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (a *ancestorQuery) Select(t iterator) NodeNavigator {
+ if a.table == nil {
+ a.table = make(map[uint64]bool)
+ }
+
+ for {
+ if a.iterator == nil {
+ node := a.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ // Reset position for a new input context node
+ a.pos = 0
+ first := true
+ node = node.Copy()
+ a.iterator = func() NodeNavigator {
+ if first {
+ first = false
+ if a.Self && a.Predicate(node) {
+ return node
+ }
+ }
+ for node.MoveToParent() {
+ if a.Predicate(node) {
+ return node
+ }
+ }
+ return nil
+ }
+ }
+
+ for node := a.iterator(); node != nil; node = a.iterator() {
+ node_id := getHashCode(node.Copy())
+ if _, ok := a.table[node_id]; !ok {
+ a.table[node_id] = true
+ // Increase position for each matched node in current input context
+ a.pos++
+ return node
+ }
+ }
+ a.iterator = nil
+ }
+}
+
+func (a *ancestorQuery) Evaluate(t iterator) interface{} {
+ a.Input.Evaluate(t)
+ a.iterator = nil
+ // Reset the table when re-evaluating to ensure clean state
+ a.table = nil
+ return a
+}
+
+func (a *ancestorQuery) Test(n NodeNavigator) bool {
+ return a.Predicate(n)
+}
+
+func (a *ancestorQuery) Clone() query {
+ return &ancestorQuery{name: a.name, Self: a.Self, Input: a.Input.Clone(), Predicate: a.Predicate}
+}
+
+func (a *ancestorQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (a *ancestorQuery) Properties() queryProp {
+ return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge | queryProps.Reverse
+}
+
+// position returns the ordinal of the current matched node within the axis
+// traversal for the current input context node. This is required so numeric
+// predicates like [1] or [2] on the ancestor axis resolve in axis order.
+func (a *ancestorQuery) position() int {
+ return a.pos
+}
+
+// attributeQuery is an XPath attribute node query.(@*)
+type attributeQuery struct {
+ name string
+ iterator func() NodeNavigator
+
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (a *attributeQuery) Select(t iterator) NodeNavigator {
+ for {
+ if a.iterator == nil {
+ node := a.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ a.iterator = func() NodeNavigator {
+ for {
+ onAttr := node.MoveToNextAttribute()
+ if !onAttr {
+ return nil
+ }
+ if a.Predicate(node) {
+ return node
+ }
+ }
+ }
+ }
+
+ if node := a.iterator(); node != nil {
+ return node
+ }
+ a.iterator = nil
+ }
+}
+
+func (a *attributeQuery) Evaluate(t iterator) interface{} {
+ a.Input.Evaluate(t)
+ a.iterator = nil
+ return a
+}
+
+func (a *attributeQuery) Test(n NodeNavigator) bool {
+ return a.Predicate(n)
+}
+
+func (a *attributeQuery) Clone() query {
+ return &attributeQuery{name: a.name, Input: a.Input.Clone(), Predicate: a.Predicate}
+}
+
+func (a *attributeQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (a *attributeQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// childQuery is an XPath child node query.(child::*)
+type childQuery struct {
+ name string
+ posit int
+ iterator func() NodeNavigator
+
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (c *childQuery) Select(t iterator) NodeNavigator {
+ for {
+ if c.iterator == nil {
+ c.posit = 0
+ node := c.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ first := true
+ c.iterator = func() NodeNavigator {
+ for {
+ if (first && !node.MoveToChild()) || (!first && !node.MoveToNext()) {
+ return nil
+ }
+ first = false
+ if c.Predicate(node) {
+ return node
+ }
+ }
+ }
+ }
+
+ if node := c.iterator(); node != nil {
+ c.posit++
+ return node
+ }
+ c.iterator = nil
+ }
+}
+
+func (c *childQuery) Evaluate(t iterator) interface{} {
+ c.Input.Evaluate(t)
+ c.iterator = nil
+ return c
+}
+
+func (c *childQuery) Test(n NodeNavigator) bool {
+ return c.Predicate(n)
+}
+
+func (c *childQuery) Clone() query {
+ return &childQuery{name: c.name, Input: c.Input.Clone(), Predicate: c.Predicate}
+}
+
+func (c *childQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (c *childQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// position returns a position of current NodeNavigator.
+func (c *childQuery) position() int {
+ return c.posit
+}
+
+type cachedChildQuery struct {
+ name string
+ posit int
+ iterator func() NodeNavigator
+
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (c *cachedChildQuery) Select(t iterator) NodeNavigator {
+ for {
+ if c.iterator == nil {
+ c.posit = 0
+ node := c.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ first := true
+ c.iterator = func() NodeNavigator {
+ for {
+ if (first && !node.MoveToChild()) || (!first && !node.MoveToNext()) {
+ return nil
+ }
+ first = false
+ if c.Predicate(node) {
+ return node
+ }
+ }
+ }
+ }
+
+ if node := c.iterator(); node != nil {
+ c.posit++
+ return node
+ }
+ c.iterator = nil
+ }
+}
+
+func (c *cachedChildQuery) Evaluate(t iterator) interface{} {
+ c.Input.Evaluate(t)
+ c.iterator = nil
+ return c
+}
+
+func (c *cachedChildQuery) position() int {
+ return c.posit
+}
+
+func (c *cachedChildQuery) Test(n NodeNavigator) bool {
+ return c.Predicate(n)
+}
+
+func (c *cachedChildQuery) Clone() query {
+ return &childQuery{name: c.name, Input: c.Input.Clone(), Predicate: c.Predicate}
+}
+
+func (c *cachedChildQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (c *cachedChildQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// descendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*)
+type descendantQuery struct {
+ name string
+ iterator func() NodeNavigator
+ posit int
+ level int
+
+ Self bool
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (d *descendantQuery) Select(t iterator) NodeNavigator {
+ for {
+ if d.iterator == nil {
+ d.posit = 0
+ node := d.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ d.level = 0
+ first := true
+ d.iterator = func() NodeNavigator {
+ if first {
+ first = false
+ if d.Self && d.Predicate(node) {
+ return node
+ }
+ }
+
+ for {
+ if node.MoveToChild() {
+ d.level = d.level + 1
+ } else {
+ for {
+ if d.level == 0 {
+ return nil
+ }
+ if node.MoveToNext() {
+ break
+ }
+ node.MoveToParent()
+ d.level = d.level - 1
+ }
+ }
+ if d.Predicate(node) {
+ return node
+ }
+ }
+ }
+ }
+
+ if node := d.iterator(); node != nil {
+ d.posit++
+ return node
+ }
+ d.iterator = nil
+ }
+}
+
+func (d *descendantQuery) Evaluate(t iterator) interface{} {
+ d.Input.Evaluate(t)
+ d.iterator = nil
+ return d
+}
+
+func (d *descendantQuery) Test(n NodeNavigator) bool {
+ return d.Predicate(n)
+}
+
+// position returns a position of current NodeNavigator.
+func (d *descendantQuery) position() int {
+ return d.posit
+}
+
+func (d *descendantQuery) depth() int {
+ return d.level
+}
+
+func (d *descendantQuery) Clone() query {
+ return &descendantQuery{name: d.name, Self: d.Self, Input: d.Input.Clone(), Predicate: d.Predicate}
+}
+
+func (d *descendantQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (d *descendantQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// followingQuery is an XPath following node query.(following::*|following-sibling::*)
+type followingQuery struct {
+ posit int
+ iterator func() NodeNavigator
+
+ Input query
+ Sibling bool // The matching sibling node of current node.
+ Predicate func(NodeNavigator) bool
+}
+
+func (f *followingQuery) Select(t iterator) NodeNavigator {
+ for {
+ if f.iterator == nil {
+ f.posit = 0
+ node := f.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ if f.Sibling {
+ f.iterator = func() NodeNavigator {
+ for {
+ if !node.MoveToNext() {
+ return nil
+ }
+ if f.Predicate(node) {
+ f.posit++
+ return node
+ }
+ }
+ }
+ } else {
+ var q *descendantQuery // descendant query
+ f.iterator = func() NodeNavigator {
+ for {
+ if q == nil {
+ for !node.MoveToNext() {
+ if !node.MoveToParent() {
+ return nil
+ }
+ }
+ q = &descendantQuery{
+ Self: true,
+ Input: &contextQuery{},
+ Predicate: f.Predicate,
+ }
+ t.Current().MoveTo(node)
+ }
+ if node := q.Select(t); node != nil {
+ f.posit = q.posit
+ return node
+ }
+ q = nil
+ }
+ }
+ }
+ }
+
+ if node := f.iterator(); node != nil {
+ return node
+ }
+ f.iterator = nil
+ }
+}
+
+func (f *followingQuery) Evaluate(t iterator) interface{} {
+ f.Input.Evaluate(t)
+ return f
+}
+
+func (f *followingQuery) Test(n NodeNavigator) bool {
+ return f.Predicate(n)
+}
+
+func (f *followingQuery) Clone() query {
+ return &followingQuery{Input: f.Input.Clone(), Sibling: f.Sibling, Predicate: f.Predicate}
+}
+
+func (f *followingQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (f *followingQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+func (f *followingQuery) position() int {
+ return f.posit
+}
+
+// precedingQuery is an XPath preceding node query.(preceding::*)
+type precedingQuery struct {
+ iterator func() NodeNavigator
+ posit int
+ Input query
+ Sibling bool // The matching sibling node of current node.
+ Predicate func(NodeNavigator) bool
+}
+
+func (p *precedingQuery) Select(t iterator) NodeNavigator {
+ for {
+ if p.iterator == nil {
+ p.posit = 0
+ node := p.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ if p.Sibling {
+ p.iterator = func() NodeNavigator {
+ for {
+ for !node.MoveToPrevious() {
+ return nil
+ }
+ if p.Predicate(node) {
+ p.posit++
+ return node
+ }
+ }
+ }
+ } else {
+ var q query
+ p.iterator = func() NodeNavigator {
+ for {
+ if q == nil {
+ for !node.MoveToPrevious() {
+ if !node.MoveToParent() {
+ return nil
+ }
+ p.posit = 0
+ }
+ q = &descendantQuery{
+ Self: true,
+ Input: &contextQuery{},
+ Predicate: p.Predicate,
+ }
+ t.Current().MoveTo(node)
+ }
+ if node := q.Select(t); node != nil {
+ p.posit++
+ return node
+ }
+ q = nil
+ }
+ }
+ }
+ }
+ if node := p.iterator(); node != nil {
+ return node
+ }
+ p.iterator = nil
+ }
+}
+
+func (p *precedingQuery) Evaluate(t iterator) interface{} {
+ p.Input.Evaluate(t)
+ return p
+}
+
+func (p *precedingQuery) Test(n NodeNavigator) bool {
+ return p.Predicate(n)
+}
+
+func (p *precedingQuery) Clone() query {
+ return &precedingQuery{Input: p.Input.Clone(), Sibling: p.Sibling, Predicate: p.Predicate}
+}
+
+func (p *precedingQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (p *precedingQuery) Properties() queryProp {
+ return queryProps.Merge | queryProps.Reverse
+}
+
+func (p *precedingQuery) position() int {
+ return p.posit
+}
+
+// parentQuery is an XPath parent node query.(parent::*)
+type parentQuery struct {
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (p *parentQuery) Select(t iterator) NodeNavigator {
+ for {
+ node := p.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+ if node.MoveToParent() && p.Predicate(node) {
+ return node
+ }
+ }
+}
+
+func (p *parentQuery) Evaluate(t iterator) interface{} {
+ p.Input.Evaluate(t)
+ return p
+}
+
+func (p *parentQuery) Clone() query {
+ return &parentQuery{Input: p.Input.Clone(), Predicate: p.Predicate}
+}
+
+func (p *parentQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (p *parentQuery) Properties() queryProp {
+ return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
+}
+
+func (p *parentQuery) Test(n NodeNavigator) bool {
+ return p.Predicate(n)
+}
+
+// selfQuery is an Self node query.(self::*)
+type selfQuery struct {
+ Input query
+ Predicate func(NodeNavigator) bool
+}
+
+func (s *selfQuery) Select(t iterator) NodeNavigator {
+ for {
+ node := s.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+
+ if s.Predicate(node) {
+ return node
+ }
+ }
+}
+
+func (s *selfQuery) Evaluate(t iterator) interface{} {
+ s.Input.Evaluate(t)
+ return s
+}
+
+func (s *selfQuery) Test(n NodeNavigator) bool {
+ return s.Predicate(n)
+}
+
+func (s *selfQuery) Clone() query {
+ return &selfQuery{Input: s.Input.Clone(), Predicate: s.Predicate}
+}
+
+func (s *selfQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (s *selfQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// filterQuery is an XPath query for predicate filter.
+type filterQuery struct {
+ Input query
+ Predicate query
+ NoPosition bool
+
+ posit int
+ positmap map[int]int
+}
+
+func (f *filterQuery) do(t iterator) bool {
+ val := reflect.ValueOf(f.Predicate.Evaluate(t))
+ switch val.Kind() {
+ case reflect.Bool:
+ return val.Bool()
+ case reflect.String:
+ return len(val.String()) > 0
+ case reflect.Float64:
+ pt := getNodePosition(f.Input)
+ return int(val.Float()) == pt
+ default:
+ if f.Predicate != nil {
+ return f.Predicate.Select(t) != nil
+ }
+ }
+ return false
+}
+
+func (f *filterQuery) position() int {
+ return f.posit
+}
+
+func (f *filterQuery) Select(t iterator) NodeNavigator {
+ if f.positmap == nil {
+ f.positmap = make(map[int]int)
+ }
+ for {
+
+ node := f.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ node = node.Copy()
+
+ t.Current().MoveTo(node)
+ if f.do(t) {
+ // fix https://github.com/antchfx/htmlquery/issues/26
+ // Calculate and keep the each of matching node's position in the same depth.
+ level := getNodeDepth(f.Input)
+ f.positmap[level]++
+ f.posit = f.positmap[level]
+ return node
+ }
+ }
+}
+
+func (f *filterQuery) Evaluate(t iterator) interface{} {
+ f.Input.Evaluate(t)
+ // Reset the position map when re-evaluating to ensure clean state
+ f.positmap = nil
+ return f
+}
+
+func (f *filterQuery) Clone() query {
+ return &filterQuery{Input: f.Input.Clone(), Predicate: f.Predicate.Clone()}
+}
+
+func (f *filterQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (f *filterQuery) Properties() queryProp {
+ return (queryProps.Position | f.Input.Properties()) & (queryProps.Reverse | queryProps.Merge)
+}
+
+// functionQuery is an XPath function that returns a computed value for
+// the Evaluate call of the current NodeNavigator node. Select call isn't
+// applicable for functionQuery.
+type functionQuery struct {
+ Input query // Node Set
+ Func func(query, iterator) interface{} // The xpath function.
+}
+
+func (f *functionQuery) Select(t iterator) NodeNavigator {
+ return nil
+}
+
+// Evaluate call a specified function that will returns the
+// following value type: number,string,boolean.
+func (f *functionQuery) Evaluate(t iterator) interface{} {
+ return f.Func(f.Input, t)
+}
+
+func (f *functionQuery) Clone() query {
+ if f.Input == nil {
+ return &functionQuery{Func: f.Func}
+ }
+ return &functionQuery{Input: f.Input.Clone(), Func: f.Func}
+}
+
+func (f *functionQuery) ValueType() resultType {
+ return xpathResultType.Any
+}
+
+func (f *functionQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// transformFunctionQuery diffs from functionQuery where the latter computes a scalar
+// value (number,string,boolean) for the current NodeNavigator node while the former
+// (transformFunctionQuery) performs a mapping or transform of the current NodeNavigator
+// and returns a new NodeNavigator. It is used for non-scalar XPath functions such as
+// reverse(), remove(), subsequence(), unordered(), etc.
+type transformFunctionQuery struct {
+ Input query
+ Func func(query, iterator) func() NodeNavigator
+ iterator func() NodeNavigator
+}
+
+func (f *transformFunctionQuery) Select(t iterator) NodeNavigator {
+ if f.iterator == nil {
+ f.iterator = f.Func(f.Input, t)
+ }
+ return f.iterator()
+}
+
+func (f *transformFunctionQuery) Evaluate(t iterator) interface{} {
+ f.Input.Evaluate(t)
+ f.iterator = nil
+ return f
+}
+
+func (f *transformFunctionQuery) Clone() query {
+ return &transformFunctionQuery{Input: f.Input.Clone(), Func: f.Func}
+}
+
+func (f *transformFunctionQuery) ValueType() resultType {
+ return xpathResultType.Any
+}
+
+func (f *transformFunctionQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// constantQuery is an XPath constant operand.
+type constantQuery struct {
+ Val interface{}
+}
+
+func (c *constantQuery) Select(t iterator) NodeNavigator {
+ return nil
+}
+
+func (c *constantQuery) Evaluate(t iterator) interface{} {
+ return c.Val
+}
+
+func (c *constantQuery) Clone() query {
+ return c
+}
+
+func (c *constantQuery) ValueType() resultType {
+ return getXPathType(c.Val)
+}
+
+func (c *constantQuery) Properties() queryProp {
+ return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
+}
+
+type groupQuery struct {
+ posit int
+
+ Input query
+}
+
+func (g *groupQuery) Select(t iterator) NodeNavigator {
+ node := g.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ g.posit++
+ return node
+}
+
+func (g *groupQuery) Evaluate(t iterator) interface{} {
+ return g.Input.Evaluate(t)
+}
+
+func (g *groupQuery) Clone() query {
+ return &groupQuery{Input: g.Input.Clone()}
+}
+
+func (g *groupQuery) ValueType() resultType {
+ return g.Input.ValueType()
+}
+
+func (g *groupQuery) Properties() queryProp {
+ return queryProps.Position
+}
+
+func (g *groupQuery) position() int {
+ return g.posit
+}
+
+// logicalQuery is an XPath logical expression.
+type logicalQuery struct {
+ Left, Right query
+
+ Do func(iterator, interface{}, interface{}) interface{}
+}
+
+func (l *logicalQuery) Select(t iterator) NodeNavigator {
+ return nil
+}
+
+func (l *logicalQuery) Evaluate(t iterator) interface{} {
+ m := l.Left.Evaluate(t)
+ n := l.Right.Evaluate(t)
+ return l.Do(t, m, n)
+}
+
+func (l *logicalQuery) Clone() query {
+ return &logicalQuery{Left: l.Left.Clone(), Right: l.Right.Clone(), Do: l.Do}
+}
+
+func (l *logicalQuery) ValueType() resultType {
+ return xpathResultType.Boolean
+}
+
+func (l *logicalQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+// numericQuery is an XPath numeric operator expression.
+type numericQuery struct {
+ Left, Right query
+
+ Do func(iterator, interface{}, interface{}) interface{}
+}
+
+func (n *numericQuery) Select(t iterator) NodeNavigator {
+ return nil
+}
+
+func (n *numericQuery) Evaluate(t iterator) interface{} {
+ m := n.Left.Evaluate(t)
+ k := n.Right.Evaluate(t)
+ return n.Do(t, m, k)
+}
+
+func (n *numericQuery) Clone() query {
+ return &numericQuery{Left: n.Left.Clone(), Right: n.Right.Clone(), Do: n.Do}
+}
+
+func (n *numericQuery) ValueType() resultType {
+ return xpathResultType.Number
+}
+
+func (n *numericQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+type booleanQuery struct {
+ IsOr bool
+ Left, Right query
+ iterator func() NodeNavigator
+}
+
+func (b *booleanQuery) Select(t iterator) NodeNavigator {
+ if b.iterator == nil {
+ var list []NodeNavigator
+ i := 0
+ root := t.Current().Copy()
+ if b.IsOr {
+ for {
+ node := b.Left.Select(t)
+ if node == nil {
+ break
+ }
+ node = node.Copy()
+ list = append(list, node)
+ }
+ t.Current().MoveTo(root)
+ for {
+ node := b.Right.Select(t)
+ if node == nil {
+ break
+ }
+ node = node.Copy()
+ list = append(list, node)
+ }
+ } else {
+ var m []NodeNavigator
+ var n []NodeNavigator
+ for {
+ node := b.Left.Select(t)
+ if node == nil {
+ break
+ }
+ node = node.Copy()
+ list = append(m, node)
+ }
+ t.Current().MoveTo(root)
+ for {
+ node := b.Right.Select(t)
+ if node == nil {
+ break
+ }
+ node = node.Copy()
+ list = append(n, node)
+ }
+ for _, k := range m {
+ for _, j := range n {
+ if k == j {
+ list = append(list, k)
+ }
+ }
+ }
+ }
+
+ b.iterator = func() NodeNavigator {
+ if i >= len(list) {
+ return nil
+ }
+ node := list[i]
+ i++
+ return node
+ }
+ }
+ return b.iterator()
+}
+
+func (b *booleanQuery) Evaluate(t iterator) interface{} {
+ n := t.Current().Copy()
+
+ m := b.Left.Evaluate(t)
+ left := asBool(t, m)
+ if b.IsOr && left {
+ return true
+ } else if !b.IsOr && !left {
+ return false
+ }
+
+ t.Current().MoveTo(n)
+ m = b.Right.Evaluate(t)
+ return asBool(t, m)
+}
+
+func (b *booleanQuery) Clone() query {
+ return &booleanQuery{IsOr: b.IsOr, Left: b.Left.Clone(), Right: b.Right.Clone()}
+}
+
+func (b *booleanQuery) ValueType() resultType {
+ return xpathResultType.Boolean
+}
+
+func (b *booleanQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+type unionQuery struct {
+ Left, Right query
+ iterator func() NodeNavigator
+}
+
+func (u *unionQuery) Select(t iterator) NodeNavigator {
+ if u.iterator == nil {
+ var list []NodeNavigator
+ var m = make(map[uint64]bool)
+ root := t.Current().Copy()
+ for {
+ node := u.Left.Select(t)
+ if node == nil {
+ break
+ }
+ code := getHashCode(node.Copy())
+ if _, ok := m[code]; !ok {
+ m[code] = true
+ list = append(list, node.Copy())
+ }
+ }
+ t.Current().MoveTo(root)
+ for {
+ node := u.Right.Select(t)
+ if node == nil {
+ break
+ }
+ code := getHashCode(node.Copy())
+ if _, ok := m[code]; !ok {
+ m[code] = true
+ list = append(list, node.Copy())
+ }
+ }
+ var i int
+ u.iterator = func() NodeNavigator {
+ if i >= len(list) {
+ return nil
+ }
+ node := list[i]
+ i++
+ return node
+ }
+ }
+ return u.iterator()
+}
+
+func (u *unionQuery) Evaluate(t iterator) interface{} {
+ u.iterator = nil
+ u.Left.Evaluate(t)
+ u.Right.Evaluate(t)
+ return u
+}
+
+func (u *unionQuery) Clone() query {
+ return &unionQuery{Left: u.Left.Clone(), Right: u.Right.Clone()}
+}
+
+func (u *unionQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (u *unionQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+type lastFuncQuery struct {
+ buffer []NodeNavigator
+ counted bool
+
+ Input query
+}
+
+func (q *lastFuncQuery) Select(t iterator) NodeNavigator {
+ return nil
+}
+
+func (q *lastFuncQuery) Evaluate(t iterator) interface{} {
+ if !q.counted {
+ for {
+ node := q.Input.Select(t)
+ if node == nil {
+ break
+ }
+ q.buffer = append(q.buffer, node.Copy())
+ }
+ q.counted = true
+ }
+ return float64(len(q.buffer))
+}
+
+func (q *lastFuncQuery) Clone() query {
+ return &lastFuncQuery{Input: q.Input.Clone()}
+}
+
+func (q *lastFuncQuery) ValueType() resultType {
+ return xpathResultType.Number
+}
+
+func (q *lastFuncQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+type descendantOverDescendantQuery struct {
+ name string
+ level int
+ posit int
+ currentNode NodeNavigator
+
+ Input query
+ MatchSelf bool
+ Predicate func(NodeNavigator) bool
+}
+
+func (d *descendantOverDescendantQuery) moveToFirstChild() bool {
+ if d.currentNode.MoveToChild() {
+ d.level++
+ return true
+ }
+ return false
+}
+
+func (d *descendantOverDescendantQuery) moveUpUntilNext() bool {
+ for !d.currentNode.MoveToNext() {
+ d.level--
+ if d.level == 0 {
+ return false
+ }
+ d.currentNode.MoveToParent()
+ }
+ return true
+}
+
+func (d *descendantOverDescendantQuery) Select(t iterator) NodeNavigator {
+ for {
+ if d.level == 0 {
+ node := d.Input.Select(t)
+ if node == nil {
+ return nil
+ }
+ d.currentNode = node.Copy()
+ d.posit = 0
+ if d.MatchSelf && d.Predicate(d.currentNode) {
+ d.posit = 1
+ return d.currentNode
+ }
+ d.moveToFirstChild()
+ } else if !d.moveUpUntilNext() {
+ continue
+ }
+ for ok := true; ok; ok = d.moveToFirstChild() {
+ if d.Predicate(d.currentNode) {
+ d.posit++
+ return d.currentNode
+ }
+ }
+ }
+}
+
+func (d *descendantOverDescendantQuery) Evaluate(t iterator) interface{} {
+ d.Input.Evaluate(t)
+ return d
+}
+
+func (d *descendantOverDescendantQuery) Clone() query {
+ return &descendantOverDescendantQuery{Input: d.Input.Clone(), Predicate: d.Predicate, MatchSelf: d.MatchSelf}
+}
+
+func (d *descendantOverDescendantQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (d *descendantOverDescendantQuery) Properties() queryProp {
+ return queryProps.Merge
+}
+
+func (d *descendantOverDescendantQuery) position() int {
+ return d.posit
+}
+
+type mergeQuery struct {
+ Input query
+ Child query
+
+ iterator func() NodeNavigator
+}
+
+func (m *mergeQuery) Select(t iterator) NodeNavigator {
+ for {
+ if m.iterator == nil {
+ root := m.Input.Select(t)
+ if root == nil {
+ return nil
+ }
+ m.Child.Evaluate(t)
+ root = root.Copy()
+ t.Current().MoveTo(root)
+ var list []NodeNavigator
+ for node := m.Child.Select(t); node != nil; node = m.Child.Select(t) {
+ list = append(list, node.Copy())
+ }
+ i := 0
+ m.iterator = func() NodeNavigator {
+ if i >= len(list) {
+ return nil
+ }
+ result := list[i]
+ i++
+ return result
+ }
+ }
+
+ if node := m.iterator(); node != nil {
+ return node
+ }
+ m.iterator = nil
+ }
+}
+
+func (m *mergeQuery) Evaluate(t iterator) interface{} {
+ m.Input.Evaluate(t)
+ return m
+}
+
+func (m *mergeQuery) Clone() query {
+ return &mergeQuery{Input: m.Input.Clone(), Child: m.Child.Clone()}
+}
+
+func (m *mergeQuery) ValueType() resultType {
+ return xpathResultType.NodeSet
+}
+
+func (m *mergeQuery) Properties() queryProp {
+ return queryProps.Position | queryProps.Count | queryProps.Cached | queryProps.Merge
+}
+
+func getHashCode(n NodeNavigator) uint64 {
+ var sb bytes.Buffer
+ switch n.NodeType() {
+ case AttributeNode, TextNode, CommentNode:
+ sb.WriteString(n.LocalName())
+ sb.WriteByte('=')
+ sb.WriteString(n.Value())
+ // https://github.com/antchfx/htmlquery/issues/25
+ d := 1
+ for n.MoveToPrevious() {
+ d++
+ }
+ sb.WriteByte('-')
+ sb.WriteString(strconv.Itoa(d))
+ for n.MoveToParent() {
+ d = 1
+ for n.MoveToPrevious() {
+ d++
+ }
+ sb.WriteByte('-')
+ sb.WriteString(strconv.Itoa(d))
+ }
+ case ElementNode:
+ sb.WriteString(n.Prefix() + n.LocalName())
+ d := 1
+ for n.MoveToPrevious() {
+ d++
+ }
+ sb.WriteByte('-')
+ sb.WriteString(strconv.Itoa(d))
+
+ for n.MoveToParent() {
+ d = 1
+ for n.MoveToPrevious() {
+ d++
+ }
+ sb.WriteByte('-')
+ sb.WriteString(strconv.Itoa(d))
+ }
+ }
+ h := fnv.New64a()
+ h.Write(sb.Bytes())
+ return h.Sum64()
+}
+
+func getNodePosition(q query) int {
+ type Position interface {
+ position() int
+ }
+ if count, ok := q.(Position); ok {
+ return count.position()
+ }
+ return 1
+}
+
+func getNodeDepth(q query) int {
+ type Depth interface {
+ depth() int
+ }
+ if count, ok := q.(Depth); ok {
+ return count.depth()
+ }
+ return 0
+}
+
+func getXPathType(i interface{}) resultType {
+ v := reflect.ValueOf(i)
+ switch v.Kind() {
+ case reflect.Float64:
+ return xpathResultType.Number
+ case reflect.String:
+ return xpathResultType.String
+ case reflect.Bool:
+ return xpathResultType.Boolean
+ default:
+ if _, ok := i.(query); ok {
+ return xpathResultType.NodeSet
+ }
+ }
+ panic(fmt.Errorf("xpath unknown value type: %v", v.Kind()))
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go
deleted file mode 100644
index 782120b8a837..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/antchfx/xpath, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/antchfx/xpath (exports: ; functions: Compile,MustCompile,Select)
-
-// Package xpath is a stub of github.com/antchfx/xpath, generated by depstubber.
-package xpath
-
-import ()
-
-func Compile(_ string) (*Expr, error) {
- return nil, nil
-}
-
-func CompileWithNS(_ string, _ map[string]string) (*Expr, error) {
- return nil, nil
-}
-
-type Expr struct{}
-
-func (_ *Expr) Evaluate(_ NodeNavigator) interface{} {
- return nil
-}
-
-func (_ *Expr) Select(_ NodeNavigator) *NodeIterator {
- return nil
-}
-
-func (_ *Expr) String() string {
- return ""
-}
-
-func MustCompile(_ string) *Expr {
- return nil
-}
-
-type NodeIterator struct{}
-
-func (_ *NodeIterator) Current() NodeNavigator {
- return nil
-}
-
-func (_ *NodeIterator) MoveNext() bool {
- return false
-}
-
-type NodeNavigator interface {
- Copy() NodeNavigator
- LocalName() string
- MoveTo(_ NodeNavigator) bool
- MoveToChild() bool
- MoveToFirst() bool
- MoveToNext() bool
- MoveToNextAttribute() bool
- MoveToParent() bool
- MoveToPrevious() bool
- MoveToRoot()
- NodeType() NodeType
- Prefix() string
- Value() string
-}
-
-type NodeType int
-
-func Select(_ NodeNavigator, _ string) *NodeIterator {
- return nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go
new file mode 100644
index 000000000000..04bbe8d4c23a
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go
@@ -0,0 +1,176 @@
+package xpath
+
+import (
+ "errors"
+ "fmt"
+)
+
+// NodeType represents a type of XPath node.
+type NodeType int
+
+const (
+ // RootNode is a root node of the XML document or node tree.
+ RootNode NodeType = iota
+
+ // ElementNode is an element, such as .
+ ElementNode
+
+ // AttributeNode is an attribute, such as id='123'.
+ AttributeNode
+
+ // TextNode is the text content of a node.
+ TextNode
+
+ // CommentNode is a comment node, such as
+ CommentNode
+
+ // allNode is any types of node, used by xpath package only to predicate match.
+ allNode
+)
+
+// NodeNavigator provides cursor model for navigating XML data.
+type NodeNavigator interface {
+ // NodeType returns the XPathNodeType of the current node.
+ NodeType() NodeType
+
+ // LocalName gets the Name of the current node.
+ LocalName() string
+
+ // Prefix returns namespace prefix associated with the current node.
+ Prefix() string
+
+ // Value gets the value of current node.
+ Value() string
+
+ // Copy does a deep copy of the NodeNavigator and all its components.
+ Copy() NodeNavigator
+
+ // MoveToRoot moves the NodeNavigator to the root node of the current node.
+ MoveToRoot()
+
+ // MoveToParent moves the NodeNavigator to the parent node of the current node.
+ MoveToParent() bool
+
+ // MoveToNextAttribute moves the NodeNavigator to the next attribute on current node.
+ MoveToNextAttribute() bool
+
+ // MoveToChild moves the NodeNavigator to the first child node of the current node.
+ MoveToChild() bool
+
+ // MoveToFirst moves the NodeNavigator to the first sibling node of the current node.
+ MoveToFirst() bool
+
+ // MoveToNext moves the NodeNavigator to the next sibling node of the current node.
+ MoveToNext() bool
+
+ // MoveToPrevious moves the NodeNavigator to the previous sibling node of the current node.
+ MoveToPrevious() bool
+
+ // MoveTo moves the NodeNavigator to the same position as the specified NodeNavigator.
+ MoveTo(NodeNavigator) bool
+}
+
+// NodeIterator holds all matched Node object.
+type NodeIterator struct {
+ node NodeNavigator
+ query query
+}
+
+// Current returns current node which matched.
+func (t *NodeIterator) Current() NodeNavigator {
+ return t.node
+}
+
+// MoveNext moves Navigator to the next match node.
+func (t *NodeIterator) MoveNext() bool {
+ n := t.query.Select(t)
+ if n == nil {
+ return false
+ }
+ if !t.node.MoveTo(n) {
+ t.node = n.Copy()
+ }
+ return true
+}
+
+// Select selects a node set using the specified XPath expression.
+// This method is deprecated, recommend using Expr.Select() method instead.
+func Select(root NodeNavigator, expr string) *NodeIterator {
+ exp, err := Compile(expr)
+ if err != nil {
+ panic(err)
+ }
+ return exp.Select(root)
+}
+
+// Expr is an XPath expression for query.
+type Expr struct {
+ s string
+ q query
+}
+
+type iteratorFunc func() NodeNavigator
+
+func (f iteratorFunc) Current() NodeNavigator {
+ return f()
+}
+
+// Evaluate returns the result of the expression.
+// The result type of the expression is one of the follow: bool,float64,string,NodeIterator).
+func (expr *Expr) Evaluate(root NodeNavigator) interface{} {
+ val := expr.q.Evaluate(iteratorFunc(func() NodeNavigator { return root }))
+ switch val.(type) {
+ case query:
+ return &NodeIterator{query: expr.q.Clone(), node: root}
+ }
+ return val
+}
+
+// Select selects a node set using the specified XPath expression.
+func (expr *Expr) Select(root NodeNavigator) *NodeIterator {
+ return &NodeIterator{query: expr.q.Clone(), node: root}
+}
+
+// String returns XPath expression string.
+func (expr *Expr) String() string {
+ return expr.s
+}
+
+// Compile compiles an XPath expression string.
+func Compile(expr string) (*Expr, error) {
+ if expr == "" {
+ return nil, errors.New("expr expression is nil")
+ }
+ qy, err := build(expr, nil)
+ if err != nil {
+ return nil, err
+ }
+ if qy == nil {
+ return nil, fmt.Errorf(fmt.Sprintf("undeclared variable in XPath expression: %s", expr))
+ }
+ return &Expr{s: expr, q: qy}, nil
+}
+
+// MustCompile compiles an XPath expression string and ignored error.
+func MustCompile(expr string) *Expr {
+ exp, err := Compile(expr)
+ if err != nil {
+ return &Expr{s: expr, q: nopQuery{}}
+ }
+ return exp
+}
+
+// CompileWithNS compiles an XPath expression string, using given namespaces map.
+func CompileWithNS(expr string, namespaces map[string]string) (*Expr, error) {
+ if expr == "" {
+ return nil, errors.New("expr expression is nil")
+ }
+ qy, err := build(expr, namespaces)
+ if err != nil {
+ return nil, err
+ }
+ if qy == nil {
+ return nil, fmt.Errorf(fmt.Sprintf("undeclared variable in XPath expression: %s", expr))
+ }
+ return &Expr{s: expr, q: qy}, nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md
new file mode 100644
index 000000000000..4d10f697b7a1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md
@@ -0,0 +1,4 @@
+Installation and usage
+----------------------
+
+See [gopkg.in/xmlpath.v2](https://gopkg.in/xmlpath.v2) for documentation and usage details.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go
new file mode 100644
index 000000000000..e81d7370a9d9
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go
@@ -0,0 +1,75 @@
+// Package xmlpath implements a strict subset of the XPath specification for the Go language.
+//
+// The XPath specification is available at:
+//
+// http://www.w3.org/TR/xpath
+//
+// Path expressions supported by this package are in the following format,
+// with all components being optional:
+//
+// /axis-name::node-test[predicate]/axis-name::node-test[predicate]
+//
+// At the moment, xmlpath is compatible with the XPath specification
+// to the following extent:
+//
+// - All axes are supported ("child", "following-sibling", etc)
+// - All abbreviated forms are supported (".", "//", etc)
+// - All node types except for namespace are supported
+// - Predicates may be [N], [path], [not(path)], [path=literal] or [contains(path, literal)]
+// - Predicates may be joined with "or", "and", and parenthesis
+// - Richer expressions and namespaces are not supported
+//
+// For example, assuming the following document:
+//
+//
+//
+//
+// 0836217462
+// Being a Dog Is a Full-Time Job
+// I'd dog paddle the deepest ocean.
+//
+//
+// Charles M Schulz
+// 1922-11-26
+// 2000-02-12
+//
+//
+// Peppermint Patty
+// 1966-08-22
+// bold, brash and tomboyish
+//
+//
+// Snoopy
+// 1950-10-04
+// extroverted beagle
+//
+//
+//
+//
+// The following examples are valid path expressions, and the first
+// match has the indicated value:
+//
+// /library/book/isbn => "0836217462"
+// library/*/isbn => "0836217462"
+// /library/book/../book/./isbn => "0836217462"
+// /library/book/character[2]/name => "Snoopy"
+// /library/book/character[born='1950-10-04']/name => "Snoopy"
+// /library/book//node()[@id='PP']/name => "Peppermint Patty"
+// //book[author/@id='CMS']/title => "Being a Dog Is a Full-Time Job",
+// /library/book/preceding::comment() => " Great book. "
+// //*[contains(born,'1922')]/name => "Charles M Schulz"
+// //*[@id='PP' or @id='Snoopy']/born => {"1966-08-22", "1950-10-04"}
+//
+// To run an expression, compile it, and then apply the compiled path to any
+// number of context nodes, from one or more parsed xml documents:
+//
+// path := xmlpath.MustCompile("/library/book/isbn")
+// root, err := xmlpath.Parse(file)
+// if err != nil {
+// log.Fatal(err)
+// }
+// if value, ok := path.String(root); ok {
+// fmt.Println("Found:", value)
+// }
+//
+package xmlpath
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go
new file mode 100644
index 000000000000..64267aa495e2
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go
@@ -0,0 +1,396 @@
+package xmlpath
+
+import (
+ "golang.org/x/net/html"
+ "encoding/xml"
+ "io"
+ "strings"
+)
+
+// Node is an item in an xml tree that was compiled to
+// be processed via xml paths. A node may represent:
+//
+// - An element in the xml document ()
+// - An attribute of an element in the xml document (href="...")
+// - A comment in the xml document ()
+// - A processing instruction in the xml document (...?>)
+// - Some text within the xml document
+//
+type Node struct {
+ kind nodeKind
+ name xml.Name
+ attr string
+ text []byte
+
+ nodes []Node
+ pos int
+ end int
+
+ up *Node
+ down []*Node
+}
+
+type nodeKind int
+
+const (
+ anyNode nodeKind = iota
+ startNode
+ endNode
+ attrNode
+ textNode
+ commentNode
+ procInstNode
+)
+
+// String returns the string value of node.
+//
+// The string value of a node is:
+//
+// - For element nodes, the concatenation of all text nodes within the element.
+// - For text nodes, the text itself.
+// - For attribute nodes, the attribute value.
+// - For comment nodes, the text within the comment delimiters.
+// - For processing instruction nodes, the content of the instruction.
+//
+func (node *Node) String() string {
+ if node.kind == attrNode {
+ return node.attr
+ }
+ return string(node.Bytes())
+}
+
+// Bytes returns the string value of node as a byte slice.
+// See Node.String for a description of what the string value of a node is.
+func (node *Node) Bytes() []byte {
+ if node.kind == attrNode {
+ return []byte(node.attr)
+ }
+ if node.kind != startNode {
+ return node.text
+ }
+ size := 0
+ for i := node.pos; i < node.end; i++ {
+ if node.nodes[i].kind == textNode {
+ size += len(node.nodes[i].text)
+ }
+ }
+ text := make([]byte, 0, size)
+ for i := node.pos; i < node.end; i++ {
+ if node.nodes[i].kind == textNode {
+ text = append(text, node.nodes[i].text...)
+ }
+ }
+ return text
+}
+
+// equals returns whether the string value of node is equal to s,
+// without allocating memory.
+func (node *Node) equals(s string) bool {
+ if node.kind == attrNode {
+ return s == node.attr
+ }
+ if node.kind != startNode {
+ if len(s) != len(node.text) {
+ return false
+ }
+ for i := range s {
+ if s[i] != node.text[i] {
+ return false
+ }
+ }
+ return true
+ }
+ si := 0
+ for i := node.pos; i < node.end; i++ {
+ if node.nodes[i].kind == textNode {
+ for _, c := range node.nodes[i].text {
+ if si > len(s) {
+ return false
+ }
+ if s[si] != c {
+ return false
+ }
+ si++
+ }
+ }
+ }
+ return si == len(s)
+}
+
+// contains returns whether the string value of node contains s,
+// without allocating memory.
+func (node *Node) contains(s string) (ok bool) {
+ if len(s) == 0 {
+ return true
+ }
+ if node.kind == attrNode {
+ return strings.Contains(node.attr, s)
+ }
+ s0 := s[0]
+ for i := node.pos; i < node.end; i++ {
+ if node.nodes[i].kind == textNode {
+ text := node.nodes[i].text
+ NextTry:
+ for ci, c := range text {
+ if c != s0 {
+ continue
+ }
+ si := 1
+ for ci++; ci < len(text) && si < len(s); ci++ {
+ if s[si] != text[ci] {
+ continue NextTry
+ }
+ si++
+ }
+ if si == len(s) {
+ return true
+ }
+ for j := i + 1; j < node.end; j++ {
+ if node.nodes[j].kind == textNode {
+ for _, c := range node.nodes[j].text {
+ if s[si] != c {
+ continue NextTry
+ }
+ si++
+ if si == len(s) {
+ return true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false
+}
+
+// Parse reads an xml document from r, parses it, and returns its root node.
+func Parse(r io.Reader) (*Node, error) {
+ return ParseDecoder(xml.NewDecoder(r))
+}
+
+// ParseDecoder parses the xml document being decoded by d and returns
+// its root node.
+func ParseDecoder(d *xml.Decoder) (*Node, error) {
+ var nodes []Node
+ var text []byte
+
+ // The root node.
+ nodes = append(nodes, Node{kind: startNode})
+
+ for {
+ t, err := d.Token()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ switch t := t.(type) {
+ case xml.EndElement:
+ nodes = append(nodes, Node{
+ kind: endNode,
+ })
+ case xml.StartElement:
+ nodes = append(nodes, Node{
+ kind: startNode,
+ name: t.Name,
+ })
+ for _, attr := range t.Attr {
+ nodes = append(nodes, Node{
+ kind: attrNode,
+ name: attr.Name,
+ attr: attr.Value,
+ })
+ }
+ case xml.CharData:
+ texti := len(text)
+ text = append(text, t...)
+ nodes = append(nodes, Node{
+ kind: textNode,
+ text: text[texti : texti+len(t)],
+ })
+ case xml.Comment:
+ texti := len(text)
+ text = append(text, t...)
+ nodes = append(nodes, Node{
+ kind: commentNode,
+ text: text[texti : texti+len(t)],
+ })
+ case xml.ProcInst:
+ texti := len(text)
+ text = append(text, t.Inst...)
+ nodes = append(nodes, Node{
+ kind: procInstNode,
+ name: xml.Name{Local: t.Target},
+ text: text[texti : texti+len(t.Inst)],
+ })
+ }
+ }
+
+ // Close the root node.
+ nodes = append(nodes, Node{kind: endNode})
+
+ stack := make([]*Node, 0, len(nodes))
+ downs := make([]*Node, len(nodes))
+ downCount := 0
+
+ for pos := range nodes {
+
+ switch nodes[pos].kind {
+
+ case startNode, attrNode, textNode, commentNode, procInstNode:
+ node := &nodes[pos]
+ node.nodes = nodes
+ node.pos = pos
+ if len(stack) > 0 {
+ node.up = stack[len(stack)-1]
+ }
+ if node.kind == startNode {
+ stack = append(stack, node)
+ } else {
+ node.end = pos + 1
+ }
+
+ case endNode:
+ node := stack[len(stack)-1]
+ node.end = pos
+ stack = stack[:len(stack)-1]
+
+ // Compute downs. Doing that here is what enables the
+ // use of a slice of a contiguous pre-allocated block.
+ node.down = downs[downCount:downCount]
+ for i := node.pos + 1; i < node.end; i++ {
+ if nodes[i].up == node {
+ switch nodes[i].kind {
+ case startNode, textNode, commentNode, procInstNode:
+ node.down = append(node.down, &nodes[i])
+ downCount++
+ }
+ }
+ }
+ if len(stack) == 0 {
+ return node, nil
+ }
+ }
+ }
+ return nil, io.EOF
+}
+
+// ParseHTML reads an HTML document from r, parses it using a proper HTML
+// parser, and returns its root node.
+//
+// The document will be processed as a properly structured HTML document,
+// emulating the behavior of a browser when processing it. This includes
+// putting the content inside proper and tags, if the
+// provided text misses them.
+func ParseHTML(r io.Reader) (*Node, error) {
+ ns, err := html.ParseFragment(r, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ var nodes []Node
+ var text []byte
+
+ n := ns[0]
+
+ // The root node.
+ nodes = append(nodes, Node{kind: startNode})
+
+ for n != nil {
+ switch n.Type {
+ case html.DocumentNode:
+ case html.ElementNode:
+ nodes = append(nodes, Node{
+ kind: startNode,
+ name: xml.Name{Local: n.Data, Space: n.Namespace},
+ })
+ for _, attr := range n.Attr {
+ nodes = append(nodes, Node{
+ kind: attrNode,
+ name: xml.Name{Local: attr.Key, Space: attr.Namespace},
+ attr: attr.Val,
+ })
+ }
+ case html.TextNode:
+ texti := len(text)
+ text = append(text, n.Data...)
+ nodes = append(nodes, Node{
+ kind: textNode,
+ text: text[texti : texti+len(n.Data)],
+ })
+ case html.CommentNode:
+ texti := len(text)
+ text = append(text, n.Data...)
+ nodes = append(nodes, Node{
+ kind: commentNode,
+ text: text[texti : texti+len(n.Data)],
+ })
+ }
+
+ if n.FirstChild != nil {
+ n = n.FirstChild
+ continue
+ }
+
+ for n != nil {
+ if n.Type == html.ElementNode {
+ nodes = append(nodes, Node{kind: endNode})
+ }
+ if n.NextSibling != nil {
+ n = n.NextSibling
+ break
+ }
+ n = n.Parent
+ }
+ }
+
+ // Close the root node.
+ nodes = append(nodes, Node{kind: endNode})
+
+ stack := make([]*Node, 0, len(nodes))
+ downs := make([]*Node, len(nodes))
+ downCount := 0
+
+ for pos := range nodes {
+
+ switch nodes[pos].kind {
+
+ case startNode, attrNode, textNode, commentNode, procInstNode:
+ node := &nodes[pos]
+ node.nodes = nodes
+ node.pos = pos
+ if len(stack) > 0 {
+ node.up = stack[len(stack)-1]
+ }
+ if node.kind == startNode {
+ stack = append(stack, node)
+ } else {
+ node.end = pos + 1
+ }
+
+ case endNode:
+ node := stack[len(stack)-1]
+ node.end = pos
+ stack = stack[:len(stack)-1]
+
+ // Compute downs. Doing that here is what enables the
+ // use of a slice of a contiguous pre-allocated block.
+ node.down = downs[downCount:downCount]
+ for i := node.pos + 1; i < node.end; i++ {
+ if nodes[i].up == node {
+ switch nodes[i].kind {
+ case startNode, textNode, commentNode, procInstNode:
+ node.down = append(node.down, &nodes[i])
+ downCount++
+ }
+ }
+ }
+ if len(stack) == 0 {
+ return node, nil
+ }
+ }
+ }
+ return nil, io.EOF
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go
new file mode 100644
index 000000000000..db38ed573623
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go
@@ -0,0 +1,790 @@
+package xmlpath
+
+import (
+ "fmt"
+ "strconv"
+ "unicode/utf8"
+)
+
+// Path is a compiled path that can be applied to a context
+// node to obtain a matching node set.
+// A single Path can be applied concurrently to any number
+// of context nodes.
+type Path struct {
+ path string
+ steps []pathStep
+}
+
+// Iter returns an iterator that goes over the list of nodes
+// that p matches on the given context.
+func (p *Path) Iter(context *Node) *Iter {
+ iter := Iter{
+ make([]pathStepState, len(p.steps)),
+ make([]bool, len(context.nodes)),
+ }
+ for i := range p.steps {
+ iter.state[i].step = &p.steps[i]
+ }
+ iter.state[0].init(context)
+ return &iter
+}
+
+// Exists returns whether any nodes match p on the given context.
+func (p *Path) Exists(context *Node) bool {
+ return p.Iter(context).Next()
+}
+
+// String returns the string value of the first node matched
+// by p on the given context.
+//
+// See the documentation of Node.String.
+func (p *Path) String(context *Node) (s string, ok bool) {
+ iter := p.Iter(context)
+ if iter.Next() {
+ return iter.Node().String(), true
+ }
+ return "", false
+}
+
+// Bytes returns as a byte slice the string value of the first
+// node matched by p on the given context.
+//
+// See the documentation of Node.String.
+func (p *Path) Bytes(node *Node) (b []byte, ok bool) {
+ iter := p.Iter(node)
+ if iter.Next() {
+ return iter.Node().Bytes(), true
+ }
+ return nil, false
+}
+
+// Iter iterates over node sets.
+type Iter struct {
+ state []pathStepState
+ seen []bool
+}
+
+// Node returns the current node.
+// Must only be called after Iter.Next returns true.
+func (iter *Iter) Node() *Node {
+ state := iter.state[len(iter.state)-1]
+ if state.pos == 0 {
+ panic("Iter.Node called before Iter.Next")
+ }
+ if state.node == nil {
+ panic("Iter.Node called after Iter.Next false")
+ }
+ return state.node
+}
+
+// Next iterates to the next node in the set, if any, and
+// returns whether there is a node available.
+func (iter *Iter) Next() bool {
+ tip := len(iter.state) - 1
+outer:
+ for {
+ for !iter.state[tip].next() {
+ tip--
+ if tip == -1 {
+ return false
+ }
+ }
+ for tip < len(iter.state)-1 {
+ tip++
+ iter.state[tip].init(iter.state[tip-1].node)
+ if !iter.state[tip].next() {
+ tip--
+ continue outer
+ }
+ }
+ if iter.seen[iter.state[tip].node.pos] {
+ continue
+ }
+ iter.seen[iter.state[tip].node.pos] = true
+ return true
+ }
+ panic("unreachable")
+}
+
+type pathStepState struct {
+ step *pathStep
+ node *Node
+ pos int
+ idx int
+ aux int
+}
+
+func (s *pathStepState) init(node *Node) {
+ s.node = node
+ s.pos = 0
+ s.idx = 0
+ s.aux = 0
+}
+
+func (s *pathStepState) next() bool {
+ for s._next() {
+ s.pos++
+ if s.step.pred == nil || s.test(s.step.pred) {
+ return true
+ }
+ }
+ return false
+}
+
+func (s *pathStepState) test(pred predicate) bool {
+ switch pred := pred.(type) {
+ case positionPredicate:
+ if pred.pos == s.pos {
+ return true
+ }
+ case existsPredicate:
+ if pred.path.Exists(s.node) {
+ return true
+ }
+ case equalsPredicate:
+ iter := pred.path.Iter(s.node)
+ for iter.Next() {
+ if iter.Node().equals(pred.value) {
+ return true
+ }
+ }
+ case containsPredicate:
+ iter := pred.path.Iter(s.node)
+ for iter.Next() {
+ if iter.Node().contains(pred.value) {
+ return true
+ }
+ }
+ case notPredicate:
+ iter := pred.path.Iter(s.node)
+ if !iter.Next() {
+ return true
+ }
+ case andPredicate:
+ for _, sub := range pred.sub {
+ if !s.test(sub) {
+ return false
+ }
+ }
+ return true
+ case orPredicate:
+ for _, sub := range pred.sub {
+ if s.test(sub) {
+ return true
+ }
+ }
+ default:
+ panic(fmt.Sprintf("internal error: unknown predicate type: %#v", s.step.pred))
+ }
+ return false
+}
+
+func (s *pathStepState) _next() bool {
+ if s.node == nil {
+ return false
+ }
+ if s.step.root && s.idx == 0 {
+ for s.node.up != nil {
+ s.node = s.node.up
+ }
+ }
+
+ switch s.step.axis {
+
+ case "self":
+ if s.idx == 0 && s.step.match(s.node) {
+ s.idx++
+ return true
+ }
+
+ case "parent":
+ if s.idx == 0 && s.node.up != nil && s.step.match(s.node.up) {
+ s.idx++
+ s.node = s.node.up
+ return true
+ }
+
+ case "ancestor", "ancestor-or-self":
+ if s.idx == 0 && s.step.axis == "ancestor-or-self" {
+ s.idx++
+ if s.step.match(s.node) {
+ return true
+ }
+ }
+ for s.node.up != nil {
+ s.node = s.node.up
+ s.idx++
+ if s.step.match(s.node) {
+ return true
+ }
+ }
+
+ case "child":
+ var down []*Node
+ if s.idx == 0 {
+ down = s.node.down
+ } else {
+ down = s.node.up.down
+ }
+ for s.idx < len(down) {
+ node := down[s.idx]
+ s.idx++
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "descendant", "descendant-or-self":
+ if s.idx == 0 {
+ s.idx = s.node.pos
+ s.aux = s.node.end
+ if s.step.axis == "descendant" {
+ s.idx++
+ }
+ }
+ for s.idx < s.aux {
+ node := &s.node.nodes[s.idx]
+ s.idx++
+ if node.kind == attrNode {
+ continue
+ }
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "following":
+ if s.idx == 0 {
+ s.idx = s.node.end
+ }
+ for s.idx < len(s.node.nodes) {
+ node := &s.node.nodes[s.idx]
+ s.idx++
+ if node.kind == attrNode {
+ continue
+ }
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "following-sibling":
+ var down []*Node
+ if s.node.up != nil {
+ down = s.node.up.down
+ if s.idx == 0 {
+ for s.idx < len(down) {
+ node := down[s.idx]
+ s.idx++
+ if node == s.node {
+ break
+ }
+ }
+ }
+ }
+ for s.idx < len(down) {
+ node := down[s.idx]
+ s.idx++
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "preceding":
+ if s.idx == 0 {
+ s.aux = s.node.pos // Detect ancestors.
+ s.idx = s.node.pos - 1
+ }
+ for s.idx >= 0 {
+ node := &s.node.nodes[s.idx]
+ s.idx--
+ if node.kind == attrNode {
+ continue
+ }
+ if node == s.node.nodes[s.aux].up {
+ s.aux = s.node.nodes[s.aux].up.pos
+ continue
+ }
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "preceding-sibling":
+ var down []*Node
+ if s.node.up != nil {
+ down = s.node.up.down
+ if s.aux == 0 {
+ s.aux = 1
+ for s.idx < len(down) {
+ node := down[s.idx]
+ s.idx++
+ if node == s.node {
+ s.idx--
+ break
+ }
+ }
+ }
+ }
+ for s.idx >= 0 {
+ node := down[s.idx]
+ s.idx--
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ case "attribute":
+ if s.idx == 0 {
+ s.idx = s.node.pos + 1
+ s.aux = s.node.end
+ }
+ for s.idx < s.aux {
+ node := &s.node.nodes[s.idx]
+ s.idx++
+ if node.kind != attrNode {
+ break
+ }
+ if s.step.match(node) {
+ s.node = node
+ return true
+ }
+ }
+
+ }
+
+ s.node = nil
+ return false
+}
+
+type positionPredicate struct {
+ pos int
+}
+
+type existsPredicate struct {
+ path *Path
+}
+
+type equalsPredicate struct {
+ path *Path
+ value string
+}
+
+type containsPredicate struct {
+ path *Path
+ value string
+}
+
+type notPredicate struct {
+ path *Path
+}
+
+type andPredicate struct {
+ sub []predicate
+}
+
+type orPredicate struct {
+ sub []predicate
+}
+
+// predicate is a marker interface for predicate types.
+type predicate interface {
+ predicate()
+}
+
+func (positionPredicate) predicate() {}
+func (existsPredicate) predicate() {}
+func (equalsPredicate) predicate() {}
+func (containsPredicate) predicate() {}
+func (notPredicate) predicate() {}
+func (andPredicate) predicate() {}
+func (orPredicate) predicate() {}
+
+type pathStep struct {
+ root bool
+ axis string
+ name string
+ kind nodeKind
+ pred predicate
+}
+
+func (step *pathStep) match(node *Node) bool {
+ return node.kind != endNode &&
+ (step.kind == anyNode || step.kind == node.kind) &&
+ (step.name == "*" || node.name.Local == step.name)
+}
+
+// MustCompile returns the compiled path, and panics if
+// there are any errors.
+func MustCompile(path string) *Path {
+ e, err := Compile(path)
+ if err != nil {
+ panic(err)
+ }
+ return e
+}
+
+// Compile returns the compiled path.
+func Compile(path string) (*Path, error) {
+ c := pathCompiler{path, 0}
+ if path == "" {
+ return nil, c.errorf("empty path")
+ }
+ p, err := c.parsePath()
+ if err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+type pathCompiler struct {
+ path string
+ i int
+}
+
+func (c *pathCompiler) errorf(format string, args ...interface{}) error {
+ return fmt.Errorf("compiling xml path %q:%d: %s", c.path, c.i, fmt.Sprintf(format, args...))
+}
+
+func (c *pathCompiler) parsePath() (path *Path, err error) {
+ var steps []pathStep
+ var start = c.i
+ for {
+ step := pathStep{axis: "child"}
+
+ c.skipSpaces()
+ if c.i == 0 && c.skipByte('/') {
+ c.skipSpaces()
+ step.root = true
+ if len(c.path) == 1 {
+ step.name = "*"
+ }
+ }
+ if c.peekByte('/') {
+ step.axis = "descendant-or-self"
+ step.name = "*"
+ } else if c.skipByte('@') {
+ mark := c.i
+ if !c.skipName() {
+ return nil, c.errorf("missing name after @")
+ }
+ step.axis = "attribute"
+ step.name = c.path[mark:c.i]
+ step.kind = attrNode
+ } else {
+ mark := c.i
+ if c.skipName() {
+ step.name = c.path[mark:c.i]
+ c.skipSpaces()
+ }
+ if step.name == "" {
+ return nil, c.errorf("missing name")
+ } else if step.name == "*" {
+ step.kind = startNode
+ } else if step.name == "." {
+ step.axis = "self"
+ step.name = "*"
+ } else if step.name == ".." {
+ step.axis = "parent"
+ step.name = "*"
+ } else {
+ if c.skipByte(':') {
+ if !c.skipByte(':') {
+ return nil, c.errorf("missing ':'")
+ }
+ c.skipSpaces()
+ switch step.name {
+ case "attribute":
+ step.kind = attrNode
+ case "self", "child", "parent":
+ case "descendant", "descendant-or-self":
+ case "ancestor", "ancestor-or-self":
+ case "following", "following-sibling":
+ case "preceding", "preceding-sibling":
+ default:
+ return nil, c.errorf("unsupported axis: %q", step.name)
+ }
+ step.axis = step.name
+
+ mark = c.i
+ if !c.skipName() {
+ return nil, c.errorf("missing name")
+ }
+ step.name = c.path[mark:c.i]
+
+ c.skipSpaces()
+ }
+ if c.skipByte('(') {
+ c.skipSpaces()
+ conflict := step.kind != anyNode
+ switch step.name {
+ case "node":
+ // must be anyNode
+ case "text":
+ step.kind = textNode
+ case "comment":
+ step.kind = commentNode
+ case "processing-instruction":
+ step.kind = procInstNode
+ default:
+ return nil, c.errorf("unsupported expression: %s()", step.name)
+ }
+ if conflict {
+ return nil, c.errorf("%s() cannot succeed on axis %q", step.name, step.axis)
+ }
+
+ name := step.name
+ literal, err := c.parseLiteral()
+ if err == errNoLiteral {
+ step.name = "*"
+ } else if err != nil {
+ return nil, c.errorf("%v", err)
+ } else if step.kind == procInstNode {
+ c.skipSpaces()
+ step.name = literal
+ } else {
+ return nil, c.errorf("%s() has no arguments", name)
+ }
+ if !c.skipByte(')') {
+ return nil, c.errorf("%s() missing ')'", name)
+ }
+ c.skipSpaces()
+ } else if step.name == "*" && step.kind == anyNode {
+ step.kind = startNode
+ }
+ }
+ }
+ if c.skipByte('[') {
+ c.skipSpaces()
+ type state struct {
+ sub []predicate
+ and bool
+ }
+ var stack []state
+ var sub []predicate
+ var and bool
+ NextPred:
+ if c.skipByte('(') {
+ stack = append(stack, state{sub, and})
+ sub = nil
+ and = false
+ }
+ var next predicate
+ if pos, ok := c.parseInt(); ok {
+ if pos == 0 {
+ return nil, c.errorf("positions start at 1")
+ }
+ next = positionPredicate{pos}
+ } else if c.skipString("contains(") {
+ path, err := c.parsePath()
+ if err != nil {
+ return nil, err
+ }
+ c.skipSpaces()
+ if !c.skipByte(',') {
+ return nil, c.errorf("contains() expected ',' followed by a literal string")
+ }
+ c.skipSpaces()
+ value, err := c.parseLiteral()
+ if err != nil {
+ return nil, err
+ }
+ c.skipSpaces()
+ if !c.skipByte(')') {
+ return nil, c.errorf("contains() missing ')'")
+ }
+ next = containsPredicate{path, value}
+ } else if c.skipString("not(") {
+ // TODO Generalize to handle any predicate expression.
+ path, err := c.parsePath()
+ if err != nil {
+ return nil, err
+ }
+ c.skipSpaces()
+ if !c.skipByte(')') {
+ return nil, c.errorf("not() missing ')'")
+ }
+ next = notPredicate{path}
+ } else {
+ path, err := c.parsePath()
+ if err != nil {
+ return nil, err
+ }
+ if path.path[0] == '-' {
+ if _, err = strconv.Atoi(path.path); err == nil {
+ return nil, c.errorf("positions must be positive")
+ }
+ }
+ c.skipSpaces()
+ if c.skipByte('=') {
+ c.skipSpaces()
+ value, err := c.parseLiteral()
+ if err != nil {
+ return nil, c.errorf("%v", err)
+ }
+ next = equalsPredicate{path, value}
+ } else {
+ next = existsPredicate{path}
+ }
+ }
+ HandleNext:
+ if and {
+ p := sub[len(sub)-1].(andPredicate)
+ p.sub = append(p.sub, next)
+ sub[len(sub)-1] = p
+ } else {
+ sub = append(sub, next)
+ }
+ if c.skipSpaces() {
+ mark := c.i
+ if c.skipString("and") && c.skipSpaces() {
+ if !and {
+ and = true
+ sub[len(sub)-1] = andPredicate{[]predicate{sub[len(sub)-1]}}
+ }
+ goto NextPred
+ } else if c.skipString("or") && c.skipSpaces() {
+ and = false
+ goto NextPred
+ } else {
+ c.i = mark
+ }
+ }
+ if c.skipByte(')') {
+ if len(stack) == 0 {
+ return nil, c.errorf("unexpected ')'")
+ }
+ if len(sub) == 1 {
+ next = sub[0]
+ } else {
+ next = orPredicate{sub}
+ }
+ s := stack[len(stack)-1]
+ stack = stack[:len(stack)-1]
+ sub = s.sub
+ and = s.and
+ goto HandleNext
+ }
+ if len(stack) > 0 {
+ return nil, c.errorf("expected ')'")
+ }
+ if len(sub) == 1 {
+ step.pred = sub[0]
+ } else {
+ step.pred = orPredicate{sub}
+ }
+ if !c.skipByte(']') {
+ return nil, c.errorf("expected ']'")
+ }
+ c.skipSpaces()
+ }
+ steps = append(steps, step)
+ //fmt.Printf("step: %#v\n", step)
+ if !c.skipByte('/') {
+ if (start == 0 || start == c.i) && c.i < len(c.path) {
+ return nil, c.errorf("unexpected %q", c.path[c.i])
+ }
+ return &Path{steps: steps, path: c.path[start:c.i]}, nil
+ }
+ }
+ panic("unreachable")
+}
+
+var errNoLiteral = fmt.Errorf("expected a literal string")
+
+func (c *pathCompiler) parseLiteral() (string, error) {
+ if c.skipByte('"') {
+ mark := c.i
+ if !c.skipByteFind('"') {
+ return "", fmt.Errorf(`missing '"'`)
+ }
+ return c.path[mark : c.i-1], nil
+ }
+ if c.skipByte('\'') {
+ mark := c.i
+ if !c.skipByteFind('\'') {
+ return "", fmt.Errorf(`missing "'"`)
+ }
+ return c.path[mark : c.i-1], nil
+ }
+ return "", errNoLiteral
+}
+
+func (c *pathCompiler) parseInt() (v int, ok bool) {
+ mark := c.i
+ for c.i < len(c.path) && c.path[c.i] >= '0' && c.path[c.i] <= '9' {
+ v *= 10
+ v += int(c.path[c.i]) - '0'
+ c.i++
+ }
+ if c.i == mark {
+ return 0, false
+ }
+ return v, true
+}
+
+func (c *pathCompiler) skipByte(b byte) bool {
+ if c.i < len(c.path) && c.path[c.i] == b {
+ c.i++
+ return true
+ }
+ return false
+}
+
+func (c *pathCompiler) skipByteFind(b byte) bool {
+ for i := c.i; i < len(c.path); i++ {
+ if c.path[i] == b {
+ c.i = i + 1
+ return true
+ }
+ }
+ return false
+}
+
+func (c *pathCompiler) peekByte(b byte) bool {
+ return c.i < len(c.path) && c.path[c.i] == b
+}
+
+func (c *pathCompiler) skipSpaces() bool {
+ mark := c.i
+ for c.i < len(c.path) {
+ if c.path[c.i] != ' ' {
+ break
+ }
+ c.i++
+ }
+ return c.i != mark
+}
+
+func (c *pathCompiler) skipString(s string) bool {
+ if c.i+len(s) <= len(c.path) && c.path[c.i:c.i+len(s)] == s {
+ c.i += len(s)
+ return true
+ }
+ return false
+}
+
+func (c *pathCompiler) skipName() bool {
+ if c.i >= len(c.path) {
+ return false
+ }
+ if c.path[c.i] == '*' {
+ c.i++
+ return true
+ }
+ start := c.i
+ for c.i < len(c.path) && (c.path[c.i] >= utf8.RuneSelf || isNameByte(c.path[c.i])) {
+ c.i++
+ }
+ return c.i > start
+}
+
+func isNameByte(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '.' || c == '-'
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go
deleted file mode 100644
index 2ec18b739dff..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/go-xmlpath/xmlpath, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/go-xmlpath/xmlpath (exports: ; functions: Compile,MustCompile)
-
-// Package xmlpath is a stub of github.com/go-xmlpath/xmlpath, generated by depstubber.
-package xmlpath
-
-import ()
-
-func Compile(_ string) (*Path, error) {
- return nil, nil
-}
-
-type Iter struct{}
-
-func (_ *Iter) Next() bool {
- return false
-}
-
-func (_ *Iter) Node() *Node {
- return nil
-}
-
-func MustCompile(_ string) *Path {
- return nil
-}
-
-type Node struct{}
-
-func (_ *Node) Bytes() []byte {
- return nil
-}
-
-func (_ *Node) String() string {
- return ""
-}
-
-type Path struct{}
-
-func (_ *Path) Bytes(_ *Node) ([]byte, bool) {
- return nil, false
-}
-
-func (_ *Path) Exists(_ *Node) bool {
- return false
-}
-
-func (_ *Path) Iter(_ *Node) *Iter {
- return nil
-}
-
-func (_ *Path) String(_ *Node) (string, bool) {
- return "", false
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE
new file mode 100644
index 000000000000..37ec93a14fdc
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go
new file mode 100644
index 000000000000..eac1c7664f99
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go
@@ -0,0 +1,133 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package lru implements an LRU cache.
+package lru
+
+import "container/list"
+
+// Cache is an LRU cache. It is not safe for concurrent access.
+type Cache struct {
+ // MaxEntries is the maximum number of cache entries before
+ // an item is evicted. Zero means no limit.
+ MaxEntries int
+
+ // OnEvicted optionally specifies a callback function to be
+ // executed when an entry is purged from the cache.
+ OnEvicted func(key Key, value interface{})
+
+ ll *list.List
+ cache map[interface{}]*list.Element
+}
+
+// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
+type Key interface{}
+
+type entry struct {
+ key Key
+ value interface{}
+}
+
+// New creates a new Cache.
+// If maxEntries is zero, the cache has no limit and it's assumed
+// that eviction is done by the caller.
+func New(maxEntries int) *Cache {
+ return &Cache{
+ MaxEntries: maxEntries,
+ ll: list.New(),
+ cache: make(map[interface{}]*list.Element),
+ }
+}
+
+// Add adds a value to the cache.
+func (c *Cache) Add(key Key, value interface{}) {
+ if c.cache == nil {
+ c.cache = make(map[interface{}]*list.Element)
+ c.ll = list.New()
+ }
+ if ee, ok := c.cache[key]; ok {
+ c.ll.MoveToFront(ee)
+ ee.Value.(*entry).value = value
+ return
+ }
+ ele := c.ll.PushFront(&entry{key, value})
+ c.cache[key] = ele
+ if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
+ c.RemoveOldest()
+ }
+}
+
+// Get looks up a key's value from the cache.
+func (c *Cache) Get(key Key) (value interface{}, ok bool) {
+ if c.cache == nil {
+ return
+ }
+ if ele, hit := c.cache[key]; hit {
+ c.ll.MoveToFront(ele)
+ return ele.Value.(*entry).value, true
+ }
+ return
+}
+
+// Remove removes the provided key from the cache.
+func (c *Cache) Remove(key Key) {
+ if c.cache == nil {
+ return
+ }
+ if ele, hit := c.cache[key]; hit {
+ c.removeElement(ele)
+ }
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *Cache) RemoveOldest() {
+ if c.cache == nil {
+ return
+ }
+ ele := c.ll.Back()
+ if ele != nil {
+ c.removeElement(ele)
+ }
+}
+
+func (c *Cache) removeElement(e *list.Element) {
+ c.ll.Remove(e)
+ kv := e.Value.(*entry)
+ delete(c.cache, kv.key)
+ if c.OnEvicted != nil {
+ c.OnEvicted(kv.key, kv.value)
+ }
+}
+
+// Len returns the number of items in the cache.
+func (c *Cache) Len() int {
+ if c.cache == nil {
+ return 0
+ }
+ return c.ll.Len()
+}
+
+// Clear purges all stored items from the cache.
+func (c *Cache) Clear() {
+ if c.OnEvicted != nil {
+ for _, e := range c.cache {
+ kv := e.Value.(*entry)
+ c.OnEvicted(kv.key, kv.value)
+ }
+ }
+ c.ll = nil
+ c.cache = nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go
new file mode 100644
index 000000000000..3b6e9db4da3b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go
@@ -0,0 +1,74 @@
+package help
+
+/*
+#cgo pkg-config: libxml-2.0
+
+#include
+#include
+#include
+#include
+#include
+
+void printMemoryLeak() { xmlMemDisplay(stdout); }
+*/
+import "C"
+
+import (
+ "sync"
+ "sync/atomic"
+)
+
+/**
+* With regards to Thread Safety
+*
+* xmlInitParser and xmlCleanupParser need to be called *once* each during the
+* lifetime of the program, regardless of how many documents you parse.
+*
+* xmlInitParser should be called at the very beginning before doing anything
+* parser related. Luckly, using the call below, we can guarantee that by
+* making sure it gets called exactly once if anyone uses any gokogiri
+* related functions.
+*
+* xmlCleanupParser is trickier because it also can only be called once, but it
+* should strictly be called at the very end of program execution, after we're
+* sure that no more documents will be parsed. If it's ever called, and a new
+* document is parsed, there is a potential for a segfault.
+*
+* For more information:
+*
+* http://www.xmlsoft.org/threads.html
+* http://www.xmlsoft.org/FAQ.html#Developer (In particular, question #7)
+**/
+
+var once sync.Once
+var cleaned = new(int32)
+
+func LibxmlInitParser() {
+ if called_clean := atomic.LoadInt32(cleaned); called_clean != 0 {
+ panic("LibxmlCleanUpParser has been called. Please make sure you only " +
+ "call it if no more document parsing will take place.")
+ }
+ once.Do(func() { C.xmlInitParser() })
+}
+
+func LibxmlCleanUpParser() {
+ // Because of our test structure, this method is called several
+ // times during a test run (but it should only be called once
+ // during the lifetime of the program).
+ once.Do(func() {
+ atomic.AddInt32(cleaned, 1)
+ C.xmlCleanupParser()
+ })
+}
+
+func LibxmlGetMemoryAllocation() int {
+ return (int)(C.xmlMemBlocks())
+}
+
+func LibxmlCheckMemoryLeak() bool {
+ return (C.xmlMemBlocks() == 0)
+}
+
+func LibxmlReportMemoryLeak() {
+ C.printMemoryLeak()
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go
new file mode 100644
index 000000000000..c3d364f09d00
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go
@@ -0,0 +1,20 @@
+package util
+
+var EmptyStringBytes = []byte{0}
+
+func AppendCStringTerminator(b []byte) []byte {
+ if num := len(b); num > 0 {
+ if b[num-1] != 0 {
+ return append(b, 0)
+ }
+ }
+ return b
+}
+
+func GetCString(b []byte) []byte {
+ b = AppendCStringTerminator(b)
+ if len(b) == 0 {
+ return EmptyStringBytes
+ }
+ return b
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go
new file mode 100644
index 000000000000..ca5ac01534cd
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go
@@ -0,0 +1,37 @@
+package xml
+
+/*
+AttributeNode represents an attribute, which has a name and a value.
+
+AttributeNodes are created by calling SetAttr or SetNsAttr on an element node,
+and retrieved by the Attribute and Attributes functions on an element node.
+
+Note that while mamespace declarations resemble attributes, they are a distinct node type
+and cannot be used or retrieved as an AttributeNode.
+*/
+type AttributeNode struct {
+ *XmlNode
+}
+
+// String returns the value of the attribute.
+func (attrNode *AttributeNode) String() string {
+ return attrNode.Content()
+}
+
+// Value returns the value of the attribute.
+func (attrNode *AttributeNode) Value() string {
+ return attrNode.Content()
+}
+
+//SetValue sets the value of the attribute. Note that the argument will
+// be converted to a string, and automatically XML-escaped when the
+// document is serialized.
+func (attrNode *AttributeNode) SetValue(val interface{}) {
+ attrNode.SetContent(val)
+}
+
+/*
+alias :value :content
+alias :to_s :content
+alias :content= :value=
+*/
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go
new file mode 100644
index 000000000000..d7cc458d157e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go
@@ -0,0 +1,12 @@
+package xml
+
+/* CDataNode represents a CDATA section. This XML node type allows the embedding of unescaped, verbatim text within an XML document.
+
+It is otherwise identical to a TextNode. It is most often used to wrap content that is whitespace-sensitive or likely to contain
+large numbers of less-than or greater-than signs (such as code snippets or example documents).
+
+If you use the XML_PARSE_NOCDATA parsing option, the parser will always present the CDATA sections as TextNodes.
+*/
+type CDataNode struct {
+ *XmlNode
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go
new file mode 100644
index 000000000000..177cf545013e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go
@@ -0,0 +1,5 @@
+package xml
+
+type CommentNode struct {
+ *XmlNode
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go
new file mode 100644
index 000000000000..6a7ec89c6fb2
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go
@@ -0,0 +1,455 @@
+package xml
+
+/*
+#cgo pkg-config: libxml-2.0
+
+#include "helper.h"
+*/
+import "C"
+
+import (
+ "errors"
+ "github.com/jbowtie/gokogiri/help"
+ . "github.com/jbowtie/gokogiri/util"
+ "github.com/jbowtie/gokogiri/xpath"
+ "os"
+ "unsafe"
+)
+
+type Document interface {
+ /* Nokogiri APIs */
+ CreateElementNode(string) *ElementNode
+ CreateCDataNode(string) *CDataNode
+ CreateTextNode(string) *TextNode
+ CreateCommentNode(string) *CommentNode
+ CreatePINode(string, string) *ProcessingInstructionNode
+ ParseFragment([]byte, []byte, ParseOption) (*DocumentFragment, error)
+
+ DocPtr() unsafe.Pointer
+ DocType() NodeType
+ DocRef() Document
+ InputEncoding() []byte
+ OutputEncoding() []byte
+ DocXPathCtx() *xpath.XPath
+ AddUnlinkedNode(unsafe.Pointer)
+ RemoveUnlinkedNode(unsafe.Pointer) bool
+ Free()
+ String() string
+ Root() *ElementNode
+ NodeById(string) *ElementNode
+ BookkeepFragment(*DocumentFragment)
+
+ RecursivelyRemoveNamespaces() error
+ UnparsedEntityURI(string) string
+ Uri() string
+}
+
+// ParseOption values allow you to tune the behaviour of the parsing engine.
+type ParseOption int
+
+const (
+ XML_PARSE_RECOVER ParseOption = 1 << iota // recover on errors
+ XML_PARSE_NOENT // substitute entities
+ XML_PARSE_DTDLOAD // load the external subset
+ XML_PARSE_DTDATTR // default DTD attributes
+ XML_PARSE_DTDVALID // validate with the DTD
+ XML_PARSE_NOERROR // suppress error reports
+ XML_PARSE_NOWARNING // suppress warning reports
+ XML_PARSE_PEDANTIC // pedantic error reporting
+ XML_PARSE_NOBLANKS // remove blank nodes
+ XML_PARSE_SAX1 // use the SAX1 interface internally
+ XML_PARSE_XINCLUDE // Implement XInclude substitition
+ XML_PARSE_NONET // Forbid network access
+ XML_PARSE_NODICT // Do not reuse the context dictionnary
+ XML_PARSE_NSCLEAN // remove redundant namespaces declarations
+ XML_PARSE_NOCDATA // merge CDATA as text nodes
+ XML_PARSE_NOXINCNODE // do not generate XINCLUDE START/END nodes
+ XML_PARSE_COMPACT // compact small text nodes; makes tree read-only
+ XML_PARSE_OLD10 // parse using XML-1.0 before update 5
+ XML_PARSE_NOBASEFIX // do not fixup XINCLUDE xml//base uris
+ XML_PARSE_HUGE // relax any hardcoded limit from the parser
+ XML_PARSE_OLDSAX // parse using SAX2 interface before 2.7.0
+ XML_PARSE_IGNORE_ENC // ignore internal document encoding hint
+ XML_PARSE_BIG_LINES // Store big lines numbers in text PSVI field
+)
+
+//DefaultParseOption provides liberal parsing highly tolerant of invalid documents. Errors and warnings
+// are suppressed and the DTD is not processed.
+const DefaultParseOption ParseOption = XML_PARSE_RECOVER |
+ XML_PARSE_NONET |
+ XML_PARSE_NOERROR |
+ XML_PARSE_NOWARNING
+
+//StrictParseOption provides standard-compliant parsing. The DTD is processed, entity
+// substitions are made, and errors and warnings are reported back.
+const StrictParseOption ParseOption = XML_PARSE_NOENT |
+ XML_PARSE_DTDLOAD |
+ XML_PARSE_DTDATTR |
+ XML_PARSE_NOCDATA
+
+//DefaultEncoding is UTF-8, which is also the default for both libxml2 and Go strings.
+const DefaultEncoding = "utf-8"
+
+var ERR_FAILED_TO_PARSE_XML = errors.New("failed to parse xml input")
+
+/*
+XmlDocument is the primary interface for working with XML documents.
+*/
+type XmlDocument struct {
+ Ptr *C.xmlDoc
+ Me Document
+ Node
+ InEncoding []byte
+ OutEncoding []byte
+ UnlinkedNodes map[*C.xmlNode]bool
+ XPathCtx *xpath.XPath
+ Type NodeType
+ InputLen int
+
+ fragments []*DocumentFragment //save the pointers to free them when the doc is freed
+}
+
+//DefaultEncodingBytes allows us to conveniently pass the DefaultEncoding to various functions that
+// expect the encoding as a byte array.
+var DefaultEncodingBytes = []byte(DefaultEncoding)
+
+const initialFragments = 2
+
+//NewDocument wraps the pointer to the C struct.
+//
+// TODO: this should probably not be exported.
+func NewDocument(p unsafe.Pointer, contentLen int, inEncoding, outEncoding []byte) (doc *XmlDocument) {
+ inEncoding = AppendCStringTerminator(inEncoding)
+ outEncoding = AppendCStringTerminator(outEncoding)
+
+ xmlNode := &XmlNode{Ptr: (*C.xmlNode)(p)}
+ docPtr := (*C.xmlDoc)(p)
+ doc = &XmlDocument{Ptr: docPtr, Node: xmlNode, InEncoding: inEncoding, OutEncoding: outEncoding, InputLen: contentLen}
+ doc.UnlinkedNodes = make(map[*C.xmlNode]bool)
+ doc.XPathCtx = xpath.NewXPath(p)
+ doc.Type = xmlNode.NodeType()
+ doc.fragments = make([]*DocumentFragment, 0, initialFragments)
+ doc.Me = doc
+ xmlNode.Document = doc
+ //runtime.SetFinalizer(doc, (*XmlDocument).Free)
+ return
+}
+
+// Parse creates an XmlDocument from some pre-existing content where the input encoding is known. Byte arrays created from
+// a Go string are utf-8 encoded (you can pass DefaultEncodingBytes in this scenario).
+//
+// If you want to build up a document programmatically, calling CreateEmptyDocument and building it up using the xml.Node
+// interface is a better approach than building a string and calling Parse.
+//
+// If you have an XML file, then ReadFile will automatically determine the encoding according to the XML specification.
+func Parse(content, inEncoding, url []byte, options ParseOption, outEncoding []byte) (doc *XmlDocument, err error) {
+ inEncoding = AppendCStringTerminator(inEncoding)
+ outEncoding = AppendCStringTerminator(outEncoding)
+
+ var docPtr *C.xmlDoc
+ contentLen := len(content)
+
+ if contentLen > 0 {
+ var contentPtr, urlPtr, encodingPtr unsafe.Pointer
+ contentPtr = unsafe.Pointer(&content[0])
+
+ if len(url) > 0 {
+ url = AppendCStringTerminator(url)
+ urlPtr = unsafe.Pointer(&url[0])
+ }
+ if len(inEncoding) > 0 {
+ encodingPtr = unsafe.Pointer(&inEncoding[0])
+ }
+
+ docPtr = C.xmlParse(contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0)
+
+ if docPtr == nil {
+ err = ERR_FAILED_TO_PARSE_XML
+ } else {
+ doc = NewDocument(unsafe.Pointer(docPtr), contentLen, inEncoding, outEncoding)
+ }
+
+ } else {
+ doc = CreateEmptyDocument(inEncoding, outEncoding)
+ }
+ return
+}
+
+// ReadFile loads an XmlDocument from a filename. The encoding declared in the document will be
+// used as the input encoding. If no encoding is declared, the library will use the alogrithm
+// in the XML standard to determine if the document is encoded with UTF-8 or UTF-16.
+func ReadFile(filename string, options ParseOption) (doc *XmlDocument, err error) {
+ // verify the file exists and can be read before we invoke C API
+ _, err = os.Stat(filename)
+ if err != nil {
+ return
+ }
+
+ dataBytes := GetCString([]byte(filename))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ var docPtr *C.xmlDoc
+ docPtr = C.xmlReadFile((*C.char)(dataPtr), nil, C.int(options))
+ if docPtr == nil {
+ err = ERR_FAILED_TO_PARSE_XML
+ } else {
+ var encoding []byte
+ // capture the detected input encoding
+ p := docPtr.encoding
+ if p != nil {
+ encoding = []byte(C.GoString((*C.char)(unsafe.Pointer(p))))
+ }
+ doc = NewDocument(unsafe.Pointer(docPtr), 0, encoding, DefaultEncodingBytes)
+ }
+ return
+}
+
+// Create an empty XML document and return an XmlDocument. The root element, along with
+// any top-level comments or processing instructions, can be added by calling
+// AddChild() on the document itself.
+func CreateEmptyDocument(inEncoding, outEncoding []byte) (doc *XmlDocument) {
+ help.LibxmlInitParser()
+ docPtr := C.newEmptyXmlDoc()
+ doc = NewDocument(unsafe.Pointer(docPtr), 0, inEncoding, outEncoding)
+ return
+}
+
+// DocPtr provides access to the libxml2 structure underlying the document.
+func (document *XmlDocument) DocPtr() (ptr unsafe.Pointer) {
+ ptr = unsafe.Pointer(document.Ptr)
+ return
+}
+
+// DocType returns one of the node type constants, usually XML_DOCUMENT_NODE. This
+// may be of use if you are working with the C API.
+func (document *XmlDocument) DocType() (t NodeType) {
+ t = document.Type
+ return
+}
+
+// DocRef returns the embedded Document interface.
+func (document *XmlDocument) DocRef() (d Document) {
+ d = document.Me
+ return
+}
+
+// InputEncoding is the original encoding of the document.
+func (document *XmlDocument) InputEncoding() (encoding []byte) {
+ encoding = document.InEncoding
+ return
+}
+
+// OutputEncoding is the encoding that will be used when the document is written out.
+// This can be overridden by explicitly specifying an encoding as an argument to any of the
+// output functions.
+func (document *XmlDocument) OutputEncoding() (encoding []byte) {
+ encoding = document.OutEncoding
+ return
+}
+
+// Returns an XPath context that can be used to compile and evaluate XPath
+// expressions.
+//
+// In most cases, you should call the Search or EvalXPath functions instead of
+// handling the context directly.
+func (document *XmlDocument) DocXPathCtx() (ctx *xpath.XPath) {
+ ctx = document.XPathCtx
+ return
+}
+
+func (document *XmlDocument) AddUnlinkedNode(nodePtr unsafe.Pointer) {
+ p := (*C.xmlNode)(nodePtr)
+ document.UnlinkedNodes[p] = true
+}
+
+func (document *XmlDocument) RemoveUnlinkedNode(nodePtr unsafe.Pointer) bool {
+ p := (*C.xmlNode)(nodePtr)
+ if document.UnlinkedNodes[p] {
+ delete(document.UnlinkedNodes, p)
+ return true
+ }
+ return false
+}
+
+func (document *XmlDocument) BookkeepFragment(fragment *DocumentFragment) {
+ document.fragments = append(document.fragments, fragment)
+}
+
+// Root returns the root node of the document. Newly created documents do not
+// have a root node until an element node is added a child of the document.
+//
+// Documents that have multiple root nodes are invalid and the behaviour is
+// not well defined.
+func (document *XmlDocument) Root() (element *ElementNode) {
+ nodePtr := C.xmlDocGetRootElement(document.Ptr)
+ if nodePtr != nil {
+ element = NewNode(unsafe.Pointer(nodePtr), document).(*ElementNode)
+ }
+ return
+}
+
+// Get an element node by the value of its ID attribute. By convention this attribute
+// is named id, but the actual name of the attribute is set by the document's DTD or schema.
+//
+// The value for an ID attribute is guaranteed to be unique within a valid document.
+func (document *XmlDocument) NodeById(id string) (element *ElementNode) {
+ dataBytes := GetCString([]byte(id))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ nodePtr := C.xmlGetID(document.Ptr, (*C.xmlChar)(dataPtr))
+ if nodePtr != nil {
+ idattr := NewNode(unsafe.Pointer(nodePtr), document).(*AttributeNode)
+ element = idattr.Parent().(*ElementNode)
+ }
+ return
+}
+
+/*
+CreateElementNode creates an element node with the specified tag name. It can be
+added as a child of any other element, or as a child of the document itself.
+
+Use SetNamespace if the element node needs to be in a namespace.
+
+Note that valid documents have only one child element, referred to as the root node.
+*/
+func (document *XmlDocument) CreateElementNode(tag string) (element *ElementNode) {
+ tagBytes := GetCString([]byte(tag))
+ tagPtr := unsafe.Pointer(&tagBytes[0])
+ newNodePtr := C.xmlNewNode(nil, (*C.xmlChar)(tagPtr))
+ newNode := NewNode(unsafe.Pointer(newNodePtr), document)
+ element = newNode.(*ElementNode)
+ return
+}
+
+//CreateTextNode creates a text node. It can be added as a child of an element.
+//
+// The data argument is XML-escaped and used as the content of the node.
+func (document *XmlDocument) CreateTextNode(data string) (text *TextNode) {
+ dataBytes := GetCString([]byte(data))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ nodePtr := C.xmlNewText((*C.xmlChar)(dataPtr))
+ if nodePtr != nil {
+ nodePtr.doc = (*C.xmlDoc)(document.DocPtr())
+ text = NewNode(unsafe.Pointer(nodePtr), document).(*TextNode)
+ }
+ return
+}
+
+//CreateCDataNode creates a CDATA node. CDATA nodes can
+// only be children of an element.
+//
+// The data argument will become the content of the newly created node.
+func (document *XmlDocument) CreateCDataNode(data string) (cdata *CDataNode) {
+ dataLen := len(data)
+ dataBytes := GetCString([]byte(data))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ nodePtr := C.xmlNewCDataBlock(document.Ptr, (*C.xmlChar)(dataPtr), C.int(dataLen))
+ if nodePtr != nil {
+ cdata = NewNode(unsafe.Pointer(nodePtr), document).(*CDataNode)
+ }
+ return
+}
+
+//CreateCommentNode creates a comment node. Comment nodes can
+// be children of an element or of the document itself.
+//
+// The data argument will become the content of the comment.
+func (document *XmlDocument) CreateCommentNode(data string) (comment *CommentNode) {
+ dataBytes := GetCString([]byte(data))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ nodePtr := C.xmlNewComment((*C.xmlChar)(dataPtr))
+ if nodePtr != nil {
+ comment = NewNode(unsafe.Pointer(nodePtr), document).(*CommentNode)
+ }
+ return
+}
+
+//CreatePINode creates a processing instruction node with the specified name and data.
+// Processing instruction nodes can be children of an element or of the document itself.
+//
+// While it's common to use an attribute-like syntax for processing instructions, the data
+// is actually an arbitrary string that you will need to generate or parse yourself.
+func (document *XmlDocument) CreatePINode(name, data string) (pi *ProcessingInstructionNode) {
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+ dataBytes := GetCString([]byte(data))
+ dataPtr := unsafe.Pointer(&dataBytes[0])
+ nodePtr := C.xmlNewDocPI(document.Ptr, (*C.xmlChar)(namePtr), (*C.xmlChar)(dataPtr))
+ if nodePtr != nil {
+ pi = NewNode(unsafe.Pointer(nodePtr), document).(*ProcessingInstructionNode)
+ }
+ return
+}
+
+func (document *XmlDocument) ParseFragment(input, url []byte, options ParseOption) (fragment *DocumentFragment, err error) {
+ root := document.Root()
+ if root == nil {
+ fragment, err = parsefragment(document, nil, input, url, options)
+ } else {
+ fragment, err = parsefragment(document, root.XmlNode, input, url, options)
+ }
+ return
+}
+
+// Return the value of an NDATA entity declared in the DTD. If there is no such entity or
+// the value cannot be encoded as a valid URI, an empty string is returned.
+//
+// Note that this library assumes you already know the name of entity and does not
+// expose any way of getting the list of entities.
+func (document *XmlDocument) UnparsedEntityURI(name string) (val string) {
+ if name == "" {
+ return
+ }
+
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+ entity := C.xmlGetDocEntity(document.Ptr, (*C.xmlChar)(namePtr))
+ if entity == nil {
+ return
+ }
+
+ // unlike entity.content (which returns the raw, unprocessed string value of the entity),
+ // it looks like entity.URI includes any escaping needed to treat the value as a URI.
+ valPtr := unsafe.Pointer(entity.URI)
+ if valPtr == nil {
+ return
+ }
+
+ val = C.GoString((*C.char)(valPtr))
+ return
+}
+
+// Free the C structures associated with this document.
+func (document *XmlDocument) Free() {
+ //must free the xpath context before freeing the fragments or unlinked nodes
+ //otherwise, it causes memory leaks and crashes when dealing with very large documents (a few MB)
+ if document.XPathCtx != nil {
+ document.XPathCtx.Free()
+ document.XPathCtx = nil
+ }
+ //must clear the fragments first
+ //because the nodes are put in the unlinked list
+ if document.fragments != nil {
+ for _, fragment := range document.fragments {
+ fragment.Remove()
+ }
+ }
+ document.fragments = nil
+ var p *C.xmlNode
+ if document.UnlinkedNodes != nil {
+ for p = range document.UnlinkedNodes {
+ C.xmlFreeNode(p)
+ }
+ }
+ document.UnlinkedNodes = nil
+ if document.Ptr != nil {
+ C.xmlFreeDoc(document.Ptr)
+ document.Ptr = nil
+ }
+}
+
+/* Uri returns the URI of the document - typically this is the filename if ReadFile was used to parse
+the document.
+*/
+func (document *XmlDocument) Uri() (val string) {
+ val = C.GoString((*C.char)(unsafe.Pointer(document.Ptr.URL)))
+ return
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go
new file mode 100644
index 000000000000..da6a92dcc4c6
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go
@@ -0,0 +1,5 @@
+package xml
+
+type ElementNode struct {
+ *XmlNode
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go
new file mode 100644
index 000000000000..7fc43f321460
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go
@@ -0,0 +1,115 @@
+package xml
+
+//#include "helper.h"
+import "C"
+import (
+ "errors"
+ . "github.com/jbowtie/gokogiri/util"
+ "unsafe"
+)
+
+type DocumentFragment struct {
+ Node
+ InEncoding []byte
+ OutEncoding []byte
+}
+
+var (
+ fragmentWrapperStart = []byte("")
+ fragmentWrapperEnd = []byte("")
+)
+
+var ErrFailParseFragment = errors.New("failed to parse xml fragment")
+var ErrEmptyFragment = errors.New("empty xml fragment")
+
+const initChildrenNumber = 4
+
+func parsefragment(document Document, node *XmlNode, content, url []byte, options ParseOption) (fragment *DocumentFragment, err error) {
+ //wrap the content before parsing
+ content = append(fragmentWrapperStart, content...)
+ content = append(content, fragmentWrapperEnd...)
+
+ //set up pointers before calling the C function
+ var contentPtr, urlPtr unsafe.Pointer
+ contentPtr = unsafe.Pointer(&content[0])
+ contentLen := len(content)
+ if len(url) > 0 {
+ url = AppendCStringTerminator(url)
+ urlPtr = unsafe.Pointer(&url[0])
+ }
+
+ var rootElementPtr *C.xmlNode
+
+ if node == nil {
+ inEncoding := document.InputEncoding()
+ var encodingPtr unsafe.Pointer
+ if len(inEncoding) > 0 {
+ encodingPtr = unsafe.Pointer(&inEncoding[0])
+ }
+ rootElementPtr = C.xmlParseFragmentAsDoc(document.DocPtr(), contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0)
+
+ } else {
+ rootElementPtr = C.xmlParseFragment(node.NodePtr(), contentPtr, C.int(contentLen), urlPtr, C.int(options), nil, 0)
+ }
+
+ //Note we've parsed the fragment within the given document
+ //the root is not the root of the document; rather it's the root of the subtree from the fragment
+ root := NewNode(unsafe.Pointer(rootElementPtr), document)
+
+ //the fragment was in invalid
+ if root == nil {
+ err = ErrFailParseFragment
+ return
+ }
+
+ fragment = &DocumentFragment{}
+ fragment.Node = root
+ fragment.InEncoding = document.InputEncoding()
+ fragment.OutEncoding = document.OutputEncoding()
+
+ document.BookkeepFragment(fragment)
+ return
+}
+
+func ParseFragment(content, inEncoding, url []byte, options ParseOption, outEncoding []byte) (fragment *DocumentFragment, err error) {
+ inEncoding = AppendCStringTerminator(inEncoding)
+ outEncoding = AppendCStringTerminator(outEncoding)
+ document := CreateEmptyDocument(inEncoding, outEncoding)
+ fragment, err = parsefragment(document, nil, content, url, options)
+ return
+}
+
+func (fragment *DocumentFragment) Remove() {
+ fragment.Node.Remove()
+}
+
+func (fragment *DocumentFragment) Children() []Node {
+ nodes := make([]Node, 0, initChildrenNumber)
+ child := fragment.FirstChild()
+ for ; child != nil; child = child.NextSibling() {
+ nodes = append(nodes, child)
+ }
+ return nodes
+}
+
+func (fragment *DocumentFragment) ToBuffer(outputBuffer []byte) []byte {
+ var b []byte
+ var size int
+ for _, node := range fragment.Children() {
+ if docType := node.MyDocument().DocType(); docType == XML_HTML_DOCUMENT_NODE {
+ b, size = node.ToHtml(fragment.OutEncoding, nil)
+ } else {
+ b, size = node.ToXml(fragment.OutEncoding, nil)
+ }
+ outputBuffer = append(outputBuffer, b[:size]...)
+ }
+ return outputBuffer
+}
+
+func (fragment *DocumentFragment) String() string {
+ b := fragment.ToBuffer(nil)
+ if b == nil {
+ return ""
+ }
+ return string(b)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c
new file mode 100644
index 000000000000..e5cfa4ddbba0
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c
@@ -0,0 +1,195 @@
+#include
+#include "helper.h"
+
+//internal callback functions
+int xml_write_callback(void *ctx, char *buffer, int len) {
+ if (len > 0) {
+ xmlNodeWriteCallback(buffer, len);
+ }
+ return len;
+}
+
+int close_callback(void * ctx) {
+ return 0;
+}
+
+xmlDoc* newEmptyXmlDoc() {
+ return xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION);
+}
+
+xmlElementType getNodeType(xmlNode *node) { return node->type; }
+
+void xmlFreeChars(char *buffer) {
+ if (buffer) {
+ xmlFree((xmlChar*)buffer);
+ }
+}
+
+char *xmlDocDumpToString(xmlDoc *doc, void *encoding, int format) {
+ xmlChar *buff;
+ int buffersize;
+ xmlDocDumpFormatMemoryEnc(doc, &buff, &buffersize, (char*)encoding, format);
+ return (char*)buff;
+}
+
+char *htmlDocDumpToString(htmlDocPtr doc, int format) {
+ xmlChar *buff;
+ int buffersize;
+ htmlDocDumpMemoryFormat(doc, &buff, &buffersize, format);
+ return (char*)buff;
+}
+
+xmlDoc* xmlParse(void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len) {
+ const char *c_buffer = (char*)buffer;
+ const char *c_url = (char*)url;
+ const char *c_encoding = (char*)encoding;
+ xmlDoc *doc = NULL;
+
+ xmlResetLastError();
+ doc = xmlReadMemory(c_buffer, buffer_len, c_url, c_encoding, options);
+
+ if(doc == NULL) {
+ xmlErrorPtr error;
+ xmlFreeDoc(doc);
+ error = xmlGetLastError();
+ if(error != NULL && error_buffer != NULL && error->level >= XML_ERR_ERROR) {
+ char *c_error_buffer = (char*)error_buffer;
+ if (error->message != NULL) {
+ strncpy(c_error_buffer, error->message, error_buffer_len-1);
+ c_error_buffer[error_buffer_len-1] = '\0';
+ }
+ else {
+ //snprintf(c_error_buffer, error_buffer_len, "xml parsing error:%d", error->code);
+ }
+ }
+ }
+ return doc;
+}
+
+xmlNode* xmlParseFragment(void *doc, void *buffer, int buffer_len, void *url, int options, void *error_buffer, int error_buffer_len) {
+ xmlNodePtr root_element = NULL;
+ xmlParserErrors errCode;
+ errCode = xmlParseInNodeContext((xmlNodePtr)doc, buffer, buffer_len, options, &root_element);
+ if (errCode != XML_ERR_OK) {
+ if (error_buffer != NULL && error_buffer_len > 0) {
+ //char *c_error_buffer = (char*)error_buffer;
+ //snprintf(c_error_buffer, error_buffer_len, "xml fragemnt parsing error (xmlParserErrors):%d", errCode);
+ }
+ printf("errorcode %d\n", errCode);
+ return NULL;
+ }
+ return root_element;
+}
+
+xmlNode* xmlParseFragmentAsDoc(void *doc, void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len) {
+ xmlDoc* tmpDoc = NULL;
+ xmlNode* tmpRoot = NULL;
+ tmpDoc = xmlReadMemory((char*)buffer, buffer_len, (char*)url, (char*)encoding, options);
+ if (tmpDoc == NULL) {
+ return NULL;
+ }
+ tmpRoot = xmlDocGetRootElement(tmpDoc);
+ if (tmpRoot == NULL) {
+ return NULL;
+ }
+ tmpRoot = xmlDocCopyNode(tmpRoot, doc, 1);
+ xmlFreeDoc(tmpDoc);
+ return tmpRoot;
+}
+
+void xmlSetContent(void *n, char *content) {
+ xmlNode *node = (xmlNode*)n;
+ xmlNode *child = node->children;
+ xmlNode *next = NULL;
+ unsigned char *encoded = xmlEncodeSpecialChars(node->doc, (xmlChar*)content);
+ if (encoded) {
+ while (child) {
+ next = child->next ;
+ xmlUnlinkNode(child);
+ //xmlFreeNode(child);
+ xmlUnlinkNodeCallback(child);
+ child = next ;
+ }
+ xmlNodeSetContent(node, (xmlChar*)encoded);
+ xmlFree(encoded);
+ }
+}
+
+int xmlUnlinkNodeWithCheck(xmlNode *node) {
+ if (xmlNodePtrCheck(node->parent)) {
+ xmlUnlinkNode(node);
+ return 1;
+ }
+ return 0;
+}
+
+int xmlNodePtrCheck(void *node) {
+ if (node == (void*)(-1))
+ return 0;
+ return 1;
+}
+
+int xmlSaveNode(void *node, void *encoding, int options) {
+ xmlSaveCtxtPtr savectx;
+ const char *c_encoding = (char*)encoding;
+
+ savectx = xmlSaveToIO(
+ (xmlOutputWriteCallback)xml_write_callback,
+ (xmlOutputCloseCallback)close_callback,
+ NULL,
+ encoding,
+ options
+ );
+ xmlSaveTree(savectx, (xmlNode*)node);
+ return xmlSaveClose(savectx);
+}
+
+void removeNamespace(xmlNs **source, xmlNs *target) {
+ xmlNs *ns, *prevns = NULL;
+
+ for (ns = *source; ns; ns = ns->next) {
+ if (ns == target) {
+ if (!prevns) {
+ // we are the first element
+ *source = ns->next;
+ } else {
+ prevns->next = ns->next;
+ }
+
+ break;
+ }
+
+ prevns = ns;
+ }
+}
+
+void removeDefaultNamespace(xmlNs *ns, xmlNode *node) {
+ removeNamespace(&node->nsDef, ns);
+
+ xmlAttr *attr;
+
+ for (attr = node->properties; attr; attr = attr->next) {
+ if (!attr->ns)
+ continue;
+
+ removeNamespace(&attr->ns, ns);
+ }
+
+ if (node->ns == ns)
+ node->ns = NULL;
+
+ xmlNode *child;
+
+ for (child = xmlFirstElementChild(node); child; child = xmlNextElementSibling(child)) {
+ removeDefaultNamespace(ns, child);
+ }
+}
+
+void xmlRemoveDefaultNamespace(xmlNode *node) {
+ if (node->ns && node->ns->prefix) {
+ // not a default namespace
+ return;
+ }
+
+ removeDefaultNamespace(node->ns, node);
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h
new file mode 100644
index 000000000000..16d3a5b97992
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h
@@ -0,0 +1,37 @@
+#ifndef __CHELPER_H__
+#define __CHELPER_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+xmlDoc* xmlParse(void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int errror_buffer_len);
+xmlNode* xmlParseFragment(void* doc, void *buffer, int buffer_len, void *url, int options, void *error_buffer, int error_buffer_len);
+xmlNode* xmlParseFragmentAsDoc(void *doc, void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len);
+int xmlSaveNode(void *node, void *encoding, int options);
+void xmlRemoveDefaultNamespace(xmlNode *node);
+
+void xmlSetContent(void *node, char *content);
+
+xmlDoc* newEmptyXmlDoc();
+xmlElementType getNodeType(xmlNode *node);
+char *xmlDocDumpToString(xmlDoc *doc, void *encoding, int format);
+char *htmlDocDumpToString(xmlDoc *doc, int format);
+void xmlFreeChars(char *buffer);
+int xmlUnlinkNodeWithCheck(xmlNode *node);
+int xmlNodePtrCheck(void *node);
+void xmlNodeWriteCallback(void *data, int data_len);
+void xmlUnlinkNodeCallback(void *nodePtr);
+
+typedef struct XmlBufferContext {
+ void *obj;
+ char *buffer;
+ int buffer_len;
+ int data_size;
+} XmlBufferContext;
+
+#endif //__CHELPER_H__
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go
new file mode 100644
index 000000000000..d94b02820252
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go
@@ -0,0 +1,1186 @@
+package xml
+
+//#include "helper.h"
+//#include
+import "C"
+
+import (
+ "errors"
+ "strconv"
+ "sync"
+ "unsafe"
+
+ . "github.com/jbowtie/gokogiri/util"
+ "github.com/jbowtie/gokogiri/xpath"
+)
+
+var (
+ ERR_UNDEFINED_COERCE_PARAM = errors.New("unexpected parameter type in coerce")
+ ERR_UNDEFINED_SET_CONTENT_PARAM = errors.New("unexpected parameter type in SetContent")
+ ERR_UNDEFINED_SEARCH_PARAM = errors.New("unexpected parameter type in Search")
+ ERR_CANNOT_MAKE_DUCMENT_AS_CHILD = errors.New("cannot add a document node as a child")
+ ERR_CANNOT_COPY_TEXT_NODE_WHEN_ADD_CHILD = errors.New("cannot copy a text node when adding it")
+)
+
+// NodeType is an enumeration that indicates the type of XmlNode.
+type NodeType int
+
+const (
+ XML_ELEMENT_NODE NodeType = iota + 1
+ XML_ATTRIBUTE_NODE
+ XML_TEXT_NODE
+ XML_CDATA_SECTION_NODE
+ XML_ENTITY_REF_NODE
+ XML_ENTITY_NODE
+ XML_PI_NODE
+ XML_COMMENT_NODE
+ XML_DOCUMENT_NODE
+ XML_DOCUMENT_TYPE_NODE
+ XML_DOCUMENT_FRAG_NODE
+ XML_NOTATION_NODE
+ XML_HTML_DOCUMENT_NODE
+ XML_DTD_NODE
+ XML_ELEMENT_DECL
+ XML_ATTRIBUTE_DECL
+ XML_ENTITY_DECL
+ XML_NAMESPACE_DECL
+ XML_XINCLUDE_START
+ XML_XINCLUDE_END
+ XML_DOCB_DOCUMENT_NODE
+)
+
+// SerializationOption is a set of flags used to control how a node is written out.
+type SerializationOption int
+
+const (
+ XML_SAVE_FORMAT SerializationOption = 1 << iota // format save output
+ XML_SAVE_NO_DECL //drop the xml declaration
+ XML_SAVE_NO_EMPTY //no empty tags
+ XML_SAVE_NO_XHTML //disable XHTML1 specific rules
+ XML_SAVE_XHTML //force XHTML1 specific rules
+ XML_SAVE_AS_XML //force XML serialization on HTML doc
+ XML_SAVE_AS_HTML //force HTML serialization on XML doc
+ XML_SAVE_WSNONSIG //format with non-significant whitespace
+)
+
+// NamespaceDeclaration represents a namespace declaration, providing both the prefix and the URI of the namespace.
+// It is returned by the DeclaredNamespaces function.
+type NamespaceDeclaration struct {
+ Prefix string
+ Uri string
+}
+
+type Node interface {
+ NodePtr() unsafe.Pointer
+ ResetNodePtr()
+ MyDocument() Document
+
+ IsValid() bool
+
+ ParseFragment([]byte, []byte, ParseOption) (*DocumentFragment, error)
+ LineNumber() int
+
+ //
+ NodeType() NodeType
+ NextSibling() Node
+ PreviousSibling() Node
+
+ Parent() Node
+ FirstChild() Node
+ LastChild() Node
+ CountChildren() int
+ Attributes() map[string]*AttributeNode
+ AttributeList() []*AttributeNode
+
+ Coerce(interface{}) ([]Node, error)
+
+ AddChild(interface{}) error
+ AddPreviousSibling(interface{}) error
+ AddNextSibling(interface{}) error
+ InsertBefore(interface{}) error
+ InsertAfter(interface{}) error
+ InsertBegin(interface{}) error
+ InsertEnd(interface{}) error
+ SetInnerHtml(interface{}) error
+ SetChildren(interface{}) error
+ Replace(interface{}) error
+ Wrap(string) error
+
+ SetContent(interface{}) error
+
+ Name() string
+ SetName(string)
+
+ Attr(string) string
+ SetAttr(string, string) string
+ SetNsAttr(string, string, string) string
+ Attribute(string) *AttributeNode
+
+ Path() string
+
+ Duplicate(int) Node
+ DuplicateTo(Document, int) Node
+
+ Search(interface{}) ([]Node, error)
+ SearchWithVariables(interface{}, xpath.VariableScope) ([]Node, error)
+ EvalXPath(interface{}, xpath.VariableScope) (interface{}, error)
+ EvalXPathAsBoolean(interface{}, xpath.VariableScope) bool
+
+ Unlink()
+ Remove()
+ ResetChildren()
+
+ SerializeWithFormat(SerializationOption, []byte, []byte) ([]byte, int)
+ ToXml([]byte, []byte) ([]byte, int)
+ ToUnformattedXml() string
+ ToHtml([]byte, []byte) ([]byte, int)
+ ToBuffer([]byte) []byte
+ String() string
+ Content() string
+ InnerHtml() string
+
+ RecursivelyRemoveNamespaces() error
+ Namespace() string
+ SetNamespace(string, string)
+ DeclareNamespace(string, string)
+ RemoveDefaultNamespace()
+ DeclaredNamespaces() []NamespaceDeclaration
+}
+
+//run out of memory
+var ErrTooLarge = errors.New("Output buffer too large")
+
+//pre-allocate a buffer for serializing the document
+const initialOutputBufferSize = 10 //100K
+
+/*
+XmlNode implements the Node interface, and as such is the heart of the API.
+*/
+type XmlNode struct {
+ Ptr *C.xmlNode
+ Document
+ valid bool
+}
+
+type WriteBuffer struct {
+ Node *XmlNode
+ Buffer []byte
+ Offset int
+}
+
+// NewNode takes a C pointer from the libxml2 library and returns a Node instance of
+// the appropriate type.
+func NewNode(nodePtr unsafe.Pointer, document Document) (node Node) {
+ if nodePtr == nil {
+ return nil
+ }
+ xmlNode := &XmlNode{
+ Ptr: (*C.xmlNode)(nodePtr),
+ Document: document,
+ valid: true,
+ }
+ nodeType := NodeType(C.getNodeType((*C.xmlNode)(nodePtr)))
+
+ switch nodeType {
+ default:
+ node = xmlNode
+ case XML_ATTRIBUTE_NODE:
+ node = &AttributeNode{XmlNode: xmlNode}
+ case XML_ELEMENT_NODE:
+ node = &ElementNode{XmlNode: xmlNode}
+ case XML_CDATA_SECTION_NODE:
+ node = &CDataNode{XmlNode: xmlNode}
+ case XML_COMMENT_NODE:
+ node = &CommentNode{XmlNode: xmlNode}
+ case XML_PI_NODE:
+ node = &ProcessingInstructionNode{XmlNode: xmlNode}
+ case XML_TEXT_NODE:
+ node = &TextNode{XmlNode: xmlNode}
+ }
+ return
+}
+
+func (xmlNode *XmlNode) coerce(data interface{}) (nodes []Node, err error) {
+ switch t := data.(type) {
+ default:
+ err = ERR_UNDEFINED_COERCE_PARAM
+ case []Node:
+ nodes = t
+ case *DocumentFragment:
+ nodes = t.Children()
+ case string:
+ f, err := xmlNode.MyDocument().ParseFragment([]byte(t), nil, DefaultParseOption)
+ if err == nil {
+ nodes = f.Children()
+ }
+ case []byte:
+ f, err := xmlNode.MyDocument().ParseFragment(t, nil, DefaultParseOption)
+ if err == nil {
+ nodes = f.Children()
+ }
+ }
+ return
+}
+
+func (xmlNode *XmlNode) Coerce(data interface{}) (nodes []Node, err error) {
+ return xmlNode.coerce(data)
+}
+
+// Add a node as a child of the current node.
+// Passing in a nodeset will add all the nodes as children of the current node.
+func (xmlNode *XmlNode) AddChild(data interface{}) (err error) {
+ switch t := data.(type) {
+ default:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for _, node := range nodes {
+ if err = xmlNode.addChild(node); err != nil {
+ break
+ }
+ }
+ }
+ case *DocumentFragment:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for _, node := range nodes {
+ if err = xmlNode.addChild(node); err != nil {
+ break
+ }
+ }
+ }
+ case Node:
+ err = xmlNode.addChild(t)
+ }
+ return
+}
+
+// Insert a node immediately before this node in the document.
+// Passing in a nodeset will add all the nodes, in order.
+func (xmlNode *XmlNode) AddPreviousSibling(data interface{}) (err error) {
+ switch t := data.(type) {
+ default:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for _, node := range nodes {
+ if err = xmlNode.addPreviousSibling(node); err != nil {
+ break
+ }
+ }
+ }
+ case *DocumentFragment:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for _, node := range nodes {
+ if err = xmlNode.addPreviousSibling(node); err != nil {
+ break
+ }
+ }
+ }
+ case Node:
+ err = xmlNode.addPreviousSibling(t)
+ }
+ return
+}
+
+// Insert a node immediately after this node in the document.
+// Passing in a nodeset will add all the nodes, in order.
+func (xmlNode *XmlNode) AddNextSibling(data interface{}) (err error) {
+ switch t := data.(type) {
+ default:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for i := len(nodes) - 1; i >= 0; i-- {
+ node := nodes[i]
+ if err = xmlNode.addNextSibling(node); err != nil {
+ break
+ }
+ }
+ }
+ case *DocumentFragment:
+ if nodes, err := xmlNode.coerce(data); err == nil {
+ for i := len(nodes) - 1; i >= 0; i-- {
+ node := nodes[i]
+ if err = xmlNode.addNextSibling(node); err != nil {
+ break
+ }
+ }
+ }
+ case Node:
+ err = xmlNode.addNextSibling(t)
+ }
+ return
+}
+
+func (xmlNode *XmlNode) ResetNodePtr() {
+ xmlNode.Ptr = nil
+ return
+}
+
+// Returns true if the node is valid. Nodes become
+// invalid when Remove() is called.
+func (xmlNode *XmlNode) IsValid() bool {
+ return xmlNode.valid
+}
+
+// Return the document containing this node. Removed or unlinked
+// nodes still have a document associated with them.
+func (xmlNode *XmlNode) MyDocument() (document Document) {
+ document = xmlNode.Document.DocRef()
+ return
+}
+
+// NodePtr returns a pointer to the underlying C struct.
+func (xmlNode *XmlNode) NodePtr() (p unsafe.Pointer) {
+ p = unsafe.Pointer(xmlNode.Ptr)
+ return
+}
+
+func (xmlNode *XmlNode) NodeType() (nodeType NodeType) {
+ nodeType = NodeType(C.getNodeType(xmlNode.Ptr))
+ return
+}
+
+// Path returns an XPath expression that can be used to
+// select this node in the document.
+func (xmlNode *XmlNode) Path() (path string) {
+ pathPtr := C.xmlGetNodePath(xmlNode.Ptr)
+ if pathPtr != nil {
+ p := (*C.char)(unsafe.Pointer(pathPtr))
+ defer C.xmlFreeChars(p)
+ path = C.GoString(p)
+ }
+ return
+}
+
+// NextSibling returns the next sibling (if any) of the current node.
+// It is often used when iterating over the children of a node.
+func (xmlNode *XmlNode) NextSibling() Node {
+ siblingPtr := (*C.xmlNode)(xmlNode.Ptr.next)
+ return NewNode(unsafe.Pointer(siblingPtr), xmlNode.Document)
+}
+
+// PreviousSibling returns the previous sibling (if any) of the current node.
+// It is often used when iterating over the children of a node in reverse.
+func (xmlNode *XmlNode) PreviousSibling() Node {
+ siblingPtr := (*C.xmlNode)(xmlNode.Ptr.prev)
+ return NewNode(unsafe.Pointer(siblingPtr), xmlNode.Document)
+}
+
+// CountChildren returns the number of child nodes.
+func (xmlNode *XmlNode) CountChildren() int {
+ return int(C.xmlLsCountNode(xmlNode.Ptr))
+}
+
+func (xmlNode *XmlNode) FirstChild() Node {
+ return NewNode(unsafe.Pointer(xmlNode.Ptr.children), xmlNode.Document)
+}
+
+func (xmlNode *XmlNode) LastChild() Node {
+ return NewNode(unsafe.Pointer(xmlNode.Ptr.last), xmlNode.Document)
+}
+
+/*
+Parent returns the parent of the current node (or nil if there isn't one).
+This will always be an element or document node, as those are the only node types
+that can have children.
+*/
+func (xmlNode *XmlNode) Parent() Node {
+ if C.xmlNodePtrCheck(unsafe.Pointer(xmlNode.Ptr.parent)) == C.int(0) {
+ return nil
+ }
+ return NewNode(unsafe.Pointer(xmlNode.Ptr.parent), xmlNode.Document)
+}
+
+func (xmlNode *XmlNode) ResetChildren() {
+ var p unsafe.Pointer
+ for childPtr := xmlNode.Ptr.children; childPtr != nil; {
+ nextPtr := childPtr.next
+ p = unsafe.Pointer(childPtr)
+ C.xmlUnlinkNodeWithCheck((*C.xmlNode)(p))
+ xmlNode.Document.AddUnlinkedNode(p)
+ childPtr = nextPtr
+ }
+}
+
+var (
+ contentNode *XmlNode
+ contentMutex sync.Mutex
+)
+
+func (xmlNode *XmlNode) SetContent(content interface{}) (err error) {
+ switch data := content.(type) {
+ default:
+ err = ERR_UNDEFINED_SET_CONTENT_PARAM
+ case string:
+ contentMutex.Lock()
+ contentNode = xmlNode
+ C.xmlSetContent(unsafe.Pointer(xmlNode.Ptr), C.CString(data))
+ contentNode = nil
+ contentMutex.Unlock()
+ case []byte:
+ err = xmlNode.SetContent(string(data))
+ }
+ return
+}
+
+func (xmlNode *XmlNode) InsertBefore(data interface{}) (err error) {
+ err = xmlNode.AddPreviousSibling(data)
+ return
+}
+
+func (xmlNode *XmlNode) InsertAfter(data interface{}) (err error) {
+ err = xmlNode.AddNextSibling(data)
+ return
+}
+
+func (xmlNode *XmlNode) InsertBegin(data interface{}) (err error) {
+ if parent := xmlNode.Parent(); parent != nil {
+ if last := parent.LastChild(); last != nil {
+ err = last.AddPreviousSibling(data)
+ }
+ }
+ return
+}
+
+func (xmlNode *XmlNode) InsertEnd(data interface{}) (err error) {
+ if parent := xmlNode.Parent(); parent != nil {
+ if first := parent.FirstChild(); first != nil {
+ err = first.AddPreviousSibling(data)
+ }
+ }
+ return
+}
+
+func (xmlNode *XmlNode) SetChildren(data interface{}) (err error) {
+ nodes, err := xmlNode.coerce(data)
+ if err != nil {
+ return
+ }
+ xmlNode.ResetChildren()
+ err = xmlNode.AddChild(nodes)
+ return nil
+}
+
+func (xmlNode *XmlNode) SetInnerHtml(data interface{}) (err error) {
+ err = xmlNode.SetChildren(data)
+ return
+}
+
+func (xmlNode *XmlNode) Replace(data interface{}) (err error) {
+ err = xmlNode.AddPreviousSibling(data)
+ if err != nil {
+ return
+ }
+ xmlNode.Remove()
+ return
+}
+
+// Return a document-ordered list of attribute nodes.
+func (xmlNode *XmlNode) AttributeList() (attributes []*AttributeNode) {
+ for prop := xmlNode.Ptr.properties; prop != nil; prop = prop.next {
+ if prop.name != nil {
+ attrPtr := unsafe.Pointer(prop)
+ attributeNode := NewNode(attrPtr, xmlNode.Document)
+ if attr, ok := attributeNode.(*AttributeNode); ok {
+ attributes = append(attributes, attr)
+ }
+ }
+ }
+ return
+}
+
+// Return the attribute nodes indexed by name.
+func (xmlNode *XmlNode) Attributes() (attributes map[string]*AttributeNode) {
+ attributes = make(map[string]*AttributeNode)
+ for prop := xmlNode.Ptr.properties; prop != nil; prop = prop.next {
+ if prop.name != nil {
+ namePtr := unsafe.Pointer(prop.name)
+ name := C.GoString((*C.char)(namePtr))
+ attrPtr := unsafe.Pointer(prop)
+ attributeNode := NewNode(attrPtr, xmlNode.Document)
+ if attr, ok := attributeNode.(*AttributeNode); ok {
+ attributes[name] = attr
+ }
+ }
+ }
+ return
+}
+
+// Return the attribute node, or nil if the attribute does not exist.
+func (xmlNode *XmlNode) Attribute(name string) (attribute *AttributeNode) {
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+ attrPtr := C.xmlHasNsProp(xmlNode.Ptr, (*C.xmlChar)(namePtr), nil)
+ if attrPtr == nil {
+ return
+ } else {
+ node := NewNode(unsafe.Pointer(attrPtr), xmlNode.Document)
+ if node, ok := node.(*AttributeNode); ok {
+ attribute = node
+ }
+ }
+ return
+}
+
+// Attr returns the value of an attribute.
+//
+// If you need to check for the existence of an attribute,
+// use Attribute.
+func (xmlNode *XmlNode) Attr(name string) (val string) {
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+ valPtr := C.xmlGetProp(xmlNode.Ptr, (*C.xmlChar)(namePtr))
+ if valPtr == nil {
+ return
+ }
+ p := unsafe.Pointer(valPtr)
+ defer C.xmlFreeChars((*C.char)(p))
+ val = C.GoString((*C.char)(p))
+ return
+}
+
+// SetAttr sets the value of an attribute. If the attribute is in a namespace,
+// use SetNsAttr instead.
+//
+// While this call accepts QNames for the name parameter, it does not check
+// their validity.
+//
+// Attributes such as "xml:lang" or "xml:space" are not is a formal namespace
+// and should be set by calling SetAttr with the prefix as part of the name.
+func (xmlNode *XmlNode) SetAttr(name, value string) (val string) {
+ val = value
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+
+ valueBytes := GetCString([]byte(value))
+ valuePtr := unsafe.Pointer(&valueBytes[0])
+
+ C.xmlSetProp(xmlNode.Ptr, (*C.xmlChar)(namePtr), (*C.xmlChar)(valuePtr))
+ return
+}
+
+// SetNsAttr sets the value of a namespaced attribute.
+//
+// Attributes such as "xml:lang" or "xml:space" are not is a formal namespace
+// and should be set by calling SetAttr with the xml prefix as part of the name.
+//
+// The namespace should already be declared and in-scope when SetNsAttr is called.
+// This restriction will be lifted in a future version.
+func (xmlNode *XmlNode) SetNsAttr(href, name, value string) (val string) {
+ val = value
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+
+ valueBytes := GetCString([]byte(value))
+ valuePtr := unsafe.Pointer(&valueBytes[0])
+
+ hrefBytes := GetCString([]byte(href))
+ hrefPtr := unsafe.Pointer(&hrefBytes[0])
+
+ ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr))
+ if ns == nil {
+ return
+ }
+
+ C.xmlSetNsProp(xmlNode.Ptr, ns, (*C.xmlChar)(namePtr), (*C.xmlChar)(valuePtr))
+ return
+}
+
+// Search for nodes that match an XPath. This is the simplest way to look for nodes.
+func (xmlNode *XmlNode) Search(data interface{}) (result []Node, err error) {
+ switch data := data.(type) {
+ default:
+ err = ERR_UNDEFINED_SEARCH_PARAM
+ case string:
+ if xpathExpr := xpath.Compile(data); xpathExpr != nil {
+ defer xpathExpr.Free()
+ result, err = xmlNode.Search(xpathExpr)
+ } else {
+ err = errors.New("cannot compile xpath: " + data)
+ }
+ case []byte:
+ result, err = xmlNode.Search(string(data))
+ case *xpath.Expression:
+ xpathCtx := xmlNode.Document.DocXPathCtx()
+ nodePtrs, err := xpathCtx.EvaluateAsNodeset(unsafe.Pointer(xmlNode.Ptr), data)
+ if nodePtrs == nil || err != nil {
+ return nil, err
+ }
+ for _, nodePtr := range nodePtrs {
+ result = append(result, NewNode(nodePtr, xmlNode.Document))
+ }
+ }
+ return
+}
+
+// As the Search function, but passing a VariableScope that can be used to reolve variable
+// names or registered function references in the XPath being evaluated.
+func (xmlNode *XmlNode) SearchWithVariables(data interface{}, v xpath.VariableScope) (result []Node, err error) {
+ switch data := data.(type) {
+ default:
+ err = ERR_UNDEFINED_SEARCH_PARAM
+ case string:
+ if xpathExpr := xpath.Compile(data); xpathExpr != nil {
+ defer xpathExpr.Free()
+ result, err = xmlNode.SearchWithVariables(xpathExpr, v)
+ } else {
+ err = errors.New("cannot compile xpath: " + data)
+ }
+ case []byte:
+ result, err = xmlNode.SearchWithVariables(string(data), v)
+ case *xpath.Expression:
+ xpathCtx := xmlNode.Document.DocXPathCtx()
+ xpathCtx.SetResolver(v)
+ nodePtrs, err := xpathCtx.EvaluateAsNodeset(unsafe.Pointer(xmlNode.Ptr), data)
+ if nodePtrs == nil || err != nil {
+ return nil, err
+ }
+ for _, nodePtr := range nodePtrs {
+ result = append(result, NewNode(nodePtr, xmlNode.Document))
+ }
+ }
+ return
+}
+
+// Evaluate an XPath and return a result of the appropriate type.
+// If a non-nil VariableScope is provided, any variables or functions present
+// in the xpath will be resolved.
+//
+// If the result is a nodeset (or the empty nodeset), a nodeset will be returned.
+//
+// If the result is a number, a float64 will be returned.
+//
+// If the result is a boolean, a bool will be returned.
+//
+// In any other cases, the result will be coerced to a string.
+func (xmlNode *XmlNode) EvalXPath(data interface{}, v xpath.VariableScope) (result interface{}, err error) {
+ switch data := data.(type) {
+ case string:
+ if xpathExpr := xpath.Compile(data); xpathExpr != nil {
+ defer xpathExpr.Free()
+ result, err = xmlNode.EvalXPath(xpathExpr, v)
+ } else {
+ err = errors.New("cannot compile xpath: " + data)
+ }
+ case []byte:
+ result, err = xmlNode.EvalXPath(string(data), v)
+ case *xpath.Expression:
+ xpathCtx := xmlNode.Document.DocXPathCtx()
+ xpathCtx.SetResolver(v)
+ err := xpathCtx.Evaluate(unsafe.Pointer(xmlNode.Ptr), data)
+ if err != nil {
+ return nil, err
+ }
+ rt := xpathCtx.ReturnType()
+ switch rt {
+ case xpath.XPATH_NODESET, xpath.XPATH_XSLT_TREE:
+ nodePtrs, err := xpathCtx.ResultAsNodeset()
+ if err != nil {
+ return nil, err
+ }
+ var output []Node
+ for _, nodePtr := range nodePtrs {
+ output = append(output, NewNode(nodePtr, xmlNode.Document))
+ }
+ result = output
+ case xpath.XPATH_NUMBER:
+ result, _ = xpathCtx.ResultAsNumber()
+ case xpath.XPATH_BOOLEAN:
+ result, _ = xpathCtx.ResultAsBoolean()
+ default:
+ result, _ = xpathCtx.ResultAsString()
+ }
+ default:
+ err = ERR_UNDEFINED_SEARCH_PARAM
+ }
+ return
+}
+
+// Evaluate an XPath and coerce the result to a boolean according to the
+// XPath rules. In the presence of an error, this function will return false
+// even if the expression cannot actually be evaluated.
+//
+// In most cases you are better advised to call EvalXPath; this function is
+// intended for packages that implement XML standards and that are fully aware
+// of the consequences of suppressing a compilation error.
+//
+// If a non-nil VariableScope is provided, any variables or registered functions present
+// in the xpath will be resolved.
+func (xmlNode *XmlNode) EvalXPathAsBoolean(data interface{}, v xpath.VariableScope) (result bool) {
+ switch data := data.(type) {
+ case string:
+ if xpathExpr := xpath.Compile(data); xpathExpr != nil {
+ defer xpathExpr.Free()
+ result = xmlNode.EvalXPathAsBoolean(xpathExpr, v)
+ } else {
+ //err = errors.New("cannot compile xpath: " + data)
+ }
+ case []byte:
+ result = xmlNode.EvalXPathAsBoolean(string(data), v)
+ case *xpath.Expression:
+ xpathCtx := xmlNode.Document.DocXPathCtx()
+ xpathCtx.SetResolver(v)
+ err := xpathCtx.Evaluate(unsafe.Pointer(xmlNode.Ptr), data)
+ if err != nil {
+ return false
+ }
+ result, _ = xpathCtx.ResultAsBoolean()
+ default:
+ //err = ERR_UNDEFINED_SEARCH_PARAM
+ }
+ return
+}
+
+// The local name of the node. Use Namespace() to get the namespace.
+func (xmlNode *XmlNode) Name() (name string) {
+ if xmlNode.Ptr.name != nil {
+ p := unsafe.Pointer(xmlNode.Ptr.name)
+ name = C.GoString((*C.char)(p))
+ }
+ return
+}
+
+// The namespace of the node. This is the empty string if there
+// no associated namespace.
+func (xmlNode *XmlNode) Namespace() (href string) {
+ if xmlNode.Ptr.ns != nil {
+ p := unsafe.Pointer(xmlNode.Ptr.ns.href)
+ href = C.GoString((*C.char)(p))
+ }
+ return
+}
+
+// Set the local name of the node. The namespace is set via SetNamespace().
+func (xmlNode *XmlNode) SetName(name string) {
+ if len(name) > 0 {
+ nameBytes := GetCString([]byte(name))
+ namePtr := unsafe.Pointer(&nameBytes[0])
+ C.xmlNodeSetName(xmlNode.Ptr, (*C.xmlChar)(namePtr))
+ }
+}
+
+func (xmlNode *XmlNode) Duplicate(level int) Node {
+ return xmlNode.DuplicateTo(xmlNode.Document, level)
+}
+
+func (xmlNode *XmlNode) DuplicateTo(doc Document, level int) (dup Node) {
+ if xmlNode.valid {
+ dupPtr := C.xmlDocCopyNode(xmlNode.Ptr, (*C.xmlDoc)(doc.DocPtr()), C.int(level))
+ if dupPtr != nil {
+ dup = NewNode(unsafe.Pointer(dupPtr), xmlNode.Document)
+ }
+ }
+ return
+}
+
+func (xmlNode *XmlNode) serialize(format SerializationOption, encoding, outputBuffer []byte) ([]byte, int) {
+ nodePtr := unsafe.Pointer(xmlNode.Ptr)
+ var encodingPtr unsafe.Pointer
+ if len(encoding) == 0 {
+ encoding = xmlNode.Document.OutputEncoding()
+ }
+ if len(encoding) > 0 {
+ encodingPtr = unsafe.Pointer(&(encoding[0]))
+ } else {
+ encodingPtr = nil
+ }
+
+ wbufferMutex.Lock()
+ defer wbufferMutex.Unlock()
+ if outputBuffer == nil {
+ outputBuffer = make([]byte, 0)
+ }
+ wbuffer = &WriteBuffer{Node: xmlNode, Buffer: outputBuffer}
+
+ ret := int(C.xmlSaveNode(nodePtr, encodingPtr, C.int(format)))
+ if ret < 0 {
+ panic("output error in xml node serialization: " + strconv.Itoa(ret))
+ }
+ b, o := wbuffer.Buffer, wbuffer.Offset
+ wbuffer = nil
+
+ return b, o
+}
+
+// SerializeWithFormat allows you to control the serialization flags passed to libxml.
+// In most cases ToXml() and ToHtml() provide sensible defaults and should be preferred.
+//
+// The format parameter should be a set of SerializationOption constants or'd together.
+// If encoding is nil, the document's output encoding is used - this defaults to UTF-8.
+// If outputBuffer is nil, one will be created for you.
+func (xmlNode *XmlNode) SerializeWithFormat(format SerializationOption, encoding, outputBuffer []byte) ([]byte, int) {
+ return xmlNode.serialize(format, encoding, outputBuffer)
+}
+
+// ToXml generates an indented XML document with an XML declaration.
+// It is not guaranteed to be well formed unless xmlNode is an element node,
+// or a document node with only one element child.
+//
+// If you need finer control over the formatting, call SerializeWithFormat.
+//
+// If encoding is nil, the document's output encoding is used - this defaults to UTF-8.
+// If outputBuffer is nil, one will be created for you.
+func (xmlNode *XmlNode) ToXml(encoding, outputBuffer []byte) ([]byte, int) {
+ return xmlNode.serialize(XML_SAVE_AS_XML|XML_SAVE_FORMAT, encoding, outputBuffer)
+}
+
+// ToUnformattedXml generates an unformatted XML document without an XML declaration.
+// This is useful for conforming to various standards and for unit testing, although
+// the output is not guaranteed to be well formed unless xmlNode is an element node.
+func (xmlNode *XmlNode) ToUnformattedXml() string {
+ var b []byte
+ var size int
+ b, size = xmlNode.serialize(XML_SAVE_AS_XML|XML_SAVE_NO_DECL, nil, nil)
+ if b == nil {
+ return ""
+ }
+ return string(b[:size])
+}
+
+// ToHtml generates an indented XML document that conforms to HTML 4.0 rules; meaning
+// that some elements may be unclosed or forced to use end tags even when empty.
+//
+// If you want to output XHTML, call SerializeWithFormat and enable the XML_SAVE_XHTML
+// flag as part of the format.
+//
+// If encoding is nil, the document's output encoding is used - this defaults to UTF-8.
+// If outputBuffer is nil, one will be created for you.
+func (xmlNode *XmlNode) ToHtml(encoding, outputBuffer []byte) ([]byte, int) {
+ return xmlNode.serialize(XML_SAVE_AS_HTML|XML_SAVE_FORMAT, encoding, outputBuffer)
+}
+
+func (xmlNode *XmlNode) ToBuffer(outputBuffer []byte) []byte {
+ var b []byte
+ var size int
+ if docType := xmlNode.Document.DocType(); docType == XML_HTML_DOCUMENT_NODE {
+ b, size = xmlNode.ToHtml(nil, outputBuffer)
+ } else {
+ b, size = xmlNode.ToXml(nil, outputBuffer)
+ }
+ return b[:size]
+}
+
+func (xmlNode *XmlNode) String() string {
+ b := xmlNode.ToBuffer(nil)
+ if b == nil {
+ return ""
+ }
+ return string(b)
+}
+
+func (xmlNode *XmlNode) Content() string {
+ contentPtr := C.xmlNodeGetContent(xmlNode.Ptr)
+ charPtr := (*C.char)(unsafe.Pointer(contentPtr))
+ defer C.xmlFreeChars(charPtr)
+ return C.GoString(charPtr)
+}
+
+func (xmlNode *XmlNode) InnerHtml() string {
+ out := ""
+
+ for child := xmlNode.FirstChild(); child != nil; child = child.NextSibling() {
+ out += child.String()
+ }
+ return out
+}
+
+func (xmlNode *XmlNode) Unlink() {
+ if int(C.xmlUnlinkNodeWithCheck(xmlNode.Ptr)) != 0 {
+ xmlNode.Document.AddUnlinkedNode(unsafe.Pointer(xmlNode.Ptr))
+ }
+}
+
+func (xmlNode *XmlNode) Remove() {
+ if xmlNode.valid && unsafe.Pointer(xmlNode.Ptr) != xmlNode.Document.DocPtr() {
+ xmlNode.Unlink()
+ xmlNode.valid = false
+ }
+}
+
+func (xmlNode *XmlNode) addChild(node Node) (err error) {
+ nodeType := node.NodeType()
+ if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE {
+ err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD
+ return
+ }
+ nodePtr := node.NodePtr()
+ if xmlNode.NodePtr() == nodePtr {
+ return
+ }
+ ret := xmlNode.isAccestor(nodePtr)
+ if ret < 0 {
+ return
+ } else if ret == 0 {
+ if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) {
+ C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr))
+ }
+ C.xmlAddChild(xmlNode.Ptr, (*C.xmlNode)(nodePtr))
+ } else if ret > 0 {
+ node.Remove()
+ }
+
+ return
+}
+
+func (xmlNode *XmlNode) addPreviousSibling(node Node) (err error) {
+ nodeType := node.NodeType()
+ if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE {
+ err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD
+ return
+ }
+ nodePtr := node.NodePtr()
+ if xmlNode.NodePtr() == nodePtr {
+ return
+ }
+ ret := xmlNode.isAccestor(nodePtr)
+ if ret < 0 {
+ return
+ } else if ret == 0 {
+ if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) {
+ C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr))
+ }
+ C.xmlAddPrevSibling(xmlNode.Ptr, (*C.xmlNode)(nodePtr))
+ } else if ret > 0 {
+ node.Remove()
+ }
+ return
+}
+
+func (xmlNode *XmlNode) addNextSibling(node Node) (err error) {
+ nodeType := node.NodeType()
+ if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE {
+ err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD
+ return
+ }
+ nodePtr := node.NodePtr()
+ if xmlNode.NodePtr() == nodePtr {
+ return
+ }
+ ret := xmlNode.isAccestor(nodePtr)
+ if ret < 0 {
+ return
+ } else if ret == 0 {
+ if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) {
+ C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr))
+ }
+ C.xmlAddNextSibling(xmlNode.Ptr, (*C.xmlNode)(nodePtr))
+ } else if ret > 0 {
+ node.Remove()
+ }
+ return
+}
+
+func (xmlNode *XmlNode) Wrap(data string) (err error) {
+ newNodes, err := xmlNode.coerce(data)
+ if err == nil && len(newNodes) > 0 {
+ newParent := newNodes[0]
+ xmlNode.addNextSibling(newParent)
+ newParent.AddChild(xmlNode)
+ }
+ return
+}
+
+func (xmlNode *XmlNode) ParseFragment(input, url []byte, options ParseOption) (fragment *DocumentFragment, err error) {
+ fragment, err = parsefragment(xmlNode.Document, xmlNode, input, url, options)
+ return
+}
+
+var (
+ wbuffer *WriteBuffer
+ wbufferMutex sync.Mutex
+)
+
+//export xmlNodeWriteCallback
+// NOTE: wbufferMutex is locked
+func xmlNodeWriteCallback(data unsafe.Pointer, data_len C.int) {
+ offset := wbuffer.Offset
+
+ if offset > len(wbuffer.Buffer) {
+ panic("fatal error in xmlNodeWriteCallback")
+ }
+
+ buffer := wbuffer.Buffer[:offset]
+ dataLen := int(data_len)
+
+ if dataLen > 0 {
+ if len(buffer)+dataLen > cap(buffer) {
+ newBuffer := grow(buffer, dataLen)
+ wbuffer.Buffer = newBuffer
+ }
+ destBufPtr := unsafe.Pointer(&(wbuffer.Buffer[offset]))
+ C.memcpy(destBufPtr, data, C.size_t(dataLen))
+ wbuffer.Offset += dataLen
+ }
+}
+
+//export xmlUnlinkNodeCallback
+// NOTE: contentMutex is locked
+func xmlUnlinkNodeCallback(nodePtr unsafe.Pointer) {
+ contentNode.Document.AddUnlinkedNode(nodePtr)
+}
+
+func grow(buffer []byte, n int) (newBuffer []byte) {
+ newBuffer = makeSlice(2*cap(buffer) + n)
+ copy(newBuffer, buffer)
+ return
+}
+
+func makeSlice(n int) []byte {
+ // If the make fails, give a known error.
+ defer func() {
+ if recover() != nil {
+ panic(ErrTooLarge)
+ }
+ }()
+ return make([]byte, n)
+}
+
+func (xmlNode *XmlNode) isAccestor(nodePtr unsafe.Pointer) int {
+ parentPtr := xmlNode.Ptr.parent
+
+ if C.xmlNodePtrCheck(unsafe.Pointer(parentPtr)) == C.int(0) {
+ return -1
+ }
+ for ; parentPtr != nil; parentPtr = parentPtr.parent {
+ if C.xmlNodePtrCheck(unsafe.Pointer(parentPtr)) == C.int(0) {
+ return -1
+ }
+ p := unsafe.Pointer(parentPtr)
+ if p == nodePtr {
+ return 1
+ }
+ }
+ return 0
+}
+
+func (xmlNode *XmlNode) RecursivelyRemoveNamespaces() (err error) {
+ nodePtr := xmlNode.Ptr
+ C.xmlSetNs(nodePtr, nil)
+
+ for child := xmlNode.FirstChild(); child != nil; {
+ child.RecursivelyRemoveNamespaces()
+ child = child.NextSibling()
+ }
+
+ nodeType := xmlNode.NodeType()
+
+ if ((nodeType == XML_ELEMENT_NODE) ||
+ (nodeType == XML_XINCLUDE_START) ||
+ (nodeType == XML_XINCLUDE_END)) &&
+ (nodePtr.nsDef != nil) {
+ C.xmlFreeNsList((*C.xmlNs)(nodePtr.nsDef))
+ nodePtr.nsDef = nil
+ }
+
+ if nodeType == XML_ELEMENT_NODE && nodePtr.properties != nil {
+ property := nodePtr.properties
+ for property != nil {
+ if property.ns != nil {
+ property.ns = nil
+ }
+ property = property.next
+ }
+ }
+ return
+}
+
+func (xmlNode *XmlNode) RemoveDefaultNamespace() {
+ nodePtr := xmlNode.Ptr
+ C.xmlRemoveDefaultNamespace(nodePtr)
+}
+
+// Returns a list of all the namespace declarations that exist on this node.
+//
+// You can add a namespace declaration by calling DeclareNamespace.
+// Calling SetNamespace will automatically add a declaration if required.
+//
+// Calling SetNsAttr does *not* automatically create a declaration. This will
+// fixed in a future version.
+func (xmlNode *XmlNode) DeclaredNamespaces() (result []NamespaceDeclaration) {
+ nodePtr := xmlNode.Ptr
+ for ns := nodePtr.nsDef; ns != nil; ns = (*C.xmlNs)(ns.next) {
+ prefixPtr := unsafe.Pointer(ns.prefix)
+ prefix := C.GoString((*C.char)(prefixPtr))
+ hrefPtr := unsafe.Pointer(ns.href)
+ uri := C.GoString((*C.char)(hrefPtr))
+ decl := NamespaceDeclaration{prefix, uri}
+ result = append(result, decl)
+ }
+ return
+}
+
+// Add a namespace declaration to an element.
+//
+// This is typically done on the root element or node high up in the tree
+// to avoid duplication. The declaration is not created if the namespace
+// is already declared in this scope with the same prefix.
+func (xmlNode *XmlNode) DeclareNamespace(prefix, href string) {
+ //can only declare namespaces on elements
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+ hrefBytes := GetCString([]byte(href))
+ hrefPtr := unsafe.Pointer(&hrefBytes[0])
+
+ //if the namespace is already declared using this prefix, just return
+ _ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr))
+ if _ns != nil {
+ _prefixPtr := unsafe.Pointer(_ns.prefix)
+ _prefix := C.GoString((*C.char)(_prefixPtr))
+ if prefix == _prefix {
+ return
+ }
+ }
+
+ prefixBytes := GetCString([]byte(prefix))
+ prefixPtr := unsafe.Pointer(&prefixBytes[0])
+ if prefix == "" {
+ prefixPtr = nil
+ }
+
+ //this adds the namespace declaration to the node
+ _ = C.xmlNewNs(xmlNode.Ptr, (*C.xmlChar)(hrefPtr), (*C.xmlChar)(prefixPtr))
+}
+
+// Set the namespace of an element.
+func (xmlNode *XmlNode) SetNamespace(prefix, href string) {
+ if xmlNode.NodeType() != XML_ELEMENT_NODE {
+ return
+ }
+
+ prefixBytes := GetCString([]byte(prefix))
+ prefixPtr := unsafe.Pointer(&prefixBytes[0])
+ if prefix == "" {
+ prefixPtr = nil
+ }
+
+ hrefBytes := GetCString([]byte(href))
+ hrefPtr := unsafe.Pointer(&hrefBytes[0])
+
+ // use the existing namespace declaration if there is one
+ _ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr))
+ if _ns != nil {
+ _prefixPtr := unsafe.Pointer(_ns.prefix)
+ _prefix := C.GoString((*C.char)(_prefixPtr))
+ if prefix == _prefix {
+ C.xmlSetNs(xmlNode.Ptr, _ns)
+ return
+ }
+ }
+
+ ns := C.xmlNewNs(xmlNode.Ptr, (*C.xmlChar)(hrefPtr), (*C.xmlChar)(prefixPtr))
+ C.xmlSetNs(xmlNode.Ptr, ns)
+}
+
+// Returns the line number on which the node appears, or a -1 if the
+// line number cannot be determined.
+func (xmlNode *XmlNode) LineNumber() int {
+ return int(C.xmlGetLineNo(xmlNode.Ptr))
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go
new file mode 100644
index 000000000000..df994c90aa7f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go
@@ -0,0 +1,48 @@
+package xml
+
+/*
+#cgo pkg-config: libxml-2.0
+
+#include
+#include
+
+*/
+import "C"
+
+import "unsafe"
+
+type Nodeset []Node
+
+// Produce a slice of unsafe.Pointer objects, suitable for passing to a C function
+func (n Nodeset) ToPointers() (pointers []unsafe.Pointer) {
+ for _, node := range n {
+ pointers = append(pointers, node.NodePtr())
+ }
+ return
+}
+
+// Produce a C.xmlXPathObjectPtr suitable for passing to libxml2
+func (n Nodeset) ToXPathNodeset() (ret C.xmlXPathObjectPtr) {
+ ret = C.xmlXPathNewNodeSet(nil)
+ for _, node := range n {
+ C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(node.NodePtr()))
+ }
+ return
+}
+
+// Produce a C.xmlXPathObjectPtr marked as a ResultValueTree, suitable for passing to libxml2
+func (n Nodeset) ToXPathValueTree() (ret C.xmlXPathObjectPtr) {
+ if len(n) == 0 {
+ ret = C.xmlXPathNewValueTree(nil)
+ return
+ }
+
+ ret = C.xmlXPathNewValueTree(nil)
+ for _, node := range n {
+ C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(node.NodePtr()))
+ }
+ //this hack-ish looking line tells libxml2 not to free the RVT
+ //if we don't do this we get horrible double-free crashes everywhere
+ ret.boolval = 0
+ return
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go
new file mode 100644
index 000000000000..bc5d9aa7ec6b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go
@@ -0,0 +1,5 @@
+package xml
+
+type ProcessingInstructionNode struct {
+ *XmlNode
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go
deleted file mode 100644
index 26db7472cdfa..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go
+++ /dev/null
@@ -1,2372 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/jbowtie/gokogiri/xml, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/jbowtie/gokogiri/xml (exports: Node; functions: )
-
-// Package xml is a stub of github.com/jbowtie/gokogiri/xml, generated by depstubber.
-package xml
-
-import ()
-
-type AttributeNode struct {
- XmlNode *XmlNode
-}
-
-func (_ AttributeNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ AttributeNode) Attr(_ string) string {
- return ""
-}
-
-func (_ AttributeNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ AttributeNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ AttributeNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ AttributeNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ AttributeNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ AttributeNode) Content() string {
- return ""
-}
-
-func (_ AttributeNode) CountChildren() int {
- return 0
-}
-
-func (_ AttributeNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ AttributeNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ AttributeNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ AttributeNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ AttributeNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ AttributeNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ AttributeNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ AttributeNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ AttributeNode) DocRef() Document {
- return nil
-}
-
-func (_ AttributeNode) DocType() NodeType {
- return 0
-}
-
-func (_ AttributeNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ AttributeNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ AttributeNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ AttributeNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ AttributeNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ AttributeNode) FirstChild() Node {
- return nil
-}
-
-func (_ AttributeNode) Free() {}
-
-func (_ AttributeNode) InnerHtml() string {
- return ""
-}
-
-func (_ AttributeNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ AttributeNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) IsValid() bool {
- return false
-}
-
-func (_ AttributeNode) LastChild() Node {
- return nil
-}
-
-func (_ AttributeNode) LineNumber() int {
- return 0
-}
-
-func (_ AttributeNode) MyDocument() Document {
- return nil
-}
-
-func (_ AttributeNode) Name() string {
- return ""
-}
-
-func (_ AttributeNode) Namespace() string {
- return ""
-}
-
-func (_ AttributeNode) NextSibling() Node {
- return nil
-}
-
-func (_ AttributeNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ AttributeNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ AttributeNode) NodeType() NodeType {
- return 0
-}
-
-func (_ AttributeNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ AttributeNode) Parent() Node {
- return nil
-}
-
-func (_ AttributeNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ AttributeNode) Path() string {
- return ""
-}
-
-func (_ AttributeNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ AttributeNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ AttributeNode) Remove() {}
-
-func (_ AttributeNode) RemoveDefaultNamespace() {}
-
-func (_ AttributeNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ AttributeNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) ResetChildren() {}
-
-func (_ AttributeNode) ResetNodePtr() {}
-
-func (_ AttributeNode) Root() *ElementNode {
- return nil
-}
-
-func (_ AttributeNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ AttributeNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ AttributeNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ AttributeNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ AttributeNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ AttributeNode) SetName(_ string) {}
-
-func (_ AttributeNode) SetNamespace(_ string, _ string) {}
-
-func (_ AttributeNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ AttributeNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ AttributeNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ AttributeNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ AttributeNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ AttributeNode) Unlink() {}
-
-func (_ AttributeNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ AttributeNode) Uri() string {
- return ""
-}
-
-func (_ AttributeNode) Wrap(_ string) error {
- return nil
-}
-
-func (_ *AttributeNode) SetValue(_ interface{}) {}
-
-func (_ *AttributeNode) String() string {
- return ""
-}
-
-func (_ *AttributeNode) Value() string {
- return ""
-}
-
-type CDataNode struct {
- XmlNode *XmlNode
-}
-
-func (_ CDataNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ CDataNode) Attr(_ string) string {
- return ""
-}
-
-func (_ CDataNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ CDataNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ CDataNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ CDataNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ CDataNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CDataNode) Content() string {
- return ""
-}
-
-func (_ CDataNode) CountChildren() int {
- return 0
-}
-
-func (_ CDataNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ CDataNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ CDataNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ CDataNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ CDataNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ CDataNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ CDataNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ CDataNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ CDataNode) DocRef() Document {
- return nil
-}
-
-func (_ CDataNode) DocType() NodeType {
- return 0
-}
-
-func (_ CDataNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ CDataNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ CDataNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ CDataNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ CDataNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ CDataNode) FirstChild() Node {
- return nil
-}
-
-func (_ CDataNode) Free() {}
-
-func (_ CDataNode) InnerHtml() string {
- return ""
-}
-
-func (_ CDataNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ CDataNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) IsValid() bool {
- return false
-}
-
-func (_ CDataNode) LastChild() Node {
- return nil
-}
-
-func (_ CDataNode) LineNumber() int {
- return 0
-}
-
-func (_ CDataNode) MyDocument() Document {
- return nil
-}
-
-func (_ CDataNode) Name() string {
- return ""
-}
-
-func (_ CDataNode) Namespace() string {
- return ""
-}
-
-func (_ CDataNode) NextSibling() Node {
- return nil
-}
-
-func (_ CDataNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ CDataNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ CDataNode) NodeType() NodeType {
- return 0
-}
-
-func (_ CDataNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ CDataNode) Parent() Node {
- return nil
-}
-
-func (_ CDataNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ CDataNode) Path() string {
- return ""
-}
-
-func (_ CDataNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ CDataNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ CDataNode) Remove() {}
-
-func (_ CDataNode) RemoveDefaultNamespace() {}
-
-func (_ CDataNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ CDataNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) ResetChildren() {}
-
-func (_ CDataNode) ResetNodePtr() {}
-
-func (_ CDataNode) Root() *ElementNode {
- return nil
-}
-
-func (_ CDataNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CDataNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CDataNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CDataNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ CDataNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ CDataNode) SetName(_ string) {}
-
-func (_ CDataNode) SetNamespace(_ string, _ string) {}
-
-func (_ CDataNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ CDataNode) String() string {
- return ""
-}
-
-func (_ CDataNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ CDataNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CDataNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ CDataNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CDataNode) Unlink() {}
-
-func (_ CDataNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ CDataNode) Uri() string {
- return ""
-}
-
-func (_ CDataNode) Wrap(_ string) error {
- return nil
-}
-
-type CommentNode struct {
- XmlNode *XmlNode
-}
-
-func (_ CommentNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ CommentNode) Attr(_ string) string {
- return ""
-}
-
-func (_ CommentNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ CommentNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ CommentNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ CommentNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ CommentNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CommentNode) Content() string {
- return ""
-}
-
-func (_ CommentNode) CountChildren() int {
- return 0
-}
-
-func (_ CommentNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ CommentNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ CommentNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ CommentNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ CommentNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ CommentNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ CommentNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ CommentNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ CommentNode) DocRef() Document {
- return nil
-}
-
-func (_ CommentNode) DocType() NodeType {
- return 0
-}
-
-func (_ CommentNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ CommentNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ CommentNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ CommentNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ CommentNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ CommentNode) FirstChild() Node {
- return nil
-}
-
-func (_ CommentNode) Free() {}
-
-func (_ CommentNode) InnerHtml() string {
- return ""
-}
-
-func (_ CommentNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ CommentNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) IsValid() bool {
- return false
-}
-
-func (_ CommentNode) LastChild() Node {
- return nil
-}
-
-func (_ CommentNode) LineNumber() int {
- return 0
-}
-
-func (_ CommentNode) MyDocument() Document {
- return nil
-}
-
-func (_ CommentNode) Name() string {
- return ""
-}
-
-func (_ CommentNode) Namespace() string {
- return ""
-}
-
-func (_ CommentNode) NextSibling() Node {
- return nil
-}
-
-func (_ CommentNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ CommentNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ CommentNode) NodeType() NodeType {
- return 0
-}
-
-func (_ CommentNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ CommentNode) Parent() Node {
- return nil
-}
-
-func (_ CommentNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ CommentNode) Path() string {
- return ""
-}
-
-func (_ CommentNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ CommentNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ CommentNode) Remove() {}
-
-func (_ CommentNode) RemoveDefaultNamespace() {}
-
-func (_ CommentNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ CommentNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) ResetChildren() {}
-
-func (_ CommentNode) ResetNodePtr() {}
-
-func (_ CommentNode) Root() *ElementNode {
- return nil
-}
-
-func (_ CommentNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CommentNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ CommentNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CommentNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ CommentNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ CommentNode) SetName(_ string) {}
-
-func (_ CommentNode) SetNamespace(_ string, _ string) {}
-
-func (_ CommentNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ CommentNode) String() string {
- return ""
-}
-
-func (_ CommentNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ CommentNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CommentNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ CommentNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ CommentNode) Unlink() {}
-
-func (_ CommentNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ CommentNode) Uri() string {
- return ""
-}
-
-func (_ CommentNode) Wrap(_ string) error {
- return nil
-}
-
-type Document interface {
- AddUnlinkedNode(_ interface{})
- BookkeepFragment(_ *DocumentFragment)
- CreateCDataNode(_ string) *CDataNode
- CreateCommentNode(_ string) *CommentNode
- CreateElementNode(_ string) *ElementNode
- CreatePINode(_ string, _ string) *ProcessingInstructionNode
- CreateTextNode(_ string) *TextNode
- DocPtr() interface{}
- DocRef() Document
- DocType() NodeType
- DocXPathCtx() interface{}
- Free()
- InputEncoding() []byte
- NodeById(_ string) *ElementNode
- OutputEncoding() []byte
- ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error)
- RecursivelyRemoveNamespaces() error
- RemoveUnlinkedNode(_ interface{}) bool
- Root() *ElementNode
- String() string
- UnparsedEntityURI(_ string) string
- Uri() string
-}
-
-type DocumentFragment struct {
- Node Node
- InEncoding []byte
- OutEncoding []byte
-}
-
-func (_ DocumentFragment) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) Attr(_ string) string {
- return ""
-}
-
-func (_ DocumentFragment) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ DocumentFragment) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ DocumentFragment) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ DocumentFragment) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ DocumentFragment) Content() string {
- return ""
-}
-
-func (_ DocumentFragment) CountChildren() int {
- return 0
-}
-
-func (_ DocumentFragment) DeclareNamespace(_ string, _ string) {}
-
-func (_ DocumentFragment) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ DocumentFragment) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ DocumentFragment) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ DocumentFragment) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ DocumentFragment) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ DocumentFragment) FirstChild() Node {
- return nil
-}
-
-func (_ DocumentFragment) InnerHtml() string {
- return ""
-}
-
-func (_ DocumentFragment) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) IsValid() bool {
- return false
-}
-
-func (_ DocumentFragment) LastChild() Node {
- return nil
-}
-
-func (_ DocumentFragment) LineNumber() int {
- return 0
-}
-
-func (_ DocumentFragment) MyDocument() Document {
- return nil
-}
-
-func (_ DocumentFragment) Name() string {
- return ""
-}
-
-func (_ DocumentFragment) Namespace() string {
- return ""
-}
-
-func (_ DocumentFragment) NextSibling() Node {
- return nil
-}
-
-func (_ DocumentFragment) NodePtr() interface{} {
- return nil
-}
-
-func (_ DocumentFragment) NodeType() NodeType {
- return 0
-}
-
-func (_ DocumentFragment) Parent() Node {
- return nil
-}
-
-func (_ DocumentFragment) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ DocumentFragment) Path() string {
- return ""
-}
-
-func (_ DocumentFragment) PreviousSibling() Node {
- return nil
-}
-
-func (_ DocumentFragment) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ DocumentFragment) RemoveDefaultNamespace() {}
-
-func (_ DocumentFragment) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) ResetChildren() {}
-
-func (_ DocumentFragment) ResetNodePtr() {}
-
-func (_ DocumentFragment) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ DocumentFragment) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ DocumentFragment) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ DocumentFragment) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ DocumentFragment) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ DocumentFragment) SetName(_ string) {}
-
-func (_ DocumentFragment) SetNamespace(_ string, _ string) {}
-
-func (_ DocumentFragment) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ DocumentFragment) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ DocumentFragment) ToUnformattedXml() string {
- return ""
-}
-
-func (_ DocumentFragment) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ DocumentFragment) Unlink() {}
-
-func (_ DocumentFragment) Wrap(_ string) error {
- return nil
-}
-
-func (_ *DocumentFragment) Children() []Node {
- return nil
-}
-
-func (_ *DocumentFragment) Remove() {}
-
-func (_ *DocumentFragment) String() string {
- return ""
-}
-
-func (_ *DocumentFragment) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-type ElementNode struct {
- XmlNode *XmlNode
-}
-
-func (_ ElementNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ ElementNode) Attr(_ string) string {
- return ""
-}
-
-func (_ ElementNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ ElementNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ ElementNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ ElementNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ ElementNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ElementNode) Content() string {
- return ""
-}
-
-func (_ ElementNode) CountChildren() int {
- return 0
-}
-
-func (_ ElementNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ ElementNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ ElementNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ ElementNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ ElementNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ ElementNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ ElementNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ ElementNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ ElementNode) DocRef() Document {
- return nil
-}
-
-func (_ ElementNode) DocType() NodeType {
- return 0
-}
-
-func (_ ElementNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ ElementNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ ElementNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ ElementNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ ElementNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ ElementNode) FirstChild() Node {
- return nil
-}
-
-func (_ ElementNode) Free() {}
-
-func (_ ElementNode) InnerHtml() string {
- return ""
-}
-
-func (_ ElementNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ ElementNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) IsValid() bool {
- return false
-}
-
-func (_ ElementNode) LastChild() Node {
- return nil
-}
-
-func (_ ElementNode) LineNumber() int {
- return 0
-}
-
-func (_ ElementNode) MyDocument() Document {
- return nil
-}
-
-func (_ ElementNode) Name() string {
- return ""
-}
-
-func (_ ElementNode) Namespace() string {
- return ""
-}
-
-func (_ ElementNode) NextSibling() Node {
- return nil
-}
-
-func (_ ElementNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ ElementNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ ElementNode) NodeType() NodeType {
- return 0
-}
-
-func (_ ElementNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ ElementNode) Parent() Node {
- return nil
-}
-
-func (_ ElementNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ ElementNode) Path() string {
- return ""
-}
-
-func (_ ElementNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ ElementNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ ElementNode) Remove() {}
-
-func (_ ElementNode) RemoveDefaultNamespace() {}
-
-func (_ ElementNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ ElementNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) ResetChildren() {}
-
-func (_ ElementNode) ResetNodePtr() {}
-
-func (_ ElementNode) Root() *ElementNode {
- return nil
-}
-
-func (_ ElementNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ElementNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ElementNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ElementNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ ElementNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ ElementNode) SetName(_ string) {}
-
-func (_ ElementNode) SetNamespace(_ string, _ string) {}
-
-func (_ ElementNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ ElementNode) String() string {
- return ""
-}
-
-func (_ ElementNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ ElementNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ElementNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ ElementNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ElementNode) Unlink() {}
-
-func (_ ElementNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ ElementNode) Uri() string {
- return ""
-}
-
-func (_ ElementNode) Wrap(_ string) error {
- return nil
-}
-
-type NamespaceDeclaration struct {
- Prefix string
- Uri string
-}
-
-type Node interface {
- AddChild(_ interface{}) error
- AddNextSibling(_ interface{}) error
- AddPreviousSibling(_ interface{}) error
- Attr(_ string) string
- Attribute(_ string) *AttributeNode
- AttributeList() []*AttributeNode
- Attributes() map[string]*AttributeNode
- Coerce(_ interface{}) ([]Node, error)
- Content() string
- CountChildren() int
- DeclareNamespace(_ string, _ string)
- DeclaredNamespaces() []NamespaceDeclaration
- Duplicate(_ int) Node
- DuplicateTo(_ Document, _ int) Node
- EvalXPath(_ interface{}, _ interface{}) (interface{}, error)
- EvalXPathAsBoolean(_ interface{}, _ interface{}) bool
- FirstChild() Node
- InnerHtml() string
- InsertAfter(_ interface{}) error
- InsertBefore(_ interface{}) error
- InsertBegin(_ interface{}) error
- InsertEnd(_ interface{}) error
- IsValid() bool
- LastChild() Node
- LineNumber() int
- MyDocument() Document
- Name() string
- Namespace() string
- NextSibling() Node
- NodePtr() interface{}
- NodeType() NodeType
- Parent() Node
- ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error)
- Path() string
- PreviousSibling() Node
- RecursivelyRemoveNamespaces() error
- Remove()
- RemoveDefaultNamespace()
- Replace(_ interface{}) error
- ResetChildren()
- ResetNodePtr()
- Search(_ interface{}) ([]Node, error)
- SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error)
- SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int)
- SetAttr(_ string, _ string) string
- SetChildren(_ interface{}) error
- SetContent(_ interface{}) error
- SetInnerHtml(_ interface{}) error
- SetName(_ string)
- SetNamespace(_ string, _ string)
- SetNsAttr(_ string, _ string, _ string) string
- String() string
- ToBuffer(_ []byte) []byte
- ToHtml(_ []byte, _ []byte) ([]byte, int)
- ToUnformattedXml() string
- ToXml(_ []byte, _ []byte) ([]byte, int)
- Unlink()
- Wrap(_ string) error
-}
-
-type NodeType int
-
-type ParseOption int
-
-type ProcessingInstructionNode struct {
- XmlNode *XmlNode
-}
-
-func (_ ProcessingInstructionNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ ProcessingInstructionNode) Attr(_ string) string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ ProcessingInstructionNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ProcessingInstructionNode) Content() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) CountChildren() int {
- return 0
-}
-
-func (_ ProcessingInstructionNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ ProcessingInstructionNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ ProcessingInstructionNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ ProcessingInstructionNode) DocRef() Document {
- return nil
-}
-
-func (_ ProcessingInstructionNode) DocType() NodeType {
- return 0
-}
-
-func (_ ProcessingInstructionNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ ProcessingInstructionNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ ProcessingInstructionNode) FirstChild() Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Free() {}
-
-func (_ ProcessingInstructionNode) InnerHtml() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ ProcessingInstructionNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) IsValid() bool {
- return false
-}
-
-func (_ ProcessingInstructionNode) LastChild() Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) LineNumber() int {
- return 0
-}
-
-func (_ ProcessingInstructionNode) MyDocument() Document {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Name() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) Namespace() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) NextSibling() Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ ProcessingInstructionNode) NodeType() NodeType {
- return 0
-}
-
-func (_ ProcessingInstructionNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Parent() Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ ProcessingInstructionNode) Path() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ ProcessingInstructionNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Remove() {}
-
-func (_ ProcessingInstructionNode) RemoveDefaultNamespace() {}
-
-func (_ ProcessingInstructionNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ ProcessingInstructionNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) ResetChildren() {}
-
-func (_ ProcessingInstructionNode) ResetNodePtr() {}
-
-func (_ ProcessingInstructionNode) Root() *ElementNode {
- return nil
-}
-
-func (_ ProcessingInstructionNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ProcessingInstructionNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ ProcessingInstructionNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ProcessingInstructionNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ ProcessingInstructionNode) SetName(_ string) {}
-
-func (_ ProcessingInstructionNode) SetNamespace(_ string, _ string) {}
-
-func (_ ProcessingInstructionNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) String() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ ProcessingInstructionNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ProcessingInstructionNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ ProcessingInstructionNode) Unlink() {}
-
-func (_ ProcessingInstructionNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) Uri() string {
- return ""
-}
-
-func (_ ProcessingInstructionNode) Wrap(_ string) error {
- return nil
-}
-
-type SerializationOption int
-
-type TextNode struct {
- XmlNode *XmlNode
-}
-
-func (_ TextNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ TextNode) Attr(_ string) string {
- return ""
-}
-
-func (_ TextNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ TextNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ TextNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ TextNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ TextNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ TextNode) Content() string {
- return ""
-}
-
-func (_ TextNode) CountChildren() int {
- return 0
-}
-
-func (_ TextNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ TextNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ TextNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ TextNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ TextNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ TextNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ TextNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ TextNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ TextNode) DocRef() Document {
- return nil
-}
-
-func (_ TextNode) DocType() NodeType {
- return 0
-}
-
-func (_ TextNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ TextNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ TextNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ TextNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ TextNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ TextNode) FirstChild() Node {
- return nil
-}
-
-func (_ TextNode) Free() {}
-
-func (_ TextNode) InnerHtml() string {
- return ""
-}
-
-func (_ TextNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ TextNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) IsValid() bool {
- return false
-}
-
-func (_ TextNode) LastChild() Node {
- return nil
-}
-
-func (_ TextNode) LineNumber() int {
- return 0
-}
-
-func (_ TextNode) MyDocument() Document {
- return nil
-}
-
-func (_ TextNode) Name() string {
- return ""
-}
-
-func (_ TextNode) Namespace() string {
- return ""
-}
-
-func (_ TextNode) NextSibling() Node {
- return nil
-}
-
-func (_ TextNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ TextNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ TextNode) NodeType() NodeType {
- return 0
-}
-
-func (_ TextNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ TextNode) Parent() Node {
- return nil
-}
-
-func (_ TextNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ TextNode) Path() string {
- return ""
-}
-
-func (_ TextNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ TextNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ TextNode) Remove() {}
-
-func (_ TextNode) RemoveDefaultNamespace() {}
-
-func (_ TextNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ TextNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) ResetChildren() {}
-
-func (_ TextNode) ResetNodePtr() {}
-
-func (_ TextNode) Root() *ElementNode {
- return nil
-}
-
-func (_ TextNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ TextNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ TextNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ TextNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ TextNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ TextNode) SetName(_ string) {}
-
-func (_ TextNode) SetNamespace(_ string, _ string) {}
-
-func (_ TextNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ TextNode) String() string {
- return ""
-}
-
-func (_ TextNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ TextNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ TextNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ TextNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ TextNode) Unlink() {}
-
-func (_ TextNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ TextNode) Uri() string {
- return ""
-}
-
-func (_ TextNode) Wrap(_ string) error {
- return nil
-}
-
-func (_ *TextNode) DisableOutputEscaping() {}
-
-type XmlNode struct {
- Ptr interface{}
- Document Document
-}
-
-func (_ XmlNode) AddUnlinkedNode(_ interface{}) {}
-
-func (_ XmlNode) BookkeepFragment(_ *DocumentFragment) {}
-
-func (_ XmlNode) CreateCDataNode(_ string) *CDataNode {
- return nil
-}
-
-func (_ XmlNode) CreateCommentNode(_ string) *CommentNode {
- return nil
-}
-
-func (_ XmlNode) CreateElementNode(_ string) *ElementNode {
- return nil
-}
-
-func (_ XmlNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode {
- return nil
-}
-
-func (_ XmlNode) CreateTextNode(_ string) *TextNode {
- return nil
-}
-
-func (_ XmlNode) DocPtr() interface{} {
- return nil
-}
-
-func (_ XmlNode) DocRef() Document {
- return nil
-}
-
-func (_ XmlNode) DocType() NodeType {
- return 0
-}
-
-func (_ XmlNode) DocXPathCtx() interface{} {
- return nil
-}
-
-func (_ XmlNode) Free() {}
-
-func (_ XmlNode) InputEncoding() []byte {
- return nil
-}
-
-func (_ XmlNode) NodeById(_ string) *ElementNode {
- return nil
-}
-
-func (_ XmlNode) OutputEncoding() []byte {
- return nil
-}
-
-func (_ XmlNode) RemoveUnlinkedNode(_ interface{}) bool {
- return false
-}
-
-func (_ XmlNode) Root() *ElementNode {
- return nil
-}
-
-func (_ XmlNode) UnparsedEntityURI(_ string) string {
- return ""
-}
-
-func (_ XmlNode) Uri() string {
- return ""
-}
-
-func (_ *XmlNode) AddChild(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) AddNextSibling(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) AddPreviousSibling(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) Attr(_ string) string {
- return ""
-}
-
-func (_ *XmlNode) Attribute(_ string) *AttributeNode {
- return nil
-}
-
-func (_ *XmlNode) AttributeList() []*AttributeNode {
- return nil
-}
-
-func (_ *XmlNode) Attributes() map[string]*AttributeNode {
- return nil
-}
-
-func (_ *XmlNode) Coerce(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ *XmlNode) Content() string {
- return ""
-}
-
-func (_ *XmlNode) CountChildren() int {
- return 0
-}
-
-func (_ *XmlNode) DeclareNamespace(_ string, _ string) {}
-
-func (_ *XmlNode) DeclaredNamespaces() []NamespaceDeclaration {
- return nil
-}
-
-func (_ *XmlNode) Duplicate(_ int) Node {
- return nil
-}
-
-func (_ *XmlNode) DuplicateTo(_ Document, _ int) Node {
- return nil
-}
-
-func (_ *XmlNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *XmlNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool {
- return false
-}
-
-func (_ *XmlNode) FirstChild() Node {
- return nil
-}
-
-func (_ *XmlNode) InnerHtml() string {
- return ""
-}
-
-func (_ *XmlNode) InsertAfter(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) InsertBefore(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) InsertBegin(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) InsertEnd(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) IsValid() bool {
- return false
-}
-
-func (_ *XmlNode) LastChild() Node {
- return nil
-}
-
-func (_ *XmlNode) LineNumber() int {
- return 0
-}
-
-func (_ *XmlNode) MyDocument() Document {
- return nil
-}
-
-func (_ *XmlNode) Name() string {
- return ""
-}
-
-func (_ *XmlNode) Namespace() string {
- return ""
-}
-
-func (_ *XmlNode) NextSibling() Node {
- return nil
-}
-
-func (_ *XmlNode) NodePtr() interface{} {
- return nil
-}
-
-func (_ *XmlNode) NodeType() NodeType {
- return 0
-}
-
-func (_ *XmlNode) Parent() Node {
- return nil
-}
-
-func (_ *XmlNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) {
- return nil, nil
-}
-
-func (_ *XmlNode) Path() string {
- return ""
-}
-
-func (_ *XmlNode) PreviousSibling() Node {
- return nil
-}
-
-func (_ *XmlNode) RecursivelyRemoveNamespaces() error {
- return nil
-}
-
-func (_ *XmlNode) Remove() {}
-
-func (_ *XmlNode) RemoveDefaultNamespace() {}
-
-func (_ *XmlNode) Replace(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) ResetChildren() {}
-
-func (_ *XmlNode) ResetNodePtr() {}
-
-func (_ *XmlNode) Search(_ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ *XmlNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) {
- return nil, nil
-}
-
-func (_ *XmlNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ *XmlNode) SetAttr(_ string, _ string) string {
- return ""
-}
-
-func (_ *XmlNode) SetChildren(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) SetContent(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) SetInnerHtml(_ interface{}) error {
- return nil
-}
-
-func (_ *XmlNode) SetName(_ string) {}
-
-func (_ *XmlNode) SetNamespace(_ string, _ string) {}
-
-func (_ *XmlNode) SetNsAttr(_ string, _ string, _ string) string {
- return ""
-}
-
-func (_ *XmlNode) String() string {
- return ""
-}
-
-func (_ *XmlNode) ToBuffer(_ []byte) []byte {
- return nil
-}
-
-func (_ *XmlNode) ToHtml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ *XmlNode) ToUnformattedXml() string {
- return ""
-}
-
-func (_ *XmlNode) ToXml(_ []byte, _ []byte) ([]byte, int) {
- return nil, 0
-}
-
-func (_ *XmlNode) Unlink() {}
-
-func (_ *XmlNode) Wrap(_ string) error {
- return nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go
new file mode 100644
index 000000000000..1723f4dacbf1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go
@@ -0,0 +1,24 @@
+package xml
+
+/*
+#include
+
+void disable_escaping(xmlNodePtr node) {
+ node->name = xmlStringTextNoenc;
+}
+*/
+import "C"
+
+type TextNode struct {
+ *XmlNode
+}
+
+// DisableOutputEscaping disables the usual safeguards against creating invalid XML and allows the
+// characters '<', '>', and '&' to be written out verbatim. Normally they are safely escaped as entities.
+//
+// This API is intended to provide support for XSLT processors and similar XML manipulation libraries that
+// may need to output unsupported entity references or use the XML API for non-XML output. It should never
+// be used in the normal course of XML processing.
+func (node *TextNode) DisableOutputEscaping() {
+ C.disable_escaping(node.Ptr)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go
new file mode 100644
index 000000000000..92526ecf4f45
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go
@@ -0,0 +1,81 @@
+package xpath
+
+/*
+#include
+#include
+#include
+
+void check_xpath_syntax_noop(void *ctx, const char *fmt, ...) {
+}
+
+char *check_xpath_syntax(const char *xpath) {
+ xmlGenericErrorFunc err_func = check_xpath_syntax_noop;
+ initGenericErrorDefaultFunc(&err_func);
+ xmlResetLastError();
+ xmlXPathCompile((const xmlChar *)xpath);
+ xmlErrorPtr err = xmlGetLastError();
+ if (err != NULL) {
+ if (err->code == XML_XPATH_EXPR_ERROR) {
+ // TODO: Not the cleanest but should scale well
+ int size = strlen(err->message) + strlen(err->str1) + err->int1 + 16;
+ char *msg = malloc(size);
+ sprintf(msg, "%s%s\n%*s^", err->message, err->str1, err->int1, " ");
+ return msg;
+ } else {
+ char *msg = malloc(strlen(err->message));
+ sprintf(msg, "%s", err->message);
+ return msg;
+ }
+ }
+ return NULL;
+}
+*/
+import "C"
+import "unsafe"
+import . "github.com/jbowtie/gokogiri/util"
+
+//import "runtime"
+import "errors"
+
+type Expression struct {
+ Ptr *C.xmlXPathCompExpr
+ xpath string
+}
+
+func Check(path string) (err error) {
+ str := C.CString(path)
+ defer C.free(unsafe.Pointer(str))
+ cstr := C.check_xpath_syntax(str)
+ if cstr != nil {
+ defer C.free(unsafe.Pointer(cstr))
+ err = errors.New(C.GoString(cstr))
+ }
+ return
+}
+
+func Compile(path string) (expr *Expression) {
+ if len(path) == 0 {
+ return
+ }
+
+ xpathBytes := GetCString([]byte(path))
+ xpathPtr := unsafe.Pointer(&xpathBytes[0])
+ ptr := C.xmlXPathCompile((*C.xmlChar)(xpathPtr))
+ if ptr == nil {
+ return
+ }
+ expr = &Expression{Ptr: ptr, xpath: path}
+ //runtime.SetFinalizer(expr, (*Expression).Free)
+ return
+}
+
+func (exp *Expression) String() string {
+ return exp.xpath
+}
+
+func (exp *Expression) Free() {
+ if exp.Ptr != nil {
+ C.xmlXPathFreeCompExpr(exp.Ptr)
+ exp.Ptr = nil
+ }
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go
deleted file mode 100644
index c1e32cba5f2c..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/jbowtie/gokogiri/xpath, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/jbowtie/gokogiri/xpath (exports: ; functions: Compile)
-
-// Package xpath is a stub of github.com/jbowtie/gokogiri/xpath, generated by depstubber.
-package xpath
-
-import ()
-
-func Compile(_ string) *Expression {
- return nil
-}
-
-type Expression struct {
- Ptr interface{}
-}
-
-func (_ *Expression) Free() {}
-
-func (_ *Expression) String() string {
- return ""
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go
new file mode 100644
index 000000000000..5d7787880537
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go
@@ -0,0 +1,146 @@
+package xpath
+
+/*
+#cgo pkg-config: libxml-2.0
+
+#include
+#include
+#include
+
+int getXPathObjectType(xmlXPathObject* o);
+
+*/
+import "C"
+
+import (
+ "sync"
+ "unsafe"
+)
+import "reflect"
+import . "github.com/jbowtie/gokogiri/util"
+
+var (
+ contextMap = make(map[unsafe.Pointer]VariableScope)
+ contextMutex sync.Mutex
+)
+
+func GetScope(ctxt unsafe.Pointer) VariableScope {
+ contextMutex.Lock()
+ context := contextMap[ctxt]
+ contextMutex.Unlock()
+ return context
+}
+
+func SetScope(ctxt unsafe.Pointer, v VariableScope) {
+ contextMutex.Lock()
+ contextMap[ctxt] = v
+ contextMutex.Unlock()
+}
+
+func ClearScope(ctxt unsafe.Pointer) {
+ contextMutex.Lock()
+ delete(contextMap, ctxt)
+ contextMutex.Unlock()
+
+}
+
+//export go_resolve_variables
+func go_resolve_variables(ctxt unsafe.Pointer, name, ns *C.char) (ret C.xmlXPathObjectPtr) {
+ if context := GetScope(ctxt); context != nil {
+ variable := C.GoString(name)
+ namespace := C.GoString(ns)
+
+ val := context.ResolveVariable(variable, namespace)
+ return ValueToXPathObject(val)
+ }
+ return nil
+}
+
+// Convert an arbitrary value into a C.xmlXPathObjectPtr
+// Unrecognised and nil values are converted to empty node sets.
+func ValueToXPathObject(val interface{}) (ret C.xmlXPathObjectPtr) {
+ if val == nil {
+ //return the empty node set
+ ret = C.xmlXPathNewNodeSet(nil)
+ return
+ }
+ switch v := val.(type) {
+ case unsafe.Pointer:
+ return (C.xmlXPathObjectPtr)(v)
+ case []unsafe.Pointer:
+ ptrs := v
+ if len(ptrs) > 0 {
+ //default - return a node set
+ ret = C.xmlXPathNewNodeSet(nil)
+ for _, p := range ptrs {
+ C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(p))
+ }
+ } else {
+ ret = C.xmlXPathNewNodeSet(nil)
+ return
+ }
+ case float64:
+ ret = C.xmlXPathNewFloat(C.double(v))
+ case string:
+ xpathBytes := GetCString([]byte(v))
+ xpathPtr := unsafe.Pointer(&xpathBytes[0])
+ ret = C.xmlXPathNewString((*C.xmlChar)(xpathPtr))
+ default:
+ typ := reflect.TypeOf(val)
+ // if a pointer to a struct is passed, get the type of the dereferenced object
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ }
+ //log the unknown type, return an empty node set
+ //fmt.Println("go-resolve wrong-type", typ.Kind())
+ ret = C.xmlXPathNewNodeSet(nil)
+ }
+ return
+}
+
+//export exec_xpath_function
+func exec_xpath_function(ctxt C.xmlXPathParserContextPtr, nargs C.int) {
+ function := C.GoString((*C.char)(unsafe.Pointer(ctxt.context.function)))
+ namespace := C.GoString((*C.char)(unsafe.Pointer(ctxt.context.functionURI)))
+
+ context := GetScope(unsafe.Pointer(ctxt.context))
+
+ argcount := int(nargs)
+ var args []interface{}
+
+ for i := 0; i < argcount; i = i + 1 {
+ args = append(args, XPathObjectToValue(C.valuePop(ctxt)))
+ }
+
+ // arguments are popped off the stack in reverse order, so
+ // we reverse the slice before invoking our callback
+ if argcount > 1 {
+ for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+ args[i], args[j] = args[j], args[i]
+ }
+ }
+
+ // push the result onto the stack
+ // if for some reason we are unable to resolve the
+ // function we push an empty nodeset
+ f := context.ResolveFunction(function, namespace)
+ if f != nil {
+ retval := f(context, args)
+ C.valuePush(ctxt, ValueToXPathObject(retval))
+ } else {
+ ret := C.xmlXPathNewNodeSet(nil)
+ C.valuePush(ctxt, ret)
+ }
+
+}
+
+//export go_can_resolve_function
+func go_can_resolve_function(ctxt unsafe.Pointer, name, ns *C.char) (ret C.int) {
+ function := C.GoString(name)
+ namespace := C.GoString(ns)
+ context := GetScope(ctxt)
+ if context != nil && context.IsFunctionRegistered(function, namespace) {
+ return C.int(1)
+ }
+ return C.int(0)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go
new file mode 100644
index 000000000000..d82e7e1af9ab
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go
@@ -0,0 +1,274 @@
+package xpath
+
+/*
+#cgo pkg-config: libxml-2.0
+
+#include
+#include
+#include
+
+xmlNode* fetchNode(xmlNodeSet *nodeset, int index) {
+ return nodeset->nodeTab[index];
+}
+
+xmlXPathObjectPtr go_resolve_variables(void* ctxt, char* name, char* ns);
+int go_can_resolve_function(void* ctxt, char* name, char* ns);
+void exec_xpath_function(xmlXPathParserContextPtr ctxt, int nargs);
+
+xmlXPathFunction go_resolve_function(void* ctxt, char* name, char* ns) {
+ if (go_can_resolve_function(ctxt, name, ns))
+ return exec_xpath_function;
+
+ return 0;
+}
+
+static void set_var_lookup(xmlXPathContext* c, void* data) {
+ c->varLookupFunc = (void *)go_resolve_variables;
+ c->varLookupData = data;
+}
+
+static void set_function_lookup(xmlXPathContext* c, void* data) {
+ c->funcLookupFunc = (void *)go_resolve_function;
+ c->funcLookupData = data;
+}
+
+int getXPathObjectType(xmlXPathObject* o) {
+ if(o == 0)
+ return 0;
+ return o->type;
+}
+*/
+import "C"
+
+import "unsafe"
+import . "github.com/jbowtie/gokogiri/util"
+import "runtime"
+import "errors"
+
+type XPath struct {
+ ContextPtr *C.xmlXPathContext
+ ResultPtr *C.xmlXPathObject
+}
+
+type XPathObjectType int
+
+const (
+ XPATH_UNDEFINED XPathObjectType = 0
+ XPATH_NODESET = 1
+ XPATH_BOOLEAN = 2
+ XPATH_NUMBER = 3
+ XPATH_STRING = 4
+ XPATH_POINT = 5
+ XPATH_RANGE = 6
+ XPATH_LOCATIONSET = 7
+ XPATH_USERS = 8
+ XPATH_XSLT_TREE = 9 // An XSLT value tree, non modifiable
+)
+
+type XPathFunction func(context VariableScope, args []interface{}) interface{}
+
+// Types that provide the VariableScope interface know how to resolve
+// XPath variable names into values.
+//
+//This interface exist primarily for the benefit of XSLT processors.
+type VariableScope interface {
+ ResolveVariable(string, string) interface{}
+ IsFunctionRegistered(string, string) bool
+ ResolveFunction(string, string) XPathFunction
+}
+
+func NewXPath(docPtr unsafe.Pointer) (xpath *XPath) {
+ if docPtr == nil {
+ return
+ }
+ xpath = &XPath{ContextPtr: C.xmlXPathNewContext((*C.xmlDoc)(docPtr)), ResultPtr: nil}
+ runtime.SetFinalizer(xpath, (*XPath).Free)
+ return
+}
+
+func (xpath *XPath) RegisterNamespace(prefix, href string) bool {
+ var prefixPtr unsafe.Pointer = nil
+ if len(prefix) > 0 {
+ prefixBytes := AppendCStringTerminator([]byte(prefix))
+ prefixPtr = unsafe.Pointer(&prefixBytes[0])
+ }
+
+ var hrefPtr unsafe.Pointer = nil
+ if len(href) > 0 {
+ hrefBytes := AppendCStringTerminator([]byte(href))
+ hrefPtr = unsafe.Pointer(&hrefBytes[0])
+ }
+
+ result := C.xmlXPathRegisterNs(xpath.ContextPtr, (*C.xmlChar)(prefixPtr), (*C.xmlChar)(hrefPtr))
+ return result == 0
+}
+
+// Evaluate an XPath and attempt to consume the result as a nodeset.
+func (xpath *XPath) EvaluateAsNodeset(nodePtr unsafe.Pointer, xpathExpr *Expression) (nodes []unsafe.Pointer, err error) {
+ if nodePtr == nil {
+ //evaluating xpath on a nil node returns no result.
+ return
+ }
+
+ err = xpath.Evaluate(nodePtr, xpathExpr)
+ if err != nil {
+ return
+ }
+
+ nodes, err = xpath.ResultAsNodeset()
+ return
+}
+
+// Evaluate an XPath. The returned result is stored in the struct. Call ReturnType to
+// discover the type of result, and call one of the ResultAs* functions to return a
+// copy of the result as a particular type.
+func (xpath *XPath) Evaluate(nodePtr unsafe.Pointer, xpathExpr *Expression) (err error) {
+ if nodePtr == nil {
+ //evaluating xpath on a nil node returns no result.
+ return
+ }
+
+ oldXPContextDoc := xpath.ContextPtr.doc
+ oldXPContextNode := xpath.ContextPtr.node
+ oldXPProximityPosition := xpath.ContextPtr.proximityPosition
+ oldXPContextSize := xpath.ContextPtr.contextSize
+ oldXPNsNr := xpath.ContextPtr.nsNr
+ oldXPNamespaces := xpath.ContextPtr.namespaces
+
+ xpath.ContextPtr.node = (*C.xmlNode)(nodePtr)
+ if xpath.ResultPtr != nil {
+ C.xmlXPathFreeObject(xpath.ResultPtr)
+ }
+ xpath.ResultPtr = C.xmlXPathCompiledEval(xpathExpr.Ptr, xpath.ContextPtr)
+
+ xpath.ContextPtr.doc = oldXPContextDoc
+ xpath.ContextPtr.node = oldXPContextNode
+ xpath.ContextPtr.proximityPosition = oldXPProximityPosition
+ xpath.ContextPtr.contextSize = oldXPContextSize
+ xpath.ContextPtr.nsNr = oldXPNsNr
+ xpath.ContextPtr.namespaces = oldXPNamespaces
+
+ if xpath.ResultPtr == nil {
+ err = errors.New("err in evaluating xpath: " + xpathExpr.String())
+ return
+ }
+ return
+}
+
+// Determine the actual return type of the XPath evaluation.
+func (xpath *XPath) ReturnType() XPathObjectType {
+ return XPathObjectType(C.getXPathObjectType(xpath.ResultPtr))
+}
+
+// Get the XPath result as a nodeset.
+func (xpath *XPath) ResultAsNodeset() (nodes []unsafe.Pointer, err error) {
+ if xpath.ResultPtr == nil {
+ return
+ }
+
+ if xpath.ReturnType() != XPATH_NODESET {
+ err = errors.New("Cannot convert XPath result to nodeset")
+ }
+
+ if nodesetPtr := xpath.ResultPtr.nodesetval; nodesetPtr != nil {
+ if nodesetSize := int(nodesetPtr.nodeNr); nodesetSize > 0 {
+ nodes = make([]unsafe.Pointer, nodesetSize)
+ for i := 0; i < nodesetSize; i++ {
+ nodes[i] = unsafe.Pointer(C.fetchNode(nodesetPtr, C.int(i)))
+ }
+ }
+ }
+ return
+}
+
+// Coerce the result into a string
+func (xpath *XPath) ResultAsString() (val string, err error) {
+ if xpath.ReturnType() != XPATH_STRING {
+ xpath.ResultPtr = C.xmlXPathConvertString(xpath.ResultPtr)
+ }
+ val = C.GoString((*C.char)(unsafe.Pointer(xpath.ResultPtr.stringval)))
+ return
+}
+
+// Coerce the result into a number
+func (xpath *XPath) ResultAsNumber() (val float64, err error) {
+ if xpath.ReturnType() != XPATH_NUMBER {
+ xpath.ResultPtr = C.xmlXPathConvertNumber(xpath.ResultPtr)
+ }
+ val = float64(xpath.ResultPtr.floatval)
+ return
+}
+
+// Coerce the result into a boolean
+func (xpath *XPath) ResultAsBoolean() (val bool, err error) {
+ xpath.ResultPtr = C.xmlXPathConvertBoolean(xpath.ResultPtr)
+ val = xpath.ResultPtr.boolval != 0
+ return
+}
+
+// Add a variable resolver.
+func (xpath *XPath) SetResolver(v VariableScope) {
+ SetScope(unsafe.Pointer(xpath.ContextPtr), v)
+ C.set_var_lookup(xpath.ContextPtr, unsafe.Pointer(xpath.ContextPtr))
+ C.set_function_lookup(xpath.ContextPtr, unsafe.Pointer(xpath.ContextPtr))
+}
+
+// SetContextPosition sets the internal values needed to
+// determine the values of position() and last() for the
+// current context node.
+func (xpath *XPath) SetContextPosition(position, size int) {
+ xpath.ContextPtr.proximityPosition = C.int(position)
+ xpath.ContextPtr.contextSize = C.int(size)
+}
+
+// GetContextPosition retrieves the internal values used to
+// determine the values of position() and last() for the
+// current context node.
+//
+// This allows values to saved and restored during processing
+// of a document.
+func (xpath *XPath) GetContextPosition() (position, size int) {
+ position = int(xpath.ContextPtr.proximityPosition)
+ size = int(xpath.ContextPtr.contextSize)
+ return
+}
+
+func (xpath *XPath) Free() {
+ if xpath.ContextPtr != nil {
+ ClearScope(unsafe.Pointer(xpath.ContextPtr))
+ C.xmlXPathFreeContext(xpath.ContextPtr)
+ xpath.ContextPtr = nil
+ }
+ if xpath.ResultPtr != nil {
+ C.xmlXPathFreeObject(xpath.ResultPtr)
+ xpath.ResultPtr = nil
+ }
+}
+
+func XPathObjectToValue(obj C.xmlXPathObjectPtr) (result interface{}) {
+ rt := XPathObjectType(C.getXPathObjectType(obj))
+ switch rt {
+ case XPATH_NODESET, XPATH_XSLT_TREE:
+ if nodesetPtr := obj.nodesetval; nodesetPtr != nil {
+ if nodesetSize := int(nodesetPtr.nodeNr); nodesetSize > 0 {
+ nodes := make([]unsafe.Pointer, nodesetSize)
+ for i := 0; i < nodesetSize; i++ {
+ nodes[i] = unsafe.Pointer(C.fetchNode(nodesetPtr, C.int(i)))
+ }
+ result = nodes
+ return
+ }
+ }
+ result = nil
+ case XPATH_NUMBER:
+ obj = C.xmlXPathConvertNumber(obj)
+ result = float64(obj.floatval)
+ case XPATH_BOOLEAN:
+ obj = C.xmlXPathConvertBoolean(obj)
+ result = obj.boolval != 0
+ default:
+ obj = C.xmlXPathConvertString(obj)
+ result = C.GoString((*C.char)(unsafe.Pointer(obj.stringval)))
+ }
+ return
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/LICENSE b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/LICENSE
new file mode 100644
index 000000000000..205e33a7f148
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 lestrrat
+
+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.
+
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/clib.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/clib.go
new file mode 100644
index 000000000000..687945f6e79e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/clib.go
@@ -0,0 +1,2256 @@
+/*
+Package clib holds all of the dirty C interaction for go-libxml2.
+
+Although this package is visible to the outside world, the API in this
+package is in NO WAY guaranteed to be stable. This package was
+initially meant to be placed in an internal package so that the
+API was not available to the outside world.
+
+The only reason this is visible is so that the REALLY advanced users
+can abuse the quasi-direct-C-API to overcome shortcomings of the
+"public" API, if any (and of course, you WILL send me a pull request
+later... won't you?)
+
+Please DO NOT rely on this API and expect that it will keep backcompat.
+When the need arises, it WILL be changed, and if you are not ready
+for it, your code WILL break in horrible ways. You have been
+warned.
+*/
+package clib
+
+/*
+#cgo pkg-config: libxml-2.0
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static inline void MY_nilErrorHandler(void *ctx, const char *msg, ...) {}
+
+static inline void MY_xmlSilenceParseErrors() {
+ xmlSetGenericErrorFunc(NULL, MY_nilErrorHandler);
+}
+
+static inline void MY_xmlDefaultParseErrors() {
+ // Checked in the libxml2 source code that using NULL in the second
+ // argument restores the default error handler
+ xmlSetGenericErrorFunc(NULL, NULL);
+}
+
+// Macro wrapper function. cgo cannot detect function-like macros,
+// so this is how we avoid it
+static inline void MY_xmlFree(void *p) {
+ xmlFree(p);
+}
+
+// Macro wrapper function. cgo cannot detect function-like macros,
+// so this is how we avoid it
+static inline xmlError* MY_xmlLastError() {
+ return (xmlError*) xmlGetLastError();
+}
+
+// Macro wrapper function. cgo cannot detect function-like macros,
+// so this is how we avoid it
+static inline xmlError* MY_xmlCtxtLastError(void *ctx) {
+ return (xmlError*) xmlCtxtGetLastError(ctx);
+}
+
+// Change xmlIndentTreeOutput global, return old value, so caller can
+// change it back to old value later
+static inline int MY_setXmlIndentTreeOutput(int i) {
+ int old = xmlIndentTreeOutput;
+ xmlIndentTreeOutput = i;
+ return old;
+}
+
+// Parse a single char out of cur
+// Stolen from XML::LibXML
+static inline int
+MY_parseChar( xmlChar *cur, int *len )
+{
+ unsigned char c;
+ unsigned int val;
+
+ // We are supposed to handle UTF8, check it's valid
+ // From rfc2044: encoding of the Unicode values on UTF-8:
+ //
+ // 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
+ //
+ // Check for the 0x110000 limit too
+
+ if ( cur == NULL || *cur == 0 ) {
+ *len = 0;
+ return(0);
+ }
+
+ c = *cur;
+ if ( (c & 0x80) == 0 ) {
+ *len = 1;
+ return((int)c);
+ }
+
+ if ((c & 0xe0) == 0xe0) {
+ if ((c & 0xf0) == 0xf0) {
+ // 4-byte code
+ *len = 4;
+ val = (cur[0] & 0x7) << 18;
+ val |= (cur[1] & 0x3f) << 12;
+ val |= (cur[2] & 0x3f) << 6;
+ val |= cur[3] & 0x3f;
+ } else {
+ // 3-byte code
+ *len = 3;
+ val = (cur[0] & 0xf) << 12;
+ val |= (cur[1] & 0x3f) << 6;
+ val |= cur[2] & 0x3f;
+ }
+ } else {
+ // 2-byte code
+ *len = 2;
+ val = (cur[0] & 0x1f) << 6;
+ val |= cur[1] & 0x3f;
+ }
+
+ if ( !IS_CHAR(val) ) {
+ *len = -1;
+ return 0;
+ }
+ return val;
+}
+
+// Checks if the given name is a valid name in XML
+// stolen from XML::LibXML
+static inline int
+MY_test_node_name( xmlChar * name )
+{
+ xmlChar * cur = name;
+ int tc = 0;
+ int len = 0;
+
+ if ( cur == NULL || *cur == 0 ) {
+ return 0;
+ }
+
+ tc = MY_parseChar( cur, &len );
+
+ if ( !( IS_LETTER( tc ) || (tc == '_') || (tc == ':')) ) {
+ return 0;
+ }
+
+ tc = 0;
+ cur += len;
+
+ while (*cur != 0 ) {
+ tc = MY_parseChar( cur, &len );
+
+ if (!(IS_LETTER(tc) || IS_DIGIT(tc) || (tc == '_') ||
+ (tc == '-') || (tc == ':') || (tc == '.') ||
+ IS_COMBINING(tc) || IS_EXTENDER(tc)) )
+ {
+ return 0;
+ }
+ tc = 0;
+ cur += len;
+ }
+
+ return(1);
+}
+
+// optimization
+static xmlNode*
+MY_xmlCreateElement(xmlDoc *doc, xmlChar *name) {
+ if (MY_test_node_name(name) == 0) {
+ return NULL;
+ }
+
+ xmlNode *ptr = xmlNewNode(NULL, name);
+ if (ptr == NULL) {
+ return NULL;
+ }
+
+ ptr->doc = doc;
+ return ptr;
+}
+
+static
+xmlNode *
+MY_xmlCreateElementNS(xmlDoc *doc, xmlChar *nsuri, xmlChar *name) {
+ xmlChar *local = name;
+ xmlChar *prefix = NULL;
+ xmlNode *node = NULL;
+ int i;
+
+ if (MY_test_node_name(name) == 0) {
+ return NULL;
+ }
+
+ for (i = 0; i < xmlStrlen(name); i++) {
+ local++;
+ // XXX boundary check!
+ if (*local == ':') {
+ local++;
+ break;
+ }
+ }
+
+ if (local != name) {
+ prefix = (xmlChar *) malloc(sizeof(xmlChar) * (local - name));
+ memcpy(prefix, name, local - name - 1);
+ prefix[(local - name - 1)] = '\0';
+ }
+
+ xmlNode *root = xmlDocGetRootElement(doc);
+ xmlNs *ns;
+ if (root == NULL) {
+ // No document element
+ ns = xmlNewNs(NULL, nsuri, prefix);
+ } else if (prefix != NULL) {
+ // Prefix exists, check if this is declared
+ ns = xmlSearchNs(doc, root, prefix);
+ if (ns == NULL) { // Not declared, create a new one
+ ns = xmlNewNs(NULL, nsuri, prefix);
+ } else { // Declared. Does the uri match?
+ if (xmlStrcmp(ns->href, nsuri) != 0) {
+ // Cleanup prefix
+ goto CLEANUP;
+ }
+ // Namespace is already registered, we don't need to provide a
+ // namespace element to xmlNewDocNode
+ ns = NULL;
+ local = name;
+ }
+ } else {
+ // If the name does not contain a prefix, check for the
+ // existence of this namespace via the URI
+ ns = xmlSearchNsByHref(doc, root, nsuri);
+ if (ns == NULL) {
+ ns = xmlNewNs(NULL, nsuri, NULL);
+ }
+ }
+
+ node = xmlNewDocNode(doc, ns, local, NULL);
+ if (ns != NULL) {
+ node->nsDef = ns;
+ }
+
+CLEANUP:
+ if (prefix != NULL) {
+ free(prefix);
+ }
+
+ return node;
+}
+
+#define GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE 32
+typedef struct go_libxml2_errwarn_accumulator {
+ char *errors[GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE];
+ char *warnings[GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE];
+ int erridx;
+ int warnidx;
+} go_libxml2_errwarn_accumulator;
+
+static
+go_libxml2_errwarn_accumulator*
+MY_createErrWarnAccumulator() {
+ int i;
+ go_libxml2_errwarn_accumulator *ctx;
+ ctx = (go_libxml2_errwarn_accumulator *) malloc(sizeof(go_libxml2_errwarn_accumulator));
+ for (i = 0; i < GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE; i++) {
+ ctx->errors[i] = NULL;
+ ctx->warnings[i] = NULL;
+ }
+ ctx->erridx = 0;
+ ctx->warnidx = 0;
+ return ctx;
+}
+
+static
+void
+MY_freeErrWarnAccumulator(go_libxml2_errwarn_accumulator* ctx) {
+ int i = 0;
+ for (i = 0; i < GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE; i++) {
+ if (ctx->errors[i] != NULL) {
+ free(ctx->errors[i]);
+ }
+ if (ctx->warnings[i] != NULL) {
+ free(ctx->errors[i]);
+ }
+ }
+ free(ctx);
+}
+
+static
+void
+MY_accumulateErr(void *ctx, const char *msg, ...) {
+ char buf[1024];
+ va_list args;
+ go_libxml2_errwarn_accumulator *accum;
+ int len;
+
+ accum = (go_libxml2_errwarn_accumulator *) ctx;
+ if (accum->erridx >= GO_LIBXML2_ERRWARN_ACCUMULATOR_SIZE) {
+ return;
+ }
+
+ va_start(args, msg);
+ len = vsnprintf(buf, sizeof(buf), msg, args);
+ va_end(args);
+
+ if (len == 0) {
+ return;
+ }
+
+ char *out = (char *) calloc(sizeof(char), len);
+ if (buf[len-1] == '\n') {
+ // don't want newlines in my error values
+ buf[len-1] = '\0';
+ len--;
+ }
+ memcpy(out, buf, len);
+
+ int i = accum->erridx++;
+ accum->errors[i] = out;
+}
+
+static
+void
+MY_setErrWarnAccumulator(xmlSchemaValidCtxtPtr ctxt, go_libxml2_errwarn_accumulator *accum) {
+ xmlSchemaSetValidErrors(ctxt, MY_accumulateErr, NULL, accum);
+}
+*/
+import "C"
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+ "unsafe"
+
+ "github.com/lestrrat-go/libxml2/internal/debug"
+ "github.com/lestrrat-go/libxml2/internal/option"
+ "github.com/pkg/errors"
+)
+
+const _XPathObjectTypeName = "XPathUndefinedXPathNodeSetXPathBooleanXPathNumberXPathStringXPathPointXPathRangeXPathLocationSetXPathUSersXPathXsltTree"
+
+var _XPathObjectTypeIndex = [...]uint8{0, 14, 26, 38, 49, 60, 70, 80, 96, 106, 119}
+
+// String returns the stringified version of XPathObjectType
+func (i XPathObjectType) String() string {
+ if i < 0 || i+1 >= XPathObjectType(len(_XPathObjectTypeIndex)) {
+ return fmt.Sprintf("XPathObjectType(%d)", i)
+ }
+ return _XPathObjectTypeName[_XPathObjectTypeIndex[i]:_XPathObjectTypeIndex[i+1]]
+}
+
+func validDocumentPtr(doc PtrSource) (*C.xmlDoc, error) {
+ if doc == nil {
+ return nil, ErrInvalidDocument
+ }
+
+ if dptr := doc.Pointer(); dptr != 0 {
+ return (*C.xmlDoc)(unsafe.Pointer(dptr)), nil
+ }
+ return nil, ErrInvalidDocument
+}
+
+func validParserCtxtPtr(s PtrSource) (*C.xmlParserCtxt, error) {
+ if s == nil {
+ return nil, ErrInvalidParser
+ }
+
+ if ptr := s.Pointer(); ptr != 0 {
+ return (*C.xmlParserCtxt)(unsafe.Pointer(ptr)), nil
+ }
+ return nil, ErrInvalidParser
+}
+
+func validNodePtr(n PtrSource) (*C.xmlNode, error) {
+ if n == nil {
+ return nil, ErrInvalidNode
+ }
+
+ nptr := n.Pointer()
+ if nptr == 0 {
+ return nil, ErrInvalidNode
+ }
+
+ return (*C.xmlNode)(unsafe.Pointer(nptr)), nil
+}
+
+func validAttributePtr(n PtrSource) (*C.xmlAttr, error) {
+ if n == nil {
+ return nil, ErrInvalidAttribute
+ }
+
+ if nptr := n.Pointer(); nptr != 0 {
+ return (*C.xmlAttr)(unsafe.Pointer(nptr)), nil
+ }
+
+ return nil, ErrInvalidAttribute
+}
+
+func validXPathContextPtr(x PtrSource) (*C.xmlXPathContext, error) {
+ if x == nil {
+ return nil, ErrInvalidXPathContext
+ }
+
+ if xptr := x.Pointer(); xptr != 0 {
+ return (*C.xmlXPathContext)(unsafe.Pointer(xptr)), nil
+ }
+ return nil, ErrInvalidXPathContext
+}
+
+func validXPathExpressionPtr(x PtrSource) (*C.xmlXPathCompExpr, error) {
+ if x == nil {
+ return nil, ErrInvalidXPathExpression
+ }
+
+ if xptr := x.Pointer(); xptr != 0 {
+ return (*C.xmlXPathCompExpr)(unsafe.Pointer(xptr)), nil
+ }
+ return nil, ErrInvalidXPathExpression
+}
+
+func validXPathObjectPtr(x PtrSource) (*C.xmlXPathObject, error) {
+ if x == nil {
+ return nil, ErrInvalidXPathObject
+ }
+
+ if xptr := x.Pointer(); xptr != 0 {
+ return (*C.xmlXPathObject)(unsafe.Pointer(xptr)), nil
+ }
+ return nil, ErrInvalidXPathObject
+}
+
+var _XMLNodeTypeIndex = [...]uint8{0, 11, 24, 32, 48, 61, 71, 77, 88, 100, 116, 132, 144, 160, 167, 178, 191, 201, 214, 227, 238, 254}
+
+const _XMLNodeTypeName = `ElementNodeAttributeNodeTextNodeCDataSectionNodeEntityRefNodeEntityNodePiNodeCommentNodeDocumentNodeDocumentTypeNodeDocumentFragNodeNotationNodeHTMLDocumentNodeDTDNodeElementDeclAttributeDeclEntityDeclNamespaceDeclXIncludeStartXIncludeEndDocbDocumentNode`
+
+// String returns the string representation of this XMLNodeType
+func (i XMLNodeType) String() string {
+ x := i - 1
+ if x < 0 || x+1 >= XMLNodeType(len(_XMLNodeTypeIndex)) {
+ return fmt.Sprintf("XMLNodeType(%d)", x+1)
+ }
+ return _XMLNodeTypeName[_XMLNodeTypeIndex[x]:_XMLNodeTypeIndex[x+1]]
+}
+
+// ReportErrors *globally* changes the behavior of reporting errors.
+// By default libxml2 spews out lots of data to stderr. When you call
+// this function with a `false` value, all those messages are suppressed.
+// When you call this function a `true` value, the default behavior is
+// restored
+func ReportErrors(b bool) {
+ if b {
+ C.MY_xmlDefaultParseErrors()
+ } else {
+ C.MY_xmlSilenceParseErrors()
+ }
+}
+
+func xmlCtxtLastError(ctx PtrSource) error {
+ return xmlCtxtLastErrorRaw(ctx.Pointer())
+}
+
+func xmlCtxtLastErrorRaw(ctx uintptr) error {
+ e := C.MY_xmlCtxtLastError(unsafe.Pointer(ctx))
+ if e == nil {
+ return errors.New(`unknown error`)
+ }
+ msg := strings.TrimSuffix(C.GoString(e.message), "\n")
+ return errors.Errorf("Entity: line %v: parser error : %v", e.line, msg)
+}
+
+func xmlCharToString(s *C.xmlChar) string {
+ return C.GoString((*C.char)(unsafe.Pointer(s)))
+}
+
+// stringToXMLChar creates a new *C.xmlChar from a Go string.
+// Remember to always free this data, as C.CString creates a copy
+// of the byte buffer contained in the string
+func stringToXMLChar(s string) *C.xmlChar {
+ return (*C.xmlChar)(unsafe.Pointer(C.CString(s)))
+}
+
+func XMLSchemaParseFromFile(path string) (uintptr, error) {
+ parserCtx := C.xmlSchemaNewParserCtxt(C.CString(path))
+ if parserCtx == nil {
+ return 0, errors.New("failed to create parser")
+ }
+ defer C.xmlSchemaFreeParserCtxt(parserCtx)
+
+ s := C.xmlSchemaParse(parserCtx)
+ if s == nil {
+ return 0, errors.New("failed to parse schema")
+ }
+
+ return uintptr(unsafe.Pointer(s)), nil
+}
+
+func XMLCreateMemoryParserCtxt(s string, o int) (uintptr, error) {
+ cs := C.CString(s)
+ defer C.free(unsafe.Pointer(cs))
+ ctx := C.xmlCreateMemoryParserCtxt(cs, C.int(len(s)))
+ if ctx == nil {
+ return 0, errors.New("error creating parser")
+ }
+ C.xmlCtxtUseOptions(ctx, C.int(o))
+
+ return uintptr(unsafe.Pointer(ctx)), nil
+}
+
+func XMLParseDocument(ctx PtrSource) error {
+ ctxptr, err := validParserCtxtPtr(ctx)
+ if err != nil {
+ return err
+ }
+
+ if C.xmlParseDocument(ctxptr) != C.int(0) {
+ return errors.Errorf("parse failed: %v", xmlCtxtLastError(ctx))
+ }
+ return nil
+}
+
+func XMLFreeParserCtxt(ctx PtrSource) error {
+ ctxptr, err := validParserCtxtPtr(ctx)
+ if err != nil {
+ return err
+ }
+
+ C.xmlFreeParserCtxt(ctxptr)
+ return nil
+}
+
+func HTMLReadDoc(content, url, encoding string, opts int) (uintptr, error) {
+ // TODO: use htmlCtxReadDoc later, so we can get the error
+ ccontent := C.CString(content)
+ curl := C.CString(url)
+ cencoding := C.CString(encoding)
+ defer C.free(unsafe.Pointer(ccontent))
+ defer C.free(unsafe.Pointer(curl))
+ defer C.free(unsafe.Pointer(cencoding))
+
+ doc := C.htmlReadDoc(
+ (*C.xmlChar)(unsafe.Pointer(ccontent)),
+ curl,
+ cencoding,
+ C.int(opts),
+ )
+
+ if doc == nil {
+ return 0, errors.New("failed to parse document")
+ }
+
+ return uintptr(unsafe.Pointer(doc)), nil
+}
+
+func XMLCreateDocument(version, encoding string) uintptr {
+ cver := stringToXMLChar(version)
+ defer C.free(unsafe.Pointer(cver))
+
+ doc := C.xmlNewDoc(cver)
+ if encoding != "" {
+ cenc := stringToXMLChar(encoding)
+ defer C.free(unsafe.Pointer(cenc))
+
+ doc.encoding = C.xmlStrdup(cenc)
+ }
+ return uintptr(unsafe.Pointer(doc))
+}
+
+func XMLEncodeEntitiesReentrant(docptr *C.xmlDoc, s string) (*C.xmlChar, error) {
+ cent := stringToXMLChar(s)
+ defer C.free(unsafe.Pointer(cent))
+
+ return C.xmlEncodeEntitiesReentrant(docptr, cent), nil
+}
+
+func isSafeName(name string) error {
+ if utf8.ValidString(name) { // UTF-8, we can do everything in go
+ if len(name) > MaxValueBufferSize {
+ return ErrValueTooLong
+ }
+ p := name
+ r, n := utf8.DecodeRuneInString(p)
+ p = p[n:]
+ if !unicode.IsLetter(r) && r != '_' && r != ':' {
+ return ErrInvalidNodeName
+ }
+
+ for len(p) > 0 {
+ r, n = utf8.DecodeRuneInString(p)
+ p = p[n:]
+ if !unicode.IsLetter(r) && !unicode.IsNumber(r) && r != '_' && r != ':' {
+ return ErrInvalidNodeName
+ }
+ }
+
+ return nil
+ }
+
+ // Need to call out to C
+ var buf [MaxValueBufferSize]C.xmlChar
+ for i := 0; i < len(name); i++ {
+ buf[i] = C.xmlChar(name[i])
+ }
+ bufptr := (uintptr)(unsafe.Pointer(&buf[0]))
+ if C.MY_test_node_name((*C.xmlChar)(unsafe.Pointer(bufptr))) == 0 {
+ return ErrInvalidNodeName
+ }
+ return nil
+}
+
+func validNamespacePtr(s PtrSource) (*C.xmlNs, error) {
+ if s == nil {
+ return nil, ErrInvalidNamespace
+ }
+
+ if ptr := s.Pointer(); ptr != 0 {
+ return (*C.xmlNs)(unsafe.Pointer(ptr)), nil
+ }
+ return nil, ErrInvalidNamespace
+}
+
+func XMLNewNode(ns PtrSource, name string) (uintptr, error) {
+ nsptr, err := validNamespacePtr(ns)
+ if err != nil {
+ return 0, err
+ }
+
+ if err := isSafeName(name); err != nil {
+ return 0, err
+ }
+
+ var cname [MaxElementNameLength]C.xmlChar
+ if len(name) > MaxElementNameLength {
+ return 0, ErrElementNameTooLong
+ }
+ for i := 0; i < len(name); i++ {
+ cname[i] = C.xmlChar(name[i])
+ }
+ cnameptr := (uintptr)(unsafe.Pointer(&cname[0]))
+
+ n := C.xmlNewNode(
+ (*C.xmlNs)(unsafe.Pointer(nsptr)),
+ (*C.xmlChar)(unsafe.Pointer(cnameptr)),
+ )
+ return uintptr(unsafe.Pointer(n)), nil
+}
+
+func XMLNewDocProp(doc PtrSource, k, v string) (uintptr, error) {
+ docptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ if err := isSafeName(k); err != nil {
+ return 0, err
+ }
+
+ if len(k) > MaxAttributeNameLength {
+ return 0, ErrAttributeNameTooLong
+ }
+
+ var kx [MaxAttributeNameLength]C.xmlChar
+ for i := 0; i < len(k); i++ {
+ kx[i] = C.xmlChar(k[i])
+ }
+ // Taking the pointer as uintptr somehow fools the go compiler
+ // to not think this escapes to heap
+ kxptr := uintptr(unsafe.Pointer(&kx[0]))
+
+ ent, err := XMLEncodeEntitiesReentrant(docptr, v)
+ if err != nil {
+ return 0, err
+ }
+ attr := C.xmlNewDocProp(docptr, (*C.xmlChar)(unsafe.Pointer(kxptr)), ent)
+ return uintptr(unsafe.Pointer(attr)), nil
+}
+
+func XMLSearchNsByHref(doc PtrSource, _ PtrSource, uri string) (uintptr, error) {
+ docptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ nptr, err := validNodePtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ if len(uri) > MaxNamespaceURILength {
+ return 0, ErrNamespaceURITooLong
+ }
+
+ var xcuri [MaxNamespaceURILength]C.xmlChar
+ for i := 0; i < len(uri); i++ {
+ xcuri[i] = C.xmlChar(uri[i])
+ }
+ xcuriptr := (uintptr)(unsafe.Pointer(&xcuri[0]))
+
+ ns := C.xmlSearchNsByHref(
+ (*C.xmlDoc)(unsafe.Pointer(docptr)),
+ (*C.xmlNode)(unsafe.Pointer(nptr)),
+ (*C.xmlChar)(unsafe.Pointer(xcuriptr)),
+ )
+ if ns == nil {
+ return 0, ErrNamespaceNotFound{Target: uri}
+ }
+ return uintptr(unsafe.Pointer(ns)), nil
+}
+
+func XMLSearchNs(doc PtrSource, n PtrSource, prefix string) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ docptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ cprefix := stringToXMLChar(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+
+ ns := C.xmlSearchNs(docptr, nptr, cprefix)
+ if ns == nil {
+ return 0, ErrNamespaceNotFound{Target: prefix}
+ }
+ return uintptr(unsafe.Pointer(ns)), nil
+}
+
+func XMLNewDocNode(doc PtrSource, ns PtrSource, local, content string) (uintptr, error) {
+ docptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ nsptr, err := validNamespacePtr(ns)
+ if err != nil {
+ return 0, err
+ }
+
+ var c *C.xmlChar
+ if len(content) > 0 {
+ c = stringToXMLChar(content)
+ defer C.free(unsafe.Pointer(c))
+ }
+
+ clocal := stringToXMLChar(local)
+ defer C.free(unsafe.Pointer(c))
+
+ ptr := C.xmlNewDocNode(docptr, nsptr, clocal, c)
+ if ptr == nil {
+ return 0, errors.New("failed to create node")
+ }
+ return uintptr(unsafe.Pointer(ptr)), nil
+}
+
+func XMLNewNs(n PtrSource, nsuri, prefix string) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ var cprefix *C.xmlChar
+
+ cnsuri := stringToXMLChar(nsuri)
+ if prefix != "" {
+ cprefix = stringToXMLChar(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+ }
+ defer C.free(unsafe.Pointer(cnsuri))
+
+ nsptr := C.xmlNewNs(nptr, cnsuri, cprefix)
+ if nsptr == nil {
+ return 0, errors.New("failed to create namespace")
+ }
+ return uintptr(unsafe.Pointer(nsptr)), nil
+}
+
+func XMLSetNs(n PtrSource, ns PtrSource) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ nsptr, err := validNamespacePtr(ns)
+ if err != nil {
+ return err
+ }
+
+ C.xmlSetNs(nptr, nsptr)
+ return nil
+}
+
+func XMLNewCDataBlock(doc PtrSource, txt string) (uintptr, error) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+ ctxt := stringToXMLChar(txt)
+ defer C.free(unsafe.Pointer(ctxt))
+
+ ptr := C.xmlNewCDataBlock(dptr, ctxt, C.int(len(txt)))
+ if ptr == nil {
+ return 0, errors.New("failed to create CDATA block")
+ }
+ return uintptr(unsafe.Pointer(ptr)), nil
+}
+
+func XMLNewComment(txt string) (uintptr, error) {
+ ctxt := stringToXMLChar(txt)
+ defer C.free(unsafe.Pointer(ctxt))
+
+ ptr := C.xmlNewComment(ctxt)
+ if ptr == nil {
+ return 0, errors.New("failed to create comment node")
+ }
+ return uintptr(unsafe.Pointer(ptr)), nil
+}
+
+func XMLNewText(txt string) (uintptr, error) {
+ ctxt := stringToXMLChar(txt)
+ defer C.free(unsafe.Pointer(ctxt))
+
+ ptr := C.xmlNewText(ctxt)
+ if ptr == nil {
+ return 0, errors.New("failed to create text node")
+ }
+ return uintptr(unsafe.Pointer(ptr)), nil
+}
+
+func XMLNodeName(n PtrSource) (string, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return "", err
+ }
+
+ var s string
+ switch XMLNodeType(nptr._type) {
+ case XIncludeStart, XIncludeEnd, EntityRefNode, EntityNode, DTDNode, EntityDecl, DocumentTypeNode, NotationNode, NamespaceDecl:
+ s = xmlCharToString(nptr.name)
+ case CommentNode:
+ s = "#comment"
+ case CDataSectionNode:
+ s = "#cdata-section"
+ case TextNode:
+ s = "#text"
+ case DocumentNode, HTMLDocumentNode, DocbDocumentNode:
+ s = "#document"
+ case DocumentFragNode:
+ s = "#document-fragment"
+ case ElementNode, AttributeNode:
+ if ns := nptr.ns; ns != nil {
+ if nsstr := xmlCharToString(ns.prefix); nsstr != "" {
+ s = fmt.Sprintf("%s:%s", xmlCharToString(ns.prefix), xmlCharToString(nptr.name))
+ }
+ }
+
+ if s == "" {
+ s = xmlCharToString(nptr.name)
+ }
+ case ElementDecl, AttributeDecl:
+ panic("unimplemented")
+ default:
+ panic("unknown")
+ }
+
+ return s, nil
+}
+
+func XMLNodeValue(n PtrSource) (string, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return "", err
+ }
+
+ var s string
+ switch XMLNodeType(nptr._type) {
+ case AttributeNode, ElementNode, TextNode, CommentNode, PiNode, EntityRefNode:
+ xc := C.xmlXPathCastNodeToString(nptr)
+ s = xmlCharToString(xc)
+ C.MY_xmlFree(unsafe.Pointer(xc))
+ case CDataSectionNode, EntityDecl:
+ if nptr.content != nil {
+ xc := C.xmlStrdup(nptr.content)
+ s = xmlCharToString(xc)
+ C.MY_xmlFree(unsafe.Pointer(xc))
+ }
+ default:
+ panic("unimplmented")
+ }
+
+ return s, nil
+}
+
+func XMLAddChild(n PtrSource, child PtrSource) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ cptr, err := validNodePtr(child)
+ if err != nil {
+ return err
+ }
+
+ if C.xmlAddChild(nptr, cptr) == nil {
+ return errors.New("failed to add child")
+ }
+ return nil
+}
+
+func XMLOwnerDocument(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ if nptr.doc == nil {
+ return 0, ErrInvalidDocument
+ }
+ return uintptr(unsafe.Pointer(nptr.doc)), nil
+}
+
+func XMLFirstChild(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ if !XMLHasChildNodes(n) {
+ return 0, errors.New("no children")
+ }
+
+ return uintptr(unsafe.Pointer(nptr.children)), nil
+}
+
+func XMLHasChildNodes(n PtrSource) bool {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return false
+ }
+ return nptr.children != nil
+}
+
+func XMLLastChild(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(unsafe.Pointer(nptr.last)), nil
+}
+
+func XMLLocalName(n PtrSource) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+
+ switch XMLNodeType(nptr._type) {
+ case ElementNode, AttributeNode, ElementDecl, AttributeDecl:
+ return xmlCharToString(nptr.name)
+ }
+ return ""
+}
+
+func XMLNamespaceURI(n PtrSource) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+
+ switch XMLNodeType(nptr._type) {
+ case ElementNode, AttributeNode, PiNode:
+ if ns := nptr.ns; ns != nil && ns.href != nil {
+ return xmlCharToString(ns.href)
+ }
+ }
+ return ""
+}
+
+func XMLNextSibling(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(unsafe.Pointer(nptr.next)), nil
+}
+
+func XMLParentNode(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(unsafe.Pointer(nptr.parent)), nil
+}
+
+func XMLPrefix(n PtrSource) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+
+ switch XMLNodeType(nptr._type) {
+ case ElementNode, AttributeNode, PiNode:
+ if ns := nptr.ns; ns != nil && ns.prefix != nil {
+ return xmlCharToString(ns.prefix)
+ }
+ }
+ return ""
+}
+
+func XMLPreviousSibling(n PtrSource) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(unsafe.Pointer(nptr.prev)), nil
+}
+
+func XMLSetNodeName(n PtrSource, name string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+ cname := stringToXMLChar(name)
+ defer C.free(unsafe.Pointer(cname))
+ C.xmlNodeSetName(nptr, cname)
+ return nil
+}
+
+func XMLSetNodeValue(n PtrSource, value string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+ cvalue := stringToXMLChar(value)
+ defer C.free(unsafe.Pointer(cvalue))
+
+ // TODO: Implement this in C
+ if XMLNodeType(nptr._type) != AttributeNode {
+ C.xmlNodeSetContent(nptr, cvalue)
+ return nil
+ }
+
+ if nptr.children != nil {
+ nptr.last = nil
+ C.xmlFreeNodeList(nptr.children)
+ }
+
+ nptr.children = C.xmlNewText(cvalue)
+ nptr.children.parent = nptr
+ nptr.children.doc = nptr.doc
+ nptr.last = nptr.children
+ return nil
+}
+
+func XMLTextContent(n PtrSource) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(C.xmlXPathCastNodeToString(nptr))
+}
+
+func XMLToString(n PtrSource, format int, _ bool) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+
+ buffer := C.xmlBufferCreate()
+ defer C.xmlBufferFree(buffer)
+
+ if format <= 0 {
+ C.xmlNodeDump(buffer, nptr.doc, nptr, 0, 0)
+ } else {
+ oIndentTreeOutput := C.MY_setXmlIndentTreeOutput(1)
+ C.xmlNodeDump(buffer, nptr.doc, nptr, 0, C.int(format))
+ C.MY_setXmlIndentTreeOutput(oIndentTreeOutput)
+ }
+ return xmlCharToString(C.xmlBufferContent(buffer))
+}
+
+func XMLLookupNamespacePrefix(n PtrSource, href string) (string, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return "", err
+ }
+
+ if href == "" {
+ return "", ErrNamespaceNotFound{Target: href}
+ }
+
+ chref := stringToXMLChar(href)
+ defer C.free(unsafe.Pointer(chref))
+ ns := C.xmlSearchNsByHref(nptr.doc, nptr, chref)
+ if ns == nil {
+ return "", ErrNamespaceNotFound{Target: href}
+ }
+
+ return xmlCharToString(ns.prefix), nil
+}
+
+func XMLLookupNamespaceURI(n PtrSource, prefix string) (string, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return "", err
+ }
+
+ if prefix == "" {
+ return "", ErrNamespaceNotFound{Target: prefix}
+ }
+
+ cprefix := stringToXMLChar(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+ ns := C.xmlSearchNs(nptr.doc, nptr, cprefix)
+ if ns == nil {
+ return "", ErrNamespaceNotFound{Target: prefix}
+ }
+
+ return xmlCharToString(ns.href), nil
+}
+
+func XMLGetNodeTypeRaw(n uintptr) XMLNodeType {
+ nptr := (*C.xmlNode)(unsafe.Pointer(n))
+ return XMLNodeType(nptr._type)
+}
+
+func XMLGetNodeType(n PtrSource) XMLNodeType {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return XMLNodeType(0)
+ }
+ return XMLNodeType(nptr._type)
+}
+
+func XMLChildNodes(n PtrSource) ([]uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid node for XMLChildNodes")
+ }
+
+ ret := []uintptr(nil)
+ for chld := nptr.children; chld != nil; chld = chld.next {
+ ret = append(ret, uintptr(unsafe.Pointer(chld)))
+ }
+ return ret, nil
+}
+
+type stringer interface {
+ String() string
+}
+
+func XMLRemoveChild(n PtrSource, t PtrSource) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return errors.Wrap(err, "failed to get valid node for XMLRemoveChild")
+ }
+
+ tptr, err := validNodePtr(t)
+ if err != nil {
+ return errors.Wrap(err, "failed to get valid node for XMLRemoveChild")
+ }
+
+ switch XMLNodeType(tptr._type) {
+ case AttributeNode, NamespaceDecl:
+ return nil
+ }
+
+ if tptr.parent != nptr {
+ return nil /* not a child! */
+ }
+
+ unlinkNode(tptr)
+ if XMLNodeType(tptr._type) == ElementNode {
+ reconcileNs(tptr)
+ }
+
+ return nil
+}
+
+func unlinkNode(nptr *C.xmlNode) {
+ if nptr == nil || (nptr.prev == nil && nptr.next == nil && nptr.parent == nil) {
+ return
+ }
+
+ if XMLNodeType(nptr._type) == DTDNode {
+ /* This clears the doc->intSubset pointer. */
+ C.xmlUnlinkNode(nptr)
+ return
+ }
+
+ if nptr.prev != nil {
+ nptr.prev.next = nptr.next
+ }
+
+ if nptr.next != nil {
+ nptr.next.prev = nptr.prev
+ }
+
+ if nptr.parent != nil {
+ if nptr == nptr.parent.last {
+ nptr.parent.last = nptr.prev
+ }
+
+ if nptr == nptr.parent.children {
+ nptr.parent.children = nptr.next
+ }
+ }
+
+ nptr.prev = nil
+ nptr.next = nil
+ nptr.parent = nil
+}
+
+func reconcileNs(tree *C.xmlNode) {
+ var unused *C.xmlNs
+ reconcileNsSave(tree, &unused)
+ if unused != nil {
+ C.xmlFreeNsList(unused)
+ }
+}
+
+func addNsChain(n *C.xmlNs, ns *C.xmlNs) *C.xmlNs {
+ if n == nil {
+ return ns
+ }
+
+ for i := n; i != nil && i != ns; i = i.next {
+ if i == nil {
+ ns.next = n
+ return ns
+ }
+ }
+
+ return n
+}
+
+func addNsDef(tree *C.xmlNode, ns *C.xmlNs) {
+ i := tree.nsDef
+ //nolint:revive
+ for ; i != nil && i != ns; i = i.next {
+ }
+
+ if i == nil {
+ ns.next = tree.nsDef
+ tree.nsDef = ns
+ }
+}
+
+func removeNsDef(tree *C.xmlNode, ns *C.xmlNs) bool {
+ if ns == tree.nsDef {
+ tree.nsDef = tree.nsDef.next
+ ns.next = nil
+ return true
+ }
+
+ for i := tree.nsDef; i != nil; i = i.next {
+ if i.next == ns {
+ i.next = ns.next
+ ns.next = nil
+ return true
+ }
+ }
+
+ return false
+}
+
+func reconcileNsSave(tree *C.xmlNode, unused **C.xmlNs) {
+ if tree.ns != nil && (XMLNodeType(tree._type) == ElementNode || XMLNodeType(tree._type) == AttributeNode) {
+ ns := C.xmlSearchNs(tree.doc, tree.parent, tree.ns.prefix)
+ if ns != nil && ns.href != nil && tree.ns.href != nil && C.xmlStrcmp(ns.href, tree.ns.href) == 0 {
+ /* Remove the declaration (if present) */
+ if removeNsDef(tree, tree.ns) {
+ /* Queue the namespace for freeing */
+
+ *unused = addNsChain(*unused, tree.ns)
+ }
+ /* Replace the namespace with the one found */
+
+ tree.ns = ns
+ } else {
+ /* If the declaration is here, we don't need to do anything */
+ if removeNsDef(tree, tree.ns) {
+ addNsDef(tree, tree.ns)
+ } else {
+ /* Restart the namespace at this point */
+ tree.ns = C.xmlCopyNamespace(tree.ns)
+ addNsDef(tree, tree.ns)
+ }
+ }
+ }
+}
+
+func SplitPrefixLocal(s string) (string, string) {
+ i := strings.IndexByte(s, ':')
+ if i == -1 {
+ return "", s
+ }
+ return s[:i], s[i+1:]
+}
+
+func XMLNamespaceHref(n PtrSource) string {
+ nsptr, err := validNamespacePtr(n)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(nsptr.href)
+}
+
+func XMLNamespacePrefix(n PtrSource) string {
+ nsptr, err := validNamespacePtr(n)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(nsptr.prefix)
+}
+
+func XMLNamespaceFree(n PtrSource) {
+ nsptr, err := validNamespacePtr(n)
+ if err != nil {
+ return
+ }
+ C.MY_xmlFree(unsafe.Pointer(nsptr))
+}
+
+func XMLCreateAttributeNS(doc PtrSource, uri, k, v string) (uintptr, error) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ rootptr := C.xmlDocGetRootElement(dptr)
+ if rootptr == nil {
+ return 0, errors.New("no document element found")
+ }
+
+ if err := isSafeName(k); err != nil {
+ return 0, err
+ }
+
+ prefix, local := SplitPrefixLocal(k)
+
+ if len(uri) > MaxNamespaceURILength {
+ return 0, ErrNamespaceURITooLong
+ }
+
+ var xcuri [MaxNamespaceURILength]C.xmlChar
+ for i := 0; i < len(uri); i++ {
+ xcuri[i] = C.xmlChar(uri[i])
+ }
+ xcuriptr := (uintptr)(unsafe.Pointer(&xcuri[0]))
+
+ ns := C.xmlSearchNsByHref(
+ (*C.xmlDoc)(unsafe.Pointer(dptr)),
+ (*C.xmlNode)(unsafe.Pointer(rootptr)),
+ (*C.xmlChar)(unsafe.Pointer(xcuriptr)),
+ )
+ if ns == nil {
+ if len(prefix) > MaxAttributeNameLength {
+ return 0, ErrAttributeNameTooLong
+ }
+ var xcprefix [MaxAttributeNameLength]C.xmlChar
+ for i := 0; i < len(prefix); i++ {
+ xcprefix[i] = C.xmlChar(prefix[i])
+ }
+ xcprefixptr := (uintptr)(unsafe.Pointer(&xcprefix))
+
+ ns = C.xmlNewNs(
+ rootptr,
+ (*C.xmlChar)(unsafe.Pointer(xcuriptr)),
+ (*C.xmlChar)(unsafe.Pointer(xcprefixptr)),
+ )
+ if ns == nil {
+ return 0, errors.New("failed to create namespace")
+ }
+ }
+
+ xcv := stringToXMLChar(v)
+ defer C.free(unsafe.Pointer(xcv))
+
+ ent := C.xmlEncodeEntitiesReentrant(dptr, xcv)
+ if ent == nil {
+ return 0, errors.New("failed to encode value")
+ }
+
+ xclocal := stringToXMLChar(local)
+ defer C.free(unsafe.Pointer(xclocal))
+
+ attr := C.xmlNewDocProp(dptr, xclocal, ent)
+
+ C.xmlSetNs((*C.xmlNode)(unsafe.Pointer(attr)), ns)
+
+ return uintptr(unsafe.Pointer(attr)), nil
+}
+
+func XMLCreateElement(d PtrSource, name string) (uintptr, error) {
+ dptr, err := validDocumentPtr(d)
+ if err != nil {
+ return 0, err
+ }
+
+ var xcname [MaxElementNameLength]C.xmlChar
+ if len(name) > MaxElementNameLength {
+ return 0, ErrElementNameTooLong
+ }
+ for i := 0; i < len(name); i++ {
+ xcname[i] = C.xmlChar(name[i])
+ }
+ xcnameptr := (uintptr)(unsafe.Pointer(&xcname[0]))
+
+ nptr := C.MY_xmlCreateElement(dptr, (*C.xmlChar)(unsafe.Pointer(xcnameptr)))
+ if nptr == nil {
+ return 0, errors.New("element creation failed")
+ }
+
+ return uintptr(unsafe.Pointer(nptr)), nil
+}
+
+func XMLCreateElementNS(doc PtrSource, nsuri, name string) (uintptr, error) {
+ if nsuri == "" {
+ return XMLCreateElement(doc, name)
+ }
+
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ if len(nsuri) > MaxNamespaceURILength {
+ return 0, ErrNamespaceURITooLong
+ }
+
+ var xcnsuri [MaxNamespaceURILength]C.xmlChar
+ for i := 0; i < len(nsuri); i++ {
+ xcnsuri[i] = C.xmlChar(nsuri[i])
+ }
+ xcnsuriptr := (uintptr)(unsafe.Pointer(&xcnsuri[0]))
+
+ var xcname [MaxElementNameLength]C.xmlChar
+ for i := 0; i < len(name); i++ {
+ xcname[i] = C.xmlChar(name[i])
+ }
+ xcnameptr := (uintptr)(unsafe.Pointer(&xcname[0]))
+
+ nptr := C.MY_xmlCreateElementNS(
+ dptr,
+ (*C.xmlChar)(unsafe.Pointer(xcnsuriptr)),
+ (*C.xmlChar)(unsafe.Pointer(xcnameptr)),
+ )
+ if nptr == nil {
+ return 0, errors.New("failed to create element")
+ }
+
+ return uintptr(unsafe.Pointer(nptr)), nil
+}
+
+func XMLDocumentEncoding(doc PtrSource) string {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(dptr.encoding)
+}
+
+func XMLDocumentStandalone(doc PtrSource) int {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0
+ }
+ return int(dptr.standalone)
+}
+
+func XMLDocumentURI(doc PtrSource) string {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(dptr.URL)
+}
+
+func XMLDocumentVersion(doc PtrSource) string {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(dptr.version)
+}
+
+func XMLDocumentElement(doc PtrSource) (uintptr, error) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return 0, err
+ }
+
+ ptr := C.xmlDocGetRootElement(dptr)
+ if ptr == nil {
+ return 0, errors.New("no document element found")
+ }
+ return uintptr(unsafe.Pointer(ptr)), nil
+}
+
+func XMLFreeDoc(doc PtrSource) error {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return err
+ }
+ C.xmlFreeDoc(dptr)
+ return nil
+}
+
+func XMLDocumentString(doc PtrSource, encoding string, format bool) string {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return ""
+ }
+
+ var intformat C.int
+ if format {
+ intformat = C.int(1)
+ } else {
+ intformat = C.int(0)
+ }
+
+ // Ideally this shouldn't happen, but you never know.
+ if encoding == "" {
+ encoding = "utf-8"
+ }
+
+ var xcencoding [MaxEncodingLength]C.char
+ for i := 0; i < len(encoding); i++ {
+ xcencoding[i] = C.char(encoding[i])
+ }
+ xcencodingptr := (uintptr)(unsafe.Pointer(&xcencoding[0]))
+
+ var i C.int
+ var xc *C.xmlChar
+ C.xmlDocDumpFormatMemoryEnc(dptr, &xc, &i, (*C.char)(unsafe.Pointer(xcencodingptr)), intformat)
+
+ defer C.MY_xmlFree(unsafe.Pointer(xc))
+ return xmlCharToString(xc)
+}
+
+func XMLNodeSetBase(doc PtrSource, s string) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return
+ }
+
+ cs := stringToXMLChar(s)
+ defer C.free(unsafe.Pointer(cs))
+ C.xmlNodeSetBase((*C.xmlNode)(unsafe.Pointer(dptr)), cs)
+}
+
+func XMLSetDocumentElement(doc PtrSource, n PtrSource) error {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return err
+ }
+
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ C.xmlDocSetRootElement(dptr, nptr)
+ return nil
+}
+
+func XMLSetDocumentEncoding(doc PtrSource, e string) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return
+ }
+
+ if dptr.encoding != nil {
+ C.MY_xmlFree(unsafe.Pointer(dptr.encoding))
+ }
+
+ // note: this doesn't need to be dup'ed, as
+ // C.CString is already duped/malloc'ed
+ dptr.encoding = stringToXMLChar(e)
+}
+
+func XMLSetDocumentStandalone(doc PtrSource, v int) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return
+ }
+ dptr.standalone = C.int(v)
+}
+
+func XMLSetDocumentVersion(doc PtrSource, v string) {
+ dptr, err := validDocumentPtr(doc)
+ if err != nil {
+ return
+ }
+
+ if dptr.version != nil {
+ C.MY_xmlFree(unsafe.Pointer(dptr.version))
+ }
+
+ // note: this doesn't need to be dup'ed, as
+ // C.CString is already duped/malloc'ed
+ dptr.version = stringToXMLChar(v)
+}
+
+func XMLSetProp(n PtrSource, name, value string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ if len(name) > MaxAttributeNameLength {
+ return ErrAttributeNameTooLong
+ }
+
+ var xcname [MaxAttributeNameLength]C.xmlChar
+ for i := 0; i < len(name); i++ {
+ xcname[i] = C.xmlChar(name[i])
+ }
+ xcnameptr := (uintptr)(unsafe.Pointer(&xcname[0]))
+
+ if len(value) > MaxValueBufferSize {
+ return ErrValueTooLong
+ }
+ var xcvalue [MaxValueBufferSize]C.xmlChar
+ for i := 0; i < len(value); i++ {
+ xcvalue[i] = C.xmlChar(value[i])
+ }
+ xcvalueptr := (uintptr)(unsafe.Pointer(&xcvalue[0]))
+
+ C.xmlSetProp(
+ nptr,
+ (*C.xmlChar)(unsafe.Pointer(xcnameptr)),
+ (*C.xmlChar)(unsafe.Pointer(xcvalueptr)),
+ )
+ return nil
+}
+
+func XMLElementAttributes(n PtrSource) ([]uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid node for XMLElementAttributes")
+ }
+
+ attrs := []uintptr{}
+ for attr := nptr.properties; attr != nil; attr = attr.next {
+ attrs = append(attrs, uintptr(unsafe.Pointer(attr)))
+ }
+ return attrs, nil
+}
+
+func XMLElementNamespaces(n PtrSource) ([]uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid node for XMLElementNamespaces")
+ }
+
+ ret := []uintptr{}
+ for ns := nptr.nsDef; ns != nil; ns = ns.next {
+ if ns.prefix == nil && ns.href == nil {
+ continue
+ }
+ // ALERT! Allocating new C struct here
+ newns := C.xmlCopyNamespace(ns)
+ if newns == nil { // XXX this is an error, no?
+ continue
+ }
+
+ ret = append(ret, uintptr(unsafe.Pointer(newns)))
+ }
+ return ret, nil
+}
+
+func XMLElementGetAttributeNode(n PtrSource, name string) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ // if this is "xmlns", look for the first namespace without
+ // the prefix
+ if name == "xmlns" {
+ for nsdef := nptr.nsDef; nsdef != nil; nsdef = nsdef.next {
+ if nsdef.prefix != nil {
+ continue
+ }
+ if debug.Enabled {
+ debug.Printf("nsdef.href -> %s", xmlCharToString(nsdef.href))
+ }
+ }
+ }
+
+ cname := stringToXMLChar(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ prop := C.xmlHasNsProp(nptr, cname, nil)
+ if debug.Enabled {
+ debug.Printf("prop = %v", prop)
+ }
+
+ if prop == nil {
+ prefix, local := SplitPrefixLocal(name)
+ if debug.Enabled {
+ debug.Printf("prefix = %s, local = %s", prefix, local)
+ }
+ if local != "" {
+ cprefix := stringToXMLChar(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+ if ns := C.xmlSearchNs(nptr.doc, nptr, cprefix); ns != nil {
+ clocal := stringToXMLChar(local)
+ defer C.free(unsafe.Pointer(clocal))
+
+ prop = C.xmlHasNsProp(nptr, clocal, ns.href)
+ }
+ }
+ }
+
+ if prop == nil || XMLNodeType(prop._type) != AttributeNode {
+ return 0, ErrAttributeNotFound
+ }
+
+ return uintptr(unsafe.Pointer(prop)), nil
+}
+
+func XMLFreeProp(attr PtrSource) error {
+ nptr, err := validAttributePtr(attr)
+ if err != nil {
+ return err
+ }
+ C.xmlFreeProp(nptr)
+ return nil
+}
+
+func XMLFreeNode(n PtrSource) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+ C.xmlFreeNode(nptr)
+ return nil
+}
+
+func XMLUnsetProp(n PtrSource, name string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ cname := stringToXMLChar(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ i := C.xmlUnsetProp(nptr, cname)
+ if i == C.int(0) {
+ return errors.New("failed to unset prop")
+ }
+ return nil
+}
+
+func XMLUnsetNsProp(n PtrSource, ns PtrSource, name string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ nsptr, err := validNamespacePtr(ns)
+ if err != nil {
+ return err
+ }
+
+ cname := stringToXMLChar(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ i := C.xmlUnsetNsProp(
+ nptr,
+ nsptr,
+ cname,
+ )
+ if i == C.int(0) {
+ return errors.New("failed to unset prop")
+ }
+ return nil
+}
+
+func XMLC14NDocDumpMemory(d PtrSource, mode int, withComments bool) (string, error) {
+ dptr, err := validDocumentPtr(d)
+ if err != nil {
+ return "", err
+ }
+
+ var result *C.xmlChar
+
+ var withCommentsInt C.int
+ if withComments {
+ withCommentsInt = 1
+ }
+
+ modeInt := C.int(mode)
+
+ written := C.xmlC14NDocDumpMemory(
+ dptr,
+ nil,
+ modeInt,
+ nil,
+ withCommentsInt,
+ &result,
+ )
+ if written < 0 {
+ e := C.MY_xmlLastError()
+ return "", errors.New("c14n dump failed: " + C.GoString(e.message))
+ }
+ defer C.MY_xmlFree(unsafe.Pointer(result))
+ return xmlCharToString(result), nil
+}
+
+func XMLAppendText(n PtrSource, s string) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ cs := stringToXMLChar(s)
+ defer C.free(unsafe.Pointer(cs))
+
+ txt := C.xmlNewText(cs)
+ if txt == nil {
+ return errors.New("failed to create text node")
+ }
+
+ if C.xmlAddChild(nptr, (*C.xmlNode)(txt)) == nil {
+ return errors.New("failed to create text node")
+ }
+ return nil
+}
+
+func XMLDocCopyNode(n PtrSource, d PtrSource, extended int) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ dptr, err := validDocumentPtr(d)
+ if err != nil {
+ return 0, err
+ }
+
+ ret := C.xmlDocCopyNode(nptr, dptr, C.int(extended))
+ if ret == nil {
+ return 0, errors.New("copy node failed")
+ }
+
+ return uintptr(unsafe.Pointer(ret)), nil
+}
+
+func XMLSetTreeDoc(n PtrSource, d PtrSource) error {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ dptr, err := validDocumentPtr(d)
+ if err != nil {
+ return err
+ }
+
+ C.xmlSetTreeDoc(nptr, dptr)
+ return nil
+}
+
+func XMLParseInNodeContext(n PtrSource, data string, o int) (uintptr, error) {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return 0, err
+ }
+
+ var ret C.xmlNodePtr
+ cdata := C.CString(data)
+ defer C.free(unsafe.Pointer(cdata))
+ if C.xmlParseInNodeContext(nptr, cdata, C.int(len(data)), C.int(o), &ret) != 0 {
+ return 0, errors.New("XXX PLACE HOLDER XXX")
+ }
+
+ return uintptr(unsafe.Pointer(ret)), nil
+}
+
+func XMLXPathNewContext(n PtrSource) (uintptr, error) {
+ ctx := C.xmlXPathNewContext(nil)
+ ctx.namespaces = nil
+
+ nptr, err := validNodePtr(n)
+ if err == nil {
+ ctx.node = (*C.xmlNode)(unsafe.Pointer(nptr))
+ }
+
+ return uintptr(unsafe.Pointer(ctx)), nil
+}
+
+func XMLXPathContextSetContextNode(x PtrSource, n PtrSource) error {
+ xptr, err := validXPathContextPtr(x)
+ if err != nil {
+ return err
+ }
+
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return err
+ }
+
+ xptr.node = nptr
+ return nil
+}
+
+func XMLXPathCompile(s string) (uintptr, error) {
+ if len(s) > MaxXPathExpressionLength {
+ return 0, ErrXPathExpressionTooLong
+ }
+
+ var xcs [MaxXPathExpressionLength]C.xmlChar
+ for i := 0; i < len(s); i++ {
+ xcs[i] = C.xmlChar(s[i])
+ }
+ xcsptr := (uintptr)(unsafe.Pointer(&xcs[0]))
+
+ if p := C.xmlXPathCompile((*C.xmlChar)(unsafe.Pointer(xcsptr))); p != nil {
+ return uintptr(unsafe.Pointer(p)), nil
+ }
+ return 0, ErrXPathCompileFailure
+}
+
+func XMLXPathFreeCompExpr(x PtrSource) error {
+ xptr, err := validXPathExpressionPtr(x)
+ if err != nil {
+ return err
+ }
+ C.xmlXPathFreeCompExpr(xptr)
+ return nil
+}
+
+func XMLXPathFreeContext(x PtrSource) error {
+ xptr, err := validXPathContextPtr(x)
+ if err != nil {
+ return err
+ }
+ C.xmlXPathFreeContext(xptr)
+ return nil
+}
+
+func XMLXPathNSLookup(x PtrSource, prefix string) (string, error) {
+ xptr, err := validXPathContextPtr(x)
+ if err != nil {
+ return "", err
+ }
+
+ cprefix := stringToXMLChar(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+
+ if s := C.xmlXPathNsLookup(xptr, cprefix); s != nil {
+ return xmlCharToString(s), nil
+ }
+
+ return "", ErrNamespaceNotFound{Target: prefix}
+}
+
+func XMLXPathRegisterNS(x PtrSource, prefix, nsuri string) error {
+ xptr, err := validXPathContextPtr(x)
+ if err != nil {
+ return err
+ }
+
+ if len(prefix) > MaxElementNameLength {
+ return ErrElementNameTooLong
+ }
+ var cprefix [MaxElementNameLength]C.xmlChar
+ for i := 0; i < len(prefix); i++ {
+ cprefix[i] = C.xmlChar(prefix[i])
+ }
+ cprefixptr := (uintptr)(unsafe.Pointer(&cprefix[0]))
+
+ if len(nsuri) > MaxNamespaceURILength {
+ return ErrNamespaceURITooLong
+ }
+ var cnsuri [MaxNamespaceURILength]C.xmlChar
+ for i := 0; i < len(nsuri); i++ {
+ cnsuri[i] = C.xmlChar(nsuri[i])
+ }
+ cnsuriptr := (uintptr)(unsafe.Pointer(&cnsuri[0]))
+
+ if res := C.xmlXPathRegisterNs(xptr, (*C.xmlChar)(unsafe.Pointer(cprefixptr)), (*C.xmlChar)(unsafe.Pointer(cnsuriptr))); res == -1 {
+ return ErrXPathNamespaceRegisterFailure
+ }
+ return nil
+}
+
+func XMLEvalXPath(x PtrSource, expr PtrSource) (uintptr, error) {
+ xptr, err := validXPathContextPtr(x)
+ if err != nil {
+ return 0, err
+ }
+
+ exprptr, err := validXPathExpressionPtr(expr)
+ if err != nil {
+ return 0, err
+ }
+
+ // If there is no document associated with this context,
+ // then xmlXPathCompiledEval() just fails to match
+ if xptr.node != nil && xptr.node.doc != nil {
+ xptr.doc = xptr.node.doc
+ }
+
+ if xptr.doc == nil {
+ var xcv [3]C.xmlChar = [3]C.xmlChar{'1', '.', '0'}
+ xcvptr := (uintptr)(unsafe.Pointer(&xcv[0]))
+ xptr.doc = C.xmlNewDoc((*C.xmlChar)(unsafe.Pointer(xcvptr)))
+
+ defer C.xmlFreeDoc(xptr.doc)
+ }
+
+ res := C.xmlXPathCompiledEval(exprptr, xptr)
+ if res == nil {
+ return 0, ErrXPathEmptyResult
+ }
+
+ return uintptr(unsafe.Pointer(res)), nil
+}
+
+func XMLXPathFreeObject(x PtrSource) {
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return
+ }
+ C.xmlXPathFreeObject(xptr)
+ // if xptr.nodesetval != nil {
+ // C.xmlXPathFreeNodeSet(xptr.nodesetval)
+ // }
+}
+
+func XMLXPathObjectNodeListLen(x PtrSource) int {
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return 0
+ }
+
+ if xptr.nodesetval == nil {
+ return 0
+ }
+
+ return int(xptr.nodesetval.nodeNr)
+}
+
+func XMLXPathObjectType(x PtrSource) XPathObjectType {
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return XPathUndefinedType
+ }
+ return XPathObjectType(xptr._type)
+}
+
+func XMLXPathObjectFloat64(x PtrSource) float64 {
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return float64(0)
+ }
+
+ return float64(xptr.floatval)
+}
+
+func XMLXPathObjectBool(x PtrSource) bool {
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return false
+ }
+
+ return xptr.boolval == 1
+}
+
+func XMLXPathObjectNodeList(x PtrSource) ([]uintptr, error) {
+ // Probably needs NodeList iterator
+ xptr, err := validXPathObjectPtr(x)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid xpath object for XMLXPathObjectNodeList")
+ }
+
+ nodeset := xptr.nodesetval
+ if nodeset == nil {
+ return nil, errors.Wrap(ErrInvalidNode, "failed to get valid node for XMLXPathObjectNodeList")
+ }
+
+ if nodeset.nodeNr == 0 {
+ return nil, errors.Wrap(ErrInvalidNode, "failed to get valid node for XMLXPathObjectNodeList")
+ }
+
+ nodes := unsafe.Slice(nodeset.nodeTab, nodeset.nodeNr)
+
+ ret := make([]uintptr, nodeset.nodeNr)
+ for i := 0; i < int(nodeset.nodeNr); i++ {
+ ret[i] = uintptr(unsafe.Pointer(nodes[i]))
+ }
+
+ return ret, nil
+}
+
+func XMLTextData(n PtrSource) string {
+ nptr, err := validNodePtr(n)
+ if err != nil {
+ return ""
+ }
+ return xmlCharToString(nptr.content)
+}
+
+func XMLSchemaParse(buf []byte, options ...option.Interface) (uintptr, error) {
+ var uri string
+ var encoding string
+ var coptions int
+ //nolint:forcetypeassert
+ for _, opt := range options {
+ switch opt.Name() {
+ case option.OptKeyWithURI:
+ uri = opt.Value().(string)
+ }
+ }
+
+ docctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), C.int(len(buf)))
+ if docctx == nil {
+ return 0, errors.New("error creating doc parser")
+ }
+
+ var curi *C.char
+ if uri != "" {
+ curi = C.CString(uri)
+ defer C.free(unsafe.Pointer(curi))
+ }
+
+ var cencoding *C.char
+ if encoding != "" {
+ cencoding = C.CString(encoding)
+ defer C.free(unsafe.Pointer(cencoding))
+ }
+
+ doc := C.xmlCtxtReadMemory(docctx, (*C.char)(unsafe.Pointer(&buf[0])), C.int(len(buf)), curi, cencoding, C.int(coptions))
+ if doc == nil {
+ return 0, errors.Errorf("failed to read schema from memory: %v",
+ xmlCtxtLastErrorRaw(uintptr(unsafe.Pointer(docctx))))
+ }
+
+ parserCtx := C.xmlSchemaNewDocParserCtxt((*C.xmlDoc)(unsafe.Pointer(doc)))
+ if parserCtx == nil {
+ return 0, errors.New("failed to create parser")
+ }
+ defer C.xmlSchemaFreeParserCtxt(parserCtx)
+
+ s := C.xmlSchemaParse(parserCtx)
+ if s == nil {
+ return 0, errors.New("failed to parse schema")
+ }
+
+ return uintptr(unsafe.Pointer(s)), nil
+}
+
+func XMLSchemaValidateDocument(schema PtrSource, document PtrSource, options ...int) []error {
+ sptr, err := validSchemaPtr(schema)
+ if err != nil {
+ return []error{err}
+ }
+
+ dptr, err := validDocumentPtr(document)
+ if err != nil {
+ return []error{err}
+ }
+
+ ctx := C.xmlSchemaNewValidCtxt(sptr)
+ if ctx == nil {
+ return []error{errors.New("failed to build validator")}
+ }
+ defer C.xmlSchemaFreeValidCtxt(ctx)
+
+ accum := C.MY_createErrWarnAccumulator()
+ defer C.MY_freeErrWarnAccumulator(accum)
+
+ C.MY_setErrWarnAccumulator(ctx, accum)
+
+ for _, option := range options {
+ C.xmlSchemaSetValidOptions(ctx, C.int(option))
+ }
+
+ if C.xmlSchemaValidateDoc(ctx, dptr) == 0 {
+ return nil
+ }
+
+ errs := make([]error, accum.erridx)
+ for i := 0; i < int(accum.erridx); i++ {
+ errs[i] = errors.New(C.GoString(accum.errors[i]))
+ }
+ return errs
+}
+
+func validSchemaPtr(schema PtrSource) (*C.xmlSchema, error) {
+ if schema == nil {
+ return nil, ErrInvalidSchema
+ }
+ sptr := schema.Pointer()
+ if sptr == 0 {
+ return nil, ErrInvalidSchema
+ }
+
+ return (*C.xmlSchema)(unsafe.Pointer(sptr)), nil
+}
+
+func XMLSchemaFree(s PtrSource) error {
+ sptr, err := validSchemaPtr(s)
+ if err != nil {
+ return err
+ }
+
+ C.xmlSchemaFree(sptr)
+ return nil
+}
+
+func XMLCtxtReadMemory(ctx PtrSource, file string, baseURL string, encoding string, options int) (uintptr, error) {
+ ctxptr, err := validParserCtxtPtr(ctx)
+ if err != nil {
+ return 0, errors.Wrap(err, "not a valid pointer")
+ }
+
+ var cfile, cbaseURL, cencoding *C.char
+ if file != "" {
+ cfile = C.CString(file)
+ defer C.free(unsafe.Pointer(cfile))
+ }
+
+ if baseURL != "" {
+ cbaseURL = C.CString(baseURL)
+ defer C.free(unsafe.Pointer(cbaseURL))
+ }
+
+ if encoding != "" {
+ cencoding = C.CString(encoding)
+ defer C.free(unsafe.Pointer(cencoding))
+ }
+
+ doc := C.xmlCtxtReadMemory(ctxptr, cfile, C.int(len(file)), cbaseURL, cencoding, C.int(options))
+ if doc == nil {
+ return 0, errors.Errorf("failed to read document from memory: %v", xmlCtxtLastError(ctx))
+ }
+ return uintptr(unsafe.Pointer(doc)), nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/interface.go
new file mode 100644
index 000000000000..835e3cd91b3c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/clib/interface.go
@@ -0,0 +1,120 @@
+package clib
+
+import "errors"
+
+const (
+ MaxEncodingLength = 256
+ MaxAttributeNameLength = 1024
+ MaxElementNameLength = 1024
+ MaxNamespaceURILength = 4096
+ MaxValueBufferSize = 4096
+ MaxXPathExpressionLength = 4096
+)
+
+// C14NMode represents the C14N mode supported by libxml2
+type C14NMode int
+
+// PtrSource is the single interface that connects the rest of
+// libxml2 package with this package. The clib packages does not
+// really care what sort of object you pass to these low-level
+// functions, as long as the arguments fulfill this interface.
+//
+// Obviously this causes problems if you pass the an Element node
+// where a Document node is expected, but it is the caller's
+// responsibility to align the argument list.
+type PtrSource interface {
+ Pointer() uintptr
+}
+
+// XMLNodeType identifies the type of the underlying C struct
+type XMLNodeType int
+
+const (
+ ElementNode XMLNodeType = iota + 1
+ AttributeNode
+ TextNode
+ CDataSectionNode
+ EntityRefNode
+ EntityNode
+ PiNode
+ CommentNode
+ DocumentNode
+ DocumentTypeNode
+ DocumentFragNode
+ NotationNode
+ HTMLDocumentNode
+ DTDNode
+ ElementDecl
+ AttributeDecl
+ EntityDecl
+ NamespaceDecl
+ XIncludeStart
+ XIncludeEnd
+ DocbDocumentNode
+)
+
+var (
+ ErrAttributeNotFound = errors.New("attribute not found")
+ ErrAttributeNameTooLong = errors.New("attribute name too long")
+ ErrElementNameTooLong = errors.New("element name too long")
+ ErrNamespaceURITooLong = errors.New("namespace uri too long")
+ ErrValueTooLong = errors.New("value too long")
+ ErrXPathExpressionTooLong = errors.New("xpath expression too long")
+ // ErrInvalidAttribute is returned when the Attribute struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidAttribute = errors.New("invalid attribute")
+ ErrInvalidArgument = errors.New("invalid argument")
+ // ErrInvalidDocument is returned when the Document struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidDocument = errors.New("invalid document")
+ // ErrInvalidParser is returned when the Parser struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidParser = errors.New("invalid parser")
+ // ErrInvalidNamespace is returned when the Namespace struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidNamespace = errors.New("invalid namespace")
+ // ErrInvalidNode is returned when the Node struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidNode = errors.New("invalid node")
+ ErrInvalidNodeName = errors.New("invalid node name")
+ // ErrInvalidXPathContext is returned when the XPathContext struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidXPathContext = errors.New("invalid xpath context")
+ // ErrInvalidXPathExpression is returned when the XPathExpression struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidXPathExpression = errors.New("invalid xpath expression")
+ // ErrInvalidXPathObject is returned when the XPathObject struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidXPathObject = errors.New("invalid xpath object")
+ // ErrInvalidSchema is returned when the Schema struct (probably
+ // the pointer to the underlying C struct is not valid)
+ ErrInvalidSchema = errors.New("invalid schema")
+ ErrNodeNotFound = errors.New("node not found")
+ ErrXPathEmptyResult = errors.New("empty xpath result")
+ ErrXPathCompileFailure = errors.New("xpath compilation failed")
+ ErrXPathNamespaceRegisterFailure = errors.New("cannot register namespace")
+)
+
+//nolint:errname
+type ErrNamespaceNotFound struct {
+ Target string
+}
+
+func (e ErrNamespaceNotFound) Error() string {
+ return "namespace not found: " + e.Target
+}
+
+type XPathObjectType int
+
+const (
+ XPathUndefinedType XPathObjectType = iota
+ XPathNodeSetType
+ XPathBooleanType
+ XPathNumberType
+ XPathStringType
+ XPathPointType
+ XPathRangeType
+ XPathLocationSetType
+ XPathUsersType
+ XPathXSLTTreeType
+)
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/dom.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/dom.go
new file mode 100644
index 000000000000..c8ecaf8586db
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/dom.go
@@ -0,0 +1,29 @@
+package dom
+
+import (
+ "sync"
+
+ "github.com/lestrrat-go/libxml2/xpath"
+)
+
+var docPool sync.Pool
+
+func init() {
+ SetupXPathCallback()
+ docPool = sync.Pool{}
+ docPool.New = func() interface{} {
+ return &Document{}
+ }
+}
+
+func SetupXPathCallback() {
+ xpath.WrapNodeFunc = WrapNode
+}
+
+func WrapDocument(n uintptr) *Document {
+ //nolint:forcetypeassert
+ doc := docPool.Get().(*Document)
+ doc.mortal = false
+ doc.ptr = n
+ return doc
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/interface.go
new file mode 100644
index 000000000000..622b738674ae
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/interface.go
@@ -0,0 +1,101 @@
+package dom
+
+import (
+ "errors"
+
+ "github.com/lestrrat-go/libxml2/clib"
+)
+
+var (
+ ErrAttributeNotFound = clib.ErrAttributeNotFound
+ ErrInvalidNodeType = errors.New("invalid node type")
+)
+
+// XMLNodeType identifies the type of the underlying C struct
+type XMLNodeType clib.XMLNodeType
+
+const (
+ ElementNode = clib.ElementNode
+ AttributeNode = clib.AttributeNode
+ TextNode = clib.TextNode
+ CDataSectionNode = clib.CDataSectionNode
+ EntityRefNode = clib.EntityRefNode
+ EntityNode = clib.EntityNode
+ PiNode = clib.PiNode
+ CommentNode = clib.CommentNode
+ DocumentNode = clib.DocumentNode
+ DocumentTypeNode = clib.DocumentTypeNode
+ DocumentFragNode = clib.DocumentFragNode
+ NotationNode = clib.NotationNode
+ HTMLDocumentNode = clib.HTMLDocumentNode
+ DTDNode = clib.DTDNode
+ ElementDecl = clib.ElementDecl
+ AttributeDecl = clib.AttributeDecl
+ EntityDecl = clib.EntityDecl
+ NamespaceDecl = clib.NamespaceDecl
+ XIncludeStart = clib.XIncludeStart
+ XIncludeEnd = clib.XIncludeEnd
+ DocbDocumentNode = clib.DocbDocumentNode
+)
+
+type XMLNode struct {
+ ptr uintptr // *C.xmlNode
+ mortal bool
+}
+
+type Attribute struct {
+ XMLNode
+}
+
+type CDataSection struct {
+ XMLNode
+}
+
+type Pi struct {
+ XMLNode
+}
+
+type Comment struct {
+ XMLNode
+}
+
+type Element struct {
+ XMLNode
+}
+
+type Document struct {
+ ptr uintptr // *C.xmlDoc
+ mortal bool
+}
+
+type Text struct {
+ XMLNode
+}
+
+type Namespace struct {
+ XMLNode
+}
+
+type Serializer interface {
+ Serialize(interface{}) (string, error)
+}
+
+// note: Serialize takes an interface because some serializers only allow
+// Document, whereas others might allow Nodes
+
+// C14NMode represents the C14N mode supported by libxml2
+type C14NMode int
+
+//nolint:revive,stylecheck
+const (
+ C14N1_0 C14NMode = iota
+ C14NExclusive1_0
+ C14N1_1
+)
+
+// C14NSerialize implements the Serializer interface, and generates
+// XML in C14N format.
+type C14NSerialize struct {
+ Mode C14NMode
+ WithComments bool
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node.go
new file mode 100644
index 000000000000..c262b018e579
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node.go
@@ -0,0 +1,292 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+ "github.com/lestrrat-go/libxml2/xpath"
+ "github.com/pkg/errors"
+)
+
+// ChildNodes returns the child nodes
+func (n *XMLNode) ChildNodes() (types.NodeList, error) {
+ list, err := clib.XMLChildNodes(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get child node pointers")
+ }
+
+ ret := make(types.NodeList, len(list))
+ for i, x := range list {
+ ret[i], err = WrapNode(x)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to wrap node pointer")
+ }
+ }
+ return ret, nil
+}
+
+func (n *XMLNode) RemoveChild(t types.Node) error {
+ return clib.XMLRemoveChild(n, t)
+}
+
+// Pointer returns the pointer to the underlying C struct
+func (n *XMLNode) Pointer() uintptr {
+ return n.ptr
+}
+
+// String returns the string representation
+func (n *XMLNode) String() string {
+ return n.ToString(0, false)
+}
+
+// OwnerDocument returns the Document that this node belongs to
+func (n *XMLNode) OwnerDocument() (types.Document, error) {
+ ptr, err := clib.XMLOwnerDocument(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid owner document")
+ }
+
+ if ptr == 0 {
+ return nil, errors.Wrap(clib.ErrInvalidDocument, "failed to get valid owner document")
+ }
+ return WrapDocument(ptr), nil
+}
+
+// NodeName returns the node name
+func (n *XMLNode) NodeName() string {
+ s, err := clib.XMLNodeName(n)
+ if err != nil {
+ return ""
+ }
+ return s
+}
+
+// NodeValue returns the node value
+func (n *XMLNode) NodeValue() string {
+ s, err := clib.XMLNodeValue(n)
+ if err != nil {
+ return ""
+ }
+ return s
+}
+
+// Literal returns the literal string value
+func (n XMLNode) Literal() (string, error) {
+ return n.String(), nil
+}
+
+// IsSameNode returns true if two nodes point to the same node
+func (n *XMLNode) IsSameNode(other types.Node) bool {
+ return n.Pointer() == other.Pointer()
+}
+
+// Copy creates a copy of the node
+func (n *XMLNode) Copy() (types.Node, error) {
+ doc, err := n.OwnerDocument()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get owner document")
+ }
+ nptr, err := clib.XMLDocCopyNode(n, doc, 1)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to copy document nodes")
+ }
+ return WrapNode(nptr)
+}
+
+// SetDocument sets the document of this node and its descendants
+func (n *XMLNode) SetDocument(d types.Document) error {
+ return clib.XMLSetTreeDoc(n, d)
+}
+
+// ParseInContext parses a chunk of XML in the context of the current
+// node. This makes it safe to append the resulting node to the current
+// node or other nodes in the same document.
+func (n *XMLNode) ParseInContext(s string, o int) (types.Node, error) {
+ nptr, err := clib.XMLParseInNodeContext(n, s, o)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to parse input")
+ }
+ return WrapNode(nptr)
+}
+
+// Find evaluates the xpath expression and returns the matching nodes
+func (n *XMLNode) Find(expr string) (types.XPathResult, error) {
+ ctx, err := xpath.NewContext(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create new XPath context")
+ }
+ defer ctx.Free()
+
+ return ctx.Find(expr)
+}
+
+// FindExpr evalues the pre-compiled xpath expression and returns the matching nodes
+func (n *XMLNode) FindExpr(expr *xpath.Expression) (types.XPathResult, error) {
+ ctx, err := xpath.NewContext(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create new XPath context")
+ }
+ defer ctx.Free()
+
+ return ctx.FindExpr(expr)
+}
+
+// HasChildNodes returns true if the node contains children
+func (n *XMLNode) HasChildNodes() bool {
+ return clib.XMLHasChildNodes(n)
+}
+
+// FirstChild reutrns the first child node
+func (n *XMLNode) FirstChild() (types.Node, error) {
+ ptr, err := clib.XMLFirstChild(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid pointer to first child")
+ }
+ return WrapNode(ptr)
+}
+
+// LastChild returns the last child node
+func (n *XMLNode) LastChild() (types.Node, error) {
+ ptr, err := clib.XMLLastChild(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid pointer to first child")
+ }
+ return WrapNode(ptr)
+}
+
+// LocalName returns the local name
+func (n *XMLNode) LocalName() string {
+ return clib.XMLLocalName(n)
+}
+
+// NamespaceURI returns the namespace URI associated with this node
+func (n *XMLNode) NamespaceURI() string {
+ return clib.XMLNamespaceURI(n)
+}
+
+// NextSibling returns the next sibling
+func (n *XMLNode) NextSibling() (types.Node, error) {
+ ptr, err := clib.XMLNextSibling(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid pointer to next child")
+ }
+ if ptr == 0 {
+ return nil, nil
+ }
+ return WrapNode(ptr)
+}
+
+// ParentNode returns the parent node
+func (n *XMLNode) ParentNode() (types.Node, error) {
+ ptr, err := clib.XMLParentNode(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid pointer to parent node")
+ }
+
+ return WrapNode(ptr)
+}
+
+// Prefix returns the prefix from the node name, if any
+func (n *XMLNode) Prefix() string {
+ return clib.XMLPrefix(n)
+}
+
+// PreviousSibling returns the previous sibling
+func (n *XMLNode) PreviousSibling() (types.Node, error) {
+ ptr, err := clib.XMLPreviousSibling(n)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid pointer to previous child")
+ }
+
+ return WrapNode(ptr)
+}
+
+// SetNodeName sets the node name
+func (n *XMLNode) SetNodeName(name string) {
+ _ = clib.XMLSetNodeName(n, name)
+}
+
+// SetNodeValue sets the node value
+func (n *XMLNode) SetNodeValue(value string) {
+ _ = clib.XMLSetNodeValue(n, value)
+}
+
+// AddChild appends the node
+func (n *XMLNode) AddChild(child types.Node) error {
+ return clib.XMLAddChild(n, child)
+}
+
+// TextContent returns the text content
+func (n *XMLNode) TextContent() string {
+ return clib.XMLTextContent(n)
+}
+
+// ToString returns the string representation. (But it should probably
+// be deprecated)
+func (n *XMLNode) ToString(format int, docencoding bool) string {
+ return clib.XMLToString(n, format, docencoding)
+}
+
+// LookupNamespacePrefix returns the prefix associated with the given URL
+func (n *XMLNode) LookupNamespacePrefix(href string) (string, error) {
+ return clib.XMLLookupNamespacePrefix(n, href)
+}
+
+// LookupNamespaceURI returns the URI associated with the given prefix
+func (n *XMLNode) LookupNamespaceURI(prefix string) (string, error) {
+ return clib.XMLLookupNamespaceURI(n, prefix)
+}
+
+// NodeType returns the XMLNodeType
+func (n *XMLNode) NodeType() clib.XMLNodeType {
+ return clib.XMLGetNodeType(n)
+}
+
+// MakeMortal flags the node so that `AutoFree` calls Free()
+// to release the underlying C resources.
+func (n *XMLNode) MakeMortal() {
+ n.mortal = true
+}
+
+// MakePersistent flags the node so that `AutoFree` becomes a no-op.
+// Make sure to call this if you used `MakeMortal` and `AutoFree`,
+// but you then decided to keep the node around.
+func (n *XMLNode) MakePersistent() {
+ n.mortal = false
+}
+
+// Free releases the underlying C struct
+func (n *XMLNode) Free() {
+ _ = clib.XMLFreeNode(n)
+ n.ptr = 0
+}
+
+func walk(n types.Node, fn func(types.Node) error) error {
+ if err := fn(n); err != nil {
+ return errors.Wrap(err, "failed to call callback")
+ }
+ children, err := n.ChildNodes()
+ if err != nil {
+ return errors.Wrap(err, "failed to fetch child nodes")
+ }
+ for _, c := range children {
+ if err := walk(c, fn); err != nil {
+ return errors.Wrap(err, "failed to walk to child nodes")
+ }
+ }
+ return nil
+}
+
+// Walk traverses through all of the nodes
+func (n *XMLNode) Walk(fn func(types.Node) error) error {
+ return walk(n, fn)
+}
+
+// AutoFree allows you to free the underlying C resources. It is
+// meant to be called from defer. If you don't call `MakeMortal()` or
+// do call `MakePersistent()`, AutoFree is a no-op.
+func (n *XMLNode) AutoFree() {
+ if !n.mortal {
+ return
+ }
+ n.Free()
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_attr.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_attr.go
new file mode 100644
index 000000000000..180e90b8e89a
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_attr.go
@@ -0,0 +1,26 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+)
+
+// Free releases the underlying C struct
+func (n *Attribute) Free() {
+ _ = clib.XMLFreeProp(n)
+}
+
+// HasChildNodes returns true if the node contains any child nodes.
+// By definition attributes cannot have children, so this always
+// returns false
+func (n *Attribute) HasChildNodes() bool {
+ return false
+}
+
+// Value returns the value of the attribute.
+func (n *Attribute) Value() string {
+ v, err := clib.XMLNodeValue(n)
+ if err != nil {
+ return ""
+ }
+ return v
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_document.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_document.go
new file mode 100644
index 000000000000..045f3cbda73a
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_document.go
@@ -0,0 +1,350 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+ "github.com/pkg/errors"
+)
+
+// CreateDocument creates a new document with version="1.0", and no encoding
+func CreateDocument() *Document {
+ return NewDocument("1.0", "")
+}
+
+// NewDocument creates a new document
+func NewDocument(version, encoding string) *Document {
+ ptr := clib.XMLCreateDocument(version, encoding)
+ return WrapDocument(ptr)
+}
+
+// Pointer returns the pointer to the underlying C struct
+func (d *Document) Pointer() uintptr {
+ return d.ptr
+}
+
+// AutoFree calls Free() if the document is moral.
+func (d *Document) AutoFree() {
+ if !d.mortal {
+ return
+ }
+ d.Free()
+}
+
+// MakeMortal sets the flag
+func (d *Document) MakeMortal() {
+ d.mortal = true
+}
+
+// MakePersistent unsets the flag
+func (d *Document) MakePersistent() {
+ d.mortal = false
+}
+
+// IsSameNode checks if the underlying C pointer points to the same C struct
+func (d *Document) IsSameNode(n types.Node) bool {
+ return d.ptr == n.Pointer()
+}
+
+// HasChildNodes returns true if the document node is available
+func (d *Document) HasChildNodes() bool {
+ _, err := d.DocumentElement()
+ return err != nil
+}
+
+// FirstChild returns the document element
+func (d *Document) FirstChild() (types.Node, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document element")
+ }
+
+ return root, nil
+}
+
+// LastChild returns the document element
+func (d *Document) LastChild() (types.Node, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document element")
+ }
+
+ return root, nil
+}
+
+// NextSibling always returns nil for Document
+func (d *Document) NextSibling() (types.Node, error) {
+ return nil, errors.New("document has no siblings")
+}
+
+// PreviousSibling always returns nil for Document
+func (d *Document) PreviousSibling() (types.Node, error) {
+ return nil, errors.New("document has no siblings")
+}
+
+// NodeName always returns an empty string for Document
+func (d *Document) NodeName() string {
+ return ""
+}
+
+// SetNodeName is a no op for document
+func (d *Document) SetNodeName(_ string) {
+ // return errors.New("cannot set node name on a document")
+}
+
+// NodeValue always returns an empty string for Document
+func (d *Document) NodeValue() string {
+ return ""
+}
+
+// SetNodeValue is a no op for document
+func (d *Document) SetNodeValue(_ string) {
+ // return errors.New("cannot set node value on a document")
+}
+
+// OwnerDocument always returns the document itself
+func (d *Document) OwnerDocument() (types.Document, error) {
+ return d, nil
+}
+
+// SetDocument always returns an error for a document
+func (d *Document) SetDocument(_ types.Document) error {
+ return errors.New("cannot set document on a document")
+}
+
+// ParentNode always returns an error for a document
+func (d *Document) ParentNode() (types.Node, error) {
+ return nil, errors.New("document has no parent node")
+}
+
+// ParseInContext is currently unimplemented
+func (d *Document) ParseInContext(_ string, _ int) (types.Node, error) {
+ return nil, errors.New("unimplemented")
+}
+
+// Literal is currently just an alias to Dump(false)
+func (d *Document) Literal() (string, error) {
+ return d.Dump(false), nil
+}
+
+// TextContent returns the text content
+func (d *Document) TextContent() string {
+ return clib.XMLTextContent(d)
+}
+
+// ToString is currently just an alias to Dump(false)
+func (d *Document) ToString(_ int, b bool) string {
+ return d.Dump(b)
+}
+
+// ChildNodes returns the document element
+func (d *Document) ChildNodes() (types.NodeList, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document element")
+ }
+
+ return []types.Node{root}, nil
+}
+
+// Copy is currently unimplemented
+func (d *Document) Copy() (types.Node, error) {
+ // Unimplemented
+ return nil, errors.New("unimplemented")
+}
+
+// AddChild is a no op for Document
+func (d *Document) AddChild(_ types.Node) error {
+ return errors.New("method AddChild is not available for Document node")
+}
+
+// CreateAttribute creates a new attribute
+func (d *Document) CreateAttribute(k, v string) (*Attribute, error) {
+ attr, err := clib.XMLNewDocProp(d, k, v)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document property")
+ }
+ return wrapAttributeNode(attr), nil
+}
+
+// CreateAttributeNS creates a new attribute with the given XML namespace
+func (d *Document) CreateAttributeNS(nsuri, k, v string) (*Attribute, error) {
+ if nsuri == "" {
+ return d.CreateAttribute(k, v)
+ }
+
+ ptr, err := clib.XMLCreateAttributeNS(d, nsuri, k, v)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create attribute")
+ }
+ return wrapAttributeNode(ptr), nil
+}
+
+// CreateCDataSection creates a new CDATA section node
+func (d *Document) CreateCDataSection(txt string) (*CDataSection, error) {
+ cdata, err := clib.XMLNewCDataBlock(d, txt)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create CDATA block")
+ }
+ return wrapCDataSectionNode(cdata), nil
+}
+
+// CreateCommentNode creates a new comment node
+func (d *Document) CreateCommentNode(txt string) (*Comment, error) {
+ ptr, err := clib.XMLNewComment(txt)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create comment")
+ }
+ return wrapCommentNode(ptr), nil
+}
+
+// CreateElement creates a new element node
+func (d *Document) CreateElement(name string) (types.Element, error) {
+ ptr, err := clib.XMLCreateElement(d, name)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create element")
+ }
+ return wrapElementNode(ptr), nil
+}
+
+// CreateElementNS creates a new element node in the given XML namespace
+func (d *Document) CreateElementNS(nsuri, name string) (types.Element, error) {
+ ptr, err := clib.XMLCreateElementNS(d, nsuri, name)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create element")
+ }
+ return wrapElementNode(ptr), nil
+}
+
+// CreateTextNode creates a new text node
+func (d *Document) CreateTextNode(txt string) (*Text, error) {
+ ptr, err := clib.XMLNewText(txt)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create text node")
+ }
+ return wrapTextNode(ptr), nil
+}
+
+// DocumentElement returns the root node of the document
+func (d *Document) DocumentElement() (types.Node, error) {
+ n, err := clib.XMLDocumentElement(d)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document element")
+ }
+ return WrapNode(n)
+}
+
+// Find returns the nodes that can be selected with the
+// given xpath string
+func (d *Document) Find(xpath string) (types.XPathResult, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get document element")
+ }
+ return root.Find(xpath)
+}
+
+// Encoding returns the d
+func (d *Document) Encoding() string {
+ return clib.XMLDocumentEncoding(d)
+}
+
+// Free releases the underlying C struct
+func (d *Document) Free() {
+ _ = clib.XMLFreeDoc(d)
+ d.ptr = 0
+ docPool.Put(d)
+}
+
+// String formats the document, always without formatting.
+func (d *Document) String() string {
+ return clib.XMLDocumentString(d, d.Encoding(), false)
+}
+
+// Dump formats the document with or withour formatting.
+func (d *Document) Dump(format bool) string {
+ return clib.XMLDocumentString(d, d.Encoding(), format)
+}
+
+// NodeType returns the XMLNodeType
+func (d *Document) NodeType() clib.XMLNodeType {
+ return DocumentNode
+}
+
+// SetBaseURI sets the base URI
+func (d *Document) SetBaseURI(s string) {
+ clib.XMLNodeSetBase(d, s)
+}
+
+// SetDocumentElement sets the document element
+func (d *Document) SetDocumentElement(n types.Node) error {
+ return clib.XMLSetDocumentElement(d, n)
+}
+
+// SetEncoding sets the encoding of the document
+func (d *Document) SetEncoding(e string) {
+ clib.XMLSetDocumentEncoding(d, e)
+}
+
+// SetStandalone sets the standalone flag
+func (d *Document) SetStandalone(v int) {
+ clib.XMLSetDocumentStandalone(d, v)
+}
+
+// SetVersion sets the version of the document
+func (d *Document) SetVersion(v string) {
+ clib.XMLSetDocumentVersion(d, v)
+}
+
+// Standalone returns the value of the standalone flag
+func (d *Document) Standalone() int {
+ return clib.XMLDocumentStandalone(d)
+}
+
+// URI returns the document URI
+func (d *Document) URI() string {
+ return clib.XMLDocumentURI(d)
+}
+
+// Version returns the version of the document
+func (d *Document) Version() string {
+ return clib.XMLDocumentVersion(d)
+}
+
+// Walk traverses the nodes in the document
+func (d *Document) Walk(fn func(types.Node) error) error {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return errors.Wrap(err, "failed to get document element")
+ }
+ return walk(root, fn)
+}
+
+// LookupNamespacePrefix looks for a namespace prefix that matches
+// the given namespace URI
+func (d *Document) LookupNamespacePrefix(href string) (string, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return "", errors.Wrap(err, "failed to get document element")
+ }
+
+ return root.LookupNamespacePrefix(href)
+}
+
+// LookupNamespaceURI looks for a namespace uri that matches
+// the given namespace prefix
+func (d *Document) LookupNamespaceURI(prefix string) (string, error) {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return "", errors.Wrap(err, "failed to get document element")
+ }
+
+ return root.LookupNamespaceURI(prefix)
+}
+
+func (d *Document) RemoveChild(n types.Node) error {
+ root, err := d.DocumentElement()
+ if err != nil {
+ return errors.Wrap(err, "failed to get document element")
+ }
+ return root.RemoveChild(n)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_element.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_element.go
new file mode 100644
index 000000000000..651cdf51b773
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_element.go
@@ -0,0 +1,146 @@
+package dom
+
+import (
+ "bytes"
+ "errors"
+ "strings"
+
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+)
+
+// SetNamespace sets up a new namespace on the given node.
+// An XML namespace declaration is explicitly created only if
+// the activate flag is enabled, and the namespace is not
+// declared in a previous tree hierarchy.
+func (n *Element) SetNamespace(uri, prefix string, activate ...bool) error {
+ var activateflag bool
+ if len(activate) < 1 {
+ activateflag = true
+ } else {
+ activateflag = activate[0]
+ }
+
+ if uri == "" && prefix == "" {
+ // Empty namespace
+ doc, err := n.OwnerDocument()
+ if err != nil {
+ return err
+ }
+ nsptr, err := clib.XMLSearchNs(doc, n, "")
+ if err != nil {
+ return err
+ }
+
+ ns := wrapNamespaceNode(nsptr)
+ if ns.URI() != "" {
+ if activateflag {
+ _ = clib.XMLSetNs(n, nil)
+ }
+ }
+ return nil
+ }
+
+ if uri == "" {
+ return errors.New("missing uri for SetNamespace")
+ }
+
+ ns, err := clib.XMLNewNs(n, uri, prefix)
+ if err != nil {
+ return err
+ }
+
+ if activateflag {
+ if err := clib.XMLSetNs(n, wrapNamespaceNode(ns)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// AppendText adds a new text node
+func (n *Element) AppendText(s string) error {
+ return clib.XMLAppendText(n, s)
+}
+
+// SetAttribute sets an attribute
+func (n *Element) SetAttribute(name, value string) error {
+ return clib.XMLSetProp(n, name, value)
+}
+
+// GetAttribute retrieves the value of an attribute
+func (n *Element) GetAttribute(name string) (types.Attribute, error) {
+ attrNode, err := clib.XMLElementGetAttributeNode(n, name)
+ if err != nil {
+ return nil, err
+ }
+ return wrapAttributeNode(attrNode), nil
+}
+
+// Attributes returns a list of attributes on a node
+func (n *Element) Attributes() ([]types.Attribute, error) {
+ attrs, err := clib.XMLElementAttributes(n)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]types.Attribute, len(attrs))
+ for i, attr := range attrs {
+ ret[i] = wrapAttributeNode(attr)
+ }
+ return ret, nil
+}
+
+// RemoveAttribute completely removes an attribute from the node
+func (n *Element) RemoveAttribute(name string) error {
+ i := strings.IndexByte(name, ':')
+ if i == -1 {
+ return clib.XMLUnsetProp(n, name)
+ }
+
+ // look for the prefix
+ doc, err := n.OwnerDocument()
+ if err != nil {
+ return err
+ }
+ ns, err := clib.XMLSearchNs(doc, n, name[:i])
+ if err != nil {
+ return ErrAttributeNotFound
+ }
+
+ return clib.XMLUnsetNsProp(n, wrapNamespaceNode(ns), name)
+}
+
+// GetNamespaces returns Namespace objects associated with this
+// element. WARNING: This method currently returns namespace
+// objects which allocates C structures for each namespace.
+// Therefore you MUST free the structures, or otherwise you
+// WILL leak memory.
+func (n *Element) GetNamespaces() ([]types.Namespace, error) {
+ list, err := clib.XMLElementNamespaces(n)
+ if err != nil {
+ return nil, err
+ }
+ ret := make([]types.Namespace, len(list))
+ for i, nsptr := range list {
+ ret[i] = wrapNamespaceNode(nsptr)
+ }
+ return ret, nil
+}
+
+// Literal returns a stringified version of this node and its
+// children, inclusive.
+func (n Element) Literal() (string, error) {
+ buf := bytes.Buffer{}
+ children, err := n.ChildNodes()
+ if err != nil {
+ return "", err
+ }
+ for _, c := range children {
+ l, err := c.Literal()
+ if err != nil {
+ return "", err
+ }
+ buf.WriteString(l)
+ }
+ return buf.String(), nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_namespace.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_namespace.go
new file mode 100644
index 000000000000..4f9595adf861
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_namespace.go
@@ -0,0 +1,21 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+)
+
+// URI returns the namespace URL
+func (n *Namespace) URI() string {
+ return clib.XMLNamespaceHref(n)
+}
+
+// Prefix returns the prefix for this namespace
+func (n *Namespace) Prefix() string {
+ return clib.XMLNamespacePrefix(n)
+}
+
+// Free releases the underlying C struct
+func (n *Namespace) Free() {
+ clib.XMLNamespaceFree(n)
+ n.ptr = 0
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_text.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_text.go
new file mode 100644
index 000000000000..b539bb4c6a7d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_text.go
@@ -0,0 +1,14 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+)
+
+func (n *CDataSection) Literal() (string, error) {
+ return clib.XMLNodeValue(n)
+}
+
+// Data returns the content associated with this node
+func (n *Text) Data() string {
+ return clib.XMLTextData(n)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_wrap.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_wrap.go
new file mode 100644
index 000000000000..29dc199aeb7f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/node_wrap.go
@@ -0,0 +1,74 @@
+package dom
+
+// Auto-generated by internal/cmd/genwrapnode/genwrapnode.go. DO NOT EDIT!
+
+import (
+ "fmt"
+
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+)
+
+func wrapNamespaceNode(ptr uintptr) *Namespace {
+ var n Namespace
+ n.ptr = ptr
+ return &n
+}
+
+func wrapAttributeNode(ptr uintptr) *Attribute {
+ var n Attribute
+ n.ptr = ptr
+ return &n
+}
+
+func wrapCDataSectionNode(ptr uintptr) *CDataSection {
+ var n CDataSection
+ n.ptr = ptr
+ return &n
+}
+
+func wrapCommentNode(ptr uintptr) *Comment {
+ var n Comment
+ n.ptr = ptr
+ return &n
+}
+
+func wrapElementNode(ptr uintptr) *Element {
+ var n Element
+ n.ptr = ptr
+ return &n
+}
+
+func wrapTextNode(ptr uintptr) *Text {
+ var n Text
+ n.ptr = ptr
+ return &n
+}
+
+func wrapPiNode(ptr uintptr) *Pi {
+ var n Pi
+ n.ptr = ptr
+ return &n
+}
+
+// WrapNode is a function created with the sole purpose of allowing
+// go-libxml2 consumers that can generate a C.xmlNode pointer to
+// create libxml2.Node types, e.g. go-xmlsec.
+func WrapNode(n uintptr) (types.Node, error) {
+ switch typ := clib.XMLGetNodeTypeRaw(n); typ {
+ case clib.AttributeNode:
+ return wrapAttributeNode(n), nil
+ case clib.CDataSectionNode:
+ return wrapCDataSectionNode(n), nil
+ case clib.CommentNode:
+ return wrapCommentNode(n), nil
+ case clib.ElementNode:
+ return wrapElementNode(n), nil
+ case clib.TextNode:
+ return wrapTextNode(n), nil
+ case clib.PiNode:
+ return wrapPiNode(n), nil
+ default:
+ return nil, fmt.Errorf("unknown node: %d", typ)
+ }
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/serialize.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/serialize.go
new file mode 100644
index 000000000000..e97eca4fde9f
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/dom/serialize.go
@@ -0,0 +1,45 @@
+package dom
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+)
+
+// Serialize produces serialization of the document, canonicalized.
+func (s C14NSerialize) Serialize(n types.Node) (string, error) {
+ /*
+ * Below document is taken from libxml2 directly. Pay special attention
+ * to the required settings when parsing the document to be canonicalized.
+ *
+ * ---
+ * Canonical form of an XML document could be created if and only if
+ * a) default attributes (if any) are added to all nodes
+ * b) all character and parsed entity references are resolved
+ * In order to achieve this in libxml2 the document MUST be loaded with
+ * following global setings:
+ *
+ * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ * xmlSubstituteEntitiesDefault(1);
+ *
+ * or corresponding parser context setting:
+ * xmlParserCtxtPtr ctxt;
+ *
+ * ...
+ * ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+ * ctxt->replaceEntities = 1;
+ * ...
+ * ---
+ *
+ * In go-libxml2, this translates to:
+ *
+ * options = XMLParserDTDLoad | XMLParserDTDAttr | XMLParserNoEnt
+ *
+ */
+ switch n.(type) {
+ case *Document:
+ default:
+ return "", ErrInvalidNodeType
+ }
+
+ return clib.XMLC14NDocDumpMemory(n, int(s.Mode), s.WithComments)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_off.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_off.go
new file mode 100644
index 000000000000..746e3362e271
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_off.go
@@ -0,0 +1,9 @@
+//go:build !debug
+// +build !debug
+
+package debug
+
+const Enabled = false
+
+// Printf is no op unless you compile with the `debug` tag
+func Printf(_ string, _ ...interface{}) {}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_on.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_on.go
new file mode 100644
index 000000000000..658cb494dcb8
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/debug/debug_on.go
@@ -0,0 +1,17 @@
+//+build debug
+
+package debug
+
+import (
+ "log"
+ "os"
+)
+
+const Enabled = true
+
+var logger = log.New(os.Stdout, "|DEBUG| ", 0)
+
+// Printf prints debug messages. Only available if compiled with "debug" tag
+func Printf(f string, args ...interface{}) {
+ logger.Printf(f, args...)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/interface.go
new file mode 100644
index 000000000000..3108ed9b9d63
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/interface.go
@@ -0,0 +1,5 @@
+package option
+
+const (
+ OptKeyWithURI = `with-uri`
+)
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/option.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/option.go
new file mode 100644
index 000000000000..9259dc51b4c2
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/internal/option/option.go
@@ -0,0 +1,25 @@
+package option
+
+type Interface interface {
+ Name() string
+ Value() interface{}
+}
+
+type Option struct {
+ name string
+ value interface{}
+}
+
+func New(name string, value interface{}) *Option {
+ return &Option{
+ name: name,
+ value: value,
+ }
+}
+
+func (o *Option) Name() string {
+ return o.name
+}
+func (o *Option) Value() interface{} {
+ return o.value
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/interface.go
new file mode 100644
index 000000000000..b6ae3bdf4d99
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/interface.go
@@ -0,0 +1,82 @@
+package parser
+
+import "errors"
+
+var (
+ // ErrMalformedXML is returned when the XML source is malformed
+ ErrMalformedXML = errors.New("malformed XML")
+)
+
+// HTMLOption represents the HTML parser options that
+// can be used when parsing HTML
+type HTMLOption int
+
+const (
+ // HTMLParseRecover enables relaxed parsing
+ HTMLParseRecover HTMLOption = 1 << 0
+ // HTMLParseNoDefDTD disables using a default doctype when absent
+ HTMLParseNoDefDTD = 1 << 2
+ // HTMLParseNoError suppresses error reports
+ HTMLParseNoError = 1 << 5
+ // HTMLParseNoWarning suppresses warning reports
+ HTMLParseNoWarning = 1 << 6
+ // HTMLParsePedantic enables pedantic error reporting
+ HTMLParsePedantic = 1 << 7
+ // HTMLParseNoBlanks removes blank nodes
+ HTMLParseNoBlanks = 1 << 8
+ // HTMLParseNoNet forbids network access during parsing
+ HTMLParseNoNet = 1 << 11
+ // HTMLParseNoImplied disables implied html/body elements
+ HTMLParseNoImplied = 1 << 13
+ // HTMLParseCompact enables compaction of small text nodes
+ HTMLParseCompact = 1 << 16
+ // HTMLParseIgnoreEnc ignores internal document encoding hints
+ HTMLParseIgnoreEnc = 1 << 21
+)
+
+// DefaultHTMLOptions represents the default set of options
+// used in the ParseHTML* functions
+const DefaultHTMLOptions = HTMLParseCompact | HTMLParseNoBlanks | HTMLParseNoError | HTMLParseNoWarning
+
+// Option represents the parser option bit
+type Option int
+
+const (
+ XMLParseRecover Option = 1 << iota /* recover on errors */
+ XMLParseNoEnt /* substitute entities */
+ XMLParseDTDLoad /* load the external subset */
+ XMLParseDTDAttr /* default DTD attributes */
+ XMLParseDTDValid /* validate with the DTD */
+ XMLParseNoError /* suppress error reports */
+ XMLParseNoWarning /* suppress warning reports */
+ XMLParsePedantic /* pedantic error reporting */
+ XMLParseNoBlanks /* remove blank nodes */
+ XMLParseSAX1 /* use the SAX1 interface internally */
+ XMLParseXInclude /* Implement XInclude substitution */
+ XMLParseNoNet /* Forbid network access */
+ XMLParseNoDict /* Do not reuse the context dictionary */
+ XMLParseNsclean /* remove redundant namespaces declarations */
+ XMLParseNoCDATA /* merge CDATA as text nodes */
+ XMLParseNoXIncNode /* do not generate XINCLUDE START/END nodes */
+ XMLParseCompact /* compact small text nodes; no modification of the tree allowed afterwards (will possibly crash if you try to modify the tree) */
+ XMLParseOld10 /* parse using XML-1.0 before update 5 */
+ XMLParseNoBaseFix /* do not fixup XINCLUDE xml:base uris */
+ XMLParseHuge /* relax any hardcoded limit from the parser */
+ XMLParseOldSAX /* parse using SAX2 interface before 2.7.0 */
+ XMLParseIgnoreEnc /* ignore internal document encoding hint */
+ XMLParseBigLines /* Store big lines numbers in text PSVI field */
+ XMLParseMax
+ XMLParseEmptyOption Option = 0
+)
+
+// Ctxt represents the Parser context. You normally should be using
+// Parser, but if you for some reason need to do more low-level
+// magic you will have to tinker with this struct
+type Ctxt struct {
+ ptr uintptr // *C.xmlParserCtxt
+}
+
+// Parser represents the high-level parser.
+type Parser struct {
+ Options Option
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/parser.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/parser.go
new file mode 100644
index 000000000000..9b707f34f678
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/parser.go
@@ -0,0 +1,152 @@
+package parser
+
+import (
+ "bytes"
+ "io"
+
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/dom"
+ "github.com/lestrrat-go/libxml2/types"
+ "github.com/pkg/errors"
+)
+
+const _OptionName = "RecoverNoEntDTDLoadDTDAttrDTDValidNoErrorNoWarningPedanticNoBlanksSAX1XIncludeNoNetNoDictNscleanNoCDATANoXIncNodeCompactOld10NoBaseFixHugeOldSAXIgnoreEncBigLines"
+
+var _OptionMap = map[int]string{
+ 1: _OptionName[0:7],
+ 2: _OptionName[7:12],
+ 4: _OptionName[12:19],
+ 8: _OptionName[19:26],
+ 16: _OptionName[26:34],
+ 32: _OptionName[34:41],
+ 64: _OptionName[41:50],
+ 128: _OptionName[50:58],
+ 256: _OptionName[58:66],
+ 512: _OptionName[66:70],
+ 1024: _OptionName[70:78],
+ 2048: _OptionName[78:83],
+ 4096: _OptionName[83:89],
+ 8192: _OptionName[89:96],
+ 16384: _OptionName[96:103],
+ 32768: _OptionName[103:113],
+ 65536: _OptionName[113:120],
+ 131072: _OptionName[120:125],
+ 262144: _OptionName[125:134],
+ 524288: _OptionName[134:138],
+ 1048576: _OptionName[138:144],
+ 2097152: _OptionName[144:153],
+ 4194304: _OptionName[153:161],
+}
+
+// Set flips the option bit in the given Option
+func (o *Option) Set(options ...Option) {
+ v := int(*o) // current value
+ for _, i := range options {
+ v = v | int(i)
+ }
+ *o = Option(v)
+}
+
+// String creates a string representation of the Option
+func (o Option) String() string {
+ if o == XMLParseEmptyOption {
+ return "[]"
+ }
+
+ i := int(o)
+ b := bytes.Buffer{}
+ b.Write([]byte{'['})
+ for x := 1; x < int(XMLParseMax); x = x << 1 {
+ if (i & x) == x {
+ v, ok := _OptionMap[x]
+ if !ok {
+ v = "Option(Unknown)"
+ }
+ b.WriteString(v)
+ b.Write([]byte{'|'})
+ }
+ }
+ x := b.Bytes()
+ if x[len(x)-1] == '|' {
+ x[len(x)-1] = ']'
+ } else {
+ x = append(x, ']')
+ }
+ return string(x)
+}
+
+// New creates a new Parser with the given options.
+func New(opts ...Option) *Parser {
+ var o Option
+
+ for _, opt := range opts {
+ o = o | opt
+ }
+
+ return &Parser{
+ Options: o,
+ }
+}
+
+// Parse parses XML from the given byte buffer
+func (p *Parser) Parse(buf []byte) (types.Document, error) {
+ return p.ParseString(string(buf))
+}
+
+// ParseString parses XML from the given string
+func (p *Parser) ParseString(s string) (types.Document, error) {
+ ctx, err := NewCtxt(s, p.Options)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create parse context")
+ }
+ defer func() { _ = ctx.Free() }()
+
+ docptr, err := clib.XMLCtxtReadMemory(ctx, s, "", "", int(p.Options))
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to create parse input")
+ }
+
+ if docptr != 0 {
+ return dom.WrapDocument(docptr), nil
+ }
+ return nil, errors.New("failed to generate document pointer")
+}
+
+// ParseReader parses XML from the given io.Reader
+func (p *Parser) ParseReader(in io.Reader) (types.Document, error) {
+ buf := &bytes.Buffer{}
+ if _, err := buf.ReadFrom(in); err != nil {
+ return nil, errors.Wrap(err, "failed to read from reader")
+ }
+
+ return p.ParseString(buf.String())
+}
+
+// NewCtxt creates a new Parser context
+func NewCtxt(s string, o Option) (*Ctxt, error) {
+ ctxptr, err := clib.XMLCreateMemoryParserCtxt(s, int(o))
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to execute XMLCreateMemoryParserCtxt")
+ }
+ return &Ctxt{ptr: ctxptr}, nil
+}
+
+// Pointer returns the underlying C struct
+func (ctx Ctxt) Pointer() uintptr {
+ return ctx.ptr
+}
+
+// Parse starts the parsing on the Ctxt
+func (ctx Ctxt) Parse() error {
+ return clib.XMLParseDocument(ctx)
+}
+
+// Free releases the underlying C struct
+func (ctx *Ctxt) Free() error {
+ if err := clib.XMLFreeParserCtxt(ctx); err != nil {
+ return errors.Wrap(err, "failed to free parser context")
+ }
+
+ ctx.ptr = 0
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/stub.go
deleted file mode 100644
index 57e83756e2f1..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/parser/stub.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/lestrrat-go/libxml2/parser, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/lestrrat-go/libxml2/parser (exports: Parser; functions: New,XMLParseNoEnt)
-
-// Package parser is a stub of github.com/lestrrat-go/libxml2/parser, generated by depstubber.
-package parser
-
-import (
- io "io"
-)
-
-func New(_ ...Option) *Parser {
- return nil
-}
-
-type Option int
-
-func (_ Option) String() string {
- return ""
-}
-
-func (_ *Option) Set(_ ...Option) {}
-
-type Parser struct {
- Options Option
-}
-
-func (_ *Parser) Parse(_ []byte) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *Parser) ParseReader(_ io.Reader) (interface{}, error) {
- return nil, nil
-}
-
-func (_ *Parser) ParseString(_ string) (interface{}, error) {
- return nil, nil
-}
-
-var XMLParseNoEnt Option = 0
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/interface.go
new file mode 100644
index 000000000000..a79a7157ad85
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/interface.go
@@ -0,0 +1,123 @@
+package types
+
+import "github.com/lestrrat-go/libxml2/clib"
+
+// PtrSource defines the interface for things that is backed by
+// a C backend
+type PtrSource interface {
+ // Pointer returns the underlying C pointer. This is an exported
+ // method to allow various internal go-libxml2 packages to interoperate
+ // on each other. End users are STRONGLY advised not to touch this
+ // method or its return values
+ Pointer() uintptr
+
+ // Free releases the underlying resources
+ Free()
+}
+
+// XPathExpression defines the interface for XPath expression
+type XPathExpression interface {
+ PtrSource
+}
+
+// XPathResult defines the interface for result of calling Find().
+type XPathResult interface {
+ Bool() bool
+ Free()
+ NodeList() NodeList
+ NodeIter() NodeIter
+ Number() float64
+ String() string
+ Type() clib.XPathObjectType
+}
+
+// Document defines the interface for XML document
+type Document interface {
+ Node
+ CreateElement(string) (Element, error)
+ CreateElementNS(string, string) (Element, error)
+ DocumentElement() (Node, error)
+ Dump(bool) string
+ Encoding() string
+}
+
+// Attribute defines the interface for XML attribute
+type Attribute interface {
+ Node
+ Value() string
+}
+
+// Element defines the interface for XML element
+//
+//nolint:interfacebloat
+type Element interface {
+ Node
+ AppendText(string) error
+ Attributes() ([]Attribute, error)
+ GetAttribute(string) (Attribute, error)
+ GetNamespaces() ([]Namespace, error)
+ LocalName() string
+ NamespaceURI() string
+ Prefix() string
+ RemoveAttribute(string) error
+ SetAttribute(string, string) error
+ SetNamespace(string, string, ...bool) error
+}
+
+// Namespace defines the interface for XML namespace
+type Namespace interface {
+ Node
+ Prefix() string
+ URI() string
+}
+
+// Node defines the basic DOM interface
+//
+//nolint:interfacebloat
+type Node interface {
+ PtrSource
+
+ ParseInContext(string, int) (Node, error)
+
+ AddChild(Node) error
+ ChildNodes() (NodeList, error)
+ Copy() (Node, error)
+ OwnerDocument() (Document, error)
+ Find(string) (XPathResult, error)
+ FirstChild() (Node, error)
+ HasChildNodes() bool
+ IsSameNode(Node) bool
+ LastChild() (Node, error)
+ // Literal is almost the same as String(), except for things like Element
+ // and Attribute nodes. String() will return the XML stringification of
+ // these, but Literal() will return the "value" associated with them.
+ Literal() (string, error)
+ LookupNamespacePrefix(string) (string, error)
+ LookupNamespaceURI(string) (string, error)
+ NextSibling() (Node, error)
+ NodeName() string
+ NodeType() clib.XMLNodeType
+ NodeValue() string
+ ParentNode() (Node, error)
+ PreviousSibling() (Node, error)
+ RemoveChild(Node) error
+ SetDocument(d Document) error
+ SetNodeName(string)
+ SetNodeValue(string)
+ String() string
+ TextContent() string
+ ToString(int, bool) string
+ Walk(func(Node) error) error
+
+ MakeMortal()
+ MakePersistent()
+ AutoFree()
+}
+
+type NodeIter interface {
+ Next() bool
+ Node() Node
+}
+
+// NodeList is a set of Nodes
+type NodeList []Node
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/types.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/types.go
new file mode 100644
index 000000000000..c94c31fe6f95
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/types/types.go
@@ -0,0 +1,54 @@
+/*
+Package types exist to provide with common types that are used
+through out in go-libxml2. This package contains mainly interfaces
+to things that are implemented else. It is in its own package
+so that any package can refer to these interfaces without introducing
+circular dependecy
+*/
+package types
+
+import "bytes"
+
+// String returns the string representation of the NodeList
+func (n NodeList) String() string {
+ buf := bytes.Buffer{}
+ for _, x := range n {
+ buf.WriteString(x.String())
+ }
+ return buf.String()
+}
+
+// NodeValue returns the concatenation of NodeValue within the nodes in NodeList
+func (n NodeList) NodeValue() string {
+ buf := bytes.Buffer{}
+ for _, x := range n {
+ buf.WriteString(x.NodeValue())
+ }
+ return buf.String()
+}
+
+// Literal returns the string representation of the NodeList (using Literal())
+func (n NodeList) Literal() (string, error) {
+ buf := bytes.Buffer{}
+ for _, x := range n {
+ l, err := x.Literal()
+ if err != nil {
+ return "", err
+ }
+ buf.WriteString(l)
+ }
+ return buf.String(), nil
+}
+
+// First returns the first node in the list, or nil otherwise.
+func (n NodeList) First() Node {
+ if n == nil {
+ return nil
+ }
+
+ if len(n) > 0 {
+ return n[0]
+ }
+
+ return nil
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/interface.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/interface.go
new file mode 100644
index 000000000000..70585dd160eb
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/interface.go
@@ -0,0 +1,44 @@
+package xpath
+
+import (
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+)
+
+const (
+ UndefinedType = clib.XPathUndefinedType
+ NodeSetType = clib.XPathNodeSetType
+ BooleanType = clib.XPathBooleanType
+ NumberType = clib.XPathNumberType
+ StringType = clib.XPathStringType
+ PointType = clib.XPathPointType
+ RangeType = clib.XPathRangeType
+ LocationSetType = clib.XPathLocationSetType
+ UsersType = clib.XPathUsersType
+ XSLTTreeType = clib.XPathXSLTTreeType
+)
+
+// Object is the concrete implementation of Result (types.XPathResult).
+// This struct contains the result of evaluating an XPath expression.
+type Object struct {
+ ptr uintptr // *C.xmlObject
+ // This flag controls if the StringValue should use the *contents* (literal value)
+ // of the nodeset instead of stringifying the node
+ ForceLiteral bool
+}
+
+// Context holds the current XPath context. You may register namespaces and
+// context nodes to evaluate your XPath expressions with it.
+type Context struct {
+ ptr uintptr // *C.xmlContext
+}
+
+// Expression is a compiled XPath expression
+type Expression struct {
+ ptr uintptr // *C.xmlCompExpr
+ // This exists mainly for debugging purposes
+ expr string
+}
+
+// Result is an alias to types.XPathResult
+type Result types.XPathResult
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/iterator.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/iterator.go
new file mode 100644
index 000000000000..a2e248e3269b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/iterator.go
@@ -0,0 +1,43 @@
+package xpath
+
+import (
+ "github.com/lestrrat-go/libxml2/types"
+)
+
+// NodeIterator is a way to get at a list of nodes returned
+// by XPath et al in a lazy (and possibly more efficient) manner.
+type NodeIterator struct {
+ cur int
+ curnode types.Node
+ nlen int
+ nodes []uintptr
+}
+
+func NewNodeIterator(nodes []uintptr) *NodeIterator {
+ return &NodeIterator{
+ cur: -1,
+ nlen: len(nodes),
+ nodes: nodes,
+ }
+}
+
+// Next returns true if there is at least one more node in the
+// iterator.
+func (n *NodeIterator) Next() bool {
+ if n.nlen == 0 || n.cur+1 >= n.nlen {
+ return false
+ }
+
+ n.cur++
+ node, err := WrapNodeFunc(n.nodes[n.cur])
+ if err != nil {
+ n.nlen = 0
+ return false
+ }
+ n.curnode = node
+ return true
+}
+
+func (n *NodeIterator) Node() types.Node {
+ return n.curnode
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/util.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/util.go
new file mode 100644
index 000000000000..326f42325e6b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/util.go
@@ -0,0 +1,63 @@
+package xpath
+
+import "github.com/lestrrat-go/libxml2/types"
+
+// String returns the string component of the result, and as a side effect
+// releases the Result by calling Free() on it. Use this if you do not
+// really care about the error value from Find()
+func String(r types.XPathResult, err error) string {
+ if err != nil {
+ return ""
+ }
+
+ defer r.Free()
+ return r.String()
+}
+
+// Bool returns the boolean component of the result, and as a side effect
+// releases the Result by calling Free() on it. Use this if you do not
+// really care about the error value from Find()
+func Bool(r types.XPathResult, err error) bool {
+ if err != nil {
+ return false
+ }
+
+ defer r.Free()
+ return r.Bool()
+}
+
+// Number returns the numeric component of the result, and as a side effect
+// releases the Result by calling Free() on it. Use this if you do not
+// really care about the error value from Find()
+func Number(r types.XPathResult, err error) float64 {
+ if err != nil {
+ return 0
+ }
+
+ defer r.Free()
+ return r.Number()
+}
+
+// NodeList returns the nodes associated with this result, and as a side effect
+// releases the result by calling Free() on it. Use this if you do not
+// really care about the error value from Find().
+func NodeList(r types.XPathResult, err error) types.NodeList {
+ if err != nil {
+ return nil
+ }
+
+ defer r.Free()
+ return r.NodeList()
+}
+
+// NodeIter returns an iterator that will return the nodes assocaied with
+// this reult, and as a side effect releases the result by calling Free()
+// on it. Use this if you do not really care about the error value from Find().
+func NodeIter(r types.XPathResult, err error) types.NodeIter {
+ if err != nil {
+ return NewNodeIterator(nil)
+ }
+
+ defer r.Free()
+ return r.NodeIter()
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/xpath.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/xpath.go
new file mode 100644
index 000000000000..98961a216bb0
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/lestrrat-go/libxml2/xpath/xpath.go
@@ -0,0 +1,234 @@
+/*
+Package xpath contains tools to handle XPath evaluation.
+
+Because of a very quirky dependency between this package and the
+github.com/lestrrat/libxml2/dom package, you MUST import both
+packages to properly use it.
+
+ import (
+ "github.com/lestrrat-go/libxml2/dom"
+ "github.com/lestrrat-go/libxml2/xpath"
+ )
+
+Or, if you have no use for dom package in your program, and you
+don't want to use the magical "_" import, you can do the initialization
+yourself just to appease the compiler:
+
+ func init() {
+ dom.SetupXPathCallback()
+ }
+*/
+package xpath
+
+import (
+ "fmt"
+
+ "github.com/lestrrat-go/libxml2/clib"
+ "github.com/lestrrat-go/libxml2/types"
+ "github.com/pkg/errors"
+)
+
+// Pointer returns the underlying C struct
+func (x Object) Pointer() uintptr {
+ return x.ptr
+}
+
+// Type returns the clib.XPathObjectType
+func (x Object) Type() clib.XPathObjectType {
+ return clib.XMLXPathObjectType(x)
+}
+
+// Number returns the floatval component of the Object as float64
+func (x Object) Number() float64 {
+ return clib.XMLXPathObjectFloat64(x)
+}
+
+// Bool returns the boolval component of the Object
+func (x Object) Bool() bool {
+ return clib.XMLXPathObjectBool(x)
+}
+
+// WrapNodeFunc is a function that gets called when Object.NodeList()
+// is called. This is necessary because during the call to NodeList(),
+// the underlying C pointers are materialized to objects in a different
+// package ("github.com/lestrrat-go/libxml2/dom"), and said package
+// uses this package... Yes, a circular dependency.
+//
+// Normally this means that both pacckages should live under the same
+// unified package, but in this case they are independent enough that
+// we have decided they warrant to be separated.
+//
+// So this WrapNodeFunc is our workaround for this problem: when
+// github.com/lestrrat-go/libxml2/dom is loaded, it automatically
+// initializes this function to an appropriate function on the fly.
+var WrapNodeFunc func(uintptr) (types.Node, error)
+
+// NodeList returns the list of nodes included in this Object
+func (x Object) NodeList() types.NodeList {
+ if WrapNodeFunc == nil {
+ panic("WarapNodeFunc not initialized. read XXX for details")
+ }
+
+ nl, err := clib.XMLXPathObjectNodeList(x)
+ if err != nil {
+ return nil
+ }
+
+ ret := make([]types.Node, len(nl))
+ for i, p := range nl {
+ n, err := WrapNodeFunc(p)
+ if err != nil {
+ return nil
+ }
+ ret[i] = n
+ }
+ return ret
+}
+
+func (x Object) NodeIter() types.NodeIter {
+ nl, err := clib.XMLXPathObjectNodeList(x)
+ if err != nil {
+ return NewNodeIterator(nil)
+ }
+ return NewNodeIterator(nl)
+}
+
+// String returns the stringified value of the nodes included in
+// this Object. If the Object is anything other than a
+// NodeSet, then we fallback to using fmt.Sprintf to generate
+// some sort of readable output
+func (x Object) String() string {
+ switch x.Type() {
+ case NodeSetType:
+ nl := x.NodeList()
+ if nl == nil {
+ return ""
+ }
+ if x.ForceLiteral {
+ s, err := nl.Literal()
+ if err == nil {
+ return s
+ }
+ return ""
+ }
+ return nl.NodeValue()
+ default:
+ return fmt.Sprintf("%T", x)
+ }
+}
+
+// Free releases the underlying C structs
+func (x *Object) Free() {
+ clib.XMLXPathFreeObject(x)
+}
+
+// NewExpression compiles the given XPath expression string
+func NewExpression(s string) (*Expression, error) {
+ ptr, err := clib.XMLXPathCompile(s)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to compile expression")
+ }
+
+ return &Expression{ptr: ptr, expr: s}, nil
+}
+
+// Pointer returns the underlying C struct
+func (x *Expression) Pointer() uintptr {
+ return x.ptr
+}
+
+// String returns the expression as it was given to NewExpression
+func (x Expression) String() string {
+ return x.expr
+}
+
+// Free releases the underlying C structs in the Expression
+func (x *Expression) Free() {
+ _ = clib.XMLXPathFreeCompExpr(x)
+}
+
+// NewContext creates a new Context, optionally providing
+// with a context node.
+//
+// Note that although we are specifying `n... Node` for the argument,
+// only the first, node is considered for the context node
+func NewContext(n ...types.Node) (*Context, error) {
+ var node types.Node
+ if len(n) > 0 {
+ node = n[0]
+ }
+
+ ctxptr, err := clib.XMLXPathNewContext(node)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get valid xpath context")
+ }
+
+ return &Context{ptr: ctxptr}, nil
+}
+
+// Pointer returns a pointer to the underlying C struct
+func (x *Context) Pointer() uintptr {
+ return x.ptr
+}
+
+// SetContextNode sets or resets the context node which
+// XPath expressions will be evaluated against.
+func (x *Context) SetContextNode(n types.Node) error {
+ return clib.XMLXPathContextSetContextNode(x, n)
+}
+
+// Exists compiles and evaluates the xpath expression, and returns
+// true if a corresponding node exists
+func (x *Context) Exists(xpath string) bool {
+ list := NodeList(x.Find(xpath))
+ if list == nil {
+ return false
+ }
+
+ return len(list) > 0
+}
+
+// Free releases the underlying C structs in the XPath
+func (x *Context) Free() {
+ _ = clib.XMLXPathFreeContext(x)
+}
+
+// Find evaluates the expression s against the nodes registered
+// in x. It returns the resulting data evaluated to an Result.
+//
+// You MUST call Free() on the Result, or you will leak memory
+// If you don't really care for errors and just want to grab the
+// value of Result, checkout xpath.String(), xpath.Number(), xpath.Bool()
+// et al.
+func (x *Context) Find(s string) (types.XPathResult, error) {
+ expr, err := NewExpression(s)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to compile expression")
+ }
+ defer expr.Free()
+
+ return x.FindExpr(expr)
+}
+
+// FindExpr evaluates the given XPath expression and returns an Object.
+// You must call `Free()` on this returned object
+//
+// You MUST call Free() on the Result, or you will leak memory
+func (x *Context) FindExpr(expr types.XPathExpression) (types.XPathResult, error) {
+ res, err := clib.XMLEvalXPath(x, expr)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to evaluate expression")
+ }
+
+ return &Object{ptr: res}, nil
+}
+
+// LookupNamespaceURI looksup the namespace URI associated with prefix
+func (x *Context) LookupNamespaceURI(prefix string) (string, error) {
+ return clib.XMLXPathNSLookup(x, prefix)
+}
+
+// RegisterNS registers a namespace so it can be used in an Expression
+func (x *Context) RegisterNS(name, nsuri string) error {
+ return clib.XMLXPathRegisterNS(x, name, nsuri)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.gitignore b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.gitignore
new file mode 100644
index 000000000000..daf913b1b347
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.travis.yml
new file mode 100644
index 000000000000..9159de03e03d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go_import_path: github.com/pkg/errors
+go:
+ - 1.11.x
+ - 1.12.x
+ - 1.13.x
+ - tip
+
+script:
+ - make check
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/LICENSE b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/LICENSE
new file mode 100644
index 000000000000..835ba3e755ce
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2015, Dave Cheney
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/Makefile b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/Makefile
new file mode 100644
index 000000000000..ce9d7cded649
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/Makefile
@@ -0,0 +1,44 @@
+PKGS := github.com/pkg/errors
+SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
+GO := go
+
+check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
+
+test:
+ $(GO) test $(PKGS)
+
+vet: | test
+ $(GO) vet $(PKGS)
+
+staticcheck:
+ $(GO) get honnef.co/go/tools/cmd/staticcheck
+ staticcheck -checks all $(PKGS)
+
+misspell:
+ $(GO) get github.com/client9/misspell/cmd/misspell
+ misspell \
+ -locale GB \
+ -error \
+ *.md *.go
+
+unconvert:
+ $(GO) get github.com/mdempsky/unconvert
+ unconvert -v $(PKGS)
+
+ineffassign:
+ $(GO) get github.com/gordonklaus/ineffassign
+ find $(SRCDIRS) -name '*.go' | xargs ineffassign
+
+pedantic: check errcheck
+
+unparam:
+ $(GO) get mvdan.cc/unparam
+ unparam ./...
+
+errcheck:
+ $(GO) get github.com/kisielk/errcheck
+ errcheck $(PKGS)
+
+gofmt:
+ @echo Checking code is gofmted
+ @test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/README.md
new file mode 100644
index 000000000000..54dfdcb12ea1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/README.md
@@ -0,0 +1,59 @@
+# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors) [](https://sourcegraph.com/github.com/pkg/errors?badge)
+
+Package errors provides simple error handling primitives.
+
+`go get github.com/pkg/errors`
+
+The traditional error handling idiom in Go is roughly akin to
+```go
+if err != nil {
+ return err
+}
+```
+which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
+
+## Adding context to an error
+
+The errors.Wrap function returns a new error that adds context to the original error. For example
+```go
+_, err := ioutil.ReadAll(r)
+if err != nil {
+ return errors.Wrap(err, "read failed")
+}
+```
+## Retrieving the cause of an error
+
+Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
+```go
+type causer interface {
+ Cause() error
+}
+```
+`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
+```go
+switch err := errors.Cause(err).(type) {
+case *MyError:
+ // handle specifically
+default:
+ // unknown error
+}
+```
+
+[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
+
+## Roadmap
+
+With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
+
+- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
+- 1.0. Final release.
+
+## Contributing
+
+Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
+
+Before sending a PR, please discuss your change by raising an issue.
+
+## License
+
+BSD-2-Clause
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/appveyor.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/appveyor.yml
new file mode 100644
index 000000000000..a932eade0240
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/appveyor.yml
@@ -0,0 +1,32 @@
+version: build-{build}.{branch}
+
+clone_folder: C:\gopath\src\github.com\pkg\errors
+shallow_clone: true # for startup speed
+
+environment:
+ GOPATH: C:\gopath
+
+platform:
+ - x64
+
+# http://www.appveyor.com/docs/installed-software
+install:
+ # some helpful output for debugging builds
+ - go version
+ - go env
+ # pre-installed MinGW at C:\MinGW is 32bit only
+ # but MSYS2 at C:\msys64 has mingw64
+ - set PATH=C:\msys64\mingw64\bin;%PATH%
+ - gcc --version
+ - g++ --version
+
+build_script:
+ - go install -v ./...
+
+test_script:
+ - set PATH=C:\gopath\bin;%PATH%
+ - go test -v ./...
+
+#artifacts:
+# - path: '%GOPATH%\bin\*.exe'
+deploy: off
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/errors.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/errors.go
new file mode 100644
index 000000000000..161aea258296
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/errors.go
@@ -0,0 +1,288 @@
+// Package errors provides simple error handling primitives.
+//
+// The traditional error handling idiom in Go is roughly akin to
+//
+// if err != nil {
+// return err
+// }
+//
+// which when applied recursively up the call stack results in error reports
+// without context or debugging information. The errors package allows
+// programmers to add context to the failure path in their code in a way
+// that does not destroy the original value of the error.
+//
+// Adding context to an error
+//
+// The errors.Wrap function returns a new error that adds context to the
+// original error by recording a stack trace at the point Wrap is called,
+// together with the supplied message. For example
+//
+// _, err := ioutil.ReadAll(r)
+// if err != nil {
+// return errors.Wrap(err, "read failed")
+// }
+//
+// If additional control is required, the errors.WithStack and
+// errors.WithMessage functions destructure errors.Wrap into its component
+// operations: annotating an error with a stack trace and with a message,
+// respectively.
+//
+// Retrieving the cause of an error
+//
+// Using errors.Wrap constructs a stack of errors, adding context to the
+// preceding error. Depending on the nature of the error it may be necessary
+// to reverse the operation of errors.Wrap to retrieve the original error
+// for inspection. Any error value which implements this interface
+//
+// type causer interface {
+// Cause() error
+// }
+//
+// can be inspected by errors.Cause. errors.Cause will recursively retrieve
+// the topmost error that does not implement causer, which is assumed to be
+// the original cause. For example:
+//
+// switch err := errors.Cause(err).(type) {
+// case *MyError:
+// // handle specifically
+// default:
+// // unknown error
+// }
+//
+// Although the causer interface is not exported by this package, it is
+// considered a part of its stable public interface.
+//
+// Formatted printing of errors
+//
+// All error values returned from this package implement fmt.Formatter and can
+// be formatted by the fmt package. The following verbs are supported:
+//
+// %s print the error. If the error has a Cause it will be
+// printed recursively.
+// %v see %s
+// %+v extended format. Each Frame of the error's StackTrace will
+// be printed in detail.
+//
+// Retrieving the stack trace of an error or wrapper
+//
+// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
+// invoked. This information can be retrieved with the following interface:
+//
+// type stackTracer interface {
+// StackTrace() errors.StackTrace
+// }
+//
+// The returned errors.StackTrace type is defined as
+//
+// type StackTrace []Frame
+//
+// The Frame type represents a call site in the stack trace. Frame supports
+// the fmt.Formatter interface that can be used for printing information about
+// the stack trace of this error. For example:
+//
+// if err, ok := err.(stackTracer); ok {
+// for _, f := range err.StackTrace() {
+// fmt.Printf("%+s:%d\n", f, f)
+// }
+// }
+//
+// Although the stackTracer interface is not exported by this package, it is
+// considered a part of its stable public interface.
+//
+// See the documentation for Frame.Format for more details.
+package errors
+
+import (
+ "fmt"
+ "io"
+)
+
+// New returns an error with the supplied message.
+// New also records the stack trace at the point it was called.
+func New(message string) error {
+ return &fundamental{
+ msg: message,
+ stack: callers(),
+ }
+}
+
+// Errorf formats according to a format specifier and returns the string
+// as a value that satisfies error.
+// Errorf also records the stack trace at the point it was called.
+func Errorf(format string, args ...interface{}) error {
+ return &fundamental{
+ msg: fmt.Sprintf(format, args...),
+ stack: callers(),
+ }
+}
+
+// fundamental is an error that has a message and a stack, but no caller.
+type fundamental struct {
+ msg string
+ *stack
+}
+
+func (f *fundamental) Error() string { return f.msg }
+
+func (f *fundamental) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ io.WriteString(s, f.msg)
+ f.stack.Format(s, verb)
+ return
+ }
+ fallthrough
+ case 's':
+ io.WriteString(s, f.msg)
+ case 'q':
+ fmt.Fprintf(s, "%q", f.msg)
+ }
+}
+
+// WithStack annotates err with a stack trace at the point WithStack was called.
+// If err is nil, WithStack returns nil.
+func WithStack(err error) error {
+ if err == nil {
+ return nil
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+type withStack struct {
+ error
+ *stack
+}
+
+func (w *withStack) Cause() error { return w.error }
+
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withStack) Unwrap() error { return w.error }
+
+func (w *withStack) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ fmt.Fprintf(s, "%+v", w.Cause())
+ w.stack.Format(s, verb)
+ return
+ }
+ fallthrough
+ case 's':
+ io.WriteString(s, w.Error())
+ case 'q':
+ fmt.Fprintf(s, "%q", w.Error())
+ }
+}
+
+// Wrap returns an error annotating err with a stack trace
+// at the point Wrap is called, and the supplied message.
+// If err is nil, Wrap returns nil.
+func Wrap(err error, message string) error {
+ if err == nil {
+ return nil
+ }
+ err = &withMessage{
+ cause: err,
+ msg: message,
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+// Wrapf returns an error annotating err with a stack trace
+// at the point Wrapf is called, and the format specifier.
+// If err is nil, Wrapf returns nil.
+func Wrapf(err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ err = &withMessage{
+ cause: err,
+ msg: fmt.Sprintf(format, args...),
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+// WithMessage annotates err with a new message.
+// If err is nil, WithMessage returns nil.
+func WithMessage(err error, message string) error {
+ if err == nil {
+ return nil
+ }
+ return &withMessage{
+ cause: err,
+ msg: message,
+ }
+}
+
+// WithMessagef annotates err with the format specifier.
+// If err is nil, WithMessagef returns nil.
+func WithMessagef(err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ return &withMessage{
+ cause: err,
+ msg: fmt.Sprintf(format, args...),
+ }
+}
+
+type withMessage struct {
+ cause error
+ msg string
+}
+
+func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
+func (w *withMessage) Cause() error { return w.cause }
+
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withMessage) Unwrap() error { return w.cause }
+
+func (w *withMessage) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ fmt.Fprintf(s, "%+v\n", w.Cause())
+ io.WriteString(s, w.msg)
+ return
+ }
+ fallthrough
+ case 's', 'q':
+ io.WriteString(s, w.Error())
+ }
+}
+
+// Cause returns the underlying cause of the error, if possible.
+// An error value has a cause if it implements the following
+// interface:
+//
+// type causer interface {
+// Cause() error
+// }
+//
+// If the error does not implement Cause, the original error will
+// be returned. If the error is nil, nil will be returned without further
+// investigation.
+func Cause(err error) error {
+ type causer interface {
+ Cause() error
+ }
+
+ for err != nil {
+ cause, ok := err.(causer)
+ if !ok {
+ break
+ }
+ err = cause.Cause()
+ }
+ return err
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/go113.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/go113.go
new file mode 100644
index 000000000000..be0d10d0c793
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/go113.go
@@ -0,0 +1,38 @@
+// +build go1.13
+
+package errors
+
+import (
+ stderrors "errors"
+)
+
+// Is reports whether any error in err's chain matches target.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error is considered to match a target if it is equal to that target or if
+// it implements a method Is(error) bool such that Is(target) returns true.
+func Is(err, target error) bool { return stderrors.Is(err, target) }
+
+// As finds the first error in err's chain that matches target, and if so, sets
+// target to that error value and returns true.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error matches target if the error's concrete value is assignable to the value
+// pointed to by target, or if the error has a method As(interface{}) bool such that
+// As(target) returns true. In the latter case, the As method is responsible for
+// setting target.
+//
+// As will panic if target is not a non-nil pointer to either a type that implements
+// error, or to any interface type. As returns false if err is nil.
+func As(err error, target interface{}) bool { return stderrors.As(err, target) }
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+func Unwrap(err error) error {
+ return stderrors.Unwrap(err)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/stack.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/stack.go
new file mode 100644
index 000000000000..779a8348fb9c
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/pkg/errors/stack.go
@@ -0,0 +1,177 @@
+package errors
+
+import (
+ "fmt"
+ "io"
+ "path"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+// Frame represents a program counter inside a stack frame.
+// For historical reasons if Frame is interpreted as a uintptr
+// its value represents the program counter + 1.
+type Frame uintptr
+
+// pc returns the program counter for this frame;
+// multiple frames may have the same PC value.
+func (f Frame) pc() uintptr { return uintptr(f) - 1 }
+
+// file returns the full path to the file that contains the
+// function for this Frame's pc.
+func (f Frame) file() string {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return "unknown"
+ }
+ file, _ := fn.FileLine(f.pc())
+ return file
+}
+
+// line returns the line number of source code of the
+// function for this Frame's pc.
+func (f Frame) line() int {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return 0
+ }
+ _, line := fn.FileLine(f.pc())
+ return line
+}
+
+// name returns the name of this function, if known.
+func (f Frame) name() string {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return "unknown"
+ }
+ return fn.Name()
+}
+
+// Format formats the frame according to the fmt.Formatter interface.
+//
+// %s source file
+// %d source line
+// %n function name
+// %v equivalent to %s:%d
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+// %+s function name and path of source file relative to the compile time
+// GOPATH separated by \n\t (\n\t)
+// %+v equivalent to %+s:%d
+func (f Frame) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 's':
+ switch {
+ case s.Flag('+'):
+ io.WriteString(s, f.name())
+ io.WriteString(s, "\n\t")
+ io.WriteString(s, f.file())
+ default:
+ io.WriteString(s, path.Base(f.file()))
+ }
+ case 'd':
+ io.WriteString(s, strconv.Itoa(f.line()))
+ case 'n':
+ io.WriteString(s, funcname(f.name()))
+ case 'v':
+ f.Format(s, 's')
+ io.WriteString(s, ":")
+ f.Format(s, 'd')
+ }
+}
+
+// MarshalText formats a stacktrace Frame as a text string. The output is the
+// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
+func (f Frame) MarshalText() ([]byte, error) {
+ name := f.name()
+ if name == "unknown" {
+ return []byte(name), nil
+ }
+ return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
+}
+
+// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
+type StackTrace []Frame
+
+// Format formats the stack of Frames according to the fmt.Formatter interface.
+//
+// %s lists source files for each Frame in the stack
+// %v lists the source file and line number for each Frame in the stack
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+// %+v Prints filename, function, and line number for each Frame in the stack.
+func (st StackTrace) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ switch {
+ case s.Flag('+'):
+ for _, f := range st {
+ io.WriteString(s, "\n")
+ f.Format(s, verb)
+ }
+ case s.Flag('#'):
+ fmt.Fprintf(s, "%#v", []Frame(st))
+ default:
+ st.formatSlice(s, verb)
+ }
+ case 's':
+ st.formatSlice(s, verb)
+ }
+}
+
+// formatSlice will format this StackTrace into the given buffer as a slice of
+// Frame, only valid when called with '%s' or '%v'.
+func (st StackTrace) formatSlice(s fmt.State, verb rune) {
+ io.WriteString(s, "[")
+ for i, f := range st {
+ if i > 0 {
+ io.WriteString(s, " ")
+ }
+ f.Format(s, verb)
+ }
+ io.WriteString(s, "]")
+}
+
+// stack represents a stack of program counters.
+type stack []uintptr
+
+func (s *stack) Format(st fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ switch {
+ case st.Flag('+'):
+ for _, pc := range *s {
+ f := Frame(pc)
+ fmt.Fprintf(st, "\n%+v", f)
+ }
+ }
+ }
+}
+
+func (s *stack) StackTrace() StackTrace {
+ f := make([]Frame, len(*s))
+ for i := 0; i < len(f); i++ {
+ f[i] = Frame((*s)[i])
+ }
+ return f
+}
+
+func callers() *stack {
+ const depth = 32
+ var pcs [depth]uintptr
+ n := runtime.Callers(3, pcs[:])
+ var st stack = pcs[0:n]
+ return &st
+}
+
+// funcname removes the path prefix component of a function's name reported by func.Name().
+func funcname(name string) string {
+ i := strings.LastIndex(name, "/")
+ name = name[i+1:]
+ i = strings.Index(name, ".")
+ return name[i+1:]
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml
new file mode 100644
index 000000000000..eb336b4ff12e
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+
+go:
+ - 1.8.1
+
+script:
+ - go test -v -race -coverprofile=coverage.txt -covermode=atomic
+
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md
new file mode 100644
index 000000000000..a8573f8d0793
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md
@@ -0,0 +1,22 @@
+# xpathparser
+
+[](https://opensource.org/licenses/BSD-3-Clause)
+[](https://godoc.org/github.com/santhosh-tekuri/xpathparser)
+[](https://goreportcard.com/report/github.com/santhosh-tekuri/xpathparser)
+[](https://travis-ci.org/santhosh-tekuri/xpathparser)
+[](https://codecov.io/github/santhosh-tekuri/xpathparser?branch=master)
+
+Package xpathparser provides lexer and parser for XPath 1.0.
+
+This Package parses given XPath expression to expression model.
+
+## Example
+
+An example of using this package:
+
+```go
+expr := xpathparser.MustParse("(/a/b)[5]")
+fmt.Println(expr)
+```
+
+This package does not evaluate xpath. For evaluating xpaths use https://github.com/santhosh-tekuri/xpath
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go
new file mode 100644
index 000000000000..3c8b59d851f1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go
@@ -0,0 +1,16 @@
+// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package xpathparser provides lexer and parser for XPath 1.0.
+
+This Package parses given XPath expression to expression model.
+
+An example of using this package:
+
+ expr := xpathparser.MustParse("(/a/b)[5]")
+ fmt.Println(expr)
+
+*/
+package xpathparser
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go
new file mode 100644
index 000000000000..ad64347059e9
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go
@@ -0,0 +1,301 @@
+// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xpathparser
+
+// see lexer specification at https://www.w3.org/TR/xpath/#exprlex
+
+import (
+ "bytes"
+ "strings"
+ "unicode/utf8"
+)
+
+type kind int
+
+const (
+ eof kind = iota - 1
+
+ // operators, note the order must same as Op enum values
+ eq
+ neq
+ lt
+ lte
+ gt
+ gte
+ plus
+ minus
+ multiply
+ mod
+ div
+ and
+ or
+ pipe
+
+ slash
+ slashSlash
+ dot
+ dotDot
+ colon
+ colonColon
+
+ at
+ dollar
+ comma
+ star
+
+ lbracket
+ rbracket
+ lparen
+ rparen
+
+ identifier
+ literal
+ number
+)
+
+var kindNames = []string{
+ ``,
+ `'='`, `"!="`, `'<'`, `"<="`, `'>'`, `">="`,
+ `'+'`, `'-'`, `'*'`, `"mod"`, `"div"`,
+ `"and"`, `"or"`, `'|'`,
+ `'/'`, `"//"`, `'.'`, `".."`, `':'`, `"::"`,
+ `'@'`, `'$'`, `','`, `'*'`,
+ `'['`, `']'`, `'('`, `')'`,
+ ``, ``, ``,
+}
+
+func (k kind) String() string {
+ return kindNames[k+1]
+}
+
+type token struct {
+ xpath string
+ kind kind
+ begin int
+ end int
+}
+
+func (t token) text() string {
+ return t.xpath[t.begin:t.end]
+}
+
+type lexer struct {
+ xpath string
+ pos int
+ expectOp bool
+}
+
+func (l *lexer) err(msg string) (token, error) {
+ return token{}, &Error{msg, l.xpath, l.pos}
+}
+
+func (l *lexer) char(i int) int {
+ if l.pos+i < len(l.xpath) {
+ return int(l.xpath[l.pos+i])
+ }
+ return -1
+}
+
+func (l *lexer) consume(n int) {
+ l.pos += n
+}
+
+func (l *lexer) hasMore() bool {
+ return l.pos < len(l.xpath)
+}
+
+func (l *lexer) token(kind kind, n int) (token, error) {
+ var t token
+ if n > 0 {
+ t = token{l.xpath, kind, l.pos, l.pos + n}
+ l.consume(n)
+ } else {
+ t = token{l.xpath, kind, l.pos + n, l.pos}
+ }
+ switch kind {
+ case at, colonColon, lparen, lbracket, and, or, mod, div, colon, slash, slashSlash,
+ pipe, dollar, plus, minus, multiply, comma, lt, gt, lte, gte, eq, neq:
+ l.expectOp = false
+ default:
+ l.expectOp = true
+ }
+ return t, nil
+}
+
+func (l *lexer) next() (token, error) {
+SkipWS:
+ for l.hasMore() {
+ switch l.char(0) {
+ case ' ', '\t', '\n', '\r':
+ l.consume(1)
+ default:
+ break SkipWS
+ }
+ }
+
+ switch l.char(0) {
+ case -1:
+ return l.token(eof, 0)
+ case '$':
+ return l.token(dollar, 1)
+ case '"', '\'':
+ return l.literal()
+ case '/':
+ if l.char(1) == '/' {
+ return l.token(slashSlash, 2)
+ }
+ return l.token(slash, 1)
+ case ',':
+ return l.token(comma, 1)
+ case '(':
+ return l.token(lparen, 1)
+ case ')':
+ return l.token(rparen, 1)
+ case '[':
+ return l.token(lbracket, 1)
+ case ']':
+ return l.token(rbracket, 1)
+ case '+':
+ return l.token(plus, 1)
+ case '-':
+ return l.token(minus, 1)
+ case '<':
+ if l.char(1) == '=' {
+ return l.token(lte, 2)
+ }
+ return l.token(lt, 1)
+ case '>':
+ if l.char(1) == '=' {
+ return l.token(gte, 2)
+ }
+ return l.token(gt, 1)
+ case '=':
+ return l.token(eq, 1)
+ case '!':
+ if l.char(1) == '=' {
+ return l.token(neq, 2)
+ }
+ return l.err("expected '!='")
+ case '|':
+ return l.token(pipe, 1)
+ case '@':
+ return l.token(at, 1)
+ case ':':
+ if l.char(1) == ':' {
+ return l.token(colonColon, 2)
+ }
+ return l.token(colon, 1)
+ case '*':
+ if l.expectOp {
+ return l.token(multiply, 1)
+ }
+ return l.token(star, 1)
+ case '.':
+ switch l.char(1) {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return l.number()
+ case '.':
+ return l.token(dotDot, 2)
+ default:
+ return l.token(dot, 1)
+ }
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return l.number()
+ default:
+ if l.expectOp {
+ return l.operator()
+ }
+ return l.identifier()
+ }
+}
+
+func (l *lexer) literal() (token, error) {
+ quote := l.char(0)
+ l.consume(1)
+ begin := l.pos
+ for {
+ switch l.char(0) {
+ case quote:
+ t, _ := l.token(literal, begin-l.pos)
+ l.consume(1)
+ return t, nil
+ case -1:
+ return l.err("unclosed literal")
+ }
+ l.consume(1)
+ }
+}
+
+func (l *lexer) number() (token, error) {
+ begin := l.pos
+ dotAllowed := true
+Loop:
+ for {
+ switch l.char(0) {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ l.consume(1)
+ case '.':
+ if dotAllowed {
+ dotAllowed = false
+ l.consume(1)
+ } else {
+ break Loop
+ }
+ default:
+ break Loop
+ }
+ }
+ return l.token(number, begin-l.pos)
+}
+
+func (l *lexer) operator() (token, error) {
+ remaining := l.xpath[l.pos:]
+ switch {
+ case strings.HasPrefix(remaining, "and"):
+ return l.token(and, 3)
+ case strings.HasPrefix(remaining, "or"):
+ return l.token(or, 2)
+ case strings.HasPrefix(remaining, "mod"):
+ return l.token(mod, 3)
+ case strings.HasPrefix(remaining, "div"):
+ return l.token(div, 3)
+ }
+ return l.err("operatorName expected")
+}
+
+func (l *lexer) identifier() (token, error) {
+ begin := l.pos
+ b, ok := l.readName()
+ if !ok {
+ return l.err("identifier expected")
+ }
+ if !isName(b) {
+ l.pos = begin
+ return l.err("invalid identifier")
+ }
+ return l.token(identifier, begin-l.pos)
+}
+
+func (l *lexer) readName() ([]byte, bool) {
+ if !l.hasMore() {
+ return nil, false
+ }
+ buf := new(bytes.Buffer)
+ b := byte(l.char(0))
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ return nil, false
+ }
+ buf.WriteByte(b)
+ l.consume(1)
+ for l.hasMore() {
+ b = byte(l.char(0))
+ if b < utf8.RuneSelf && !isNameByte(b) {
+ break
+ }
+ buf.WriteByte(b)
+ l.consume(1)
+ }
+ return buf.Bytes(), true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go
new file mode 100644
index 000000000000..e802e9542bf9
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go
@@ -0,0 +1,352 @@
+// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xpathparser
+
+import (
+ "unicode"
+ "unicode/utf8"
+)
+
+var first = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
+ },
+}
+
+var second = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
+ },
+}
+
+func isNameByte(c byte) bool {
+ return 'A' <= c && c <= 'Z' ||
+ 'a' <= c && c <= 'z' ||
+ '0' <= c && c <= '9' ||
+ c == '_' || c == '.' || c == '-'
+}
+
+func isName(s []byte) bool {
+ if len(s) == 0 {
+ return false
+ }
+ c, n := utf8.DecodeRune(s)
+ if c == utf8.RuneError && n == 1 {
+ return false
+ }
+ if !unicode.Is(first, c) {
+ return false
+ }
+ for n < len(s) {
+ s = s[n:]
+ c, n = utf8.DecodeRune(s)
+ if c == utf8.RuneError && n == 1 {
+ return false
+ }
+ if !unicode.Is(first, c) && !unicode.Is(second, c) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go
new file mode 100644
index 000000000000..a12d4a0ee19d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go
@@ -0,0 +1,435 @@
+// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xpathparser
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type parser struct {
+ lexer lexer
+ tokens []token
+}
+
+func (p *parser) error(format string, args ...interface{}) error {
+ return &Error{fmt.Sprintf(format, args...), p.lexer.xpath, p.token(0).begin}
+}
+
+func (p *parser) unexpectedToken() error {
+ return p.error("unexpected token %s", p.token(0).kind)
+}
+
+func (p *parser) expectedTokens(expected ...kind) error {
+ tokens := make([]string, len(expected))
+ for i, k := range expected {
+ tokens[i] = k.String()
+ }
+ return p.error("expected %s, but got %v", strings.Join(tokens, " or "), p.token(0).kind)
+}
+
+func (p *parser) token(i int) token {
+ for i > len(p.tokens)-1 {
+ t, err := p.lexer.next()
+ if err != nil {
+ panic(err)
+ }
+ p.tokens = append(p.tokens, t)
+ }
+ return p.tokens[i]
+}
+
+func (p *parser) match(k kind) token {
+ t := p.token(0)
+ if t.kind != k {
+ panic(p.error("expected %v, but got %v", k, t.kind))
+ }
+ p.tokens = p.tokens[1:]
+ return t
+}
+
+func (p *parser) parse() Expr {
+ expr := p.orExpr()
+ p.match(eof)
+ return expr
+}
+
+func (p *parser) orExpr() Expr {
+ expr := p.andExpr()
+ if p.token(0).kind == or {
+ p.match(or)
+ return &BinaryExpr{expr, Or, p.orExpr()}
+ }
+ return expr
+}
+
+func (p *parser) andExpr() Expr {
+ expr := p.equalityExpr()
+ if p.token(0).kind == and {
+ p.match(and)
+ return &BinaryExpr{expr, And, p.andExpr()}
+ }
+ return expr
+}
+
+func (p *parser) equalityExpr() Expr {
+ expr := p.relationalExpr()
+ for {
+ switch kind := p.token(0).kind; kind {
+ case eq, neq:
+ p.match(kind)
+ expr = &BinaryExpr{expr, Op(kind), p.relationalExpr()}
+ default:
+ return expr
+ }
+ }
+}
+
+func (p *parser) relationalExpr() Expr {
+ expr := p.additiveExpr()
+ for {
+ switch kind := p.token(0).kind; kind {
+ case lt, lte, gt, gte:
+ p.match(kind)
+ expr = &BinaryExpr{expr, Op(kind), p.additiveExpr()}
+ default:
+ return expr
+ }
+ }
+}
+
+func (p *parser) additiveExpr() Expr {
+ expr := p.multiplicativeExpr()
+ for {
+ switch kind := p.token(0).kind; kind {
+ case plus, minus:
+ p.match(kind)
+ expr = &BinaryExpr{expr, Op(kind), p.multiplicativeExpr()}
+ default:
+ return expr
+ }
+ }
+}
+
+func (p *parser) multiplicativeExpr() Expr {
+ expr := p.unaryExpr()
+ for {
+ switch kind := p.token(0).kind; kind {
+ case multiply, div, mod:
+ p.match(kind)
+ expr = &BinaryExpr{expr, Op(kind), p.unaryExpr()}
+ default:
+ return expr
+ }
+ }
+}
+
+func (p *parser) unaryExpr() Expr {
+ if p.token(0).kind == minus {
+ p.match(minus)
+ return &NegateExpr{p.unionExpr()}
+ }
+ return p.unionExpr()
+}
+
+func (p *parser) unionExpr() Expr {
+ expr := p.pathExpr()
+ if p.token(0).kind == pipe {
+ p.match(pipe)
+ return &BinaryExpr{expr, Union, p.orExpr()}
+ }
+ return expr
+}
+
+func (p *parser) pathExpr() Expr {
+ switch p.token(0).kind {
+ case number, literal:
+ filter := p.filterExpr()
+ switch p.token(0).kind {
+ case slash, slashSlash:
+ panic(p.error("nodeset expected"))
+ }
+ return filter
+ case lparen, dollar:
+ filter := p.filterExpr()
+ switch p.token(0).kind {
+ case slash, slashSlash:
+ return &PathExpr{filter, p.locationPath(false)}
+ }
+ return filter
+ case identifier:
+ if (p.token(1).kind == lparen && !isNodeTypeName(p.token(0))) || (p.token(1).kind == colon && p.token(3).kind == lparen) {
+ filter := p.filterExpr()
+ switch p.token(0).kind {
+ case slash, slashSlash:
+ return &PathExpr{filter, p.locationPath(false)}
+ }
+ return filter
+ }
+ return p.locationPath(false)
+ case dot, dotDot, star, at:
+ return p.locationPath(false)
+ case slash, slashSlash:
+ return p.locationPath(true)
+ default:
+ panic(p.unexpectedToken())
+ }
+}
+
+func (p *parser) filterExpr() Expr {
+ var expr Expr
+ switch p.token(0).kind {
+ case number:
+ f, err := strconv.ParseFloat(p.match(number).text(), 64)
+ if err != nil {
+ panic(err)
+ }
+ expr = Number(f)
+ case literal:
+ expr = String(p.match(literal).text())
+ case lparen:
+ p.match(lparen)
+ expr = p.orExpr()
+ p.match(rparen)
+ case identifier:
+ expr = p.functionCall()
+ case dollar:
+ expr = p.variableReference()
+ }
+ predicates := p.predicates()
+ if len(predicates) == 0 {
+ return expr
+ }
+ return &FilterExpr{expr, predicates}
+}
+
+func (p *parser) functionCall() *FuncCall {
+ prefix := ""
+ if p.token(1).kind == colon {
+ prefix = p.match(identifier).text()
+ p.match(colon)
+ }
+ local := p.match(identifier).text()
+ p.match(lparen)
+ args := p.arguments()
+ p.match(rparen)
+ return &FuncCall{prefix, local, args}
+}
+
+func (p *parser) arguments() []Expr {
+ var args []Expr
+ for p.token(0).kind != rparen {
+ args = append(args, p.orExpr())
+ if p.token(0).kind == comma {
+ p.match(comma)
+ continue
+ }
+ break
+ }
+ return args
+}
+
+func (p *parser) predicates() []Expr {
+ var predicates []Expr
+ for p.token(0).kind == lbracket {
+ p.match(lbracket)
+ predicates = append(predicates, p.orExpr())
+ p.match(rbracket)
+ }
+ return predicates
+}
+
+func (p *parser) variableReference() *VarRef {
+ p.match(dollar)
+ prefix := ""
+ if p.token(1).kind == colon {
+ prefix = p.match(identifier).text()
+ p.match(colon)
+ }
+ return &VarRef{prefix, p.match(identifier).text()}
+}
+
+func (p *parser) locationPath(abs bool) *LocationPath {
+ switch p.token(0).kind {
+ case slash, slashSlash:
+ if abs {
+ return p.absoluteLocationPath()
+ }
+ return p.relativeLocationPath()
+ case at, identifier, dot, dotDot, star:
+ return p.relativeLocationPath()
+ }
+ panic(p.unexpectedToken())
+}
+
+func (p *parser) absoluteLocationPath() *LocationPath {
+ var steps []*Step
+ switch p.token(0).kind {
+ case slash:
+ p.match(slash)
+ switch p.token(0).kind {
+ case dot, dotDot, at, identifier, star:
+ steps = p.steps()
+ }
+ case slashSlash:
+ p.match(slashSlash)
+ steps = append(steps, &Step{DescendantOrSelf, Node, nil})
+ switch p.token(0).kind {
+ case dot, dotDot, at, identifier, star:
+ steps = append(steps, p.steps()...)
+ default:
+ panic(p.error(`locationPath cannot end with "//"`))
+ }
+ }
+ return &LocationPath{true, steps}
+}
+
+func (p *parser) relativeLocationPath() *LocationPath {
+ var steps []*Step
+ switch p.token(0).kind {
+ case slash:
+ p.match(slash)
+ case slashSlash:
+ p.match(slashSlash)
+ steps = append(steps, &Step{DescendantOrSelf, Node, nil})
+ }
+ steps = append(steps, p.steps()...)
+ return &LocationPath{false, steps}
+}
+
+func (p *parser) steps() []*Step {
+ var steps []*Step
+ switch p.token(0).kind {
+ case dot, dotDot, at, identifier, star:
+ steps = append(steps, p.step())
+ case eof:
+ return steps
+ default:
+ panic(p.expectedTokens(dot, dotDot, at, identifier, star))
+ }
+ for {
+ switch p.token(0).kind {
+ case slash:
+ p.match(slash)
+ case slashSlash:
+ p.match(slashSlash)
+ steps = append(steps, &Step{DescendantOrSelf, Node, nil})
+ default:
+ return steps
+ }
+ switch p.token(0).kind {
+ case dot, dotDot, at, identifier, star:
+ steps = append(steps, p.step())
+ default:
+ panic(p.expectedTokens(dot, dotDot, at, identifier, star))
+ }
+ }
+}
+
+func (p *parser) step() *Step {
+ var axis Axis
+ var nodeTest NodeTest
+ switch p.token(0).kind {
+ case dot:
+ p.match(dot)
+ axis, nodeTest = Self, Node
+ case dotDot:
+ p.match(dotDot)
+ axis, nodeTest = Parent, Node
+ default:
+ switch p.token(0).kind {
+ case at:
+ p.match(at)
+ axis = Attribute
+ case identifier:
+ if p.token(1).kind == colonColon {
+ axis = p.axisSpecifier()
+ } else {
+ axis = Child
+ }
+ case star:
+ axis = Child
+ }
+ nodeTest = p.nodeTest(axis)
+ }
+ return &Step{axis, nodeTest, p.predicates()}
+}
+
+func (p *parser) nodeTest(axis Axis) NodeTest {
+ switch p.token(0).kind {
+ case identifier:
+ if p.token(1).kind == lparen {
+ return p.nodeTypeTest(axis)
+ }
+ return p.nameTest(axis)
+ case star:
+ return p.nameTest(axis)
+ }
+ panic(p.expectedTokens(identifier, star))
+}
+
+func (p *parser) nodeTypeTest(axis Axis) NodeTest {
+ ntype := p.match(identifier).text()
+ p.match(lparen)
+ var nodeTest NodeTest
+ switch ntype {
+ case "processing-instruction":
+ piName := ""
+ if p.token(0).kind == literal {
+ piName = p.match(literal).text()
+ }
+ nodeTest = PITest(piName)
+ case "node":
+ nodeTest = Node
+ case "text":
+ nodeTest = Text
+ case "comment":
+ nodeTest = Comment
+ default:
+ panic(p.error("invalid nodeType %q", ntype))
+ }
+ p.match(rparen)
+ return nodeTest
+}
+
+func (p *parser) nameTest(axis Axis) NodeTest {
+ var prefix string
+ if p.token(0).kind == identifier && p.token(1).kind == colon {
+ prefix = p.match(identifier).text()
+ p.match(colon)
+ }
+ var local string
+ switch p.token(0).kind {
+ case identifier:
+ local = p.match(identifier).text()
+ case star:
+ p.match(star)
+ local = "*"
+ default:
+ // let us assume localName as empty-string and continue
+ }
+ return &NameTest{prefix, local}
+}
+
+func (p *parser) axisSpecifier() Axis {
+ name := p.token(0).text()
+ axis, ok := name2Axis[name]
+ if !ok {
+ panic(p.error("invalid axis %s", name))
+ }
+ p.match(identifier)
+ p.match(colonColon)
+ return axis
+}
+
+func isNodeTypeName(t token) bool {
+ switch t.text() {
+ case "node", "comment", "text", "processing-instruction":
+ return true
+ default:
+ return false
+ }
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go
deleted file mode 100644
index 8bb9a6ced330..000000000000
--- a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Code generated by depstubber. DO NOT EDIT.
-// This is a simple stub for github.com/santhosh-tekuri/xpathparser, strictly for use in testing.
-
-// See the LICENSE file for information about the licensing of the original library.
-// Source: github.com/santhosh-tekuri/xpathparser (exports: ; functions: Parse,MustParse)
-
-// Package xpathparser is a stub of github.com/santhosh-tekuri/xpathparser, generated by depstubber.
-package xpathparser
-
-import ()
-
-type Expr interface{}
-
-func MustParse(_ string) Expr {
- return nil
-}
-
-func Parse(_ string) (Expr, error) {
- return nil, nil
-}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go
new file mode 100644
index 000000000000..c35469865158
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go
@@ -0,0 +1,288 @@
+// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xpathparser
+
+import (
+ "fmt"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+// Error is the error type returned by Parse function.
+//
+// It represents a syntax error in the XPath expression.
+type Error struct {
+ Msg string
+ XPath string
+ Offset int
+}
+
+func (e *Error) Error() string {
+ return fmt.Sprintf("%s in xpath %s at offset %d", e.Msg, e.XPath, e.Offset)
+}
+
+// Axis specifies the tree relationship between the nodes selected by the location step and the context node.
+type Axis int
+
+// Possible values for Axis.
+const (
+ Child Axis = iota
+ Descendant
+ Parent
+ Ancestor
+ FollowingSibling
+ PrecedingSibling
+ Following
+ Preceding
+ Attribute
+ Namespace
+ Self
+ DescendantOrSelf
+ AncestorOrSelf
+)
+
+var axisNames = []string{
+ "child",
+ "descendant",
+ "parent",
+ "ancestor",
+ "following-sibling",
+ "preceding-sibling",
+ "following",
+ "preceding",
+ "attribute",
+ "namespace",
+ "self",
+ "descendant-or-self",
+ "ancestor-or-self",
+}
+
+func (a Axis) String() string {
+ return axisNames[a]
+}
+
+var name2Axis = make(map[string]Axis)
+
+func init() {
+ for i, name := range axisNames {
+ name2Axis[name] = Axis(i)
+ }
+}
+
+// NodeType represents test on node type.
+type NodeType int
+
+// Possible values for NodeType.
+const (
+ Comment NodeType = iota
+ Text
+ Node
+)
+
+var nodeTypeNames = []string{"comment()", "text()", "node()"}
+
+func (nt NodeType) String() string {
+ return nodeTypeNames[nt]
+}
+
+// Op represents XPath binrary operator.
+type Op int
+
+// Possible values for Op.
+const (
+ EQ Op = iota
+ NEQ
+ LT
+ LTE
+ GT
+ GTE
+ Add
+ Subtract
+ Multiply
+ Mod
+ Div
+ And
+ Or
+ Union
+)
+
+func (op Op) String() string {
+ str := kind(op).String()
+ return str[1 : len(str)-1]
+}
+
+// An Expr is an interface holding one of the types:
+// *LocationPath, *FilterExpr, *PathExpr, *BinaryExpr, *NegateExpr, *VarRef, *FuncCall, Number or String
+type Expr interface{}
+
+// BinaryExpr represents a binary operation.
+type BinaryExpr struct {
+ LHS Expr
+ Op Op
+ RHS Expr
+}
+
+func (b *BinaryExpr) String() string {
+ return fmt.Sprintf("(%s %s %s)", b.LHS, b.Op, b.RHS)
+}
+
+// NegateExpr represents unary operator `-`.
+type NegateExpr struct {
+ Expr Expr
+}
+
+func (n *NegateExpr) String() string {
+ return fmt.Sprintf("-%s", n.Expr)
+}
+
+// LocationPath represents XPath location path.
+type LocationPath struct {
+ Abs bool
+ Steps []*Step
+}
+
+func (lp *LocationPath) String() string {
+ s := make([]string, len(lp.Steps))
+ for i, step := range lp.Steps {
+ s[i] = step.String()
+ }
+ if lp.Abs {
+ return fmt.Sprintf("/%s", strings.Join(s, "/"))
+ }
+ return fmt.Sprintf("%s", strings.Join(s, "/"))
+}
+
+// FilterExpr represents https://www.w3.org/TR/xpath/#NT-FilterExpr.
+type FilterExpr struct {
+ Expr Expr
+ Predicates []Expr
+}
+
+func (f *FilterExpr) String() string {
+ return fmt.Sprintf("(%s)%s", f.Expr, predicatesString(f.Predicates))
+}
+
+// PathExpr represents https://www.w3.org/TR/xpath/#NT-PathExpr.
+type PathExpr struct {
+ Filter Expr
+ LocationPath *LocationPath
+}
+
+func (p *PathExpr) String() string {
+ return fmt.Sprintf("(%s)/%s", p.Filter, p.LocationPath)
+}
+
+// Step represents XPath location step.
+type Step struct {
+ Axis Axis
+ NodeTest NodeTest
+ Predicates []Expr
+}
+
+func (s *Step) String() string {
+ return fmt.Sprintf("%v::%s%s", s.Axis, s.NodeTest, predicatesString(s.Predicates))
+}
+
+// A NodeTest is an interface holding one of the types:
+// NodeType, *NameTest, or PITest.
+type NodeTest interface{}
+
+// NameTest represents https://www.w3.org/TR/xpath/#NT-NameTest.
+type NameTest struct {
+ Prefix string
+ Local string
+}
+
+func (nt *NameTest) String() string {
+ if nt.Prefix == "" {
+ return nt.Local
+ }
+ return fmt.Sprintf("%s:%s", nt.Prefix, nt.Local)
+}
+
+// PITest represents processing-instruction test.
+type PITest string
+
+func (pt PITest) String() string {
+ return fmt.Sprintf("processing-instruction(%q)", string(pt))
+}
+
+// VarRef represents https://www.w3.org/TR/xpath/#NT-VariableReference.
+type VarRef struct {
+ Prefix string
+ Local string
+}
+
+func (vr *VarRef) String() string {
+ if vr.Prefix == "" {
+ return fmt.Sprintf("$%s", vr.Local)
+ }
+ return fmt.Sprintf("$%s:%s", vr.Prefix, vr.Local)
+}
+
+// FuncCall represents https://www.w3.org/TR/xpath/#section-Function-Calls.
+type FuncCall struct {
+ Prefix string
+ Local string
+ Args []Expr
+}
+
+func (fc *FuncCall) String() string {
+ p := make([]string, len(fc.Args))
+ for i, param := range fc.Args {
+ p[i] = fmt.Sprint(param)
+ }
+ if fc.Prefix == "" {
+ return fmt.Sprintf("%s(%s)", fc.Local, strings.Join(p, ", "))
+ }
+ return fmt.Sprintf("%s:%s(%s)", fc.Prefix, fc.Local, strings.Join(p, ", "))
+}
+
+// Number represents number literal.
+type Number float64
+
+func (n Number) String() string {
+ return strconv.FormatFloat(float64(n), 'f', -1, 64)
+}
+
+// String represents string literal.
+type String string
+
+func (s String) String() string {
+ return strconv.Quote(string(s))
+}
+
+// MustParse is like Parse but panics if the xpath expression has error.
+// It simplifies safe initialization of global variables holding parsed expressions.
+func MustParse(xpath string) Expr {
+ p := &parser{lexer: lexer{xpath: xpath}}
+ return p.parse()
+}
+
+// Parse parses given xpath 1.0 expression.
+func Parse(xpath string) (expr Expr, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ if _, ok := r.(error); ok {
+ err = r.(error)
+ } else {
+ err = fmt.Errorf("%v", r)
+ }
+ }
+ }()
+ return MustParse(xpath), nil
+}
+
+func predicatesString(predicates []Expr) string {
+ p := make([]string, len(predicates))
+ for i, predicate := range predicates {
+ p[i] = fmt.Sprintf("[%s]", predicate)
+ }
+ return strings.Join(p, "")
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE
new file mode 100644
index 000000000000..2a7cf70da6e4
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 The Go Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google LLC nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS
new file mode 100644
index 000000000000..733099041f84
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go
new file mode 100644
index 000000000000..cd0a8ac15451
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go
@@ -0,0 +1,78 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package atom provides integer codes (also known as atoms) for a fixed set of
+// frequently occurring HTML strings: tag names and attribute keys such as "p"
+// and "id".
+//
+// Sharing an atom's name between all elements with the same tag can result in
+// fewer string allocations when tokenizing and parsing HTML. Integer
+// comparisons are also generally faster than string comparisons.
+//
+// The value of an atom's particular code is not guaranteed to stay the same
+// between versions of this package. Neither is any ordering guaranteed:
+// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
+// be dense. The only guarantees are that e.g. looking up "div" will yield
+// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
+package atom // import "golang.org/x/net/html/atom"
+
+// Atom is an integer code for a string. The zero value maps to "".
+type Atom uint32
+
+// String returns the atom's name.
+func (a Atom) String() string {
+ start := uint32(a >> 8)
+ n := uint32(a & 0xff)
+ if start+n > uint32(len(atomText)) {
+ return ""
+ }
+ return atomText[start : start+n]
+}
+
+func (a Atom) string() string {
+ return atomText[a>>8 : a>>8+a&0xff]
+}
+
+// fnv computes the FNV hash with an arbitrary starting value h.
+func fnv(h uint32, s []byte) uint32 {
+ for i := range s {
+ h ^= uint32(s[i])
+ h *= 16777619
+ }
+ return h
+}
+
+func match(s string, t []byte) bool {
+ for i, c := range t {
+ if s[i] != c {
+ return false
+ }
+ }
+ return true
+}
+
+// Lookup returns the atom whose name is s. It returns zero if there is no
+// such atom. The lookup is case sensitive.
+func Lookup(s []byte) Atom {
+ if len(s) == 0 || len(s) > maxAtomLen {
+ return 0
+ }
+ h := fnv(hash0, s)
+ if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
+ return a
+ }
+ if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
+ return a
+ }
+ return 0
+}
+
+// String returns a string whose contents are equal to s. In that sense, it is
+// equivalent to string(s) but may be more efficient.
+func String(s []byte) string {
+ if a := Lookup(s); a != 0 {
+ return a.String()
+ }
+ return string(s)
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go
new file mode 100644
index 000000000000..b460e6f722b9
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go
@@ -0,0 +1,785 @@
+// Code generated by go generate gen.go; DO NOT EDIT.
+
+//go:generate go run gen.go
+
+package atom
+
+const (
+ A Atom = 0x1
+ Abbr Atom = 0x4
+ Accept Atom = 0x1a06
+ AcceptCharset Atom = 0x1a0e
+ Accesskey Atom = 0x2c09
+ Acronym Atom = 0xaa07
+ Action Atom = 0x26506
+ Address Atom = 0x6f107
+ Align Atom = 0xb105
+ Allowfullscreen Atom = 0x3280f
+ Allowpaymentrequest Atom = 0xc113
+ Allowusermedia Atom = 0xdd0e
+ Alt Atom = 0xf303
+ Annotation Atom = 0x1c90a
+ AnnotationXml Atom = 0x1c90e
+ Applet Atom = 0x30806
+ Area Atom = 0x35004
+ Article Atom = 0x3f607
+ As Atom = 0x3c02
+ Aside Atom = 0x10705
+ Async Atom = 0xff05
+ Audio Atom = 0x11505
+ Autocomplete Atom = 0x26b0c
+ Autofocus Atom = 0x12109
+ Autoplay Atom = 0x13c08
+ B Atom = 0x101
+ Base Atom = 0x3b04
+ Basefont Atom = 0x3b08
+ Bdi Atom = 0xba03
+ Bdo Atom = 0x14b03
+ Bgsound Atom = 0x15e07
+ Big Atom = 0x17003
+ Blink Atom = 0x17305
+ Blockquote Atom = 0x1870a
+ Body Atom = 0x2804
+ Br Atom = 0x202
+ Button Atom = 0x19106
+ Canvas Atom = 0x10306
+ Caption Atom = 0x22407
+ Center Atom = 0x21306
+ Challenge Atom = 0x28e09
+ Charset Atom = 0x2107
+ Checked Atom = 0x5b507
+ Cite Atom = 0x19c04
+ Class Atom = 0x55805
+ Code Atom = 0x5ee04
+ Col Atom = 0x1ab03
+ Colgroup Atom = 0x1ab08
+ Color Atom = 0x1bf05
+ Cols Atom = 0x1c404
+ Colspan Atom = 0x1c407
+ Command Atom = 0x1d707
+ Content Atom = 0x57b07
+ Contenteditable Atom = 0x57b0f
+ Contextmenu Atom = 0x37a0b
+ Controls Atom = 0x1de08
+ Coords Atom = 0x1f006
+ Crossorigin Atom = 0x1fa0b
+ Data Atom = 0x49904
+ Datalist Atom = 0x49908
+ Datetime Atom = 0x2ab08
+ Dd Atom = 0x2bf02
+ Default Atom = 0x10a07
+ Defer Atom = 0x5f005
+ Del Atom = 0x44c03
+ Desc Atom = 0x55504
+ Details Atom = 0x7207
+ Dfn Atom = 0x8703
+ Dialog Atom = 0xbb06
+ Dir Atom = 0x9303
+ Dirname Atom = 0x9307
+ Disabled Atom = 0x16408
+ Div Atom = 0x16b03
+ Dl Atom = 0x5d602
+ Download Atom = 0x45d08
+ Draggable Atom = 0x17a09
+ Dropzone Atom = 0x3ff08
+ Dt Atom = 0x64002
+ Em Atom = 0x6e02
+ Embed Atom = 0x6e05
+ Enctype Atom = 0x28007
+ Face Atom = 0x21104
+ Fieldset Atom = 0x21908
+ Figcaption Atom = 0x2210a
+ Figure Atom = 0x23b06
+ Font Atom = 0x3f04
+ Footer Atom = 0xf606
+ For Atom = 0x24703
+ ForeignObject Atom = 0x2470d
+ Foreignobject Atom = 0x2540d
+ Form Atom = 0x26104
+ Formaction Atom = 0x2610a
+ Formenctype Atom = 0x27c0b
+ Formmethod Atom = 0x2970a
+ Formnovalidate Atom = 0x2a10e
+ Formtarget Atom = 0x2b30a
+ Frame Atom = 0x8b05
+ Frameset Atom = 0x8b08
+ H1 Atom = 0x15c02
+ H2 Atom = 0x56102
+ H3 Atom = 0x2cd02
+ H4 Atom = 0x2fc02
+ H5 Atom = 0x33f02
+ H6 Atom = 0x34902
+ Head Atom = 0x32004
+ Header Atom = 0x32006
+ Headers Atom = 0x32007
+ Height Atom = 0x5206
+ Hgroup Atom = 0x64206
+ Hidden Atom = 0x2bd06
+ High Atom = 0x2ca04
+ Hr Atom = 0x15702
+ Href Atom = 0x2cf04
+ Hreflang Atom = 0x2cf08
+ Html Atom = 0x5604
+ HttpEquiv Atom = 0x2d70a
+ I Atom = 0x601
+ Icon Atom = 0x57a04
+ Id Atom = 0x10902
+ Iframe Atom = 0x2eb06
+ Image Atom = 0x2f105
+ Img Atom = 0x2f603
+ Input Atom = 0x44505
+ Inputmode Atom = 0x44509
+ Ins Atom = 0x20303
+ Integrity Atom = 0x23209
+ Is Atom = 0x16502
+ Isindex Atom = 0x2fe07
+ Ismap Atom = 0x30505
+ Itemid Atom = 0x38506
+ Itemprop Atom = 0x19d08
+ Itemref Atom = 0x3c707
+ Itemscope Atom = 0x66f09
+ Itemtype Atom = 0x30e08
+ Kbd Atom = 0xb903
+ Keygen Atom = 0x3206
+ Keytype Atom = 0xd607
+ Kind Atom = 0x17704
+ Label Atom = 0x5905
+ Lang Atom = 0x2d304
+ Legend Atom = 0x18106
+ Li Atom = 0xb202
+ Link Atom = 0x17404
+ List Atom = 0x49d04
+ Listing Atom = 0x49d07
+ Loop Atom = 0x5d04
+ Low Atom = 0xc303
+ Main Atom = 0x1004
+ Malignmark Atom = 0xb00a
+ Manifest Atom = 0x6d508
+ Map Atom = 0x30703
+ Mark Atom = 0xb604
+ Marquee Atom = 0x31607
+ Math Atom = 0x31d04
+ Max Atom = 0x33703
+ Maxlength Atom = 0x33709
+ Media Atom = 0xe605
+ Mediagroup Atom = 0xe60a
+ Menu Atom = 0x38104
+ Menuitem Atom = 0x38108
+ Meta Atom = 0x4ac04
+ Meter Atom = 0x9805
+ Method Atom = 0x29b06
+ Mglyph Atom = 0x2f706
+ Mi Atom = 0x34102
+ Min Atom = 0x34103
+ Minlength Atom = 0x34109
+ Mn Atom = 0x2a402
+ Mo Atom = 0xa402
+ Ms Atom = 0x67202
+ Mtext Atom = 0x34b05
+ Multiple Atom = 0x35908
+ Muted Atom = 0x36105
+ Name Atom = 0x9604
+ Nav Atom = 0x1303
+ Nobr Atom = 0x3704
+ Noembed Atom = 0x6c07
+ Noframes Atom = 0x8908
+ Nomodule Atom = 0xa208
+ Nonce Atom = 0x1a605
+ Noscript Atom = 0x2c208
+ Novalidate Atom = 0x2a50a
+ Object Atom = 0x25b06
+ Ol Atom = 0x13702
+ Onabort Atom = 0x19507
+ Onafterprint Atom = 0x2290c
+ Onautocomplete Atom = 0x2690e
+ Onautocompleteerror Atom = 0x26913
+ Onauxclick Atom = 0x6140a
+ Onbeforeprint Atom = 0x69c0d
+ Onbeforeunload Atom = 0x6e50e
+ Onblur Atom = 0x1ea06
+ Oncancel Atom = 0x11908
+ Oncanplay Atom = 0x14d09
+ Oncanplaythrough Atom = 0x14d10
+ Onchange Atom = 0x41508
+ Onclick Atom = 0x2e407
+ Onclose Atom = 0x36607
+ Oncontextmenu Atom = 0x3780d
+ Oncopy Atom = 0x38b06
+ Oncuechange Atom = 0x3910b
+ Oncut Atom = 0x39c05
+ Ondblclick Atom = 0x3a10a
+ Ondrag Atom = 0x3ab06
+ Ondragend Atom = 0x3ab09
+ Ondragenter Atom = 0x3b40b
+ Ondragexit Atom = 0x3bf0a
+ Ondragleave Atom = 0x3d90b
+ Ondragover Atom = 0x3e40a
+ Ondragstart Atom = 0x3ee0b
+ Ondrop Atom = 0x3fd06
+ Ondurationchange Atom = 0x40d10
+ Onemptied Atom = 0x40409
+ Onended Atom = 0x41d07
+ Onerror Atom = 0x42407
+ Onfocus Atom = 0x42b07
+ Onhashchange Atom = 0x4370c
+ Oninput Atom = 0x44307
+ Oninvalid Atom = 0x44f09
+ Onkeydown Atom = 0x45809
+ Onkeypress Atom = 0x4650a
+ Onkeyup Atom = 0x47407
+ Onlanguagechange Atom = 0x48110
+ Onload Atom = 0x49106
+ Onloadeddata Atom = 0x4910c
+ Onloadedmetadata Atom = 0x4a410
+ Onloadend Atom = 0x4ba09
+ Onloadstart Atom = 0x4c30b
+ Onmessage Atom = 0x4ce09
+ Onmessageerror Atom = 0x4ce0e
+ Onmousedown Atom = 0x4dc0b
+ Onmouseenter Atom = 0x4e70c
+ Onmouseleave Atom = 0x4f30c
+ Onmousemove Atom = 0x4ff0b
+ Onmouseout Atom = 0x50a0a
+ Onmouseover Atom = 0x5170b
+ Onmouseup Atom = 0x52209
+ Onmousewheel Atom = 0x5300c
+ Onoffline Atom = 0x53c09
+ Ononline Atom = 0x54508
+ Onpagehide Atom = 0x54d0a
+ Onpageshow Atom = 0x5630a
+ Onpaste Atom = 0x56f07
+ Onpause Atom = 0x58a07
+ Onplay Atom = 0x59406
+ Onplaying Atom = 0x59409
+ Onpopstate Atom = 0x59d0a
+ Onprogress Atom = 0x5a70a
+ Onratechange Atom = 0x5bc0c
+ Onrejectionhandled Atom = 0x5c812
+ Onreset Atom = 0x5da07
+ Onresize Atom = 0x5e108
+ Onscroll Atom = 0x5f508
+ Onsecuritypolicyviolation Atom = 0x5fd19
+ Onseeked Atom = 0x61e08
+ Onseeking Atom = 0x62609
+ Onselect Atom = 0x62f08
+ Onshow Atom = 0x63906
+ Onsort Atom = 0x64d06
+ Onstalled Atom = 0x65709
+ Onstorage Atom = 0x66009
+ Onsubmit Atom = 0x66908
+ Onsuspend Atom = 0x67909
+ Ontimeupdate Atom = 0x400c
+ Ontoggle Atom = 0x68208
+ Onunhandledrejection Atom = 0x68a14
+ Onunload Atom = 0x6a908
+ Onvolumechange Atom = 0x6b10e
+ Onwaiting Atom = 0x6bf09
+ Onwheel Atom = 0x6c807
+ Open Atom = 0x1a304
+ Optgroup Atom = 0x5f08
+ Optimum Atom = 0x6cf07
+ Option Atom = 0x6e106
+ Output Atom = 0x51106
+ P Atom = 0xc01
+ Param Atom = 0xc05
+ Pattern Atom = 0x6607
+ Picture Atom = 0x7b07
+ Ping Atom = 0xef04
+ Placeholder Atom = 0x1310b
+ Plaintext Atom = 0x1b209
+ Playsinline Atom = 0x1400b
+ Poster Atom = 0x64706
+ Pre Atom = 0x46a03
+ Preload Atom = 0x47a07
+ Progress Atom = 0x5a908
+ Prompt Atom = 0x52a06
+ Public Atom = 0x57606
+ Q Atom = 0xcf01
+ Radiogroup Atom = 0x30a
+ Rb Atom = 0x3a02
+ Readonly Atom = 0x35108
+ Referrerpolicy Atom = 0x3cb0e
+ Rel Atom = 0x47b03
+ Required Atom = 0x23f08
+ Reversed Atom = 0x8008
+ Rows Atom = 0x9c04
+ Rowspan Atom = 0x9c07
+ Rp Atom = 0x22f02
+ Rt Atom = 0x19a02
+ Rtc Atom = 0x19a03
+ Ruby Atom = 0xfb04
+ S Atom = 0x2501
+ Samp Atom = 0x7804
+ Sandbox Atom = 0x12907
+ Scope Atom = 0x67305
+ Scoped Atom = 0x67306
+ Script Atom = 0x2c406
+ Seamless Atom = 0x36b08
+ Search Atom = 0x55c06
+ Section Atom = 0x1e507
+ Select Atom = 0x63106
+ Selected Atom = 0x63108
+ Shape Atom = 0x1f505
+ Size Atom = 0x5e504
+ Sizes Atom = 0x5e505
+ Slot Atom = 0x20504
+ Small Atom = 0x32605
+ Sortable Atom = 0x64f08
+ Sorted Atom = 0x37206
+ Source Atom = 0x43106
+ Spacer Atom = 0x46e06
+ Span Atom = 0x9f04
+ Spellcheck Atom = 0x5b00a
+ Src Atom = 0x5e903
+ Srcdoc Atom = 0x5e906
+ Srclang Atom = 0x6f707
+ Srcset Atom = 0x6fe06
+ Start Atom = 0x3f405
+ Step Atom = 0x57304
+ Strike Atom = 0xd206
+ Strong Atom = 0x6db06
+ Style Atom = 0x70405
+ Sub Atom = 0x66b03
+ Summary Atom = 0x70907
+ Sup Atom = 0x71003
+ Svg Atom = 0x71303
+ System Atom = 0x71606
+ Tabindex Atom = 0x4b208
+ Table Atom = 0x58505
+ Target Atom = 0x2b706
+ Tbody Atom = 0x2705
+ Td Atom = 0x9202
+ Template Atom = 0x71908
+ Textarea Atom = 0x34c08
+ Tfoot Atom = 0xf505
+ Th Atom = 0x15602
+ Thead Atom = 0x31f05
+ Time Atom = 0x4204
+ Title Atom = 0x11005
+ Tr Atom = 0xcc02
+ Track Atom = 0x1ba05
+ Translate Atom = 0x20809
+ Tt Atom = 0x6802
+ Type Atom = 0xd904
+ Typemustmatch Atom = 0x2830d
+ U Atom = 0xb01
+ Ul Atom = 0xa702
+ Updateviacache Atom = 0x460e
+ Usemap Atom = 0x58e06
+ Value Atom = 0x1505
+ Var Atom = 0x16d03
+ Video Atom = 0x2e005
+ Wbr Atom = 0x56c03
+ Width Atom = 0x63e05
+ Workertype Atom = 0x7210a
+ Wrap Atom = 0x72b04
+ Xmp Atom = 0x12f03
+)
+
+const hash0 = 0x84f70e16
+
+const maxAtomLen = 25
+
+var table = [1 << 9]Atom{
+ 0x1: 0x3ff08, // dropzone
+ 0x2: 0x3b08, // basefont
+ 0x3: 0x23209, // integrity
+ 0x4: 0x43106, // source
+ 0x5: 0x2c09, // accesskey
+ 0x6: 0x1a06, // accept
+ 0x7: 0x6c807, // onwheel
+ 0xb: 0x47407, // onkeyup
+ 0xc: 0x32007, // headers
+ 0xd: 0x67306, // scoped
+ 0xe: 0x67909, // onsuspend
+ 0xf: 0x8908, // noframes
+ 0x10: 0x1fa0b, // crossorigin
+ 0x11: 0x2e407, // onclick
+ 0x12: 0x3f405, // start
+ 0x13: 0x37a0b, // contextmenu
+ 0x14: 0x5e903, // src
+ 0x15: 0x1c404, // cols
+ 0x16: 0xbb06, // dialog
+ 0x17: 0x47a07, // preload
+ 0x18: 0x3c707, // itemref
+ 0x1b: 0x2f105, // image
+ 0x1d: 0x4ba09, // onloadend
+ 0x1e: 0x45d08, // download
+ 0x1f: 0x46a03, // pre
+ 0x23: 0x2970a, // formmethod
+ 0x24: 0x71303, // svg
+ 0x25: 0xcf01, // q
+ 0x26: 0x64002, // dt
+ 0x27: 0x1de08, // controls
+ 0x2a: 0x2804, // body
+ 0x2b: 0xd206, // strike
+ 0x2c: 0x3910b, // oncuechange
+ 0x2d: 0x4c30b, // onloadstart
+ 0x2e: 0x2fe07, // isindex
+ 0x2f: 0xb202, // li
+ 0x30: 0x1400b, // playsinline
+ 0x31: 0x34102, // mi
+ 0x32: 0x30806, // applet
+ 0x33: 0x4ce09, // onmessage
+ 0x35: 0x13702, // ol
+ 0x36: 0x1a304, // open
+ 0x39: 0x14d09, // oncanplay
+ 0x3a: 0x6bf09, // onwaiting
+ 0x3b: 0x11908, // oncancel
+ 0x3c: 0x6a908, // onunload
+ 0x3e: 0x53c09, // onoffline
+ 0x3f: 0x1a0e, // accept-charset
+ 0x40: 0x32004, // head
+ 0x42: 0x3ab09, // ondragend
+ 0x43: 0x1310b, // placeholder
+ 0x44: 0x2b30a, // formtarget
+ 0x45: 0x2540d, // foreignobject
+ 0x47: 0x400c, // ontimeupdate
+ 0x48: 0xdd0e, // allowusermedia
+ 0x4a: 0x69c0d, // onbeforeprint
+ 0x4b: 0x5604, // html
+ 0x4c: 0x9f04, // span
+ 0x4d: 0x64206, // hgroup
+ 0x4e: 0x16408, // disabled
+ 0x4f: 0x4204, // time
+ 0x51: 0x42b07, // onfocus
+ 0x53: 0xb00a, // malignmark
+ 0x55: 0x4650a, // onkeypress
+ 0x56: 0x55805, // class
+ 0x57: 0x1ab08, // colgroup
+ 0x58: 0x33709, // maxlength
+ 0x59: 0x5a908, // progress
+ 0x5b: 0x70405, // style
+ 0x5c: 0x2a10e, // formnovalidate
+ 0x5e: 0x38b06, // oncopy
+ 0x60: 0x26104, // form
+ 0x61: 0xf606, // footer
+ 0x64: 0x30a, // radiogroup
+ 0x66: 0xfb04, // ruby
+ 0x67: 0x4ff0b, // onmousemove
+ 0x68: 0x19d08, // itemprop
+ 0x69: 0x2d70a, // http-equiv
+ 0x6a: 0x15602, // th
+ 0x6c: 0x6e02, // em
+ 0x6d: 0x38108, // menuitem
+ 0x6e: 0x63106, // select
+ 0x6f: 0x48110, // onlanguagechange
+ 0x70: 0x31f05, // thead
+ 0x71: 0x15c02, // h1
+ 0x72: 0x5e906, // srcdoc
+ 0x75: 0x9604, // name
+ 0x76: 0x19106, // button
+ 0x77: 0x55504, // desc
+ 0x78: 0x17704, // kind
+ 0x79: 0x1bf05, // color
+ 0x7c: 0x58e06, // usemap
+ 0x7d: 0x30e08, // itemtype
+ 0x7f: 0x6d508, // manifest
+ 0x81: 0x5300c, // onmousewheel
+ 0x82: 0x4dc0b, // onmousedown
+ 0x84: 0xc05, // param
+ 0x85: 0x2e005, // video
+ 0x86: 0x4910c, // onloadeddata
+ 0x87: 0x6f107, // address
+ 0x8c: 0xef04, // ping
+ 0x8d: 0x24703, // for
+ 0x8f: 0x62f08, // onselect
+ 0x90: 0x30703, // map
+ 0x92: 0xc01, // p
+ 0x93: 0x8008, // reversed
+ 0x94: 0x54d0a, // onpagehide
+ 0x95: 0x3206, // keygen
+ 0x96: 0x34109, // minlength
+ 0x97: 0x3e40a, // ondragover
+ 0x98: 0x42407, // onerror
+ 0x9a: 0x2107, // charset
+ 0x9b: 0x29b06, // method
+ 0x9c: 0x101, // b
+ 0x9d: 0x68208, // ontoggle
+ 0x9e: 0x2bd06, // hidden
+ 0xa0: 0x3f607, // article
+ 0xa2: 0x63906, // onshow
+ 0xa3: 0x64d06, // onsort
+ 0xa5: 0x57b0f, // contenteditable
+ 0xa6: 0x66908, // onsubmit
+ 0xa8: 0x44f09, // oninvalid
+ 0xaa: 0x202, // br
+ 0xab: 0x10902, // id
+ 0xac: 0x5d04, // loop
+ 0xad: 0x5630a, // onpageshow
+ 0xb0: 0x2cf04, // href
+ 0xb2: 0x2210a, // figcaption
+ 0xb3: 0x2690e, // onautocomplete
+ 0xb4: 0x49106, // onload
+ 0xb6: 0x9c04, // rows
+ 0xb7: 0x1a605, // nonce
+ 0xb8: 0x68a14, // onunhandledrejection
+ 0xbb: 0x21306, // center
+ 0xbc: 0x59406, // onplay
+ 0xbd: 0x33f02, // h5
+ 0xbe: 0x49d07, // listing
+ 0xbf: 0x57606, // public
+ 0xc2: 0x23b06, // figure
+ 0xc3: 0x57a04, // icon
+ 0xc4: 0x1ab03, // col
+ 0xc5: 0x47b03, // rel
+ 0xc6: 0xe605, // media
+ 0xc7: 0x12109, // autofocus
+ 0xc8: 0x19a02, // rt
+ 0xca: 0x2d304, // lang
+ 0xcc: 0x49908, // datalist
+ 0xce: 0x2eb06, // iframe
+ 0xcf: 0x36105, // muted
+ 0xd0: 0x6140a, // onauxclick
+ 0xd2: 0x3c02, // as
+ 0xd6: 0x3fd06, // ondrop
+ 0xd7: 0x1c90a, // annotation
+ 0xd8: 0x21908, // fieldset
+ 0xdb: 0x2cf08, // hreflang
+ 0xdc: 0x4e70c, // onmouseenter
+ 0xdd: 0x2a402, // mn
+ 0xde: 0xe60a, // mediagroup
+ 0xdf: 0x9805, // meter
+ 0xe0: 0x56c03, // wbr
+ 0xe2: 0x63e05, // width
+ 0xe3: 0x2290c, // onafterprint
+ 0xe4: 0x30505, // ismap
+ 0xe5: 0x1505, // value
+ 0xe7: 0x1303, // nav
+ 0xe8: 0x54508, // ononline
+ 0xe9: 0xb604, // mark
+ 0xea: 0xc303, // low
+ 0xeb: 0x3ee0b, // ondragstart
+ 0xef: 0x12f03, // xmp
+ 0xf0: 0x22407, // caption
+ 0xf1: 0xd904, // type
+ 0xf2: 0x70907, // summary
+ 0xf3: 0x6802, // tt
+ 0xf4: 0x20809, // translate
+ 0xf5: 0x1870a, // blockquote
+ 0xf8: 0x15702, // hr
+ 0xfa: 0x2705, // tbody
+ 0xfc: 0x7b07, // picture
+ 0xfd: 0x5206, // height
+ 0xfe: 0x19c04, // cite
+ 0xff: 0x2501, // s
+ 0x101: 0xff05, // async
+ 0x102: 0x56f07, // onpaste
+ 0x103: 0x19507, // onabort
+ 0x104: 0x2b706, // target
+ 0x105: 0x14b03, // bdo
+ 0x106: 0x1f006, // coords
+ 0x107: 0x5e108, // onresize
+ 0x108: 0x71908, // template
+ 0x10a: 0x3a02, // rb
+ 0x10b: 0x2a50a, // novalidate
+ 0x10c: 0x460e, // updateviacache
+ 0x10d: 0x71003, // sup
+ 0x10e: 0x6c07, // noembed
+ 0x10f: 0x16b03, // div
+ 0x110: 0x6f707, // srclang
+ 0x111: 0x17a09, // draggable
+ 0x112: 0x67305, // scope
+ 0x113: 0x5905, // label
+ 0x114: 0x22f02, // rp
+ 0x115: 0x23f08, // required
+ 0x116: 0x3780d, // oncontextmenu
+ 0x117: 0x5e504, // size
+ 0x118: 0x5b00a, // spellcheck
+ 0x119: 0x3f04, // font
+ 0x11a: 0x9c07, // rowspan
+ 0x11b: 0x10a07, // default
+ 0x11d: 0x44307, // oninput
+ 0x11e: 0x38506, // itemid
+ 0x11f: 0x5ee04, // code
+ 0x120: 0xaa07, // acronym
+ 0x121: 0x3b04, // base
+ 0x125: 0x2470d, // foreignObject
+ 0x126: 0x2ca04, // high
+ 0x127: 0x3cb0e, // referrerpolicy
+ 0x128: 0x33703, // max
+ 0x129: 0x59d0a, // onpopstate
+ 0x12a: 0x2fc02, // h4
+ 0x12b: 0x4ac04, // meta
+ 0x12c: 0x17305, // blink
+ 0x12e: 0x5f508, // onscroll
+ 0x12f: 0x59409, // onplaying
+ 0x130: 0xc113, // allowpaymentrequest
+ 0x131: 0x19a03, // rtc
+ 0x132: 0x72b04, // wrap
+ 0x134: 0x8b08, // frameset
+ 0x135: 0x32605, // small
+ 0x137: 0x32006, // header
+ 0x138: 0x40409, // onemptied
+ 0x139: 0x34902, // h6
+ 0x13a: 0x35908, // multiple
+ 0x13c: 0x52a06, // prompt
+ 0x13f: 0x28e09, // challenge
+ 0x141: 0x4370c, // onhashchange
+ 0x142: 0x57b07, // content
+ 0x143: 0x1c90e, // annotation-xml
+ 0x144: 0x36607, // onclose
+ 0x145: 0x14d10, // oncanplaythrough
+ 0x148: 0x5170b, // onmouseover
+ 0x149: 0x64f08, // sortable
+ 0x14a: 0xa402, // mo
+ 0x14b: 0x2cd02, // h3
+ 0x14c: 0x2c406, // script
+ 0x14d: 0x41d07, // onended
+ 0x14f: 0x64706, // poster
+ 0x150: 0x7210a, // workertype
+ 0x153: 0x1f505, // shape
+ 0x154: 0x4, // abbr
+ 0x155: 0x1, // a
+ 0x156: 0x2bf02, // dd
+ 0x157: 0x71606, // system
+ 0x158: 0x4ce0e, // onmessageerror
+ 0x159: 0x36b08, // seamless
+ 0x15a: 0x2610a, // formaction
+ 0x15b: 0x6e106, // option
+ 0x15c: 0x31d04, // math
+ 0x15d: 0x62609, // onseeking
+ 0x15e: 0x39c05, // oncut
+ 0x15f: 0x44c03, // del
+ 0x160: 0x11005, // title
+ 0x161: 0x11505, // audio
+ 0x162: 0x63108, // selected
+ 0x165: 0x3b40b, // ondragenter
+ 0x166: 0x46e06, // spacer
+ 0x167: 0x4a410, // onloadedmetadata
+ 0x168: 0x44505, // input
+ 0x16a: 0x58505, // table
+ 0x16b: 0x41508, // onchange
+ 0x16e: 0x5f005, // defer
+ 0x171: 0x50a0a, // onmouseout
+ 0x172: 0x20504, // slot
+ 0x175: 0x3704, // nobr
+ 0x177: 0x1d707, // command
+ 0x17a: 0x7207, // details
+ 0x17b: 0x38104, // menu
+ 0x17c: 0xb903, // kbd
+ 0x17d: 0x57304, // step
+ 0x17e: 0x20303, // ins
+ 0x17f: 0x13c08, // autoplay
+ 0x182: 0x34103, // min
+ 0x183: 0x17404, // link
+ 0x185: 0x40d10, // ondurationchange
+ 0x186: 0x9202, // td
+ 0x187: 0x8b05, // frame
+ 0x18a: 0x2ab08, // datetime
+ 0x18b: 0x44509, // inputmode
+ 0x18c: 0x35108, // readonly
+ 0x18d: 0x21104, // face
+ 0x18f: 0x5e505, // sizes
+ 0x191: 0x4b208, // tabindex
+ 0x192: 0x6db06, // strong
+ 0x193: 0xba03, // bdi
+ 0x194: 0x6fe06, // srcset
+ 0x196: 0x67202, // ms
+ 0x197: 0x5b507, // checked
+ 0x198: 0xb105, // align
+ 0x199: 0x1e507, // section
+ 0x19b: 0x6e05, // embed
+ 0x19d: 0x15e07, // bgsound
+ 0x1a2: 0x49d04, // list
+ 0x1a3: 0x61e08, // onseeked
+ 0x1a4: 0x66009, // onstorage
+ 0x1a5: 0x2f603, // img
+ 0x1a6: 0xf505, // tfoot
+ 0x1a9: 0x26913, // onautocompleteerror
+ 0x1aa: 0x5fd19, // onsecuritypolicyviolation
+ 0x1ad: 0x9303, // dir
+ 0x1ae: 0x9307, // dirname
+ 0x1b0: 0x5a70a, // onprogress
+ 0x1b2: 0x65709, // onstalled
+ 0x1b5: 0x66f09, // itemscope
+ 0x1b6: 0x49904, // data
+ 0x1b7: 0x3d90b, // ondragleave
+ 0x1b8: 0x56102, // h2
+ 0x1b9: 0x2f706, // mglyph
+ 0x1ba: 0x16502, // is
+ 0x1bb: 0x6e50e, // onbeforeunload
+ 0x1bc: 0x2830d, // typemustmatch
+ 0x1bd: 0x3ab06, // ondrag
+ 0x1be: 0x5da07, // onreset
+ 0x1c0: 0x51106, // output
+ 0x1c1: 0x12907, // sandbox
+ 0x1c2: 0x1b209, // plaintext
+ 0x1c4: 0x34c08, // textarea
+ 0x1c7: 0xd607, // keytype
+ 0x1c8: 0x34b05, // mtext
+ 0x1c9: 0x6b10e, // onvolumechange
+ 0x1ca: 0x1ea06, // onblur
+ 0x1cb: 0x58a07, // onpause
+ 0x1cd: 0x5bc0c, // onratechange
+ 0x1ce: 0x10705, // aside
+ 0x1cf: 0x6cf07, // optimum
+ 0x1d1: 0x45809, // onkeydown
+ 0x1d2: 0x1c407, // colspan
+ 0x1d3: 0x1004, // main
+ 0x1d4: 0x66b03, // sub
+ 0x1d5: 0x25b06, // object
+ 0x1d6: 0x55c06, // search
+ 0x1d7: 0x37206, // sorted
+ 0x1d8: 0x17003, // big
+ 0x1d9: 0xb01, // u
+ 0x1db: 0x26b0c, // autocomplete
+ 0x1dc: 0xcc02, // tr
+ 0x1dd: 0xf303, // alt
+ 0x1df: 0x7804, // samp
+ 0x1e0: 0x5c812, // onrejectionhandled
+ 0x1e1: 0x4f30c, // onmouseleave
+ 0x1e2: 0x28007, // enctype
+ 0x1e3: 0xa208, // nomodule
+ 0x1e5: 0x3280f, // allowfullscreen
+ 0x1e6: 0x5f08, // optgroup
+ 0x1e8: 0x27c0b, // formenctype
+ 0x1e9: 0x18106, // legend
+ 0x1ea: 0x10306, // canvas
+ 0x1eb: 0x6607, // pattern
+ 0x1ec: 0x2c208, // noscript
+ 0x1ed: 0x601, // i
+ 0x1ee: 0x5d602, // dl
+ 0x1ef: 0xa702, // ul
+ 0x1f2: 0x52209, // onmouseup
+ 0x1f4: 0x1ba05, // track
+ 0x1f7: 0x3a10a, // ondblclick
+ 0x1f8: 0x3bf0a, // ondragexit
+ 0x1fa: 0x8703, // dfn
+ 0x1fc: 0x26506, // action
+ 0x1fd: 0x35004, // area
+ 0x1fe: 0x31607, // marquee
+ 0x1ff: 0x16d03, // var
+}
+
+const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" +
+ "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" +
+ "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" +
+ "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" +
+ "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" +
+ "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" +
+ "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" +
+ "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" +
+ "ntrolsectionblurcoordshapecrossoriginslotranslatefacenterfie" +
+ "ldsetfigcaptionafterprintegrityfigurequiredforeignObjectfore" +
+ "ignobjectformactionautocompleteerrorformenctypemustmatchalle" +
+ "ngeformmethodformnovalidatetimeformtargethiddenoscripthigh3h" +
+ "reflanghttp-equivideonclickiframeimageimglyph4isindexismappl" +
+ "etitemtypemarqueematheadersmallowfullscreenmaxlength5minleng" +
+ "th6mtextareadonlymultiplemutedoncloseamlessortedoncontextmen" +
+ "uitemidoncopyoncuechangeoncutondblclickondragendondragentero" +
+ "ndragexitemreferrerpolicyondragleaveondragoverondragstarticl" +
+ "eondropzonemptiedondurationchangeonendedonerroronfocusourceo" +
+ "nhashchangeoninputmodeloninvalidonkeydownloadonkeypresspacer" +
+ "onkeyupreloadonlanguagechangeonloadeddatalistingonloadedmeta" +
+ "databindexonloadendonloadstartonmessageerroronmousedownonmou" +
+ "seenteronmouseleaveonmousemoveonmouseoutputonmouseoveronmous" +
+ "eupromptonmousewheelonofflineononlineonpagehidesclassearch2o" +
+ "npageshowbronpastepublicontenteditableonpausemaponplayingonp" +
+ "opstateonprogresspellcheckedonratechangeonrejectionhandledon" +
+ "resetonresizesrcdocodeferonscrollonsecuritypolicyviolationau" +
+ "xclickonseekedonseekingonselectedonshowidthgrouposteronsorta" +
+ "bleonstalledonstorageonsubmitemscopedonsuspendontoggleonunha" +
+ "ndledrejectionbeforeprintonunloadonvolumechangeonwaitingonwh" +
+ "eeloptimumanifestrongoptionbeforeunloaddressrclangsrcsetstyl" +
+ "esummarysupsvgsystemplateworkertypewrap"
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go
new file mode 100644
index 000000000000..13bed1599f71
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go
@@ -0,0 +1,257 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package charset provides common text encodings for HTML documents.
+//
+// The mapping from encoding labels to encodings is defined at
+// https://encoding.spec.whatwg.org/.
+package charset // import "golang.org/x/net/html/charset"
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "mime"
+ "strings"
+ "unicode/utf8"
+
+ "golang.org/x/net/html"
+ "golang.org/x/text/encoding"
+ "golang.org/x/text/encoding/charmap"
+ "golang.org/x/text/encoding/htmlindex"
+ "golang.org/x/text/transform"
+)
+
+// Lookup returns the encoding with the specified label, and its canonical
+// name. It returns nil and the empty string if label is not one of the
+// standard encodings for HTML. Matching is case-insensitive and ignores
+// leading and trailing whitespace. Encoders will use HTML escape sequences for
+// runes that are not supported by the character set.
+func Lookup(label string) (e encoding.Encoding, name string) {
+ e, err := htmlindex.Get(label)
+ if err != nil {
+ return nil, ""
+ }
+ name, _ = htmlindex.Name(e)
+ return &htmlEncoding{e}, name
+}
+
+type htmlEncoding struct{ encoding.Encoding }
+
+func (h *htmlEncoding) NewEncoder() *encoding.Encoder {
+ // HTML requires a non-terminating legacy encoder. We use HTML escapes to
+ // substitute unsupported code points.
+ return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder())
+}
+
+// DetermineEncoding determines the encoding of an HTML document by examining
+// up to the first 1024 bytes of content and the declared Content-Type.
+//
+// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
+func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) {
+ if len(content) > 1024 {
+ content = content[:1024]
+ }
+
+ for _, b := range boms {
+ if bytes.HasPrefix(content, b.bom) {
+ e, name = Lookup(b.enc)
+ return e, name, true
+ }
+ }
+
+ if _, params, err := mime.ParseMediaType(contentType); err == nil {
+ if cs, ok := params["charset"]; ok {
+ if e, name = Lookup(cs); e != nil {
+ return e, name, true
+ }
+ }
+ }
+
+ if len(content) > 0 {
+ e, name = prescan(content)
+ if e != nil {
+ return e, name, false
+ }
+ }
+
+ // Try to detect UTF-8.
+ // First eliminate any partial rune at the end.
+ for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- {
+ b := content[i]
+ if b < 0x80 {
+ break
+ }
+ if utf8.RuneStart(b) {
+ content = content[:i]
+ break
+ }
+ }
+ hasHighBit := false
+ for _, c := range content {
+ if c >= 0x80 {
+ hasHighBit = true
+ break
+ }
+ }
+ if hasHighBit && utf8.Valid(content) {
+ return encoding.Nop, "utf-8", false
+ }
+
+ // TODO: change default depending on user's locale?
+ return charmap.Windows1252, "windows-1252", false
+}
+
+// NewReader returns an io.Reader that converts the content of r to UTF-8.
+// It calls DetermineEncoding to find out what r's encoding is.
+func NewReader(r io.Reader, contentType string) (io.Reader, error) {
+ preview := make([]byte, 1024)
+ n, err := io.ReadFull(r, preview)
+ switch {
+ case err == io.ErrUnexpectedEOF:
+ preview = preview[:n]
+ r = bytes.NewReader(preview)
+ case err != nil:
+ return nil, err
+ default:
+ r = io.MultiReader(bytes.NewReader(preview), r)
+ }
+
+ if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop {
+ r = transform.NewReader(r, e.NewDecoder())
+ }
+ return r, nil
+}
+
+// NewReaderLabel returns a reader that converts from the specified charset to
+// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
+// returns an error if Lookup returns nil. It is suitable for use as
+// encoding/xml.Decoder's CharsetReader function.
+func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
+ e, _ := Lookup(label)
+ if e == nil {
+ return nil, fmt.Errorf("unsupported charset: %q", label)
+ }
+ return transform.NewReader(input, e.NewDecoder()), nil
+}
+
+func prescan(content []byte) (e encoding.Encoding, name string) {
+ z := html.NewTokenizer(bytes.NewReader(content))
+ for {
+ switch z.Next() {
+ case html.ErrorToken:
+ return nil, ""
+
+ case html.StartTagToken, html.SelfClosingTagToken:
+ tagName, hasAttr := z.TagName()
+ if !bytes.Equal(tagName, []byte("meta")) {
+ continue
+ }
+ attrList := make(map[string]bool)
+ gotPragma := false
+
+ const (
+ dontKnow = iota
+ doNeedPragma
+ doNotNeedPragma
+ )
+ needPragma := dontKnow
+
+ name = ""
+ e = nil
+ for hasAttr {
+ var key, val []byte
+ key, val, hasAttr = z.TagAttr()
+ ks := string(key)
+ if attrList[ks] {
+ continue
+ }
+ attrList[ks] = true
+ for i, c := range val {
+ if 'A' <= c && c <= 'Z' {
+ val[i] = c + 0x20
+ }
+ }
+
+ switch ks {
+ case "http-equiv":
+ if bytes.Equal(val, []byte("content-type")) {
+ gotPragma = true
+ }
+
+ case "content":
+ if e == nil {
+ name = fromMetaElement(string(val))
+ if name != "" {
+ e, name = Lookup(name)
+ if e != nil {
+ needPragma = doNeedPragma
+ }
+ }
+ }
+
+ case "charset":
+ e, name = Lookup(string(val))
+ needPragma = doNotNeedPragma
+ }
+ }
+
+ if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma {
+ continue
+ }
+
+ if strings.HasPrefix(name, "utf-16") {
+ name = "utf-8"
+ e = encoding.Nop
+ }
+
+ if e != nil {
+ return e, name
+ }
+ }
+ }
+}
+
+func fromMetaElement(s string) string {
+ for s != "" {
+ csLoc := strings.Index(s, "charset")
+ if csLoc == -1 {
+ return ""
+ }
+ s = s[csLoc+len("charset"):]
+ s = strings.TrimLeft(s, " \t\n\f\r")
+ if !strings.HasPrefix(s, "=") {
+ continue
+ }
+ s = s[1:]
+ s = strings.TrimLeft(s, " \t\n\f\r")
+ if s == "" {
+ return ""
+ }
+ if q := s[0]; q == '"' || q == '\'' {
+ s = s[1:]
+ closeQuote := strings.IndexRune(s, rune(q))
+ if closeQuote == -1 {
+ return ""
+ }
+ return s[:closeQuote]
+ }
+
+ end := strings.IndexAny(s, "; \t\n\f\r")
+ if end == -1 {
+ end = len(s)
+ }
+ return s[:end]
+ }
+ return ""
+}
+
+var boms = []struct {
+ bom []byte
+ enc string
+}{
+ {[]byte{0xfe, 0xff}, "utf-16be"},
+ {[]byte{0xff, 0xfe}, "utf-16le"},
+ {[]byte{0xef, 0xbb, 0xbf}, "utf-8"},
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go
new file mode 100644
index 000000000000..ff7acf2d5b4b
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go
@@ -0,0 +1,111 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// Section 12.2.4.2 of the HTML5 specification says "The following elements
+// have varying levels of special parsing rules".
+// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
+var isSpecialElementMap = map[string]bool{
+ "address": true,
+ "applet": true,
+ "area": true,
+ "article": true,
+ "aside": true,
+ "base": true,
+ "basefont": true,
+ "bgsound": true,
+ "blockquote": true,
+ "body": true,
+ "br": true,
+ "button": true,
+ "caption": true,
+ "center": true,
+ "col": true,
+ "colgroup": true,
+ "dd": true,
+ "details": true,
+ "dir": true,
+ "div": true,
+ "dl": true,
+ "dt": true,
+ "embed": true,
+ "fieldset": true,
+ "figcaption": true,
+ "figure": true,
+ "footer": true,
+ "form": true,
+ "frame": true,
+ "frameset": true,
+ "h1": true,
+ "h2": true,
+ "h3": true,
+ "h4": true,
+ "h5": true,
+ "h6": true,
+ "head": true,
+ "header": true,
+ "hgroup": true,
+ "hr": true,
+ "html": true,
+ "iframe": true,
+ "img": true,
+ "input": true,
+ "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
+ "li": true,
+ "link": true,
+ "listing": true,
+ "main": true,
+ "marquee": true,
+ "menu": true,
+ "meta": true,
+ "nav": true,
+ "noembed": true,
+ "noframes": true,
+ "noscript": true,
+ "object": true,
+ "ol": true,
+ "p": true,
+ "param": true,
+ "plaintext": true,
+ "pre": true,
+ "script": true,
+ "section": true,
+ "select": true,
+ "source": true,
+ "style": true,
+ "summary": true,
+ "table": true,
+ "tbody": true,
+ "td": true,
+ "template": true,
+ "textarea": true,
+ "tfoot": true,
+ "th": true,
+ "thead": true,
+ "title": true,
+ "tr": true,
+ "track": true,
+ "ul": true,
+ "wbr": true,
+ "xmp": true,
+}
+
+func isSpecialElement(element *Node) bool {
+ switch element.Namespace {
+ case "", "html":
+ return isSpecialElementMap[element.Data]
+ case "math":
+ switch element.Data {
+ case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
+ return true
+ }
+ case "svg":
+ switch element.Data {
+ case "foreignObject", "desc", "title":
+ return true
+ }
+ }
+ return false
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go
new file mode 100644
index 000000000000..885c4c5936b1
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package html implements an HTML5-compliant tokenizer and parser.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+ z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ // ...
+ return ...
+ }
+ // Process the current token.
+ }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+ Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "<") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+ for {
+ if z.Next() == html.ErrorToken {
+ // Returning io.EOF indicates success.
+ return z.Err()
+ }
+ emitToken(z.Token())
+ }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+ depth := 0
+ for {
+ tt := z.Next()
+ switch tt {
+ case html.ErrorToken:
+ return z.Err()
+ case html.TextToken:
+ if depth > 0 {
+ // emitBytes should copy the []byte it receives,
+ // if it doesn't process it immediately.
+ emitBytes(z.Text())
+ }
+ case html.StartTagToken, html.EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == html.StartTagToken {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+
+Parsing is done by calling Parse with an io.Reader, which returns the root of
+the parse tree (the document element) as a *Node. It is the caller's
+responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
+example, to process each anchor node in depth-first order:
+
+ doc, err := html.Parse(r)
+ if err != nil {
+ // ...
+ }
+ for n := range doc.Descendants() {
+ if n.Type == html.ElementNode && n.Data == "a" {
+ // Do something with n...
+ }
+ }
+
+The relevant specifications include:
+https://html.spec.whatwg.org/multipage/syntax.html and
+https://html.spec.whatwg.org/multipage/syntax.html#tokenization
+
+# Security Considerations
+
+Care should be taken when parsing and interpreting HTML, whether full documents
+or fragments, within the framework of the HTML specification, especially with
+regard to untrusted inputs.
+
+This package provides both a tokenizer and a parser, which implement the
+tokenization, and tokenization and tree construction stages of the WHATWG HTML
+parsing specification respectively. While the tokenizer parses and normalizes
+individual HTML tokens, only the parser constructs the DOM tree from the
+tokenized HTML, as described in the tree construction stage of the
+specification, dynamically modifying or extending the document's DOM tree.
+
+If your use case requires semantically well-formed HTML documents, as defined by
+the WHATWG specification, the parser should be used rather than the tokenizer.
+
+In security contexts, if trust decisions are being made using the tokenized or
+parsed content, the input must be re-serialized (for instance by using Render or
+Token.String) in order for those trust decisions to hold, as the process of
+tokenization or parsing may alter the content.
+*/
+package html // import "golang.org/x/net/html"
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go
new file mode 100644
index 000000000000..bca3ae9a0c22
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go
@@ -0,0 +1,156 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "strings"
+)
+
+// parseDoctype parses the data from a DoctypeToken into a name,
+// public identifier, and system identifier. It returns a Node whose Type
+// is DoctypeNode, whose Data is the name, and which has attributes
+// named "system" and "public" for the two identifiers if they were present.
+// quirks is whether the document should be parsed in "quirks mode".
+func parseDoctype(s string) (n *Node, quirks bool) {
+ n = &Node{Type: DoctypeNode}
+
+ // Find the name.
+ space := strings.IndexAny(s, whitespace)
+ if space == -1 {
+ space = len(s)
+ }
+ n.Data = s[:space]
+ // The comparison to "html" is case-sensitive.
+ if n.Data != "html" {
+ quirks = true
+ }
+ n.Data = strings.ToLower(n.Data)
+ s = strings.TrimLeft(s[space:], whitespace)
+
+ if len(s) < 6 {
+ // It can't start with "PUBLIC" or "SYSTEM".
+ // Ignore the rest of the string.
+ return n, quirks || s != ""
+ }
+
+ key := strings.ToLower(s[:6])
+ s = s[6:]
+ for key == "public" || key == "system" {
+ s = strings.TrimLeft(s, whitespace)
+ if s == "" {
+ break
+ }
+ quote := s[0]
+ if quote != '"' && quote != '\'' {
+ break
+ }
+ s = s[1:]
+ q := strings.IndexRune(s, rune(quote))
+ var id string
+ if q == -1 {
+ id = s
+ s = ""
+ } else {
+ id = s[:q]
+ s = s[q+1:]
+ }
+ n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
+ if key == "public" {
+ key = "system"
+ } else {
+ key = ""
+ }
+ }
+
+ if key != "" || s != "" {
+ quirks = true
+ } else if len(n.Attr) > 0 {
+ if n.Attr[0].Key == "public" {
+ public := strings.ToLower(n.Attr[0].Val)
+ switch public {
+ case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
+ quirks = true
+ default:
+ for _, q := range quirkyIDs {
+ if strings.HasPrefix(public, q) {
+ quirks = true
+ break
+ }
+ }
+ }
+ // The following two public IDs only cause quirks mode if there is no system ID.
+ if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
+ strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
+ quirks = true
+ }
+ }
+ if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
+ strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
+ quirks = true
+ }
+ }
+
+ return n, quirks
+}
+
+// quirkyIDs is a list of public doctype identifiers that cause a document
+// to be interpreted in quirks mode. The identifiers should be in lower case.
+var quirkyIDs = []string{
+ "+//silmaril//dtd html pro v0r11 19970101//",
+ "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
+ "-//as//dtd html 3.0 aswedit + extensions//",
+ "-//ietf//dtd html 2.0 level 1//",
+ "-//ietf//dtd html 2.0 level 2//",
+ "-//ietf//dtd html 2.0 strict level 1//",
+ "-//ietf//dtd html 2.0 strict level 2//",
+ "-//ietf//dtd html 2.0 strict//",
+ "-//ietf//dtd html 2.0//",
+ "-//ietf//dtd html 2.1e//",
+ "-//ietf//dtd html 3.0//",
+ "-//ietf//dtd html 3.2 final//",
+ "-//ietf//dtd html 3.2//",
+ "-//ietf//dtd html 3//",
+ "-//ietf//dtd html level 0//",
+ "-//ietf//dtd html level 1//",
+ "-//ietf//dtd html level 2//",
+ "-//ietf//dtd html level 3//",
+ "-//ietf//dtd html strict level 0//",
+ "-//ietf//dtd html strict level 1//",
+ "-//ietf//dtd html strict level 2//",
+ "-//ietf//dtd html strict level 3//",
+ "-//ietf//dtd html strict//",
+ "-//ietf//dtd html//",
+ "-//metrius//dtd metrius presentational//",
+ "-//microsoft//dtd internet explorer 2.0 html strict//",
+ "-//microsoft//dtd internet explorer 2.0 html//",
+ "-//microsoft//dtd internet explorer 2.0 tables//",
+ "-//microsoft//dtd internet explorer 3.0 html strict//",
+ "-//microsoft//dtd internet explorer 3.0 html//",
+ "-//microsoft//dtd internet explorer 3.0 tables//",
+ "-//netscape comm. corp.//dtd html//",
+ "-//netscape comm. corp.//dtd strict html//",
+ "-//o'reilly and associates//dtd html 2.0//",
+ "-//o'reilly and associates//dtd html extended 1.0//",
+ "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+ "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
+ "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
+ "-//spyglass//dtd html 2.0 extended//",
+ "-//sq//dtd html 2.0 hotmetal + extensions//",
+ "-//sun microsystems corp.//dtd hotjava html//",
+ "-//sun microsystems corp.//dtd hotjava strict html//",
+ "-//w3c//dtd html 3 1995-03-24//",
+ "-//w3c//dtd html 3.2 draft//",
+ "-//w3c//dtd html 3.2 final//",
+ "-//w3c//dtd html 3.2//",
+ "-//w3c//dtd html 3.2s draft//",
+ "-//w3c//dtd html 4.0 frameset//",
+ "-//w3c//dtd html 4.0 transitional//",
+ "-//w3c//dtd html experimental 19960712//",
+ "-//w3c//dtd html experimental 970421//",
+ "-//w3c//dtd w3 html//",
+ "-//w3o//dtd w3 html 3.0//",
+ "-//webtechs//dtd mozilla html 2.0//",
+ "-//webtechs//dtd mozilla html//",
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go
new file mode 100644
index 000000000000..b628880a014d
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go
@@ -0,0 +1,2253 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// All entities that do not end with ';' are 6 or fewer bytes long.
+const longestEntityWithoutSemicolon = 6
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references
+// lists both "amp" and "amp;" as two separate entries.
+//
+// Note that the HTML5 list is larger than the HTML4 list at
+// http://www.w3.org/TR/html4/sgml/entities.html
+var entity = map[string]rune{
+ "AElig;": '\U000000C6',
+ "AMP;": '\U00000026',
+ "Aacute;": '\U000000C1',
+ "Abreve;": '\U00000102',
+ "Acirc;": '\U000000C2',
+ "Acy;": '\U00000410',
+ "Afr;": '\U0001D504',
+ "Agrave;": '\U000000C0',
+ "Alpha;": '\U00000391',
+ "Amacr;": '\U00000100',
+ "And;": '\U00002A53',
+ "Aogon;": '\U00000104',
+ "Aopf;": '\U0001D538',
+ "ApplyFunction;": '\U00002061',
+ "Aring;": '\U000000C5',
+ "Ascr;": '\U0001D49C',
+ "Assign;": '\U00002254',
+ "Atilde;": '\U000000C3',
+ "Auml;": '\U000000C4',
+ "Backslash;": '\U00002216',
+ "Barv;": '\U00002AE7',
+ "Barwed;": '\U00002306',
+ "Bcy;": '\U00000411',
+ "Because;": '\U00002235',
+ "Bernoullis;": '\U0000212C',
+ "Beta;": '\U00000392',
+ "Bfr;": '\U0001D505',
+ "Bopf;": '\U0001D539',
+ "Breve;": '\U000002D8',
+ "Bscr;": '\U0000212C',
+ "Bumpeq;": '\U0000224E',
+ "CHcy;": '\U00000427',
+ "COPY;": '\U000000A9',
+ "Cacute;": '\U00000106',
+ "Cap;": '\U000022D2',
+ "CapitalDifferentialD;": '\U00002145',
+ "Cayleys;": '\U0000212D',
+ "Ccaron;": '\U0000010C',
+ "Ccedil;": '\U000000C7',
+ "Ccirc;": '\U00000108',
+ "Cconint;": '\U00002230',
+ "Cdot;": '\U0000010A',
+ "Cedilla;": '\U000000B8',
+ "CenterDot;": '\U000000B7',
+ "Cfr;": '\U0000212D',
+ "Chi;": '\U000003A7',
+ "CircleDot;": '\U00002299',
+ "CircleMinus;": '\U00002296',
+ "CirclePlus;": '\U00002295',
+ "CircleTimes;": '\U00002297',
+ "ClockwiseContourIntegral;": '\U00002232',
+ "CloseCurlyDoubleQuote;": '\U0000201D',
+ "CloseCurlyQuote;": '\U00002019',
+ "Colon;": '\U00002237',
+ "Colone;": '\U00002A74',
+ "Congruent;": '\U00002261',
+ "Conint;": '\U0000222F',
+ "ContourIntegral;": '\U0000222E',
+ "Copf;": '\U00002102',
+ "Coproduct;": '\U00002210',
+ "CounterClockwiseContourIntegral;": '\U00002233',
+ "Cross;": '\U00002A2F',
+ "Cscr;": '\U0001D49E',
+ "Cup;": '\U000022D3',
+ "CupCap;": '\U0000224D',
+ "DD;": '\U00002145',
+ "DDotrahd;": '\U00002911',
+ "DJcy;": '\U00000402',
+ "DScy;": '\U00000405',
+ "DZcy;": '\U0000040F',
+ "Dagger;": '\U00002021',
+ "Darr;": '\U000021A1',
+ "Dashv;": '\U00002AE4',
+ "Dcaron;": '\U0000010E',
+ "Dcy;": '\U00000414',
+ "Del;": '\U00002207',
+ "Delta;": '\U00000394',
+ "Dfr;": '\U0001D507',
+ "DiacriticalAcute;": '\U000000B4',
+ "DiacriticalDot;": '\U000002D9',
+ "DiacriticalDoubleAcute;": '\U000002DD',
+ "DiacriticalGrave;": '\U00000060',
+ "DiacriticalTilde;": '\U000002DC',
+ "Diamond;": '\U000022C4',
+ "DifferentialD;": '\U00002146',
+ "Dopf;": '\U0001D53B',
+ "Dot;": '\U000000A8',
+ "DotDot;": '\U000020DC',
+ "DotEqual;": '\U00002250',
+ "DoubleContourIntegral;": '\U0000222F',
+ "DoubleDot;": '\U000000A8',
+ "DoubleDownArrow;": '\U000021D3',
+ "DoubleLeftArrow;": '\U000021D0',
+ "DoubleLeftRightArrow;": '\U000021D4',
+ "DoubleLeftTee;": '\U00002AE4',
+ "DoubleLongLeftArrow;": '\U000027F8',
+ "DoubleLongLeftRightArrow;": '\U000027FA',
+ "DoubleLongRightArrow;": '\U000027F9',
+ "DoubleRightArrow;": '\U000021D2',
+ "DoubleRightTee;": '\U000022A8',
+ "DoubleUpArrow;": '\U000021D1',
+ "DoubleUpDownArrow;": '\U000021D5',
+ "DoubleVerticalBar;": '\U00002225',
+ "DownArrow;": '\U00002193',
+ "DownArrowBar;": '\U00002913',
+ "DownArrowUpArrow;": '\U000021F5',
+ "DownBreve;": '\U00000311',
+ "DownLeftRightVector;": '\U00002950',
+ "DownLeftTeeVector;": '\U0000295E',
+ "DownLeftVector;": '\U000021BD',
+ "DownLeftVectorBar;": '\U00002956',
+ "DownRightTeeVector;": '\U0000295F',
+ "DownRightVector;": '\U000021C1',
+ "DownRightVectorBar;": '\U00002957',
+ "DownTee;": '\U000022A4',
+ "DownTeeArrow;": '\U000021A7',
+ "Downarrow;": '\U000021D3',
+ "Dscr;": '\U0001D49F',
+ "Dstrok;": '\U00000110',
+ "ENG;": '\U0000014A',
+ "ETH;": '\U000000D0',
+ "Eacute;": '\U000000C9',
+ "Ecaron;": '\U0000011A',
+ "Ecirc;": '\U000000CA',
+ "Ecy;": '\U0000042D',
+ "Edot;": '\U00000116',
+ "Efr;": '\U0001D508',
+ "Egrave;": '\U000000C8',
+ "Element;": '\U00002208',
+ "Emacr;": '\U00000112',
+ "EmptySmallSquare;": '\U000025FB',
+ "EmptyVerySmallSquare;": '\U000025AB',
+ "Eogon;": '\U00000118',
+ "Eopf;": '\U0001D53C',
+ "Epsilon;": '\U00000395',
+ "Equal;": '\U00002A75',
+ "EqualTilde;": '\U00002242',
+ "Equilibrium;": '\U000021CC',
+ "Escr;": '\U00002130',
+ "Esim;": '\U00002A73',
+ "Eta;": '\U00000397',
+ "Euml;": '\U000000CB',
+ "Exists;": '\U00002203',
+ "ExponentialE;": '\U00002147',
+ "Fcy;": '\U00000424',
+ "Ffr;": '\U0001D509',
+ "FilledSmallSquare;": '\U000025FC',
+ "FilledVerySmallSquare;": '\U000025AA',
+ "Fopf;": '\U0001D53D',
+ "ForAll;": '\U00002200',
+ "Fouriertrf;": '\U00002131',
+ "Fscr;": '\U00002131',
+ "GJcy;": '\U00000403',
+ "GT;": '\U0000003E',
+ "Gamma;": '\U00000393',
+ "Gammad;": '\U000003DC',
+ "Gbreve;": '\U0000011E',
+ "Gcedil;": '\U00000122',
+ "Gcirc;": '\U0000011C',
+ "Gcy;": '\U00000413',
+ "Gdot;": '\U00000120',
+ "Gfr;": '\U0001D50A',
+ "Gg;": '\U000022D9',
+ "Gopf;": '\U0001D53E',
+ "GreaterEqual;": '\U00002265',
+ "GreaterEqualLess;": '\U000022DB',
+ "GreaterFullEqual;": '\U00002267',
+ "GreaterGreater;": '\U00002AA2',
+ "GreaterLess;": '\U00002277',
+ "GreaterSlantEqual;": '\U00002A7E',
+ "GreaterTilde;": '\U00002273',
+ "Gscr;": '\U0001D4A2',
+ "Gt;": '\U0000226B',
+ "HARDcy;": '\U0000042A',
+ "Hacek;": '\U000002C7',
+ "Hat;": '\U0000005E',
+ "Hcirc;": '\U00000124',
+ "Hfr;": '\U0000210C',
+ "HilbertSpace;": '\U0000210B',
+ "Hopf;": '\U0000210D',
+ "HorizontalLine;": '\U00002500',
+ "Hscr;": '\U0000210B',
+ "Hstrok;": '\U00000126',
+ "HumpDownHump;": '\U0000224E',
+ "HumpEqual;": '\U0000224F',
+ "IEcy;": '\U00000415',
+ "IJlig;": '\U00000132',
+ "IOcy;": '\U00000401',
+ "Iacute;": '\U000000CD',
+ "Icirc;": '\U000000CE',
+ "Icy;": '\U00000418',
+ "Idot;": '\U00000130',
+ "Ifr;": '\U00002111',
+ "Igrave;": '\U000000CC',
+ "Im;": '\U00002111',
+ "Imacr;": '\U0000012A',
+ "ImaginaryI;": '\U00002148',
+ "Implies;": '\U000021D2',
+ "Int;": '\U0000222C',
+ "Integral;": '\U0000222B',
+ "Intersection;": '\U000022C2',
+ "InvisibleComma;": '\U00002063',
+ "InvisibleTimes;": '\U00002062',
+ "Iogon;": '\U0000012E',
+ "Iopf;": '\U0001D540',
+ "Iota;": '\U00000399',
+ "Iscr;": '\U00002110',
+ "Itilde;": '\U00000128',
+ "Iukcy;": '\U00000406',
+ "Iuml;": '\U000000CF',
+ "Jcirc;": '\U00000134',
+ "Jcy;": '\U00000419',
+ "Jfr;": '\U0001D50D',
+ "Jopf;": '\U0001D541',
+ "Jscr;": '\U0001D4A5',
+ "Jsercy;": '\U00000408',
+ "Jukcy;": '\U00000404',
+ "KHcy;": '\U00000425',
+ "KJcy;": '\U0000040C',
+ "Kappa;": '\U0000039A',
+ "Kcedil;": '\U00000136',
+ "Kcy;": '\U0000041A',
+ "Kfr;": '\U0001D50E',
+ "Kopf;": '\U0001D542',
+ "Kscr;": '\U0001D4A6',
+ "LJcy;": '\U00000409',
+ "LT;": '\U0000003C',
+ "Lacute;": '\U00000139',
+ "Lambda;": '\U0000039B',
+ "Lang;": '\U000027EA',
+ "Laplacetrf;": '\U00002112',
+ "Larr;": '\U0000219E',
+ "Lcaron;": '\U0000013D',
+ "Lcedil;": '\U0000013B',
+ "Lcy;": '\U0000041B',
+ "LeftAngleBracket;": '\U000027E8',
+ "LeftArrow;": '\U00002190',
+ "LeftArrowBar;": '\U000021E4',
+ "LeftArrowRightArrow;": '\U000021C6',
+ "LeftCeiling;": '\U00002308',
+ "LeftDoubleBracket;": '\U000027E6',
+ "LeftDownTeeVector;": '\U00002961',
+ "LeftDownVector;": '\U000021C3',
+ "LeftDownVectorBar;": '\U00002959',
+ "LeftFloor;": '\U0000230A',
+ "LeftRightArrow;": '\U00002194',
+ "LeftRightVector;": '\U0000294E',
+ "LeftTee;": '\U000022A3',
+ "LeftTeeArrow;": '\U000021A4',
+ "LeftTeeVector;": '\U0000295A',
+ "LeftTriangle;": '\U000022B2',
+ "LeftTriangleBar;": '\U000029CF',
+ "LeftTriangleEqual;": '\U000022B4',
+ "LeftUpDownVector;": '\U00002951',
+ "LeftUpTeeVector;": '\U00002960',
+ "LeftUpVector;": '\U000021BF',
+ "LeftUpVectorBar;": '\U00002958',
+ "LeftVector;": '\U000021BC',
+ "LeftVectorBar;": '\U00002952',
+ "Leftarrow;": '\U000021D0',
+ "Leftrightarrow;": '\U000021D4',
+ "LessEqualGreater;": '\U000022DA',
+ "LessFullEqual;": '\U00002266',
+ "LessGreater;": '\U00002276',
+ "LessLess;": '\U00002AA1',
+ "LessSlantEqual;": '\U00002A7D',
+ "LessTilde;": '\U00002272',
+ "Lfr;": '\U0001D50F',
+ "Ll;": '\U000022D8',
+ "Lleftarrow;": '\U000021DA',
+ "Lmidot;": '\U0000013F',
+ "LongLeftArrow;": '\U000027F5',
+ "LongLeftRightArrow;": '\U000027F7',
+ "LongRightArrow;": '\U000027F6',
+ "Longleftarrow;": '\U000027F8',
+ "Longleftrightarrow;": '\U000027FA',
+ "Longrightarrow;": '\U000027F9',
+ "Lopf;": '\U0001D543',
+ "LowerLeftArrow;": '\U00002199',
+ "LowerRightArrow;": '\U00002198',
+ "Lscr;": '\U00002112',
+ "Lsh;": '\U000021B0',
+ "Lstrok;": '\U00000141',
+ "Lt;": '\U0000226A',
+ "Map;": '\U00002905',
+ "Mcy;": '\U0000041C',
+ "MediumSpace;": '\U0000205F',
+ "Mellintrf;": '\U00002133',
+ "Mfr;": '\U0001D510',
+ "MinusPlus;": '\U00002213',
+ "Mopf;": '\U0001D544',
+ "Mscr;": '\U00002133',
+ "Mu;": '\U0000039C',
+ "NJcy;": '\U0000040A',
+ "Nacute;": '\U00000143',
+ "Ncaron;": '\U00000147',
+ "Ncedil;": '\U00000145',
+ "Ncy;": '\U0000041D',
+ "NegativeMediumSpace;": '\U0000200B',
+ "NegativeThickSpace;": '\U0000200B',
+ "NegativeThinSpace;": '\U0000200B',
+ "NegativeVeryThinSpace;": '\U0000200B',
+ "NestedGreaterGreater;": '\U0000226B',
+ "NestedLessLess;": '\U0000226A',
+ "NewLine;": '\U0000000A',
+ "Nfr;": '\U0001D511',
+ "NoBreak;": '\U00002060',
+ "NonBreakingSpace;": '\U000000A0',
+ "Nopf;": '\U00002115',
+ "Not;": '\U00002AEC',
+ "NotCongruent;": '\U00002262',
+ "NotCupCap;": '\U0000226D',
+ "NotDoubleVerticalBar;": '\U00002226',
+ "NotElement;": '\U00002209',
+ "NotEqual;": '\U00002260',
+ "NotExists;": '\U00002204',
+ "NotGreater;": '\U0000226F',
+ "NotGreaterEqual;": '\U00002271',
+ "NotGreaterLess;": '\U00002279',
+ "NotGreaterTilde;": '\U00002275',
+ "NotLeftTriangle;": '\U000022EA',
+ "NotLeftTriangleEqual;": '\U000022EC',
+ "NotLess;": '\U0000226E',
+ "NotLessEqual;": '\U00002270',
+ "NotLessGreater;": '\U00002278',
+ "NotLessTilde;": '\U00002274',
+ "NotPrecedes;": '\U00002280',
+ "NotPrecedesSlantEqual;": '\U000022E0',
+ "NotReverseElement;": '\U0000220C',
+ "NotRightTriangle;": '\U000022EB',
+ "NotRightTriangleEqual;": '\U000022ED',
+ "NotSquareSubsetEqual;": '\U000022E2',
+ "NotSquareSupersetEqual;": '\U000022E3',
+ "NotSubsetEqual;": '\U00002288',
+ "NotSucceeds;": '\U00002281',
+ "NotSucceedsSlantEqual;": '\U000022E1',
+ "NotSupersetEqual;": '\U00002289',
+ "NotTilde;": '\U00002241',
+ "NotTildeEqual;": '\U00002244',
+ "NotTildeFullEqual;": '\U00002247',
+ "NotTildeTilde;": '\U00002249',
+ "NotVerticalBar;": '\U00002224',
+ "Nscr;": '\U0001D4A9',
+ "Ntilde;": '\U000000D1',
+ "Nu;": '\U0000039D',
+ "OElig;": '\U00000152',
+ "Oacute;": '\U000000D3',
+ "Ocirc;": '\U000000D4',
+ "Ocy;": '\U0000041E',
+ "Odblac;": '\U00000150',
+ "Ofr;": '\U0001D512',
+ "Ograve;": '\U000000D2',
+ "Omacr;": '\U0000014C',
+ "Omega;": '\U000003A9',
+ "Omicron;": '\U0000039F',
+ "Oopf;": '\U0001D546',
+ "OpenCurlyDoubleQuote;": '\U0000201C',
+ "OpenCurlyQuote;": '\U00002018',
+ "Or;": '\U00002A54',
+ "Oscr;": '\U0001D4AA',
+ "Oslash;": '\U000000D8',
+ "Otilde;": '\U000000D5',
+ "Otimes;": '\U00002A37',
+ "Ouml;": '\U000000D6',
+ "OverBar;": '\U0000203E',
+ "OverBrace;": '\U000023DE',
+ "OverBracket;": '\U000023B4',
+ "OverParenthesis;": '\U000023DC',
+ "PartialD;": '\U00002202',
+ "Pcy;": '\U0000041F',
+ "Pfr;": '\U0001D513',
+ "Phi;": '\U000003A6',
+ "Pi;": '\U000003A0',
+ "PlusMinus;": '\U000000B1',
+ "Poincareplane;": '\U0000210C',
+ "Popf;": '\U00002119',
+ "Pr;": '\U00002ABB',
+ "Precedes;": '\U0000227A',
+ "PrecedesEqual;": '\U00002AAF',
+ "PrecedesSlantEqual;": '\U0000227C',
+ "PrecedesTilde;": '\U0000227E',
+ "Prime;": '\U00002033',
+ "Product;": '\U0000220F',
+ "Proportion;": '\U00002237',
+ "Proportional;": '\U0000221D',
+ "Pscr;": '\U0001D4AB',
+ "Psi;": '\U000003A8',
+ "QUOT;": '\U00000022',
+ "Qfr;": '\U0001D514',
+ "Qopf;": '\U0000211A',
+ "Qscr;": '\U0001D4AC',
+ "RBarr;": '\U00002910',
+ "REG;": '\U000000AE',
+ "Racute;": '\U00000154',
+ "Rang;": '\U000027EB',
+ "Rarr;": '\U000021A0',
+ "Rarrtl;": '\U00002916',
+ "Rcaron;": '\U00000158',
+ "Rcedil;": '\U00000156',
+ "Rcy;": '\U00000420',
+ "Re;": '\U0000211C',
+ "ReverseElement;": '\U0000220B',
+ "ReverseEquilibrium;": '\U000021CB',
+ "ReverseUpEquilibrium;": '\U0000296F',
+ "Rfr;": '\U0000211C',
+ "Rho;": '\U000003A1',
+ "RightAngleBracket;": '\U000027E9',
+ "RightArrow;": '\U00002192',
+ "RightArrowBar;": '\U000021E5',
+ "RightArrowLeftArrow;": '\U000021C4',
+ "RightCeiling;": '\U00002309',
+ "RightDoubleBracket;": '\U000027E7',
+ "RightDownTeeVector;": '\U0000295D',
+ "RightDownVector;": '\U000021C2',
+ "RightDownVectorBar;": '\U00002955',
+ "RightFloor;": '\U0000230B',
+ "RightTee;": '\U000022A2',
+ "RightTeeArrow;": '\U000021A6',
+ "RightTeeVector;": '\U0000295B',
+ "RightTriangle;": '\U000022B3',
+ "RightTriangleBar;": '\U000029D0',
+ "RightTriangleEqual;": '\U000022B5',
+ "RightUpDownVector;": '\U0000294F',
+ "RightUpTeeVector;": '\U0000295C',
+ "RightUpVector;": '\U000021BE',
+ "RightUpVectorBar;": '\U00002954',
+ "RightVector;": '\U000021C0',
+ "RightVectorBar;": '\U00002953',
+ "Rightarrow;": '\U000021D2',
+ "Ropf;": '\U0000211D',
+ "RoundImplies;": '\U00002970',
+ "Rrightarrow;": '\U000021DB',
+ "Rscr;": '\U0000211B',
+ "Rsh;": '\U000021B1',
+ "RuleDelayed;": '\U000029F4',
+ "SHCHcy;": '\U00000429',
+ "SHcy;": '\U00000428',
+ "SOFTcy;": '\U0000042C',
+ "Sacute;": '\U0000015A',
+ "Sc;": '\U00002ABC',
+ "Scaron;": '\U00000160',
+ "Scedil;": '\U0000015E',
+ "Scirc;": '\U0000015C',
+ "Scy;": '\U00000421',
+ "Sfr;": '\U0001D516',
+ "ShortDownArrow;": '\U00002193',
+ "ShortLeftArrow;": '\U00002190',
+ "ShortRightArrow;": '\U00002192',
+ "ShortUpArrow;": '\U00002191',
+ "Sigma;": '\U000003A3',
+ "SmallCircle;": '\U00002218',
+ "Sopf;": '\U0001D54A',
+ "Sqrt;": '\U0000221A',
+ "Square;": '\U000025A1',
+ "SquareIntersection;": '\U00002293',
+ "SquareSubset;": '\U0000228F',
+ "SquareSubsetEqual;": '\U00002291',
+ "SquareSuperset;": '\U00002290',
+ "SquareSupersetEqual;": '\U00002292',
+ "SquareUnion;": '\U00002294',
+ "Sscr;": '\U0001D4AE',
+ "Star;": '\U000022C6',
+ "Sub;": '\U000022D0',
+ "Subset;": '\U000022D0',
+ "SubsetEqual;": '\U00002286',
+ "Succeeds;": '\U0000227B',
+ "SucceedsEqual;": '\U00002AB0',
+ "SucceedsSlantEqual;": '\U0000227D',
+ "SucceedsTilde;": '\U0000227F',
+ "SuchThat;": '\U0000220B',
+ "Sum;": '\U00002211',
+ "Sup;": '\U000022D1',
+ "Superset;": '\U00002283',
+ "SupersetEqual;": '\U00002287',
+ "Supset;": '\U000022D1',
+ "THORN;": '\U000000DE',
+ "TRADE;": '\U00002122',
+ "TSHcy;": '\U0000040B',
+ "TScy;": '\U00000426',
+ "Tab;": '\U00000009',
+ "Tau;": '\U000003A4',
+ "Tcaron;": '\U00000164',
+ "Tcedil;": '\U00000162',
+ "Tcy;": '\U00000422',
+ "Tfr;": '\U0001D517',
+ "Therefore;": '\U00002234',
+ "Theta;": '\U00000398',
+ "ThinSpace;": '\U00002009',
+ "Tilde;": '\U0000223C',
+ "TildeEqual;": '\U00002243',
+ "TildeFullEqual;": '\U00002245',
+ "TildeTilde;": '\U00002248',
+ "Topf;": '\U0001D54B',
+ "TripleDot;": '\U000020DB',
+ "Tscr;": '\U0001D4AF',
+ "Tstrok;": '\U00000166',
+ "Uacute;": '\U000000DA',
+ "Uarr;": '\U0000219F',
+ "Uarrocir;": '\U00002949',
+ "Ubrcy;": '\U0000040E',
+ "Ubreve;": '\U0000016C',
+ "Ucirc;": '\U000000DB',
+ "Ucy;": '\U00000423',
+ "Udblac;": '\U00000170',
+ "Ufr;": '\U0001D518',
+ "Ugrave;": '\U000000D9',
+ "Umacr;": '\U0000016A',
+ "UnderBar;": '\U0000005F',
+ "UnderBrace;": '\U000023DF',
+ "UnderBracket;": '\U000023B5',
+ "UnderParenthesis;": '\U000023DD',
+ "Union;": '\U000022C3',
+ "UnionPlus;": '\U0000228E',
+ "Uogon;": '\U00000172',
+ "Uopf;": '\U0001D54C',
+ "UpArrow;": '\U00002191',
+ "UpArrowBar;": '\U00002912',
+ "UpArrowDownArrow;": '\U000021C5',
+ "UpDownArrow;": '\U00002195',
+ "UpEquilibrium;": '\U0000296E',
+ "UpTee;": '\U000022A5',
+ "UpTeeArrow;": '\U000021A5',
+ "Uparrow;": '\U000021D1',
+ "Updownarrow;": '\U000021D5',
+ "UpperLeftArrow;": '\U00002196',
+ "UpperRightArrow;": '\U00002197',
+ "Upsi;": '\U000003D2',
+ "Upsilon;": '\U000003A5',
+ "Uring;": '\U0000016E',
+ "Uscr;": '\U0001D4B0',
+ "Utilde;": '\U00000168',
+ "Uuml;": '\U000000DC',
+ "VDash;": '\U000022AB',
+ "Vbar;": '\U00002AEB',
+ "Vcy;": '\U00000412',
+ "Vdash;": '\U000022A9',
+ "Vdashl;": '\U00002AE6',
+ "Vee;": '\U000022C1',
+ "Verbar;": '\U00002016',
+ "Vert;": '\U00002016',
+ "VerticalBar;": '\U00002223',
+ "VerticalLine;": '\U0000007C',
+ "VerticalSeparator;": '\U00002758',
+ "VerticalTilde;": '\U00002240',
+ "VeryThinSpace;": '\U0000200A',
+ "Vfr;": '\U0001D519',
+ "Vopf;": '\U0001D54D',
+ "Vscr;": '\U0001D4B1',
+ "Vvdash;": '\U000022AA',
+ "Wcirc;": '\U00000174',
+ "Wedge;": '\U000022C0',
+ "Wfr;": '\U0001D51A',
+ "Wopf;": '\U0001D54E',
+ "Wscr;": '\U0001D4B2',
+ "Xfr;": '\U0001D51B',
+ "Xi;": '\U0000039E',
+ "Xopf;": '\U0001D54F',
+ "Xscr;": '\U0001D4B3',
+ "YAcy;": '\U0000042F',
+ "YIcy;": '\U00000407',
+ "YUcy;": '\U0000042E',
+ "Yacute;": '\U000000DD',
+ "Ycirc;": '\U00000176',
+ "Ycy;": '\U0000042B',
+ "Yfr;": '\U0001D51C',
+ "Yopf;": '\U0001D550',
+ "Yscr;": '\U0001D4B4',
+ "Yuml;": '\U00000178',
+ "ZHcy;": '\U00000416',
+ "Zacute;": '\U00000179',
+ "Zcaron;": '\U0000017D',
+ "Zcy;": '\U00000417',
+ "Zdot;": '\U0000017B',
+ "ZeroWidthSpace;": '\U0000200B',
+ "Zeta;": '\U00000396',
+ "Zfr;": '\U00002128',
+ "Zopf;": '\U00002124',
+ "Zscr;": '\U0001D4B5',
+ "aacute;": '\U000000E1',
+ "abreve;": '\U00000103',
+ "ac;": '\U0000223E',
+ "acd;": '\U0000223F',
+ "acirc;": '\U000000E2',
+ "acute;": '\U000000B4',
+ "acy;": '\U00000430',
+ "aelig;": '\U000000E6',
+ "af;": '\U00002061',
+ "afr;": '\U0001D51E',
+ "agrave;": '\U000000E0',
+ "alefsym;": '\U00002135',
+ "aleph;": '\U00002135',
+ "alpha;": '\U000003B1',
+ "amacr;": '\U00000101',
+ "amalg;": '\U00002A3F',
+ "amp;": '\U00000026',
+ "and;": '\U00002227',
+ "andand;": '\U00002A55',
+ "andd;": '\U00002A5C',
+ "andslope;": '\U00002A58',
+ "andv;": '\U00002A5A',
+ "ang;": '\U00002220',
+ "ange;": '\U000029A4',
+ "angle;": '\U00002220',
+ "angmsd;": '\U00002221',
+ "angmsdaa;": '\U000029A8',
+ "angmsdab;": '\U000029A9',
+ "angmsdac;": '\U000029AA',
+ "angmsdad;": '\U000029AB',
+ "angmsdae;": '\U000029AC',
+ "angmsdaf;": '\U000029AD',
+ "angmsdag;": '\U000029AE',
+ "angmsdah;": '\U000029AF',
+ "angrt;": '\U0000221F',
+ "angrtvb;": '\U000022BE',
+ "angrtvbd;": '\U0000299D',
+ "angsph;": '\U00002222',
+ "angst;": '\U000000C5',
+ "angzarr;": '\U0000237C',
+ "aogon;": '\U00000105',
+ "aopf;": '\U0001D552',
+ "ap;": '\U00002248',
+ "apE;": '\U00002A70',
+ "apacir;": '\U00002A6F',
+ "ape;": '\U0000224A',
+ "apid;": '\U0000224B',
+ "apos;": '\U00000027',
+ "approx;": '\U00002248',
+ "approxeq;": '\U0000224A',
+ "aring;": '\U000000E5',
+ "ascr;": '\U0001D4B6',
+ "ast;": '\U0000002A',
+ "asymp;": '\U00002248',
+ "asympeq;": '\U0000224D',
+ "atilde;": '\U000000E3',
+ "auml;": '\U000000E4',
+ "awconint;": '\U00002233',
+ "awint;": '\U00002A11',
+ "bNot;": '\U00002AED',
+ "backcong;": '\U0000224C',
+ "backepsilon;": '\U000003F6',
+ "backprime;": '\U00002035',
+ "backsim;": '\U0000223D',
+ "backsimeq;": '\U000022CD',
+ "barvee;": '\U000022BD',
+ "barwed;": '\U00002305',
+ "barwedge;": '\U00002305',
+ "bbrk;": '\U000023B5',
+ "bbrktbrk;": '\U000023B6',
+ "bcong;": '\U0000224C',
+ "bcy;": '\U00000431',
+ "bdquo;": '\U0000201E',
+ "becaus;": '\U00002235',
+ "because;": '\U00002235',
+ "bemptyv;": '\U000029B0',
+ "bepsi;": '\U000003F6',
+ "bernou;": '\U0000212C',
+ "beta;": '\U000003B2',
+ "beth;": '\U00002136',
+ "between;": '\U0000226C',
+ "bfr;": '\U0001D51F',
+ "bigcap;": '\U000022C2',
+ "bigcirc;": '\U000025EF',
+ "bigcup;": '\U000022C3',
+ "bigodot;": '\U00002A00',
+ "bigoplus;": '\U00002A01',
+ "bigotimes;": '\U00002A02',
+ "bigsqcup;": '\U00002A06',
+ "bigstar;": '\U00002605',
+ "bigtriangledown;": '\U000025BD',
+ "bigtriangleup;": '\U000025B3',
+ "biguplus;": '\U00002A04',
+ "bigvee;": '\U000022C1',
+ "bigwedge;": '\U000022C0',
+ "bkarow;": '\U0000290D',
+ "blacklozenge;": '\U000029EB',
+ "blacksquare;": '\U000025AA',
+ "blacktriangle;": '\U000025B4',
+ "blacktriangledown;": '\U000025BE',
+ "blacktriangleleft;": '\U000025C2',
+ "blacktriangleright;": '\U000025B8',
+ "blank;": '\U00002423',
+ "blk12;": '\U00002592',
+ "blk14;": '\U00002591',
+ "blk34;": '\U00002593',
+ "block;": '\U00002588',
+ "bnot;": '\U00002310',
+ "bopf;": '\U0001D553',
+ "bot;": '\U000022A5',
+ "bottom;": '\U000022A5',
+ "bowtie;": '\U000022C8',
+ "boxDL;": '\U00002557',
+ "boxDR;": '\U00002554',
+ "boxDl;": '\U00002556',
+ "boxDr;": '\U00002553',
+ "boxH;": '\U00002550',
+ "boxHD;": '\U00002566',
+ "boxHU;": '\U00002569',
+ "boxHd;": '\U00002564',
+ "boxHu;": '\U00002567',
+ "boxUL;": '\U0000255D',
+ "boxUR;": '\U0000255A',
+ "boxUl;": '\U0000255C',
+ "boxUr;": '\U00002559',
+ "boxV;": '\U00002551',
+ "boxVH;": '\U0000256C',
+ "boxVL;": '\U00002563',
+ "boxVR;": '\U00002560',
+ "boxVh;": '\U0000256B',
+ "boxVl;": '\U00002562',
+ "boxVr;": '\U0000255F',
+ "boxbox;": '\U000029C9',
+ "boxdL;": '\U00002555',
+ "boxdR;": '\U00002552',
+ "boxdl;": '\U00002510',
+ "boxdr;": '\U0000250C',
+ "boxh;": '\U00002500',
+ "boxhD;": '\U00002565',
+ "boxhU;": '\U00002568',
+ "boxhd;": '\U0000252C',
+ "boxhu;": '\U00002534',
+ "boxminus;": '\U0000229F',
+ "boxplus;": '\U0000229E',
+ "boxtimes;": '\U000022A0',
+ "boxuL;": '\U0000255B',
+ "boxuR;": '\U00002558',
+ "boxul;": '\U00002518',
+ "boxur;": '\U00002514',
+ "boxv;": '\U00002502',
+ "boxvH;": '\U0000256A',
+ "boxvL;": '\U00002561',
+ "boxvR;": '\U0000255E',
+ "boxvh;": '\U0000253C',
+ "boxvl;": '\U00002524',
+ "boxvr;": '\U0000251C',
+ "bprime;": '\U00002035',
+ "breve;": '\U000002D8',
+ "brvbar;": '\U000000A6',
+ "bscr;": '\U0001D4B7',
+ "bsemi;": '\U0000204F',
+ "bsim;": '\U0000223D',
+ "bsime;": '\U000022CD',
+ "bsol;": '\U0000005C',
+ "bsolb;": '\U000029C5',
+ "bsolhsub;": '\U000027C8',
+ "bull;": '\U00002022',
+ "bullet;": '\U00002022',
+ "bump;": '\U0000224E',
+ "bumpE;": '\U00002AAE',
+ "bumpe;": '\U0000224F',
+ "bumpeq;": '\U0000224F',
+ "cacute;": '\U00000107',
+ "cap;": '\U00002229',
+ "capand;": '\U00002A44',
+ "capbrcup;": '\U00002A49',
+ "capcap;": '\U00002A4B',
+ "capcup;": '\U00002A47',
+ "capdot;": '\U00002A40',
+ "caret;": '\U00002041',
+ "caron;": '\U000002C7',
+ "ccaps;": '\U00002A4D',
+ "ccaron;": '\U0000010D',
+ "ccedil;": '\U000000E7',
+ "ccirc;": '\U00000109',
+ "ccups;": '\U00002A4C',
+ "ccupssm;": '\U00002A50',
+ "cdot;": '\U0000010B',
+ "cedil;": '\U000000B8',
+ "cemptyv;": '\U000029B2',
+ "cent;": '\U000000A2',
+ "centerdot;": '\U000000B7',
+ "cfr;": '\U0001D520',
+ "chcy;": '\U00000447',
+ "check;": '\U00002713',
+ "checkmark;": '\U00002713',
+ "chi;": '\U000003C7',
+ "cir;": '\U000025CB',
+ "cirE;": '\U000029C3',
+ "circ;": '\U000002C6',
+ "circeq;": '\U00002257',
+ "circlearrowleft;": '\U000021BA',
+ "circlearrowright;": '\U000021BB',
+ "circledR;": '\U000000AE',
+ "circledS;": '\U000024C8',
+ "circledast;": '\U0000229B',
+ "circledcirc;": '\U0000229A',
+ "circleddash;": '\U0000229D',
+ "cire;": '\U00002257',
+ "cirfnint;": '\U00002A10',
+ "cirmid;": '\U00002AEF',
+ "cirscir;": '\U000029C2',
+ "clubs;": '\U00002663',
+ "clubsuit;": '\U00002663',
+ "colon;": '\U0000003A',
+ "colone;": '\U00002254',
+ "coloneq;": '\U00002254',
+ "comma;": '\U0000002C',
+ "commat;": '\U00000040',
+ "comp;": '\U00002201',
+ "compfn;": '\U00002218',
+ "complement;": '\U00002201',
+ "complexes;": '\U00002102',
+ "cong;": '\U00002245',
+ "congdot;": '\U00002A6D',
+ "conint;": '\U0000222E',
+ "copf;": '\U0001D554',
+ "coprod;": '\U00002210',
+ "copy;": '\U000000A9',
+ "copysr;": '\U00002117',
+ "crarr;": '\U000021B5',
+ "cross;": '\U00002717',
+ "cscr;": '\U0001D4B8',
+ "csub;": '\U00002ACF',
+ "csube;": '\U00002AD1',
+ "csup;": '\U00002AD0',
+ "csupe;": '\U00002AD2',
+ "ctdot;": '\U000022EF',
+ "cudarrl;": '\U00002938',
+ "cudarrr;": '\U00002935',
+ "cuepr;": '\U000022DE',
+ "cuesc;": '\U000022DF',
+ "cularr;": '\U000021B6',
+ "cularrp;": '\U0000293D',
+ "cup;": '\U0000222A',
+ "cupbrcap;": '\U00002A48',
+ "cupcap;": '\U00002A46',
+ "cupcup;": '\U00002A4A',
+ "cupdot;": '\U0000228D',
+ "cupor;": '\U00002A45',
+ "curarr;": '\U000021B7',
+ "curarrm;": '\U0000293C',
+ "curlyeqprec;": '\U000022DE',
+ "curlyeqsucc;": '\U000022DF',
+ "curlyvee;": '\U000022CE',
+ "curlywedge;": '\U000022CF',
+ "curren;": '\U000000A4',
+ "curvearrowleft;": '\U000021B6',
+ "curvearrowright;": '\U000021B7',
+ "cuvee;": '\U000022CE',
+ "cuwed;": '\U000022CF',
+ "cwconint;": '\U00002232',
+ "cwint;": '\U00002231',
+ "cylcty;": '\U0000232D',
+ "dArr;": '\U000021D3',
+ "dHar;": '\U00002965',
+ "dagger;": '\U00002020',
+ "daleth;": '\U00002138',
+ "darr;": '\U00002193',
+ "dash;": '\U00002010',
+ "dashv;": '\U000022A3',
+ "dbkarow;": '\U0000290F',
+ "dblac;": '\U000002DD',
+ "dcaron;": '\U0000010F',
+ "dcy;": '\U00000434',
+ "dd;": '\U00002146',
+ "ddagger;": '\U00002021',
+ "ddarr;": '\U000021CA',
+ "ddotseq;": '\U00002A77',
+ "deg;": '\U000000B0',
+ "delta;": '\U000003B4',
+ "demptyv;": '\U000029B1',
+ "dfisht;": '\U0000297F',
+ "dfr;": '\U0001D521',
+ "dharl;": '\U000021C3',
+ "dharr;": '\U000021C2',
+ "diam;": '\U000022C4',
+ "diamond;": '\U000022C4',
+ "diamondsuit;": '\U00002666',
+ "diams;": '\U00002666',
+ "die;": '\U000000A8',
+ "digamma;": '\U000003DD',
+ "disin;": '\U000022F2',
+ "div;": '\U000000F7',
+ "divide;": '\U000000F7',
+ "divideontimes;": '\U000022C7',
+ "divonx;": '\U000022C7',
+ "djcy;": '\U00000452',
+ "dlcorn;": '\U0000231E',
+ "dlcrop;": '\U0000230D',
+ "dollar;": '\U00000024',
+ "dopf;": '\U0001D555',
+ "dot;": '\U000002D9',
+ "doteq;": '\U00002250',
+ "doteqdot;": '\U00002251',
+ "dotminus;": '\U00002238',
+ "dotplus;": '\U00002214',
+ "dotsquare;": '\U000022A1',
+ "doublebarwedge;": '\U00002306',
+ "downarrow;": '\U00002193',
+ "downdownarrows;": '\U000021CA',
+ "downharpoonleft;": '\U000021C3',
+ "downharpoonright;": '\U000021C2',
+ "drbkarow;": '\U00002910',
+ "drcorn;": '\U0000231F',
+ "drcrop;": '\U0000230C',
+ "dscr;": '\U0001D4B9',
+ "dscy;": '\U00000455',
+ "dsol;": '\U000029F6',
+ "dstrok;": '\U00000111',
+ "dtdot;": '\U000022F1',
+ "dtri;": '\U000025BF',
+ "dtrif;": '\U000025BE',
+ "duarr;": '\U000021F5',
+ "duhar;": '\U0000296F',
+ "dwangle;": '\U000029A6',
+ "dzcy;": '\U0000045F',
+ "dzigrarr;": '\U000027FF',
+ "eDDot;": '\U00002A77',
+ "eDot;": '\U00002251',
+ "eacute;": '\U000000E9',
+ "easter;": '\U00002A6E',
+ "ecaron;": '\U0000011B',
+ "ecir;": '\U00002256',
+ "ecirc;": '\U000000EA',
+ "ecolon;": '\U00002255',
+ "ecy;": '\U0000044D',
+ "edot;": '\U00000117',
+ "ee;": '\U00002147',
+ "efDot;": '\U00002252',
+ "efr;": '\U0001D522',
+ "eg;": '\U00002A9A',
+ "egrave;": '\U000000E8',
+ "egs;": '\U00002A96',
+ "egsdot;": '\U00002A98',
+ "el;": '\U00002A99',
+ "elinters;": '\U000023E7',
+ "ell;": '\U00002113',
+ "els;": '\U00002A95',
+ "elsdot;": '\U00002A97',
+ "emacr;": '\U00000113',
+ "empty;": '\U00002205',
+ "emptyset;": '\U00002205',
+ "emptyv;": '\U00002205',
+ "emsp;": '\U00002003',
+ "emsp13;": '\U00002004',
+ "emsp14;": '\U00002005',
+ "eng;": '\U0000014B',
+ "ensp;": '\U00002002',
+ "eogon;": '\U00000119',
+ "eopf;": '\U0001D556',
+ "epar;": '\U000022D5',
+ "eparsl;": '\U000029E3',
+ "eplus;": '\U00002A71',
+ "epsi;": '\U000003B5',
+ "epsilon;": '\U000003B5',
+ "epsiv;": '\U000003F5',
+ "eqcirc;": '\U00002256',
+ "eqcolon;": '\U00002255',
+ "eqsim;": '\U00002242',
+ "eqslantgtr;": '\U00002A96',
+ "eqslantless;": '\U00002A95',
+ "equals;": '\U0000003D',
+ "equest;": '\U0000225F',
+ "equiv;": '\U00002261',
+ "equivDD;": '\U00002A78',
+ "eqvparsl;": '\U000029E5',
+ "erDot;": '\U00002253',
+ "erarr;": '\U00002971',
+ "escr;": '\U0000212F',
+ "esdot;": '\U00002250',
+ "esim;": '\U00002242',
+ "eta;": '\U000003B7',
+ "eth;": '\U000000F0',
+ "euml;": '\U000000EB',
+ "euro;": '\U000020AC',
+ "excl;": '\U00000021',
+ "exist;": '\U00002203',
+ "expectation;": '\U00002130',
+ "exponentiale;": '\U00002147',
+ "fallingdotseq;": '\U00002252',
+ "fcy;": '\U00000444',
+ "female;": '\U00002640',
+ "ffilig;": '\U0000FB03',
+ "fflig;": '\U0000FB00',
+ "ffllig;": '\U0000FB04',
+ "ffr;": '\U0001D523',
+ "filig;": '\U0000FB01',
+ "flat;": '\U0000266D',
+ "fllig;": '\U0000FB02',
+ "fltns;": '\U000025B1',
+ "fnof;": '\U00000192',
+ "fopf;": '\U0001D557',
+ "forall;": '\U00002200',
+ "fork;": '\U000022D4',
+ "forkv;": '\U00002AD9',
+ "fpartint;": '\U00002A0D',
+ "frac12;": '\U000000BD',
+ "frac13;": '\U00002153',
+ "frac14;": '\U000000BC',
+ "frac15;": '\U00002155',
+ "frac16;": '\U00002159',
+ "frac18;": '\U0000215B',
+ "frac23;": '\U00002154',
+ "frac25;": '\U00002156',
+ "frac34;": '\U000000BE',
+ "frac35;": '\U00002157',
+ "frac38;": '\U0000215C',
+ "frac45;": '\U00002158',
+ "frac56;": '\U0000215A',
+ "frac58;": '\U0000215D',
+ "frac78;": '\U0000215E',
+ "frasl;": '\U00002044',
+ "frown;": '\U00002322',
+ "fscr;": '\U0001D4BB',
+ "gE;": '\U00002267',
+ "gEl;": '\U00002A8C',
+ "gacute;": '\U000001F5',
+ "gamma;": '\U000003B3',
+ "gammad;": '\U000003DD',
+ "gap;": '\U00002A86',
+ "gbreve;": '\U0000011F',
+ "gcirc;": '\U0000011D',
+ "gcy;": '\U00000433',
+ "gdot;": '\U00000121',
+ "ge;": '\U00002265',
+ "gel;": '\U000022DB',
+ "geq;": '\U00002265',
+ "geqq;": '\U00002267',
+ "geqslant;": '\U00002A7E',
+ "ges;": '\U00002A7E',
+ "gescc;": '\U00002AA9',
+ "gesdot;": '\U00002A80',
+ "gesdoto;": '\U00002A82',
+ "gesdotol;": '\U00002A84',
+ "gesles;": '\U00002A94',
+ "gfr;": '\U0001D524',
+ "gg;": '\U0000226B',
+ "ggg;": '\U000022D9',
+ "gimel;": '\U00002137',
+ "gjcy;": '\U00000453',
+ "gl;": '\U00002277',
+ "glE;": '\U00002A92',
+ "gla;": '\U00002AA5',
+ "glj;": '\U00002AA4',
+ "gnE;": '\U00002269',
+ "gnap;": '\U00002A8A',
+ "gnapprox;": '\U00002A8A',
+ "gne;": '\U00002A88',
+ "gneq;": '\U00002A88',
+ "gneqq;": '\U00002269',
+ "gnsim;": '\U000022E7',
+ "gopf;": '\U0001D558',
+ "grave;": '\U00000060',
+ "gscr;": '\U0000210A',
+ "gsim;": '\U00002273',
+ "gsime;": '\U00002A8E',
+ "gsiml;": '\U00002A90',
+ "gt;": '\U0000003E',
+ "gtcc;": '\U00002AA7',
+ "gtcir;": '\U00002A7A',
+ "gtdot;": '\U000022D7',
+ "gtlPar;": '\U00002995',
+ "gtquest;": '\U00002A7C',
+ "gtrapprox;": '\U00002A86',
+ "gtrarr;": '\U00002978',
+ "gtrdot;": '\U000022D7',
+ "gtreqless;": '\U000022DB',
+ "gtreqqless;": '\U00002A8C',
+ "gtrless;": '\U00002277',
+ "gtrsim;": '\U00002273',
+ "hArr;": '\U000021D4',
+ "hairsp;": '\U0000200A',
+ "half;": '\U000000BD',
+ "hamilt;": '\U0000210B',
+ "hardcy;": '\U0000044A',
+ "harr;": '\U00002194',
+ "harrcir;": '\U00002948',
+ "harrw;": '\U000021AD',
+ "hbar;": '\U0000210F',
+ "hcirc;": '\U00000125',
+ "hearts;": '\U00002665',
+ "heartsuit;": '\U00002665',
+ "hellip;": '\U00002026',
+ "hercon;": '\U000022B9',
+ "hfr;": '\U0001D525',
+ "hksearow;": '\U00002925',
+ "hkswarow;": '\U00002926',
+ "hoarr;": '\U000021FF',
+ "homtht;": '\U0000223B',
+ "hookleftarrow;": '\U000021A9',
+ "hookrightarrow;": '\U000021AA',
+ "hopf;": '\U0001D559',
+ "horbar;": '\U00002015',
+ "hscr;": '\U0001D4BD',
+ "hslash;": '\U0000210F',
+ "hstrok;": '\U00000127',
+ "hybull;": '\U00002043',
+ "hyphen;": '\U00002010',
+ "iacute;": '\U000000ED',
+ "ic;": '\U00002063',
+ "icirc;": '\U000000EE',
+ "icy;": '\U00000438',
+ "iecy;": '\U00000435',
+ "iexcl;": '\U000000A1',
+ "iff;": '\U000021D4',
+ "ifr;": '\U0001D526',
+ "igrave;": '\U000000EC',
+ "ii;": '\U00002148',
+ "iiiint;": '\U00002A0C',
+ "iiint;": '\U0000222D',
+ "iinfin;": '\U000029DC',
+ "iiota;": '\U00002129',
+ "ijlig;": '\U00000133',
+ "imacr;": '\U0000012B',
+ "image;": '\U00002111',
+ "imagline;": '\U00002110',
+ "imagpart;": '\U00002111',
+ "imath;": '\U00000131',
+ "imof;": '\U000022B7',
+ "imped;": '\U000001B5',
+ "in;": '\U00002208',
+ "incare;": '\U00002105',
+ "infin;": '\U0000221E',
+ "infintie;": '\U000029DD',
+ "inodot;": '\U00000131',
+ "int;": '\U0000222B',
+ "intcal;": '\U000022BA',
+ "integers;": '\U00002124',
+ "intercal;": '\U000022BA',
+ "intlarhk;": '\U00002A17',
+ "intprod;": '\U00002A3C',
+ "iocy;": '\U00000451',
+ "iogon;": '\U0000012F',
+ "iopf;": '\U0001D55A',
+ "iota;": '\U000003B9',
+ "iprod;": '\U00002A3C',
+ "iquest;": '\U000000BF',
+ "iscr;": '\U0001D4BE',
+ "isin;": '\U00002208',
+ "isinE;": '\U000022F9',
+ "isindot;": '\U000022F5',
+ "isins;": '\U000022F4',
+ "isinsv;": '\U000022F3',
+ "isinv;": '\U00002208',
+ "it;": '\U00002062',
+ "itilde;": '\U00000129',
+ "iukcy;": '\U00000456',
+ "iuml;": '\U000000EF',
+ "jcirc;": '\U00000135',
+ "jcy;": '\U00000439',
+ "jfr;": '\U0001D527',
+ "jmath;": '\U00000237',
+ "jopf;": '\U0001D55B',
+ "jscr;": '\U0001D4BF',
+ "jsercy;": '\U00000458',
+ "jukcy;": '\U00000454',
+ "kappa;": '\U000003BA',
+ "kappav;": '\U000003F0',
+ "kcedil;": '\U00000137',
+ "kcy;": '\U0000043A',
+ "kfr;": '\U0001D528',
+ "kgreen;": '\U00000138',
+ "khcy;": '\U00000445',
+ "kjcy;": '\U0000045C',
+ "kopf;": '\U0001D55C',
+ "kscr;": '\U0001D4C0',
+ "lAarr;": '\U000021DA',
+ "lArr;": '\U000021D0',
+ "lAtail;": '\U0000291B',
+ "lBarr;": '\U0000290E',
+ "lE;": '\U00002266',
+ "lEg;": '\U00002A8B',
+ "lHar;": '\U00002962',
+ "lacute;": '\U0000013A',
+ "laemptyv;": '\U000029B4',
+ "lagran;": '\U00002112',
+ "lambda;": '\U000003BB',
+ "lang;": '\U000027E8',
+ "langd;": '\U00002991',
+ "langle;": '\U000027E8',
+ "lap;": '\U00002A85',
+ "laquo;": '\U000000AB',
+ "larr;": '\U00002190',
+ "larrb;": '\U000021E4',
+ "larrbfs;": '\U0000291F',
+ "larrfs;": '\U0000291D',
+ "larrhk;": '\U000021A9',
+ "larrlp;": '\U000021AB',
+ "larrpl;": '\U00002939',
+ "larrsim;": '\U00002973',
+ "larrtl;": '\U000021A2',
+ "lat;": '\U00002AAB',
+ "latail;": '\U00002919',
+ "late;": '\U00002AAD',
+ "lbarr;": '\U0000290C',
+ "lbbrk;": '\U00002772',
+ "lbrace;": '\U0000007B',
+ "lbrack;": '\U0000005B',
+ "lbrke;": '\U0000298B',
+ "lbrksld;": '\U0000298F',
+ "lbrkslu;": '\U0000298D',
+ "lcaron;": '\U0000013E',
+ "lcedil;": '\U0000013C',
+ "lceil;": '\U00002308',
+ "lcub;": '\U0000007B',
+ "lcy;": '\U0000043B',
+ "ldca;": '\U00002936',
+ "ldquo;": '\U0000201C',
+ "ldquor;": '\U0000201E',
+ "ldrdhar;": '\U00002967',
+ "ldrushar;": '\U0000294B',
+ "ldsh;": '\U000021B2',
+ "le;": '\U00002264',
+ "leftarrow;": '\U00002190',
+ "leftarrowtail;": '\U000021A2',
+ "leftharpoondown;": '\U000021BD',
+ "leftharpoonup;": '\U000021BC',
+ "leftleftarrows;": '\U000021C7',
+ "leftrightarrow;": '\U00002194',
+ "leftrightarrows;": '\U000021C6',
+ "leftrightharpoons;": '\U000021CB',
+ "leftrightsquigarrow;": '\U000021AD',
+ "leftthreetimes;": '\U000022CB',
+ "leg;": '\U000022DA',
+ "leq;": '\U00002264',
+ "leqq;": '\U00002266',
+ "leqslant;": '\U00002A7D',
+ "les;": '\U00002A7D',
+ "lescc;": '\U00002AA8',
+ "lesdot;": '\U00002A7F',
+ "lesdoto;": '\U00002A81',
+ "lesdotor;": '\U00002A83',
+ "lesges;": '\U00002A93',
+ "lessapprox;": '\U00002A85',
+ "lessdot;": '\U000022D6',
+ "lesseqgtr;": '\U000022DA',
+ "lesseqqgtr;": '\U00002A8B',
+ "lessgtr;": '\U00002276',
+ "lesssim;": '\U00002272',
+ "lfisht;": '\U0000297C',
+ "lfloor;": '\U0000230A',
+ "lfr;": '\U0001D529',
+ "lg;": '\U00002276',
+ "lgE;": '\U00002A91',
+ "lhard;": '\U000021BD',
+ "lharu;": '\U000021BC',
+ "lharul;": '\U0000296A',
+ "lhblk;": '\U00002584',
+ "ljcy;": '\U00000459',
+ "ll;": '\U0000226A',
+ "llarr;": '\U000021C7',
+ "llcorner;": '\U0000231E',
+ "llhard;": '\U0000296B',
+ "lltri;": '\U000025FA',
+ "lmidot;": '\U00000140',
+ "lmoust;": '\U000023B0',
+ "lmoustache;": '\U000023B0',
+ "lnE;": '\U00002268',
+ "lnap;": '\U00002A89',
+ "lnapprox;": '\U00002A89',
+ "lne;": '\U00002A87',
+ "lneq;": '\U00002A87',
+ "lneqq;": '\U00002268',
+ "lnsim;": '\U000022E6',
+ "loang;": '\U000027EC',
+ "loarr;": '\U000021FD',
+ "lobrk;": '\U000027E6',
+ "longleftarrow;": '\U000027F5',
+ "longleftrightarrow;": '\U000027F7',
+ "longmapsto;": '\U000027FC',
+ "longrightarrow;": '\U000027F6',
+ "looparrowleft;": '\U000021AB',
+ "looparrowright;": '\U000021AC',
+ "lopar;": '\U00002985',
+ "lopf;": '\U0001D55D',
+ "loplus;": '\U00002A2D',
+ "lotimes;": '\U00002A34',
+ "lowast;": '\U00002217',
+ "lowbar;": '\U0000005F',
+ "loz;": '\U000025CA',
+ "lozenge;": '\U000025CA',
+ "lozf;": '\U000029EB',
+ "lpar;": '\U00000028',
+ "lparlt;": '\U00002993',
+ "lrarr;": '\U000021C6',
+ "lrcorner;": '\U0000231F',
+ "lrhar;": '\U000021CB',
+ "lrhard;": '\U0000296D',
+ "lrm;": '\U0000200E',
+ "lrtri;": '\U000022BF',
+ "lsaquo;": '\U00002039',
+ "lscr;": '\U0001D4C1',
+ "lsh;": '\U000021B0',
+ "lsim;": '\U00002272',
+ "lsime;": '\U00002A8D',
+ "lsimg;": '\U00002A8F',
+ "lsqb;": '\U0000005B',
+ "lsquo;": '\U00002018',
+ "lsquor;": '\U0000201A',
+ "lstrok;": '\U00000142',
+ "lt;": '\U0000003C',
+ "ltcc;": '\U00002AA6',
+ "ltcir;": '\U00002A79',
+ "ltdot;": '\U000022D6',
+ "lthree;": '\U000022CB',
+ "ltimes;": '\U000022C9',
+ "ltlarr;": '\U00002976',
+ "ltquest;": '\U00002A7B',
+ "ltrPar;": '\U00002996',
+ "ltri;": '\U000025C3',
+ "ltrie;": '\U000022B4',
+ "ltrif;": '\U000025C2',
+ "lurdshar;": '\U0000294A',
+ "luruhar;": '\U00002966',
+ "mDDot;": '\U0000223A',
+ "macr;": '\U000000AF',
+ "male;": '\U00002642',
+ "malt;": '\U00002720',
+ "maltese;": '\U00002720',
+ "map;": '\U000021A6',
+ "mapsto;": '\U000021A6',
+ "mapstodown;": '\U000021A7',
+ "mapstoleft;": '\U000021A4',
+ "mapstoup;": '\U000021A5',
+ "marker;": '\U000025AE',
+ "mcomma;": '\U00002A29',
+ "mcy;": '\U0000043C',
+ "mdash;": '\U00002014',
+ "measuredangle;": '\U00002221',
+ "mfr;": '\U0001D52A',
+ "mho;": '\U00002127',
+ "micro;": '\U000000B5',
+ "mid;": '\U00002223',
+ "midast;": '\U0000002A',
+ "midcir;": '\U00002AF0',
+ "middot;": '\U000000B7',
+ "minus;": '\U00002212',
+ "minusb;": '\U0000229F',
+ "minusd;": '\U00002238',
+ "minusdu;": '\U00002A2A',
+ "mlcp;": '\U00002ADB',
+ "mldr;": '\U00002026',
+ "mnplus;": '\U00002213',
+ "models;": '\U000022A7',
+ "mopf;": '\U0001D55E',
+ "mp;": '\U00002213',
+ "mscr;": '\U0001D4C2',
+ "mstpos;": '\U0000223E',
+ "mu;": '\U000003BC',
+ "multimap;": '\U000022B8',
+ "mumap;": '\U000022B8',
+ "nLeftarrow;": '\U000021CD',
+ "nLeftrightarrow;": '\U000021CE',
+ "nRightarrow;": '\U000021CF',
+ "nVDash;": '\U000022AF',
+ "nVdash;": '\U000022AE',
+ "nabla;": '\U00002207',
+ "nacute;": '\U00000144',
+ "nap;": '\U00002249',
+ "napos;": '\U00000149',
+ "napprox;": '\U00002249',
+ "natur;": '\U0000266E',
+ "natural;": '\U0000266E',
+ "naturals;": '\U00002115',
+ "nbsp;": '\U000000A0',
+ "ncap;": '\U00002A43',
+ "ncaron;": '\U00000148',
+ "ncedil;": '\U00000146',
+ "ncong;": '\U00002247',
+ "ncup;": '\U00002A42',
+ "ncy;": '\U0000043D',
+ "ndash;": '\U00002013',
+ "ne;": '\U00002260',
+ "neArr;": '\U000021D7',
+ "nearhk;": '\U00002924',
+ "nearr;": '\U00002197',
+ "nearrow;": '\U00002197',
+ "nequiv;": '\U00002262',
+ "nesear;": '\U00002928',
+ "nexist;": '\U00002204',
+ "nexists;": '\U00002204',
+ "nfr;": '\U0001D52B',
+ "nge;": '\U00002271',
+ "ngeq;": '\U00002271',
+ "ngsim;": '\U00002275',
+ "ngt;": '\U0000226F',
+ "ngtr;": '\U0000226F',
+ "nhArr;": '\U000021CE',
+ "nharr;": '\U000021AE',
+ "nhpar;": '\U00002AF2',
+ "ni;": '\U0000220B',
+ "nis;": '\U000022FC',
+ "nisd;": '\U000022FA',
+ "niv;": '\U0000220B',
+ "njcy;": '\U0000045A',
+ "nlArr;": '\U000021CD',
+ "nlarr;": '\U0000219A',
+ "nldr;": '\U00002025',
+ "nle;": '\U00002270',
+ "nleftarrow;": '\U0000219A',
+ "nleftrightarrow;": '\U000021AE',
+ "nleq;": '\U00002270',
+ "nless;": '\U0000226E',
+ "nlsim;": '\U00002274',
+ "nlt;": '\U0000226E',
+ "nltri;": '\U000022EA',
+ "nltrie;": '\U000022EC',
+ "nmid;": '\U00002224',
+ "nopf;": '\U0001D55F',
+ "not;": '\U000000AC',
+ "notin;": '\U00002209',
+ "notinva;": '\U00002209',
+ "notinvb;": '\U000022F7',
+ "notinvc;": '\U000022F6',
+ "notni;": '\U0000220C',
+ "notniva;": '\U0000220C',
+ "notnivb;": '\U000022FE',
+ "notnivc;": '\U000022FD',
+ "npar;": '\U00002226',
+ "nparallel;": '\U00002226',
+ "npolint;": '\U00002A14',
+ "npr;": '\U00002280',
+ "nprcue;": '\U000022E0',
+ "nprec;": '\U00002280',
+ "nrArr;": '\U000021CF',
+ "nrarr;": '\U0000219B',
+ "nrightarrow;": '\U0000219B',
+ "nrtri;": '\U000022EB',
+ "nrtrie;": '\U000022ED',
+ "nsc;": '\U00002281',
+ "nsccue;": '\U000022E1',
+ "nscr;": '\U0001D4C3',
+ "nshortmid;": '\U00002224',
+ "nshortparallel;": '\U00002226',
+ "nsim;": '\U00002241',
+ "nsime;": '\U00002244',
+ "nsimeq;": '\U00002244',
+ "nsmid;": '\U00002224',
+ "nspar;": '\U00002226',
+ "nsqsube;": '\U000022E2',
+ "nsqsupe;": '\U000022E3',
+ "nsub;": '\U00002284',
+ "nsube;": '\U00002288',
+ "nsubseteq;": '\U00002288',
+ "nsucc;": '\U00002281',
+ "nsup;": '\U00002285',
+ "nsupe;": '\U00002289',
+ "nsupseteq;": '\U00002289',
+ "ntgl;": '\U00002279',
+ "ntilde;": '\U000000F1',
+ "ntlg;": '\U00002278',
+ "ntriangleleft;": '\U000022EA',
+ "ntrianglelefteq;": '\U000022EC',
+ "ntriangleright;": '\U000022EB',
+ "ntrianglerighteq;": '\U000022ED',
+ "nu;": '\U000003BD',
+ "num;": '\U00000023',
+ "numero;": '\U00002116',
+ "numsp;": '\U00002007',
+ "nvDash;": '\U000022AD',
+ "nvHarr;": '\U00002904',
+ "nvdash;": '\U000022AC',
+ "nvinfin;": '\U000029DE',
+ "nvlArr;": '\U00002902',
+ "nvrArr;": '\U00002903',
+ "nwArr;": '\U000021D6',
+ "nwarhk;": '\U00002923',
+ "nwarr;": '\U00002196',
+ "nwarrow;": '\U00002196',
+ "nwnear;": '\U00002927',
+ "oS;": '\U000024C8',
+ "oacute;": '\U000000F3',
+ "oast;": '\U0000229B',
+ "ocir;": '\U0000229A',
+ "ocirc;": '\U000000F4',
+ "ocy;": '\U0000043E',
+ "odash;": '\U0000229D',
+ "odblac;": '\U00000151',
+ "odiv;": '\U00002A38',
+ "odot;": '\U00002299',
+ "odsold;": '\U000029BC',
+ "oelig;": '\U00000153',
+ "ofcir;": '\U000029BF',
+ "ofr;": '\U0001D52C',
+ "ogon;": '\U000002DB',
+ "ograve;": '\U000000F2',
+ "ogt;": '\U000029C1',
+ "ohbar;": '\U000029B5',
+ "ohm;": '\U000003A9',
+ "oint;": '\U0000222E',
+ "olarr;": '\U000021BA',
+ "olcir;": '\U000029BE',
+ "olcross;": '\U000029BB',
+ "oline;": '\U0000203E',
+ "olt;": '\U000029C0',
+ "omacr;": '\U0000014D',
+ "omega;": '\U000003C9',
+ "omicron;": '\U000003BF',
+ "omid;": '\U000029B6',
+ "ominus;": '\U00002296',
+ "oopf;": '\U0001D560',
+ "opar;": '\U000029B7',
+ "operp;": '\U000029B9',
+ "oplus;": '\U00002295',
+ "or;": '\U00002228',
+ "orarr;": '\U000021BB',
+ "ord;": '\U00002A5D',
+ "order;": '\U00002134',
+ "orderof;": '\U00002134',
+ "ordf;": '\U000000AA',
+ "ordm;": '\U000000BA',
+ "origof;": '\U000022B6',
+ "oror;": '\U00002A56',
+ "orslope;": '\U00002A57',
+ "orv;": '\U00002A5B',
+ "oscr;": '\U00002134',
+ "oslash;": '\U000000F8',
+ "osol;": '\U00002298',
+ "otilde;": '\U000000F5',
+ "otimes;": '\U00002297',
+ "otimesas;": '\U00002A36',
+ "ouml;": '\U000000F6',
+ "ovbar;": '\U0000233D',
+ "par;": '\U00002225',
+ "para;": '\U000000B6',
+ "parallel;": '\U00002225',
+ "parsim;": '\U00002AF3',
+ "parsl;": '\U00002AFD',
+ "part;": '\U00002202',
+ "pcy;": '\U0000043F',
+ "percnt;": '\U00000025',
+ "period;": '\U0000002E',
+ "permil;": '\U00002030',
+ "perp;": '\U000022A5',
+ "pertenk;": '\U00002031',
+ "pfr;": '\U0001D52D',
+ "phi;": '\U000003C6',
+ "phiv;": '\U000003D5',
+ "phmmat;": '\U00002133',
+ "phone;": '\U0000260E',
+ "pi;": '\U000003C0',
+ "pitchfork;": '\U000022D4',
+ "piv;": '\U000003D6',
+ "planck;": '\U0000210F',
+ "planckh;": '\U0000210E',
+ "plankv;": '\U0000210F',
+ "plus;": '\U0000002B',
+ "plusacir;": '\U00002A23',
+ "plusb;": '\U0000229E',
+ "pluscir;": '\U00002A22',
+ "plusdo;": '\U00002214',
+ "plusdu;": '\U00002A25',
+ "pluse;": '\U00002A72',
+ "plusmn;": '\U000000B1',
+ "plussim;": '\U00002A26',
+ "plustwo;": '\U00002A27',
+ "pm;": '\U000000B1',
+ "pointint;": '\U00002A15',
+ "popf;": '\U0001D561',
+ "pound;": '\U000000A3',
+ "pr;": '\U0000227A',
+ "prE;": '\U00002AB3',
+ "prap;": '\U00002AB7',
+ "prcue;": '\U0000227C',
+ "pre;": '\U00002AAF',
+ "prec;": '\U0000227A',
+ "precapprox;": '\U00002AB7',
+ "preccurlyeq;": '\U0000227C',
+ "preceq;": '\U00002AAF',
+ "precnapprox;": '\U00002AB9',
+ "precneqq;": '\U00002AB5',
+ "precnsim;": '\U000022E8',
+ "precsim;": '\U0000227E',
+ "prime;": '\U00002032',
+ "primes;": '\U00002119',
+ "prnE;": '\U00002AB5',
+ "prnap;": '\U00002AB9',
+ "prnsim;": '\U000022E8',
+ "prod;": '\U0000220F',
+ "profalar;": '\U0000232E',
+ "profline;": '\U00002312',
+ "profsurf;": '\U00002313',
+ "prop;": '\U0000221D',
+ "propto;": '\U0000221D',
+ "prsim;": '\U0000227E',
+ "prurel;": '\U000022B0',
+ "pscr;": '\U0001D4C5',
+ "psi;": '\U000003C8',
+ "puncsp;": '\U00002008',
+ "qfr;": '\U0001D52E',
+ "qint;": '\U00002A0C',
+ "qopf;": '\U0001D562',
+ "qprime;": '\U00002057',
+ "qscr;": '\U0001D4C6',
+ "quaternions;": '\U0000210D',
+ "quatint;": '\U00002A16',
+ "quest;": '\U0000003F',
+ "questeq;": '\U0000225F',
+ "quot;": '\U00000022',
+ "rAarr;": '\U000021DB',
+ "rArr;": '\U000021D2',
+ "rAtail;": '\U0000291C',
+ "rBarr;": '\U0000290F',
+ "rHar;": '\U00002964',
+ "racute;": '\U00000155',
+ "radic;": '\U0000221A',
+ "raemptyv;": '\U000029B3',
+ "rang;": '\U000027E9',
+ "rangd;": '\U00002992',
+ "range;": '\U000029A5',
+ "rangle;": '\U000027E9',
+ "raquo;": '\U000000BB',
+ "rarr;": '\U00002192',
+ "rarrap;": '\U00002975',
+ "rarrb;": '\U000021E5',
+ "rarrbfs;": '\U00002920',
+ "rarrc;": '\U00002933',
+ "rarrfs;": '\U0000291E',
+ "rarrhk;": '\U000021AA',
+ "rarrlp;": '\U000021AC',
+ "rarrpl;": '\U00002945',
+ "rarrsim;": '\U00002974',
+ "rarrtl;": '\U000021A3',
+ "rarrw;": '\U0000219D',
+ "ratail;": '\U0000291A',
+ "ratio;": '\U00002236',
+ "rationals;": '\U0000211A',
+ "rbarr;": '\U0000290D',
+ "rbbrk;": '\U00002773',
+ "rbrace;": '\U0000007D',
+ "rbrack;": '\U0000005D',
+ "rbrke;": '\U0000298C',
+ "rbrksld;": '\U0000298E',
+ "rbrkslu;": '\U00002990',
+ "rcaron;": '\U00000159',
+ "rcedil;": '\U00000157',
+ "rceil;": '\U00002309',
+ "rcub;": '\U0000007D',
+ "rcy;": '\U00000440',
+ "rdca;": '\U00002937',
+ "rdldhar;": '\U00002969',
+ "rdquo;": '\U0000201D',
+ "rdquor;": '\U0000201D',
+ "rdsh;": '\U000021B3',
+ "real;": '\U0000211C',
+ "realine;": '\U0000211B',
+ "realpart;": '\U0000211C',
+ "reals;": '\U0000211D',
+ "rect;": '\U000025AD',
+ "reg;": '\U000000AE',
+ "rfisht;": '\U0000297D',
+ "rfloor;": '\U0000230B',
+ "rfr;": '\U0001D52F',
+ "rhard;": '\U000021C1',
+ "rharu;": '\U000021C0',
+ "rharul;": '\U0000296C',
+ "rho;": '\U000003C1',
+ "rhov;": '\U000003F1',
+ "rightarrow;": '\U00002192',
+ "rightarrowtail;": '\U000021A3',
+ "rightharpoondown;": '\U000021C1',
+ "rightharpoonup;": '\U000021C0',
+ "rightleftarrows;": '\U000021C4',
+ "rightleftharpoons;": '\U000021CC',
+ "rightrightarrows;": '\U000021C9',
+ "rightsquigarrow;": '\U0000219D',
+ "rightthreetimes;": '\U000022CC',
+ "ring;": '\U000002DA',
+ "risingdotseq;": '\U00002253',
+ "rlarr;": '\U000021C4',
+ "rlhar;": '\U000021CC',
+ "rlm;": '\U0000200F',
+ "rmoust;": '\U000023B1',
+ "rmoustache;": '\U000023B1',
+ "rnmid;": '\U00002AEE',
+ "roang;": '\U000027ED',
+ "roarr;": '\U000021FE',
+ "robrk;": '\U000027E7',
+ "ropar;": '\U00002986',
+ "ropf;": '\U0001D563',
+ "roplus;": '\U00002A2E',
+ "rotimes;": '\U00002A35',
+ "rpar;": '\U00000029',
+ "rpargt;": '\U00002994',
+ "rppolint;": '\U00002A12',
+ "rrarr;": '\U000021C9',
+ "rsaquo;": '\U0000203A',
+ "rscr;": '\U0001D4C7',
+ "rsh;": '\U000021B1',
+ "rsqb;": '\U0000005D',
+ "rsquo;": '\U00002019',
+ "rsquor;": '\U00002019',
+ "rthree;": '\U000022CC',
+ "rtimes;": '\U000022CA',
+ "rtri;": '\U000025B9',
+ "rtrie;": '\U000022B5',
+ "rtrif;": '\U000025B8',
+ "rtriltri;": '\U000029CE',
+ "ruluhar;": '\U00002968',
+ "rx;": '\U0000211E',
+ "sacute;": '\U0000015B',
+ "sbquo;": '\U0000201A',
+ "sc;": '\U0000227B',
+ "scE;": '\U00002AB4',
+ "scap;": '\U00002AB8',
+ "scaron;": '\U00000161',
+ "sccue;": '\U0000227D',
+ "sce;": '\U00002AB0',
+ "scedil;": '\U0000015F',
+ "scirc;": '\U0000015D',
+ "scnE;": '\U00002AB6',
+ "scnap;": '\U00002ABA',
+ "scnsim;": '\U000022E9',
+ "scpolint;": '\U00002A13',
+ "scsim;": '\U0000227F',
+ "scy;": '\U00000441',
+ "sdot;": '\U000022C5',
+ "sdotb;": '\U000022A1',
+ "sdote;": '\U00002A66',
+ "seArr;": '\U000021D8',
+ "searhk;": '\U00002925',
+ "searr;": '\U00002198',
+ "searrow;": '\U00002198',
+ "sect;": '\U000000A7',
+ "semi;": '\U0000003B',
+ "seswar;": '\U00002929',
+ "setminus;": '\U00002216',
+ "setmn;": '\U00002216',
+ "sext;": '\U00002736',
+ "sfr;": '\U0001D530',
+ "sfrown;": '\U00002322',
+ "sharp;": '\U0000266F',
+ "shchcy;": '\U00000449',
+ "shcy;": '\U00000448',
+ "shortmid;": '\U00002223',
+ "shortparallel;": '\U00002225',
+ "shy;": '\U000000AD',
+ "sigma;": '\U000003C3',
+ "sigmaf;": '\U000003C2',
+ "sigmav;": '\U000003C2',
+ "sim;": '\U0000223C',
+ "simdot;": '\U00002A6A',
+ "sime;": '\U00002243',
+ "simeq;": '\U00002243',
+ "simg;": '\U00002A9E',
+ "simgE;": '\U00002AA0',
+ "siml;": '\U00002A9D',
+ "simlE;": '\U00002A9F',
+ "simne;": '\U00002246',
+ "simplus;": '\U00002A24',
+ "simrarr;": '\U00002972',
+ "slarr;": '\U00002190',
+ "smallsetminus;": '\U00002216',
+ "smashp;": '\U00002A33',
+ "smeparsl;": '\U000029E4',
+ "smid;": '\U00002223',
+ "smile;": '\U00002323',
+ "smt;": '\U00002AAA',
+ "smte;": '\U00002AAC',
+ "softcy;": '\U0000044C',
+ "sol;": '\U0000002F',
+ "solb;": '\U000029C4',
+ "solbar;": '\U0000233F',
+ "sopf;": '\U0001D564',
+ "spades;": '\U00002660',
+ "spadesuit;": '\U00002660',
+ "spar;": '\U00002225',
+ "sqcap;": '\U00002293',
+ "sqcup;": '\U00002294',
+ "sqsub;": '\U0000228F',
+ "sqsube;": '\U00002291',
+ "sqsubset;": '\U0000228F',
+ "sqsubseteq;": '\U00002291',
+ "sqsup;": '\U00002290',
+ "sqsupe;": '\U00002292',
+ "sqsupset;": '\U00002290',
+ "sqsupseteq;": '\U00002292',
+ "squ;": '\U000025A1',
+ "square;": '\U000025A1',
+ "squarf;": '\U000025AA',
+ "squf;": '\U000025AA',
+ "srarr;": '\U00002192',
+ "sscr;": '\U0001D4C8',
+ "ssetmn;": '\U00002216',
+ "ssmile;": '\U00002323',
+ "sstarf;": '\U000022C6',
+ "star;": '\U00002606',
+ "starf;": '\U00002605',
+ "straightepsilon;": '\U000003F5',
+ "straightphi;": '\U000003D5',
+ "strns;": '\U000000AF',
+ "sub;": '\U00002282',
+ "subE;": '\U00002AC5',
+ "subdot;": '\U00002ABD',
+ "sube;": '\U00002286',
+ "subedot;": '\U00002AC3',
+ "submult;": '\U00002AC1',
+ "subnE;": '\U00002ACB',
+ "subne;": '\U0000228A',
+ "subplus;": '\U00002ABF',
+ "subrarr;": '\U00002979',
+ "subset;": '\U00002282',
+ "subseteq;": '\U00002286',
+ "subseteqq;": '\U00002AC5',
+ "subsetneq;": '\U0000228A',
+ "subsetneqq;": '\U00002ACB',
+ "subsim;": '\U00002AC7',
+ "subsub;": '\U00002AD5',
+ "subsup;": '\U00002AD3',
+ "succ;": '\U0000227B',
+ "succapprox;": '\U00002AB8',
+ "succcurlyeq;": '\U0000227D',
+ "succeq;": '\U00002AB0',
+ "succnapprox;": '\U00002ABA',
+ "succneqq;": '\U00002AB6',
+ "succnsim;": '\U000022E9',
+ "succsim;": '\U0000227F',
+ "sum;": '\U00002211',
+ "sung;": '\U0000266A',
+ "sup;": '\U00002283',
+ "sup1;": '\U000000B9',
+ "sup2;": '\U000000B2',
+ "sup3;": '\U000000B3',
+ "supE;": '\U00002AC6',
+ "supdot;": '\U00002ABE',
+ "supdsub;": '\U00002AD8',
+ "supe;": '\U00002287',
+ "supedot;": '\U00002AC4',
+ "suphsol;": '\U000027C9',
+ "suphsub;": '\U00002AD7',
+ "suplarr;": '\U0000297B',
+ "supmult;": '\U00002AC2',
+ "supnE;": '\U00002ACC',
+ "supne;": '\U0000228B',
+ "supplus;": '\U00002AC0',
+ "supset;": '\U00002283',
+ "supseteq;": '\U00002287',
+ "supseteqq;": '\U00002AC6',
+ "supsetneq;": '\U0000228B',
+ "supsetneqq;": '\U00002ACC',
+ "supsim;": '\U00002AC8',
+ "supsub;": '\U00002AD4',
+ "supsup;": '\U00002AD6',
+ "swArr;": '\U000021D9',
+ "swarhk;": '\U00002926',
+ "swarr;": '\U00002199',
+ "swarrow;": '\U00002199',
+ "swnwar;": '\U0000292A',
+ "szlig;": '\U000000DF',
+ "target;": '\U00002316',
+ "tau;": '\U000003C4',
+ "tbrk;": '\U000023B4',
+ "tcaron;": '\U00000165',
+ "tcedil;": '\U00000163',
+ "tcy;": '\U00000442',
+ "tdot;": '\U000020DB',
+ "telrec;": '\U00002315',
+ "tfr;": '\U0001D531',
+ "there4;": '\U00002234',
+ "therefore;": '\U00002234',
+ "theta;": '\U000003B8',
+ "thetasym;": '\U000003D1',
+ "thetav;": '\U000003D1',
+ "thickapprox;": '\U00002248',
+ "thicksim;": '\U0000223C',
+ "thinsp;": '\U00002009',
+ "thkap;": '\U00002248',
+ "thksim;": '\U0000223C',
+ "thorn;": '\U000000FE',
+ "tilde;": '\U000002DC',
+ "times;": '\U000000D7',
+ "timesb;": '\U000022A0',
+ "timesbar;": '\U00002A31',
+ "timesd;": '\U00002A30',
+ "tint;": '\U0000222D',
+ "toea;": '\U00002928',
+ "top;": '\U000022A4',
+ "topbot;": '\U00002336',
+ "topcir;": '\U00002AF1',
+ "topf;": '\U0001D565',
+ "topfork;": '\U00002ADA',
+ "tosa;": '\U00002929',
+ "tprime;": '\U00002034',
+ "trade;": '\U00002122',
+ "triangle;": '\U000025B5',
+ "triangledown;": '\U000025BF',
+ "triangleleft;": '\U000025C3',
+ "trianglelefteq;": '\U000022B4',
+ "triangleq;": '\U0000225C',
+ "triangleright;": '\U000025B9',
+ "trianglerighteq;": '\U000022B5',
+ "tridot;": '\U000025EC',
+ "trie;": '\U0000225C',
+ "triminus;": '\U00002A3A',
+ "triplus;": '\U00002A39',
+ "trisb;": '\U000029CD',
+ "tritime;": '\U00002A3B',
+ "trpezium;": '\U000023E2',
+ "tscr;": '\U0001D4C9',
+ "tscy;": '\U00000446',
+ "tshcy;": '\U0000045B',
+ "tstrok;": '\U00000167',
+ "twixt;": '\U0000226C',
+ "twoheadleftarrow;": '\U0000219E',
+ "twoheadrightarrow;": '\U000021A0',
+ "uArr;": '\U000021D1',
+ "uHar;": '\U00002963',
+ "uacute;": '\U000000FA',
+ "uarr;": '\U00002191',
+ "ubrcy;": '\U0000045E',
+ "ubreve;": '\U0000016D',
+ "ucirc;": '\U000000FB',
+ "ucy;": '\U00000443',
+ "udarr;": '\U000021C5',
+ "udblac;": '\U00000171',
+ "udhar;": '\U0000296E',
+ "ufisht;": '\U0000297E',
+ "ufr;": '\U0001D532',
+ "ugrave;": '\U000000F9',
+ "uharl;": '\U000021BF',
+ "uharr;": '\U000021BE',
+ "uhblk;": '\U00002580',
+ "ulcorn;": '\U0000231C',
+ "ulcorner;": '\U0000231C',
+ "ulcrop;": '\U0000230F',
+ "ultri;": '\U000025F8',
+ "umacr;": '\U0000016B',
+ "uml;": '\U000000A8',
+ "uogon;": '\U00000173',
+ "uopf;": '\U0001D566',
+ "uparrow;": '\U00002191',
+ "updownarrow;": '\U00002195',
+ "upharpoonleft;": '\U000021BF',
+ "upharpoonright;": '\U000021BE',
+ "uplus;": '\U0000228E',
+ "upsi;": '\U000003C5',
+ "upsih;": '\U000003D2',
+ "upsilon;": '\U000003C5',
+ "upuparrows;": '\U000021C8',
+ "urcorn;": '\U0000231D',
+ "urcorner;": '\U0000231D',
+ "urcrop;": '\U0000230E',
+ "uring;": '\U0000016F',
+ "urtri;": '\U000025F9',
+ "uscr;": '\U0001D4CA',
+ "utdot;": '\U000022F0',
+ "utilde;": '\U00000169',
+ "utri;": '\U000025B5',
+ "utrif;": '\U000025B4',
+ "uuarr;": '\U000021C8',
+ "uuml;": '\U000000FC',
+ "uwangle;": '\U000029A7',
+ "vArr;": '\U000021D5',
+ "vBar;": '\U00002AE8',
+ "vBarv;": '\U00002AE9',
+ "vDash;": '\U000022A8',
+ "vangrt;": '\U0000299C',
+ "varepsilon;": '\U000003F5',
+ "varkappa;": '\U000003F0',
+ "varnothing;": '\U00002205',
+ "varphi;": '\U000003D5',
+ "varpi;": '\U000003D6',
+ "varpropto;": '\U0000221D',
+ "varr;": '\U00002195',
+ "varrho;": '\U000003F1',
+ "varsigma;": '\U000003C2',
+ "vartheta;": '\U000003D1',
+ "vartriangleleft;": '\U000022B2',
+ "vartriangleright;": '\U000022B3',
+ "vcy;": '\U00000432',
+ "vdash;": '\U000022A2',
+ "vee;": '\U00002228',
+ "veebar;": '\U000022BB',
+ "veeeq;": '\U0000225A',
+ "vellip;": '\U000022EE',
+ "verbar;": '\U0000007C',
+ "vert;": '\U0000007C',
+ "vfr;": '\U0001D533',
+ "vltri;": '\U000022B2',
+ "vopf;": '\U0001D567',
+ "vprop;": '\U0000221D',
+ "vrtri;": '\U000022B3',
+ "vscr;": '\U0001D4CB',
+ "vzigzag;": '\U0000299A',
+ "wcirc;": '\U00000175',
+ "wedbar;": '\U00002A5F',
+ "wedge;": '\U00002227',
+ "wedgeq;": '\U00002259',
+ "weierp;": '\U00002118',
+ "wfr;": '\U0001D534',
+ "wopf;": '\U0001D568',
+ "wp;": '\U00002118',
+ "wr;": '\U00002240',
+ "wreath;": '\U00002240',
+ "wscr;": '\U0001D4CC',
+ "xcap;": '\U000022C2',
+ "xcirc;": '\U000025EF',
+ "xcup;": '\U000022C3',
+ "xdtri;": '\U000025BD',
+ "xfr;": '\U0001D535',
+ "xhArr;": '\U000027FA',
+ "xharr;": '\U000027F7',
+ "xi;": '\U000003BE',
+ "xlArr;": '\U000027F8',
+ "xlarr;": '\U000027F5',
+ "xmap;": '\U000027FC',
+ "xnis;": '\U000022FB',
+ "xodot;": '\U00002A00',
+ "xopf;": '\U0001D569',
+ "xoplus;": '\U00002A01',
+ "xotime;": '\U00002A02',
+ "xrArr;": '\U000027F9',
+ "xrarr;": '\U000027F6',
+ "xscr;": '\U0001D4CD',
+ "xsqcup;": '\U00002A06',
+ "xuplus;": '\U00002A04',
+ "xutri;": '\U000025B3',
+ "xvee;": '\U000022C1',
+ "xwedge;": '\U000022C0',
+ "yacute;": '\U000000FD',
+ "yacy;": '\U0000044F',
+ "ycirc;": '\U00000177',
+ "ycy;": '\U0000044B',
+ "yen;": '\U000000A5',
+ "yfr;": '\U0001D536',
+ "yicy;": '\U00000457',
+ "yopf;": '\U0001D56A',
+ "yscr;": '\U0001D4CE',
+ "yucy;": '\U0000044E',
+ "yuml;": '\U000000FF',
+ "zacute;": '\U0000017A',
+ "zcaron;": '\U0000017E',
+ "zcy;": '\U00000437',
+ "zdot;": '\U0000017C',
+ "zeetrf;": '\U00002128',
+ "zeta;": '\U000003B6',
+ "zfr;": '\U0001D537',
+ "zhcy;": '\U00000436',
+ "zigrarr;": '\U000021DD',
+ "zopf;": '\U0001D56B',
+ "zscr;": '\U0001D4CF',
+ "zwj;": '\U0000200D',
+ "zwnj;": '\U0000200C',
+ "AElig": '\U000000C6',
+ "AMP": '\U00000026',
+ "Aacute": '\U000000C1',
+ "Acirc": '\U000000C2',
+ "Agrave": '\U000000C0',
+ "Aring": '\U000000C5',
+ "Atilde": '\U000000C3',
+ "Auml": '\U000000C4',
+ "COPY": '\U000000A9',
+ "Ccedil": '\U000000C7',
+ "ETH": '\U000000D0',
+ "Eacute": '\U000000C9',
+ "Ecirc": '\U000000CA',
+ "Egrave": '\U000000C8',
+ "Euml": '\U000000CB',
+ "GT": '\U0000003E',
+ "Iacute": '\U000000CD',
+ "Icirc": '\U000000CE',
+ "Igrave": '\U000000CC',
+ "Iuml": '\U000000CF',
+ "LT": '\U0000003C',
+ "Ntilde": '\U000000D1',
+ "Oacute": '\U000000D3',
+ "Ocirc": '\U000000D4',
+ "Ograve": '\U000000D2',
+ "Oslash": '\U000000D8',
+ "Otilde": '\U000000D5',
+ "Ouml": '\U000000D6',
+ "QUOT": '\U00000022',
+ "REG": '\U000000AE',
+ "THORN": '\U000000DE',
+ "Uacute": '\U000000DA',
+ "Ucirc": '\U000000DB',
+ "Ugrave": '\U000000D9',
+ "Uuml": '\U000000DC',
+ "Yacute": '\U000000DD',
+ "aacute": '\U000000E1',
+ "acirc": '\U000000E2',
+ "acute": '\U000000B4',
+ "aelig": '\U000000E6',
+ "agrave": '\U000000E0',
+ "amp": '\U00000026',
+ "aring": '\U000000E5',
+ "atilde": '\U000000E3',
+ "auml": '\U000000E4',
+ "brvbar": '\U000000A6',
+ "ccedil": '\U000000E7',
+ "cedil": '\U000000B8',
+ "cent": '\U000000A2',
+ "copy": '\U000000A9',
+ "curren": '\U000000A4',
+ "deg": '\U000000B0',
+ "divide": '\U000000F7',
+ "eacute": '\U000000E9',
+ "ecirc": '\U000000EA',
+ "egrave": '\U000000E8',
+ "eth": '\U000000F0',
+ "euml": '\U000000EB',
+ "frac12": '\U000000BD',
+ "frac14": '\U000000BC',
+ "frac34": '\U000000BE',
+ "gt": '\U0000003E',
+ "iacute": '\U000000ED',
+ "icirc": '\U000000EE',
+ "iexcl": '\U000000A1',
+ "igrave": '\U000000EC',
+ "iquest": '\U000000BF',
+ "iuml": '\U000000EF',
+ "laquo": '\U000000AB',
+ "lt": '\U0000003C',
+ "macr": '\U000000AF',
+ "micro": '\U000000B5',
+ "middot": '\U000000B7',
+ "nbsp": '\U000000A0',
+ "not": '\U000000AC',
+ "ntilde": '\U000000F1',
+ "oacute": '\U000000F3',
+ "ocirc": '\U000000F4',
+ "ograve": '\U000000F2',
+ "ordf": '\U000000AA',
+ "ordm": '\U000000BA',
+ "oslash": '\U000000F8',
+ "otilde": '\U000000F5',
+ "ouml": '\U000000F6',
+ "para": '\U000000B6',
+ "plusmn": '\U000000B1',
+ "pound": '\U000000A3',
+ "quot": '\U00000022',
+ "raquo": '\U000000BB',
+ "reg": '\U000000AE',
+ "sect": '\U000000A7',
+ "shy": '\U000000AD',
+ "sup1": '\U000000B9',
+ "sup2": '\U000000B2',
+ "sup3": '\U000000B3',
+ "szlig": '\U000000DF',
+ "thorn": '\U000000FE',
+ "times": '\U000000D7',
+ "uacute": '\U000000FA',
+ "ucirc": '\U000000FB',
+ "ugrave": '\U000000F9',
+ "uml": '\U000000A8',
+ "uuml": '\U000000FC',
+ "yacute": '\U000000FD',
+ "yen": '\U000000A5',
+ "yuml": '\U000000FF',
+}
+
+// HTML entities that are two unicode codepoints.
+var entity2 = map[string][2]rune{
+ // TODO(nigeltao): Handle replacements that are wider than their names.
+ // "nLt;": {'\u226A', '\u20D2'},
+ // "nGt;": {'\u226B', '\u20D2'},
+ "NotEqualTilde;": {'\u2242', '\u0338'},
+ "NotGreaterFullEqual;": {'\u2267', '\u0338'},
+ "NotGreaterGreater;": {'\u226B', '\u0338'},
+ "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
+ "NotHumpDownHump;": {'\u224E', '\u0338'},
+ "NotHumpEqual;": {'\u224F', '\u0338'},
+ "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
+ "NotLessLess;": {'\u226A', '\u0338'},
+ "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
+ "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
+ "NotNestedLessLess;": {'\u2AA1', '\u0338'},
+ "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
+ "NotRightTriangleBar;": {'\u29D0', '\u0338'},
+ "NotSquareSubset;": {'\u228F', '\u0338'},
+ "NotSquareSuperset;": {'\u2290', '\u0338'},
+ "NotSubset;": {'\u2282', '\u20D2'},
+ "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
+ "NotSucceedsTilde;": {'\u227F', '\u0338'},
+ "NotSuperset;": {'\u2283', '\u20D2'},
+ "ThickSpace;": {'\u205F', '\u200A'},
+ "acE;": {'\u223E', '\u0333'},
+ "bne;": {'\u003D', '\u20E5'},
+ "bnequiv;": {'\u2261', '\u20E5'},
+ "caps;": {'\u2229', '\uFE00'},
+ "cups;": {'\u222A', '\uFE00'},
+ "fjlig;": {'\u0066', '\u006A'},
+ "gesl;": {'\u22DB', '\uFE00'},
+ "gvertneqq;": {'\u2269', '\uFE00'},
+ "gvnE;": {'\u2269', '\uFE00'},
+ "lates;": {'\u2AAD', '\uFE00'},
+ "lesg;": {'\u22DA', '\uFE00'},
+ "lvertneqq;": {'\u2268', '\uFE00'},
+ "lvnE;": {'\u2268', '\uFE00'},
+ "nGg;": {'\u22D9', '\u0338'},
+ "nGtv;": {'\u226B', '\u0338'},
+ "nLl;": {'\u22D8', '\u0338'},
+ "nLtv;": {'\u226A', '\u0338'},
+ "nang;": {'\u2220', '\u20D2'},
+ "napE;": {'\u2A70', '\u0338'},
+ "napid;": {'\u224B', '\u0338'},
+ "nbump;": {'\u224E', '\u0338'},
+ "nbumpe;": {'\u224F', '\u0338'},
+ "ncongdot;": {'\u2A6D', '\u0338'},
+ "nedot;": {'\u2250', '\u0338'},
+ "nesim;": {'\u2242', '\u0338'},
+ "ngE;": {'\u2267', '\u0338'},
+ "ngeqq;": {'\u2267', '\u0338'},
+ "ngeqslant;": {'\u2A7E', '\u0338'},
+ "nges;": {'\u2A7E', '\u0338'},
+ "nlE;": {'\u2266', '\u0338'},
+ "nleqq;": {'\u2266', '\u0338'},
+ "nleqslant;": {'\u2A7D', '\u0338'},
+ "nles;": {'\u2A7D', '\u0338'},
+ "notinE;": {'\u22F9', '\u0338'},
+ "notindot;": {'\u22F5', '\u0338'},
+ "nparsl;": {'\u2AFD', '\u20E5'},
+ "npart;": {'\u2202', '\u0338'},
+ "npre;": {'\u2AAF', '\u0338'},
+ "npreceq;": {'\u2AAF', '\u0338'},
+ "nrarrc;": {'\u2933', '\u0338'},
+ "nrarrw;": {'\u219D', '\u0338'},
+ "nsce;": {'\u2AB0', '\u0338'},
+ "nsubE;": {'\u2AC5', '\u0338'},
+ "nsubset;": {'\u2282', '\u20D2'},
+ "nsubseteqq;": {'\u2AC5', '\u0338'},
+ "nsucceq;": {'\u2AB0', '\u0338'},
+ "nsupE;": {'\u2AC6', '\u0338'},
+ "nsupset;": {'\u2283', '\u20D2'},
+ "nsupseteqq;": {'\u2AC6', '\u0338'},
+ "nvap;": {'\u224D', '\u20D2'},
+ "nvge;": {'\u2265', '\u20D2'},
+ "nvgt;": {'\u003E', '\u20D2'},
+ "nvle;": {'\u2264', '\u20D2'},
+ "nvlt;": {'\u003C', '\u20D2'},
+ "nvltrie;": {'\u22B4', '\u20D2'},
+ "nvrtrie;": {'\u22B5', '\u20D2'},
+ "nvsim;": {'\u223C', '\u20D2'},
+ "race;": {'\u223D', '\u0331'},
+ "smtes;": {'\u2AAC', '\uFE00'},
+ "sqcaps;": {'\u2293', '\uFE00'},
+ "sqcups;": {'\u2294', '\uFE00'},
+ "varsubsetneq;": {'\u228A', '\uFE00'},
+ "varsubsetneqq;": {'\u2ACB', '\uFE00'},
+ "varsupsetneq;": {'\u228B', '\uFE00'},
+ "varsupsetneqq;": {'\u2ACC', '\uFE00'},
+ "vnsub;": {'\u2282', '\u20D2'},
+ "vnsup;": {'\u2283', '\u20D2'},
+ "vsubnE;": {'\u2ACB', '\uFE00'},
+ "vsubne;": {'\u228A', '\uFE00'},
+ "vsupnE;": {'\u2ACC', '\uFE00'},
+ "vsupne;": {'\u228B', '\uFE00'},
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go
new file mode 100644
index 000000000000..12f227370625
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go
@@ -0,0 +1,339 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "strings"
+ "unicode/utf8"
+)
+
+// These replacements permit compatibility with old numeric entities that
+// assumed Windows-1252 encoding.
+// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
+var replacementTable = [...]rune{
+ '\u20AC', // First entry is what 0x80 should be replaced with.
+ '\u0081',
+ '\u201A',
+ '\u0192',
+ '\u201E',
+ '\u2026',
+ '\u2020',
+ '\u2021',
+ '\u02C6',
+ '\u2030',
+ '\u0160',
+ '\u2039',
+ '\u0152',
+ '\u008D',
+ '\u017D',
+ '\u008F',
+ '\u0090',
+ '\u2018',
+ '\u2019',
+ '\u201C',
+ '\u201D',
+ '\u2022',
+ '\u2013',
+ '\u2014',
+ '\u02DC',
+ '\u2122',
+ '\u0161',
+ '\u203A',
+ '\u0153',
+ '\u009D',
+ '\u017E',
+ '\u0178', // Last entry is 0x9F.
+ // 0x00->'\uFFFD' is handled programmatically.
+ // 0x0D->'\u000D' is a no-op.
+}
+
+// unescapeEntity reads an entity like "<" from b[src:] and writes the
+// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
+// Precondition: b[src] == '&' && dst <= src.
+// attribute should be true if parsing an attribute value.
+func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
+ // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
+
+ // i starts at 1 because we already know that s[0] == '&'.
+ i, s := 1, b[src:]
+
+ if len(s) <= 1 {
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if s[i] == '#' {
+ if len(s) <= 3 { // We need to have at least ".".
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+ i++
+ c := s[i]
+ hex := false
+ if c == 'x' || c == 'X' {
+ hex = true
+ i++
+ }
+
+ x := '\x00'
+ for i < len(s) {
+ c = s[i]
+ i++
+ if hex {
+ if '0' <= c && c <= '9' {
+ x = 16*x + rune(c) - '0'
+ continue
+ } else if 'a' <= c && c <= 'f' {
+ x = 16*x + rune(c) - 'a' + 10
+ continue
+ } else if 'A' <= c && c <= 'F' {
+ x = 16*x + rune(c) - 'A' + 10
+ continue
+ }
+ } else if '0' <= c && c <= '9' {
+ x = 10*x + rune(c) - '0'
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ if i <= 3 { // No characters matched.
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if 0x80 <= x && x <= 0x9F {
+ // Replace characters from Windows-1252 with UTF-8 equivalents.
+ x = replacementTable[x-0x80]
+ } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
+ // Replace invalid characters with the replacement character.
+ x = '\uFFFD'
+ }
+
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ }
+
+ // Consume the maximum number of characters possible, with the
+ // consumed characters matching one of the named references.
+
+ for i < len(s) {
+ c := s[i]
+ i++
+ // Lower-cased characters are more common in entities, so we check for them first.
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ entityName := string(s[1:i])
+ if entityName == "" {
+ // No-op.
+ } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
+ // No-op.
+ } else if x := entity[entityName]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ } else if x := entity2[entityName]; x[0] != 0 {
+ dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
+ return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ } else if !attribute {
+ maxLen := len(entityName) - 1
+ if maxLen > longestEntityWithoutSemicolon {
+ maxLen = longestEntityWithoutSemicolon
+ }
+ for j := maxLen; j > 1; j-- {
+ if x := entity[entityName[:j]]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
+ }
+ }
+ }
+
+ dst1, src1 = dst+i, src+i
+ copy(b[dst:dst1], b[src:src1])
+ return dst1, src1
+}
+
+// unescape unescapes b's entities in-place, so that "a<b" becomes "a' byte that, per above, we'd like to avoid escaping unless we have to.
+//
+// Studying the summary table (and T actions in its '>' column) closely, we
+// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
+// start of the comment data. State 52 is after a '!'. The other three states
+// are after a '-'.
+//
+// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
+// - The '>' is after a '!' or '-' (in the unescaped data) or
+// - The '>' is at the start of the comment data (after the opening ""); err != nil {
+ return err
+ }
+ return nil
+ case DoctypeNode:
+ if _, err := w.WriteString("')
+ case RawNode:
+ _, err := w.WriteString(n.Data)
+ return err
+ default:
+ return errors.New("html: unknown node type")
+ }
+
+ // Render the opening tag.
+ if err := w.WriteByte('<'); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(n.Data); err != nil {
+ return err
+ }
+ for _, a := range n.Attr {
+ if err := w.WriteByte(' '); err != nil {
+ return err
+ }
+ if a.Namespace != "" {
+ if _, err := w.WriteString(a.Namespace); err != nil {
+ return err
+ }
+ if err := w.WriteByte(':'); err != nil {
+ return err
+ }
+ }
+ if _, err := w.WriteString(a.Key); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(`="`); err != nil {
+ return err
+ }
+ if err := escape(w, a.Val); err != nil {
+ return err
+ }
+ if err := w.WriteByte('"'); err != nil {
+ return err
+ }
+ }
+ if voidElements[n.Data] {
+ if n.FirstChild != nil {
+ return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
+ }
+ _, err := w.WriteString("/>")
+ return err
+ }
+ if err := w.WriteByte('>'); err != nil {
+ return err
+ }
+
+ // Add initial newline where there is danger of a newline being ignored.
+ if c := n.FirstChild; c != nil && c.Type == TextNode && strings.HasPrefix(c.Data, "\n") {
+ switch n.Data {
+ case "pre", "listing", "textarea":
+ if err := w.WriteByte('\n'); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Render any child nodes
+ if childTextNodesAreLiteral(n) {
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if c.Type == TextNode {
+ if _, err := w.WriteString(c.Data); err != nil {
+ return err
+ }
+ } else {
+ if err := render1(w, c); err != nil {
+ return err
+ }
+ }
+ }
+ if n.Data == "plaintext" {
+ // Don't render anything else. must be the
+ // last element in the file, with no closing tag.
+ return plaintextAbort
+ }
+ } else {
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if err := render1(w, c); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Render the closing tag.
+ if _, err := w.WriteString(""); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(n.Data); err != nil {
+ return err
+ }
+ return w.WriteByte('>')
+}
+
+func childTextNodesAreLiteral(n *Node) bool {
+ // Per WHATWG HTML 13.3, if the parent of the current node is a style,
+ // script, xmp, iframe, noembed, noframes, or plaintext element, and the
+ // current node is a text node, append the value of the node's data
+ // literally. The specification is not explicit about it, but we only
+ // enforce this if we are in the HTML namespace (i.e. when the namespace is
+ // "").
+ // NOTE: we also always include noscript elements, although the
+ // specification states that they should only be rendered as such if
+ // scripting is enabled for the node (which is not something we track).
+ if n.Namespace != "" {
+ return false
+ }
+ switch n.Data {
+ case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
+ return true
+ default:
+ return false
+ }
+}
+
+// writeQuoted writes s to w surrounded by quotes. Normally it will use double
+// quotes, but if s contains a double quote, it will use single quotes.
+// It is used for writing the identifiers in a doctype declaration.
+// In valid HTML, they can't contain both types of quotes.
+func writeQuoted(w writer, s string) error {
+ var q byte = '"'
+ if strings.Contains(s, `"`) {
+ q = '\''
+ }
+ if err := w.WriteByte(q); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(s); err != nil {
+ return err
+ }
+ if err := w.WriteByte(q); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Section 12.1.2, "Elements", gives this list of void elements. Void elements
+// are those that can't have any contents.
+var voidElements = map[string]bool{
+ "area": true,
+ "base": true,
+ "br": true,
+ "col": true,
+ "embed": true,
+ "hr": true,
+ "img": true,
+ "input": true,
+ "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
+ "link": true,
+ "meta": true,
+ "param": true,
+ "source": true,
+ "track": true,
+ "wbr": true,
+}
diff --git a/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/token.go b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/token.go
new file mode 100644
index 000000000000..6598c1f7b320
--- /dev/null
+++ b/go/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/token.go
@@ -0,0 +1,1286 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strconv"
+ "strings"
+
+ "golang.org/x/net/html/atom"
+)
+
+// A TokenType is the type of a Token.
+type TokenType uint32
+
+const (
+ // ErrorToken means that an error occurred during tokenization.
+ ErrorToken TokenType = iota
+ // TextToken means a text node.
+ TextToken
+ // A StartTagToken looks like .
+ StartTagToken
+ // An EndTagToken looks like .
+ EndTagToken
+ // A SelfClosingTagToken tag looks like .
+ SelfClosingTagToken
+ // A CommentToken looks like .
+ CommentToken
+ // A DoctypeToken looks like
+ DoctypeToken
+)
+
+// ErrBufferExceeded means that the buffering limit was exceeded.
+var ErrBufferExceeded = errors.New("max buffer exceeded")
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+ switch t {
+ case ErrorToken:
+ return "Error"
+ case TextToken:
+ return "Text"
+ case StartTagToken:
+ return "StartTag"
+ case EndTagToken:
+ return "EndTag"
+ case SelfClosingTagToken:
+ return "SelfClosingTag"
+ case CommentToken:
+ return "Comment"
+ case DoctypeToken:
+ return "Doctype"
+ }
+ return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute namespace-key-value triple. Namespace is
+// non-empty for foreign attributes like xlink, Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a"
+ case EndTagToken:
+ return "" + t.tagString() + ">"
+ case SelfClosingTagToken:
+ return "<" + t.tagString() + "/>"
+ case CommentToken:
+ return ""
+ case DoctypeToken:
+ return ""
+ }
+ return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// span is a range of bytes in a Tokenizer's buffer. The start is inclusive,
+// the end is exclusive.
+type span struct {
+ start, end int
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+ // r is the source of the HTML text.
+ r io.Reader
+ // tt is the TokenType of the current token.
+ tt TokenType
+ // err is the first error encountered during tokenization. It is possible
+ // for tt != Error && err != nil to hold: this means that Next returned a
+ // valid token but the subsequent Next call will return an error token.
+ // For example, if the HTML text input was just "plain", then the first
+ // Next call would set z.err to io.EOF but return a TextToken, and all
+ // subsequent Next calls would return an ErrorToken.
+ // err is never reset. Once it becomes non-nil, it stays non-nil.
+ err error
+ // readErr is the error returned by the io.Reader r. It is separate from
+ // err because it is valid for an io.Reader to return (n int, err1 error)
+ // such that n > 0 && err1 != nil, and callers should always process the
+ // n > 0 bytes before considering the error err1.
+ readErr error
+ // buf[raw.start:raw.end] holds the raw bytes of the current token.
+ // buf[raw.end:] is buffered input that will yield future tokens.
+ raw span
+ buf []byte
+ // maxBuf limits the data buffered in buf. A value of 0 means unlimited.
+ maxBuf int
+ // buf[data.start:data.end] holds the raw bytes of the current token's data:
+ // a text token's text, a tag token's tag name, etc.
+ data span
+ // pendingAttr is the attribute key and value currently being tokenized.
+ // When complete, pendingAttr is pushed onto attr. nAttrReturned is
+ // incremented on each call to TagAttr.
+ pendingAttr [2]span
+ attr [][2]span
+ nAttrReturned int
+ // rawTag is the "script" in "" that closes the next token. If
+ // non-empty, the subsequent call to Next will return a raw or RCDATA text
+ // token: one that treats "
" as text instead of an element.
+ // rawTag's contents are lower-cased.
+ rawTag string
+ // textIsRaw is whether the current text token's data is not escaped.
+ textIsRaw bool
+ // convertNUL is whether NUL bytes in the current token's data should
+ // be converted into \ufffd replacement characters.
+ convertNUL bool
+ // allowCDATA is whether CDATA sections are allowed in the current context.
+ allowCDATA bool
+}
+
+// AllowCDATA sets whether or not the tokenizer recognizes as
+// the text "foo". The default value is false, which means to recognize it as
+// a bogus comment "" instead.
+//
+// Strictly speaking, an HTML5 compliant tokenizer should allow CDATA if and
+// only if tokenizing foreign content, such as MathML and SVG. However,
+// tracking foreign-contentness is difficult to do purely in the tokenizer,
+// as opposed to the parser, due to HTML integration points: an