private[io] def dumpHexAndTextBytes()

in daffodil-io/src/main/scala/org/apache/daffodil/io/Dump.scala [243:377]


  private[io] def dumpHexAndTextBytes(
    startByteAddress0b: Long,
    lengthInBytes: Int,
    byteBuffer: ByteBuffer,
    includeHeadingLine: Boolean,
    optEncodingName: Option[String],
    indicatorInfoInBytes: Option[(Long, Int)]
  ): Seq[String] = {

    Assert.usage(startByteAddress0b >= 0)
    Assert.usage(lengthInBytes >= 0)

    val (textDataHeader, textByteWidth, optEncName) = getTextParameters(optEncodingName)
    val decoder = getReportingDecoder(optEncName)

    val endByteAddress0b = math.max(startByteAddress0b + lengthInBytes - 1, 0)
    val addressHeader = """87654321  """
    val hexHeader = """0011 2233 4455 6677 8899 aabb ccdd eeff""" // space on the end is needed
    val headingHex = addressHeader + hexHeader
    val firstGutter = ": "
    val offset0b = (startByteAddress0b & 0xf).toInt
    val hexRegionInitialWhitespace = {
      val offset2 = offset0b / 2
      val res = "     " * offset2 +
        ("  " * (offset0b & 0x1)) // blank first half of pair
      res
    }
    val textRegionInitialWhitespace = (" " * textByteWidth) * offset0b

    val indicatorLine =
      makeHexAndTextIndicatorLine(
        indicatorInfoInBytes,
        startByteAddress0b,
        lengthInBytes,
        hexHeader.length,
        addressHeader.length,
        textByteWidth
      )

    var isFirstRow = true
    var isLastRow = false
    val firstLeftAddress = startByteAddress0b & 0x7fffffffffffff0L
    val lastLeftAddress =
      math.max(0, (startByteAddress0b + lengthInBytes - 1)) & 0x7ffffffffffffff0L

    val headingLine = headingHex + "  " + textDataHeader

    val ab = scala.collection.mutable.ArrayBuffer[String]()
    indicatorLine.foreach { line => ab += line }
    if (includeHeadingLine) ab += headingLine

    val hexsb = new StringBuilder
    val txtsb = new StringBuilder
    var rowStart0b = offset0b
    var limit0b = 15 // except for last row it will be shortened. Inclusive limit.

    //
    // These vars are used by the txt dump when the multiple bytes of a
    // character wrap from one line to the next.
    //
    paddingFromPriorLine = ""
    nPadBytesFromPriorLine = 0

    (firstLeftAddress to lastLeftAddress by 16).foreach {
      //
      // for each line/row, we assemble the address part, the hex part, and the text part
      //
      addr =>
        if (addr == lastLeftAddress) {
          isLastRow = true
          limit0b = (endByteAddress0b & 0xf).toInt // might be fewer than all 16 for last row
        }
        val addrString = "%08x".format(addr)
        hexsb ++= addrString + firstGutter
        if (isFirstRow) {
          isFirstRow = false
          hexsb ++= hexRegionInitialWhitespace
          txtsb ++= textRegionInitialWhitespace
        }

        //
        // Hex dump
        //
        (rowStart0b to limit0b).foreach { i =>
          val bytePos0b = addr + i - startByteAddress0b
          val byteValue =
            try {
              byteBuffer.get(bytePos0b.toInt)
            } catch {
              case e: IndexOutOfBoundsException => 0.toByte
            }
          val hex = "%02x".format(byteValue)
          val gutter = if ((i & 0x1) == 0) "" else " "
          hexsb ++= hex + gutter
        }
        //
        // Text dump
        //
        textDump(
          addr - startByteAddress0b,
          rowStart0b,
          txtsb,
          limit0b,
          endByteAddress0b,
          byteBuffer,
          decoder,
          textByteWidth
        )

        if (isLastRow) {
          //
          // Trailing spaces on the hex dump
          //
          ((limit0b + 1) to 15).foreach { i =>
            val gutter = if ((i & 0x1) == 1) " " else ""
            hexsb ++= "  " + gutter
          }
          //
          // Trailing spaces on the text dump
          //
          ((limit0b + 1) to 15).foreach { i =>
            txtsb ++= (" " * textByteWidth)
          }
        }
        ab += hexsb.mkString + " " + txtsb.mkString
        hexsb.clear()
        txtsb.clear()
        //
        // we're done with first row, so subsequent rows will have
        // zero as the row start.
        //
        rowStart0b = 0
    }
    ab.toSeq
  }