package d2svgimport

import (
	
	
	
	
)

const (
	dublinCoreNamespace     = "http://purl.org/dc/elements/1.1/"
	creativeCommonsNS       = "http://creativecommons.org/ns#"
	rdfNamespace            = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	sodipodiNamespace       = "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
	inkscapeNamespace       = "http://www.inkscape.org/namespaces/inkscape"
	stillImageResource      = "http://purl.org/dc/dcmitype/StillImage"
	metadataFormatMediaType = "image/svg+xml"
)

var inkscapeMetadataAttributes = map[string]map[string]struct{}{
	"svg": {
		"export-filename": {}, "export-xdpi": {}, "export-ydpi": {}, "version": {},
	},
	"g": {
		"groupmode": {}, "label": {},
	},
	"path": {
		"connector-curvature": {}, "export-filename": {}, "export-xdpi": {}, "export-ydpi": {},
	},
	"sodipodi:namedview": {
		"current-layer": {}, "cx": {}, "cy": {}, "document-units": {}, "pageopacity": {},
		"pageshadow": {}, "snap-global": {}, "window-height": {}, "window-maximized": {},
		"window-width": {}, "window-x": {}, "window-y": {}, "zoom": {},
	},
}

var sodipodiMetadataAttributes = map[string]map[string]struct{}{
	"svg":  {"docname": {}},
	"path": {"nodetypes": {}},
}

func isNonRenderingElement( string) bool {
	switch  {
	case "title", "metadata", "rdf:RDF", "cc:Work", "dc:format", "dc:type", "sodipodi:namedview":
		return true
	default:
		return false
	}
}

func hasRenderingChildren( *svgElement) bool {
	for ,  := range .children {
		if !isNonRenderingElement(.name) {
			return true
		}
	}
	return false
}

// validateNonRenderingTree constrains ignored XML to the exact non-painting
// structures found in the renderer corpus. Recognized namespace names are not
// enough by themselves: foreign elements in any other position remain errors.
func ( *svgImporter) ( *svgElement) error {
	type  struct {
		 *svgElement
		  *svgElement
	}
	 := []{{: }}
	for len() != 0 {
		if  := .ctx.Err();  != nil {
			return 
		}
		 := [len()-1]
		 = [:len()-1]
		 := .
		 := .

		if  != nil {
			switch .name {
			case "metadata":
				if .name != "rdf:RDF" {
					return .errorf("element <metadata> has unsupported child <%s>", displayXMLName(.name))
				}
			case "rdf:RDF":
				if .name != "cc:Work" {
					return .errorf("element <rdf:RDF> has unsupported child <%s>", displayXMLName(.name))
				}
			case "cc:Work":
				if .name != "dc:format" && .name != "dc:type" {
					return .errorf("element <cc:Work> has unsupported child <%s>", displayXMLName(.name))
				}
			case "title", "dc:format", "dc:type", "sodipodi:namedview":
				return .errorf("non-rendering element <%s> cannot contain child elements", .name)
			}
		}

		switch .name {
		case "metadata", "sodipodi:namedview":
			if  !=  {
				return .errorf("non-rendering element <%s> must be a direct child of the root <svg>", .name)
			}
		case "rdf:RDF":
			if  == nil || .name != "metadata" {
				return .errorf("element <rdf:RDF> is only supported inside <metadata>")
			}
		case "cc:Work":
			if  == nil || .name != "rdf:RDF" {
				return .errorf("element <cc:Work> is only supported inside <rdf:RDF>")
			}
		case "dc:format", "dc:type":
			if  == nil || .name != "cc:Work" {
				return .errorf("element <%s> is only supported inside <cc:Work>", .name)
			}
		}
		if .name == "dc:format" {
			,  := trimSVGSpace(.ctx, string(.text))
			if  != nil {
				return 
			}
			if  != metadataFormatMediaType {
				return .errorf("element <dc:format> has unsupported metadata text")
			}
		}
		for  := len(.children) - 1;  >= 0; -- {
			 = append(, {: .children[], : })
		}
	}
	 := []*svgElement{}
	for len() != 0 {
		if  := .ctx.Err();  != nil {
			return 
		}
		 := [len()-1]
		 = [:len()-1]
		if  := .validateMetadataCardinality();  != nil {
			return 
		}
		 = append(, .children...)
	}
	return nil
}

func ( *svgImporter) ( *svgElement) error {
	switch .name {
	case "metadata":
		if len(.children) != 1 || .children[0].name != "rdf:RDF" {
			return .errorf("element <metadata> must contain exactly one <rdf:RDF>")
		}
	case "rdf:RDF":
		if len(.children) != 1 || .children[0].name != "cc:Work" {
			return .errorf("element <rdf:RDF> must contain exactly one <cc:Work>")
		}
	case "cc:Work":
		if len(.children) != 2 {
			return .errorf("element <cc:Work> must contain exactly one <dc:format> and one <dc:type>")
		}
		,  := 0, 0
		for ,  := range .children {
			switch .name {
			case "dc:format":
				++
			case "dc:type":
				++
			}
		}
		if  != 1 ||  != 1 {
			return .errorf("element <cc:Work> must contain exactly one <dc:format> and one <dc:type>")
		}
	}
	return nil
}

func ( *svgImporter) ( *svgElement,  []byte) error {
	const  = 4096
	for len() != 0 {
		if  := .ctx.Err();  != nil {
			return 
		}
		 := len()
		if  >  {
			 = 
		}
		if  > .limits.MaxBytes-len(.text) {
			return .errorf("metadata text exceeds byte limit %d", .limits.MaxBytes)
		}
		.text = append(.text, [:]...)
		 = [:]
	}
	return .ctx.Err()
}

