another.im-ios/AnotherIM/xmpp/utils/String+XML.swift
2024-12-16 08:19:58 +01:00

69 lines
2.1 KiB
Swift

import Foundation
// swiftlint:disable:next large_tuple
private typealias Replace = (orig: String, asName: String, asCode: String)
private let replaces = [
Replace("&", "&", "&"),
Replace("<", "&lt;", "&#60;"),
Replace(">", "&gt;", "&#62;"),
Replace("\"", "&quot;", "&#34;"),
Replace("'", "&apos;", "&#39;")
]
extension String {
var unescaped: String {
if !contains("&") {
return self
}
var result = self
var indx = replaces.count - 1
while indx >= 0 {
// this is for libxml2 as it replaces every &amp; with &#38; which in XML both replaces &
result = result.replacingOccurrences(of: replaces[indx].asCode, with: replaces[indx].orig)
// this is for normal replacement (may not be needed but let's keep it for compatibility
result = result.replacingOccurrences(of: replaces[indx].asName, with: replaces[indx].orig)
indx -= 1
}
return result
}
var escaped: String {
var result = self
var indx = 0
while indx < replaces.count {
result = result.replacingOccurrences(of: replaces[indx].orig, with: replaces[indx].asName)
indx += 1
}
return result
}
}
extension String {
var prettyStr: String {
var line = self
line.replace(">", with: ">\n")
line.replace("</", with: "\n</")
var formattedString = ""
var indentLevel = 0
let lines = line.split(separator: "\n")
for line in lines {
let trimmedLine = line.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmedLine.isEmpty {
continue
}
if trimmedLine.hasPrefix("</") {
indentLevel -= 1
}
let indent = String(repeating: " ", count: indentLevel)
formattedString += indent + trimmedLine + "\n"
if trimmedLine.hasPrefix("<") && !trimmedLine.hasPrefix("</") && !trimmedLine.hasSuffix("/>") {
indentLevel += 1
}
}
return formattedString
}
}