You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

130 lines
3.9 KiB

/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.resources.vector.xmldom
import platform.Foundation.NSError
import platform.Foundation.NSString
import platform.Foundation.NSUTF8StringEncoding
import platform.Foundation.NSXMLParser
import platform.Foundation.NSXMLParserDelegateProtocol
import platform.Foundation.dataUsingEncoding
import platform.darwin.NSObject
internal fun parse(xml: String): Element {
val parser = DomXmlParser()
@Suppress("CAST_NEVER_SUCCEEDS")
NSXMLParser((xml as NSString).dataUsingEncoding(NSUTF8StringEncoding)!!).apply {
shouldReportNamespacePrefixes = true
shouldProcessNamespaces = true
delegate = parser
}.parse()
return parser.root!!
}
private class ElementImpl(
override val localName: String,
override val nodeName: String,
override val namespaceURI: String,
val prefixMap: Map<String, String>,
val attributes: Map<Any?, *>
) : Element {
override var textContent: String? = null
override val childNodes: NodeList
get() = object : NodeList {
override fun item(i: Int): Node {
return childs[i]
}
override val length: Int
get() = childs.size
}
var childs = mutableListOf<Node>()
override fun getAttributeNS(nameSpaceURI: String, localName: String): String {
val prefix = prefixMap[nameSpaceURI]
val attrKey = if (prefix == null) localName else "$prefix:$localName"
return getAttribute(attrKey)
}
override fun getAttribute(name: String): String = attributes[name] as String? ?: ""
override fun lookupPrefix(namespaceURI: String): String = prefixMap[namespaceURI] ?: ""
}
@Suppress("CONFLICTING_OVERLOADS", "PARAMETER_NAME_CHANGED_ON_OVERRIDE")
private class DomXmlParser : NSObject(), NSXMLParserDelegateProtocol {
val curPrefixMapInverted = mutableMapOf<String, String>()
var curPrefixMap: Map<String, String> = emptyMap()
val nodeStack = mutableListOf<ElementImpl>()
var root: Element? = null
override fun parser(
parser: NSXMLParser,
didStartElement: String,
namespaceURI: String?,
qualifiedName: String?,
attributes: Map<Any?, *>
) {
val node = ElementImpl(
didStartElement,
qualifiedName!!,
namespaceURI ?: "",
curPrefixMap,
attributes
)
if (root == null) root = node
if (!nodeStack.isEmpty())
nodeStack.last().childs.add(node)
nodeStack.add(node)
}
override fun parser(parser: NSXMLParser, foundCharacters: String) {
nodeStack.lastOrNull()?.textContent = foundCharacters
}
override fun parser(
parser: NSXMLParser,
didEndElement: String,
namespaceURI: String?,
qualifiedName: String?
) {
val node = nodeStack.removeLast()
assert(node.localName.equals(didEndElement))
}
override fun parser(
parser: NSXMLParser,
didStartMappingPrefix: String,
toURI: String
) {
curPrefixMapInverted.put(didStartMappingPrefix, toURI)
curPrefixMap = curPrefixMapInverted.entries.associateBy({ it.value }, { it.key })
}
override fun parser(parser: NSXMLParser, didEndMappingPrefix: String) {
curPrefixMapInverted.remove(didEndMappingPrefix)
curPrefixMap = curPrefixMapInverted.entries.associateBy({ it.value }, { it.key })
}
override fun parser(parser: NSXMLParser, validationErrorOccurred: NSError) {
throw MalformedXMLException("validation error occurred")
}
override fun parser(parser: NSXMLParser, parseErrorOccurred: NSError) {
throw MalformedXMLException("parse error occurred")
}
}