func checkpointXMLText( context.Context,  []byte) error {
	for  := 0;  < len();  += 4096 {
		if  := .Err();  != nil {
			return 
		}
	}
	return .Err()
}

// ignoredNamespacedAttribute accepts only namespace-qualified editor and RDF
// metadata proven non-painting by the bounded element/topology allowlist.
func ( *svgImporter) ( string,  xml.Attr) (bool, error) {
	switch .Name.Space {
	case xmlNamespace:
		if .Name.Local != "space" {
			return false, .errorf("element <%s> has unsupported xml attribute %q", , displayXMLName(.Name.Local))
		}
		,  := trimSVGSpace(.ctx, .Value)
		if  != nil {
			return false, 
		}
		if  != "default" &&  != "preserve" {
			return false, .errorf("element <%s> has invalid xml:space", )
		}
		return true, nil
	case inkscapeNamespace:
		 := inkscapeMetadataAttributes[]
		if ,  := [.Name.Local]; ! {
			return false, .errorf("element <%s> has unsupported Inkscape metadata attribute %q", , displayXMLName(.Name.Local))
		}
		return true, nil
	case sodipodiNamespace:
		 := sodipodiMetadataAttributes[]
		if ,  := [.Name.Local]; ! {
			return false, .errorf("element <%s> has unsupported Sodipodi metadata attribute %q", , displayXMLName(.Name.Local))
		}
		return true, nil
	case rdfNamespace:
		switch {
		case  == "cc:Work" && .Name.Local == "about" && .Value == "":
			return true, nil
		case  == "dc:type" && .Name.Local == "resource" && .Value == stillImageResource:
			return true, nil
		default:
			return false, .errorf("element <%s> has unsupported RDF metadata attribute %q", , displayXMLName(.Name.Local))
		}
	default:
		return false, nil
	}
}

func ( *svgImporter) (, ,  string) (bool, error) {
	if strings.HasPrefix(, "data-") {
		if len() == len("data-") {
			return false, .errorf("element <%s> has invalid data-* metadata attribute", )
		}
		for  := len("data-");  < len(); ++ {
			if &4095 == 0 {
				if  := .ctx.Err();  != nil {
					return false, 
				}
			}
			 := []
			if !isASCIIAlpha() && ( < '0' ||  > '9') &&  != '-' &&  != '_' {
				return false, .errorf("element <%s> has invalid data-* metadata attribute", )
			}
		}
		return true, nil
	}
	if  == "role" {
		,  := trimSVGSpace(.ctx, )
		if  != nil {
			return false, 
		}
		if  != "img" &&  != "none" &&  != "presentation" {
			return false, .errorf("element <%s> has unsupported non-rendering role", )
		}
		return true, nil
	}
	if  == "focusable" {
		,  := trimSVGSpace(.ctx, )
		if  != nil {
			return false, 
		}
		if  != "false" {
			return false, .errorf("element <%s> focusable metadata must be false", )
		}
		return true, nil
	}
	return false, nil
}

func ( *svgImporter) ( *svgElement) error {
	if ,  := .attrs["version"];  {
		,  := trimSVGSpace(.ctx, )
		if  != nil {
			return 
		}
		if  != "1.0" &&  != "1.1" {
			return .errorf("root <svg> has unsupported version")
		}
	}
	for ,  := range []string{"x", "y"} {
		if ,  := .attrs[];  {
			,  := parseSVGLength(, true)
			if  != nil ||  != 0 {
				return .errorf("root <svg> %s must be a zero absolute length", )
			}
		}
	}
	if ,  := .attrs["enable-background"];  {
		if  := validateEnableBackground(.ctx, );  != nil {
			if  := .ctx.Err();  != nil {
				return 
			}
			return .errorf("root <svg> has invalid enable-background: %v", )
		}
	}
	return nil
}

func validateEnableBackground( context.Context,  string) error {
	,  := trimSVGSpace(, )
	if  != nil {
		return 
	}
	 := 0
	for  < len() && !isSVGListSpace([]) {
		++
		if &4095 == 0 {
			if  := .Err();  != nil {
				return 
			}
		}
	}
	if !equalASCIIEqualFold([:], "new") ||  == len() {
		return fmt.Errorf("only a finite new x y width height region is supported")
	}
	,  := splitEnableBackgroundFields(, [:])
	if  != nil {
		return 
	}
	if len() != 4 {
		return fmt.Errorf("only a finite new x y width height region is supported")
	}
	 := make([]float64, len())
	for ,  := range  {
		if  := .Err();  != nil {
			return 
		}
		[],  = parseSVGNumber()
		if  != nil {
			return fmt.Errorf("only a finite new x y width height region is supported")
		}
	}
	if [2] <= 0 || [3] <= 0 {
		return fmt.Errorf("enable-background width and height must be positive")
	}
	return .Err()
}

func splitEnableBackgroundFields( context.Context,  string) ([]string, error) {
	 := make([]string, 0, 4)
	 := -1
	for  := 0;  <= len(); ++ {
		if &4095 == 0 {
			if  := .Err();  != nil {
				return nil, 
			}
		}
		 :=  == len() || isSVGListSpace([])
		if ! {
			if [] == ',' {
				return nil, fmt.Errorf("only whitespace-separated enable-background coordinates are supported")
			}
			if  < 0 {
				 = 
			}
			continue
		}
		if  < 0 {
			continue
		}
		if len() == cap() {
			return nil, fmt.Errorf("only a finite new x y width height region is supported")
		}
		 = append(, [:])
		 = -1
	}
	return , .Err()
}