private def makeHexAndTextIndicatorLine()

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
    }
  }