All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.binaryfoo.DecodedData.kt Maven / Gradle / Ivy

There is a newer version: 0.1.8
Show newest version
package io.github.binaryfoo

import io.github.binaryfoo.decoders.annotator.BackgroundReading
import io.github.binaryfoo.hex.HexDumpElement
import io.github.binaryfoo.tlv.BerTlv
import io.github.binaryfoo.tlv.ISOUtil
import io.github.binaryfoo.tlv.Tag
import org.apache.commons.lang.StringUtils
import java.util.*

/**
 * A rather oddly named class that attempts to order a description of the bits (a decoding) into a hierarchy.
 * Each instance represents a single level in the hierarchy. Leaf nodes have no children.
 *
 * Examples:
 * 
    *
  • A TLV object with children
  • *
  • A primitive value interpreted as a bit string, like TVR, where the children are the "on" bits.
  • *
*/ data class DecodedData( val tag: Tag?, val rawData: String, // Not a great name. Used as a label for the decoded data. val fullDecodedData: String, val startIndex: Int = 0, // in bytes val endIndex: Int = 0, // in bytes var kids: List = listOf(), var backgroundReading: Map? = null, // wordy explanation. Eg to show in tooltip/popover, val tlv: BerTlv? = null, var category: String = "" ) { var hexDump: List? = null private val _children: MutableList = ArrayList(kids) val children: List get() { return _children } /** * Position within the #hexDump of the bytes this decoding represents. * For a decoding of a TLV this will include the T, L and V components. The whole kit and caboodle. */ val positionInHexDump: ClosedRange get() { return startIndex..endIndex-1 } /** * Position within the #hexDump of the bytes comprising the T (tag) in the TLV this decoding represents. * Null if this decoding didn't come from a TLV. */ val tagPositionInHexDump: ClosedRange? get() { return if (tlv != null) startIndex..(startIndex + tlv.tag.bytes.size - 1) else null } /** * Position within the #hexDump of the bytes comprising the L (length) in the TLV this decoding represents. * Null if this decoding didn't come from a TLV. */ val lengthPositionInHexDump: ClosedRange? get() { return if (tlv != null) { val firstLengthByte = tagPositionInHexDump!!.endInclusive + 1 firstLengthByte..(firstLengthByte + tlv.lengthInBytesOfEncodedLength - 1) } else { null } } private fun trim(decodedData: String): String { return if (decodedData.length >= 60) decodedData.substring(0, 56) + "..." + StringUtils.right(decodedData, 4) else decodedData } /** * For an element with children this is usually the hex value (ie the real raw data). * For an element without children this is the decoded value: ascii, numeric, enumerated or even just hex. */ fun getDecodedData(): String { return if (isComposite()) trim(fullDecodedData) else fullDecodedData } fun getChild(index: Int): DecodedData { return children[index] } fun isComposite(): Boolean { return !children.isEmpty() } /** * For values that can't be decoded in the first pass. Like decrypted ones. */ fun addChildren(child: List) { _children.addAll(child) } override fun toString(): String { var s = "raw=[$rawData] decoded=[$fullDecodedData] indexes=[$startIndex,$endIndex]" if (backgroundReading != null) { s += " background=[$backgroundReading]" } if (tag != null) { s += " tag=$tag" } if (tlv != null) { s += " tlv=$tlv" } if (isComposite()) { for (d in children) { s += "\n" + d } } return s } companion object { @JvmStatic fun primitive(rawData: String, decodedData: String, startIndex: Int = 0, endIndex: Int = 0): DecodedData { return DecodedData(null, rawData, decodedData, startIndex, endIndex, backgroundReading = BackgroundReading.readingFor(rawData)) } @JvmStatic fun byteRange(rawData: String, bytes: ByteArray, startIndexWithinBytes: Int, length: Int, startIndexWithinFullDecoding: Int): DecodedData { val decodedData = ISOUtil.hexString(bytes, startIndexWithinBytes, length) return DecodedData(null, rawData, decodedData, startIndexWithinFullDecoding + startIndexWithinBytes, startIndexWithinFullDecoding + startIndexWithinBytes + length, listOf()) } @JvmStatic fun byteRange(rawData: String, decodedData: String, startIndexWithinBytes: Int, length: Int, startIndexWithinFullDecoding: Int): DecodedData { return DecodedData(null, rawData, decodedData, startIndexWithinFullDecoding + startIndexWithinBytes, startIndexWithinFullDecoding + startIndexWithinBytes + length, listOf()) } @JvmStatic fun constructed(rawData: String, decodedData: String, startIndex: Int = 0, endIndex: Int = 0, children: List): DecodedData { return DecodedData(null, rawData, decodedData, startIndex, endIndex, children, BackgroundReading.readingFor(rawData)) } /** * Attach a Tag but the data wasn't actually encoded as TLV. Eg a bunch of values are concatenated in a stream. */ @JvmStatic fun withTag(tag: Tag, metadata: TagMetaData, decodedData: String, startIndex: Int, endIndex: Int, children: List = listOf()): DecodedData { val tagInfo = metadata.get(tag) return DecodedData(tag, tag.toString(tagInfo), decodedData, startIndex, endIndex, children, tagInfo.backgroundReading) } /** * Decoded from a TLV. */ @JvmStatic fun fromTlv(tlv: BerTlv, metadata: TagMetaData, decodedData: String, startIndex: Int, endIndex: Int, children: List = listOf()): DecodedData { val tag = tlv.tag val tagInfo = metadata.get(tag) return DecodedData(tag, tag.toString(tagInfo), decodedData, startIndex, endIndex, children, tagInfo.backgroundReading, tlv) } @JvmStatic fun findForTag(tag: Tag, decoded: List): DecodedData? { val matches = decoded.findAllForTag(tag) return if (matches.isEmpty()) null else matches[0] } @JvmStatic fun findAllForTag(tag: Tag, decoded: List): List { var matches = ArrayList() decoded.forEach { if (it.tag == tag) { matches.add(it) } matches.addAll(it.children.findAllForTag(tag)) } return matches } @JvmStatic fun findForValue(value: String, decoded: List): DecodedData? { val matches = decoded.findAllForValue(value) return if (matches.isEmpty()) null else matches[0] } @JvmStatic fun findAllForValue(value: String, decoded: List): List { var matches = ArrayList() decoded.forEach { if (it.fullDecodedData == value) { matches.add(it) } matches.addAll(it.children.findAllForValue(value)) } return matches } } } fun List.findForTag(tag: Tag): DecodedData? { return DecodedData.findForTag(tag, this) } fun List.findTlvForTag(tag: Tag): BerTlv? { return DecodedData.findAllForTag(tag, this).lastOrNull()?.tlv } fun List.findValueForTag(tag: Tag): String? { return DecodedData.findAllForTag(tag, this).lastOrNull()?.tlv?.valueAsHexString } fun List.findAllForTag(tag: Tag): List { return DecodedData.findAllForTag(tag, this) } fun List.findForValue(value: String): DecodedData? { return DecodedData.findForValue(value, this) } fun List.findAllForValue(value: String): List { return DecodedData.findAllForValue(value, this) } fun List.toSimpleString(indent: String = ""): String { val b = StringBuilder() for (d in this) { b.append(indent) val decodedData = d.getDecodedData() if ("" != d.rawData) { b.append(d.rawData).append(":") if ("" != decodedData) { b.append(" ") } } b.append(decodedData).append("\n") b.append(d.children.toSimpleString(indent + " ")) } return b.toString() }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy