shithub: mycel

Download patch

ref: bcce6fc26675a60c9fc0a4cf41f76f6258c789bc
parent: 2b0707b83858f8fecb4de49776126c482abfce34
author: Philip Silva <philip.silva@protonmail.com>
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)
+		}
+	}
+}
+