in daffodil-io/src/main/scala/org/apache/daffodil/io/Dump.scala [391:479]
private def makeHexAndTextIndicatorLine(
indicatorInfoInBytes: Option[(Long, Int)],
startByteAddress0b: Long,
lengthInBytes: Int,
hexHeaderLength: Int,
addressHeaderLength: Int,
textByteWidth: Int
) = {
indicatorInfoInBytes.map { case (goalIndByteAddress0b: Long, indLengthInBytes: Int) =>
val indByteAddress0b = math.max(goalIndByteAddress0b, startByteAddress0b)
val delta = indByteAddress0b - startByteAddress0b
val realLengthInBytes = math.min(indLengthInBytes, lengthInBytes)
//
// if the delta is more than this, the indicator will be ambiguous because what it
// points at isn't directly below, but possibly a further row down.
//
Assert.usage(delta < 16)
Assert.usage(indLengthInBytes >= 0) // if too big we'll clamp it.
val indicatorOffset0b = indByteAddress0b.toInt % 16
val indOffset2 = indicatorOffset0b / 2
val initialHexSpaces = " " * indOffset2 +
(" " * (indicatorOffset0b & 0x1)) // blank first half of pair
val pictureLengthInBytes = math.min(16 - indicatorOffset0b.toInt, realLengthInBytes)
val hexIndicator = {
val picture =
(pictureLengthInBytes, indByteAddress0b % 2) match {
case (0, _) => "│"
case (1, _) if realLengthInBytes =#= 1 => "├┤"
case (1, _) => "├═"
case (2, 0) if realLengthInBytes =#= 2 => "├──┤"
case (2, 0) => "├──═"
case (2, 1) => "├───┤" // middle dash spans the gutter
case (n, s) => {
Assert.invariant(n >= 3)
val startCap = "├─"
val endCap =
if (realLengthInBytes > n) "─═"
else "─┤"
val startBytePic = if (s =#= 0) startCap + "──" else startCap
val endBytePic =
if (((indicatorOffset0b.toInt + n) % 2) =#= 0) "──" + endCap else endCap
val startRoundUp2 =
(indicatorOffset0b.toInt + 2) - (indicatorOffset0b.toInt + 2) % 2
val endRoundDown2 =
(indicatorOffset0b.toInt + n - 1) - (indicatorOffset0b.toInt + n - 1) % 2
val middleBytes = (endRoundDown2 - startRoundUp2) / 2
val middleBytePics = Seq.fill(middleBytes.toInt)("────")
val bytePix = startBytePic +: middleBytePics :+ endBytePic
val pic = bytePix.mkString("─") // for the single space gutters between
pic
}
}
val pictureOnly = initialHexSpaces + picture
val endPadLength = hexHeaderLength - pictureOnly.length
val endPad = " " * endPadLength
val finalPicture = pictureOnly + endPad
finalPicture
}
val textIndicator = {
val initialTextSpaces = " " * textByteWidth * indicatorOffset0b
val picture =
(pictureLengthInBytes, textByteWidth) match {
case (0, _) => "│"
case (1, 1) => "║"
case (1, 2) => "├┤"
case (n, w) => {
val pad = if (w =#= 1) "" else "─"
val startCap = "├" + pad
val endCap =
if (realLengthInBytes > n) pad + "═"
else pad + "┤"
val middleBytePics = (1 to (pictureLengthInBytes - 2)).map { _ => "─" + pad }
val allPix = startCap +: middleBytePics :+ endCap
val pic = allPix.mkString
pic
}
}
val finalPicture = initialTextSpaces + picture
finalPicture
}
val initialSpaces = " " * addressHeaderLength
val line = initialSpaces + hexIndicator + " " + textIndicator
line
}
}