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  }