ref: bcce6fc26675a60c9fc0a4cf41f76f6258c789bc
parent: 2b0707b83858f8fecb4de49776126c482abfce34
author: Philip Silva <[email protected]>
date: Sun Jan 31 09:53:48 EST 2021
add missing quotes in svg xml attrs
--- a/img/img.go
+++ b/img/img.go
@@ -34,14 +34,15 @@
parts := strings.Split(addr, ",")
var ctStr string
+
if strings.Contains(parts[0], ";") {
header := strings.Split(parts[0], ";")
- ctStr = header[1]
+ ctStr = header[0]
} else {
ctStr = parts[0]
}
if ct, err = opossum.NewContentType(ctStr, nil); err != nil {
- return nil, ct, err
+ return nil, ct, fmt.Errorf("content type: %v: %w", ctStr, err)
}
if strings.Contains(addr, "base64") {
@@ -62,10 +63,100 @@
return
}
+func quoteAttrsInTag(s string) string {
+ eqs := make([]int, 0, 5)
+ offset := 0
+
+ for {
+ i := strings.Index(s[offset:], "=")
+ if i >= 0 {
+ eqs = append(eqs, i+offset)
+ offset += i + 1
+ } else {
+ break
+ }
+ }
+
+ keyStarts := make([]int, len(eqs))
+ for i, eq := range eqs {
+ j := strings.LastIndex(s[:eq], " ")
+ keyStarts[i] = j
+ }
+
+ valueEnds := make([]int, len(keyStarts))
+ for i, _ := range keyStarts {
+ if i+1 < len(keyStarts) {
+ valueEnds[i] = keyStarts[i+1]
+ } else {
+ off := eqs[i]
+ jj := strings.Index(s[off:], ">")
+ valueEnds[i] = jj+off
+ if s[valueEnds[i]-1:valueEnds[i]] == "/" {
+ valueEnds[i]--
+ }
+ }
+ }
+
+ for i := len(eqs) - 1; i >= 0; i-- {
+ s = s[:valueEnds[i]] + `"` + s[valueEnds[i]:]
+ s = s[:eqs[i]+1] + `"` + s[eqs[i]+1:]
+ }
+
+ return s
+}
+
+func quoteAttrs(s string) string {
+ if strings.Contains(s, `"`) {
+ return s
+ }
+
+ tagStarts := make([]int, 0, 5)
+ tagEnds := make([]int, 0, 5)
+
+ offset := 0
+ for {
+ i := strings.Index(s[offset:], "<")
+ if i >= 0 {
+ tagStarts = append(tagStarts, i+offset)
+ offset += i + 1
+ } else {
+ break
+ }
+ }
+
+ offset = 0
+ for {
+ i := strings.Index(s[offset:], ">")
+ if i >= 0 {
+ tagEnds = append(tagEnds, i+offset)
+ offset += i + 1
+ } else {
+ break
+ }
+ }
+
+ if len(tagStarts) != len(tagEnds) {
+ log.Errorf("quoteAttrs: len(tagStarts) != len(tagEnds)")
+ return s
+ }
+
+ for i := len(tagStarts) - 1; i >= 0; i-- {
+ from := tagStarts[i]
+ to := tagEnds[i] + 1
+ q := quoteAttrsInTag(s[from:to])
+ s = s[:tagStarts[i]] + q + s[tagEnds[i]+1:]
+ }
+
+ return s
+}
+
// Svg returns the svg+xml encoded as jpg with the sizing defined in
// viewbox unless w and h != 0
func Svg(data string, w, h int) (bs []byte, err error) {
data = strings.ReplaceAll(data, "currentColor", "black")
+ data = strings.ReplaceAll(data, "inherit", "black")
+ data = quoteAttrs(data)
+
r := bytes.NewReader([]byte(data))
icon, err := oksvg.ReadIconStream(r)
if err != nil {
--- a/img/img_test.go
+++ b/img/img_test.go
@@ -6,6 +6,10 @@
)
func init() {
+ f := false
+ logger.Quiet = &f
+ logger.Init()
+ log = &logger.Logger{Debug: true}
SetLogger(&logger.Logger{})
}
@@ -15,6 +19,7 @@
// svg examples from github.com/tigt/mini-svg-data-uri (MIT License, (c) 2018 Taylor Hunt)
"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' %3e%3cpath d='M22 38V51L32 32l19-19v12C44 26 43 10 38 0 52 15 49 39 22 38z'/%3e %3c/svg%3e",
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MCA1MCI+PHBhdGggZD0iTTIyIDM4VjUxTDMyIDMybDE5LTE5djEyQzQ0IDI2IDQzIDEwIDM4IDAgNTIgMTUgNDkgMzkgMjIgMzh6Ii8+PC9zdmc+",
+ `data:image/svg+xml;charset=utf-8,%3Csvg xmlns=http://www.w3.org/2000/svg%3E%3C/svg%3E`,
}
for _, src := range srcs {
@@ -37,3 +42,33 @@
t.Fatalf(err.Error())
}
}
+
+func TestSvgUnquoted(t *testing.T) {
+ xml := `
+ <svg fill=currentColor height=24 viewBox=0 0 24 24 width=24>
+ <g fill=green></g>
+ <g fill=yellow/>
+ </svg>
+ `
+ xml=`<svg xmlns=http://www.w3.org/2000/svg viewBox=0 0 37 37 fill=#000000><path class=border fill=blue stroke=green/></svg>`
+
+ _, err := Svg(xml, 0, 0)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+}
+
+func TestQuoteAttrsInTag(t *testing.T) {
+ cases := map[string]string{
+ `<svg xmlns=http://www.w3.org/2000/svg viewBox=0 0 37 37 fill=#000000>`: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 37" fill="#000000">`,
+ `<path class=border fill=yellow stroke=green d=M29.2 21.3 0z/>`: `<path class="border" fill="yellow" stroke="green" d="M29.2 21.3 0z"/>`,
+ `</svg>`: `</svg>`,
+ }
+ for c, exp := range cases {
+ q := quoteAttrsInTag(c)
+ if q != exp {
+ t.Errorf("%+v != %+v", q, exp)
+ }
+ }
+}
+