package dev.openrs2.deob.ast.gl import com.google.common.collect.HashMultimap import com.google.common.collect.ImmutableSetMultimap import org.jdom2.input.SAXBuilder import java.io.InputStream data class GlEnum(val name: String, val value: Long) data class GlGroup(val name: String, val enums: List) data class GlParameter(val name: String, val bitfield: Boolean, val group: GlGroup?) data class GlCommand(val name: String, val parameters: List) data class GlRegistry(val enums: ImmutableSetMultimap, val commands: Map) { companion object { private fun parseValue(s: String): Long { return if (s.startsWith("0x")) { java.lang.Long.parseUnsignedLong(s.substring(2), 16) } else { s.toLong() } } fun parse(): GlRegistry { return GlRegistry::class.java.getResourceAsStream("/dev/openrs2/deob/ast/gl.xml").use(::parse) } fun parse(input: InputStream): GlRegistry { val root = SAXBuilder().build(input).rootElement // create enums and groups val enumsBuilder = ImmutableSetMultimap.builder() val groupsBuilder = HashMultimap.create() for (elements in root.getChildren("enums")) { for (element in elements.getChildren("enum")) { val name = element.getAttributeValue("name") val value = parseValue(element.getAttributeValue("value")) val enum = GlEnum(name, value) enumsBuilder.put(value, enum) val groups = element.getAttributeValue("group") ?: continue for (group in groups.split(",")) { groupsBuilder.put(group, enum) } } } val groups = groupsBuilder.asMap().mapValues { entry -> // sort by name length ascending so names with vendor suffixes come last GlGroup(entry.key, entry.value.sortedBy { enum -> enum.name.length }.toList()) } // create parameters and commands val commands = mutableMapOf() for (element in root.getChild("commands").getChildren("command")) { val commandName = element.getChild("proto").getChildText("name") val parameters = mutableListOf() for (paramElement in element.getChildren("param")) { val paramName = paramElement.getChildText("name") val type = paramElement.getChildText("ptype") val bitfield = type == "GLbitfield" val groupName = paramElement.getAttributeValue("group") val group = if (groupName != null) { groups[groupName] } else { null } parameters += GlParameter(paramName, bitfield, group) } commands[commandName] = GlCommand(commandName, parameters) } return GlRegistry(enumsBuilder.build(), commands) } } }