code.gitea.io/gitea@v1.22.3/modules/svg/processor.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package svg 5 6 import ( 7 "bytes" 8 "fmt" 9 "regexp" 10 "sync" 11 ) 12 13 type normalizeVarsStruct struct { 14 reXMLDoc, 15 reComment, 16 reAttrXMLNs, 17 reAttrSize, 18 reAttrClassPrefix *regexp.Regexp 19 } 20 21 var ( 22 normalizeVars *normalizeVarsStruct 23 normalizeVarsOnce sync.Once 24 ) 25 26 // Normalize normalizes the SVG content: set default width/height, remove unnecessary tags/attributes 27 // It's designed to work with valid SVG content. For invalid SVG content, the returned content is not guaranteed. 28 func Normalize(data []byte, size int) []byte { 29 normalizeVarsOnce.Do(func() { 30 normalizeVars = &normalizeVarsStruct{ 31 reXMLDoc: regexp.MustCompile(`(?s)<\?xml.*?>`), 32 reComment: regexp.MustCompile(`(?s)<!--.*?-->`), 33 34 reAttrXMLNs: regexp.MustCompile(`(?s)\s+xmlns\s*=\s*"[^"]*"`), 35 reAttrSize: regexp.MustCompile(`(?s)\s+(width|height)\s*=\s*"[^"]+"`), 36 reAttrClassPrefix: regexp.MustCompile(`(?s)\s+class\s*=\s*"`), 37 } 38 }) 39 data = normalizeVars.reXMLDoc.ReplaceAll(data, nil) 40 data = normalizeVars.reComment.ReplaceAll(data, nil) 41 42 data = bytes.TrimSpace(data) 43 svgTag, svgRemaining, ok := bytes.Cut(data, []byte(">")) 44 if !ok || !bytes.HasPrefix(svgTag, []byte(`<svg`)) { 45 return data 46 } 47 normalized := bytes.Clone(svgTag) 48 normalized = normalizeVars.reAttrXMLNs.ReplaceAll(normalized, nil) 49 normalized = normalizeVars.reAttrSize.ReplaceAll(normalized, nil) 50 normalized = normalizeVars.reAttrClassPrefix.ReplaceAll(normalized, []byte(` class="`)) 51 normalized = bytes.TrimSpace(normalized) 52 normalized = fmt.Appendf(normalized, ` width="%d" height="%d"`, size, size) 53 if !bytes.Contains(normalized, []byte(` class="`)) { 54 normalized = append(normalized, ` class="svg"`...) 55 } 56 normalized = append(normalized, '>') 57 normalized = append(normalized, svgRemaining...) 58 return normalized 59 }