LibreTube/app/src/main/java/com/github/libretube/util/HtmlParser.kt
2023-01-19 17:21:06 +01:00

86 lines
2.5 KiB
Kotlin

package com.github.libretube.util
import android.text.Editable
import android.text.Html
import org.xml.sax.Attributes
import org.xml.sax.ContentHandler
import org.xml.sax.Locator
import org.xml.sax.XMLReader
class HtmlParser(
private val handler: LinkHandler
) : Html.TagHandler, ContentHandler {
private val tagStatus = ArrayDeque<Boolean>()
private var wrapped: ContentHandler? = null
private var text: Editable? = null
override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: XMLReader) {
if (wrapped == null) {
// record result object
text = output
// record current content handler
wrapped = xmlReader.contentHandler
// replace content handler with our own that forwards to calls to original when needed
xmlReader.contentHandler = this
// add false to the stack to make sure we always have a tag to pop
tagStatus.addLast(false)
}
}
override fun startElement(
uri: String,
localName: String,
qName: String,
attributes: Attributes
) {
val isHandled = handler.handleTag(true, localName, text, attributes)
tagStatus.addLast(isHandled)
if (!isHandled) {
wrapped?.startElement(uri, localName, qName, attributes)
}
}
override fun endElement(uri: String, localName: String, qName: String) {
if (!tagStatus.removeLast()) {
wrapped?.endElement(uri, localName, qName)
}
handler.handleTag(false, localName, text, null)
}
override fun setDocumentLocator(locator: Locator) {
wrapped?.setDocumentLocator(locator)
}
override fun startDocument() {
wrapped?.startDocument()
}
override fun endDocument() {
wrapped?.endDocument()
}
override fun startPrefixMapping(prefix: String, uri: String) {
wrapped?.startPrefixMapping(prefix, uri)
}
override fun endPrefixMapping(prefix: String) {
wrapped?.endPrefixMapping(prefix)
}
override fun characters(ch: CharArray, start: Int, length: Int) {
wrapped?.characters(ch, start, length)
}
override fun ignorableWhitespace(ch: CharArray, start: Int, length: Int) {
wrapped?.ignorableWhitespace(ch, start, length)
}
override fun processingInstruction(target: String, data: String) {
wrapped?.processingInstruction(target, data)
}
override fun skippedEntity(name: String) {
wrapped?.skippedEntity(name)
}
}