@@ -807,9 +807,9 @@ sealed abstract class ByteVector
807
807
}
808
808
809
809
/** Generates a hex dump of this vector using the default format (with no color / ANSI escapes).
810
- * To customize the output, use the `ByteVector. HexDumpFormat` class instead.
811
- * For example, `ByteVector. HexDumpFormat.NoAscii.render(bytes)` or
812
- * `ByteVector. HexDumpFormat.Default.withIncludeAddressColumn(false).render(bytes)`.
810
+ * To customize the output, use the `HexDumpFormat` class instead.
811
+ * For example, `HexDumpFormat.NoAscii.render(bytes)` or
812
+ * `HexDumpFormat.Default.withIncludeAddressColumn(false).render(bytes)`.
813
813
*
814
814
* @group conversions
815
815
*/
@@ -823,7 +823,7 @@ sealed abstract class ByteVector
823
823
824
824
/** Prints this vector as a colorized hex dump to standard out.
825
825
*/
826
- final def printHexDump (): Unit = print(toHexDumpColorized )
826
+ final def printHexDump (): Unit = HexDumpFormat . Default . print(this )
827
827
828
828
/** Helper alias for [[toHex:String* ]]
829
829
*
@@ -2344,195 +2344,4 @@ object ByteVector extends ByteVectorCompanionCrossPlatform {
2344
2344
}
2345
2345
}
2346
2346
}
2347
-
2348
- final class HexDumpFormat private (
2349
- includeAddressColumn : Boolean ,
2350
- dataColumnCount : Int ,
2351
- dataColumnWidthInBytes : Int ,
2352
- includeAsciiColumn : Boolean ,
2353
- alphabet : Bases .HexAlphabet ,
2354
- ansiEnabled : Boolean
2355
- ) {
2356
- def withIncludeAddressColumn (newIncludeAddressColumn : Boolean ): HexDumpFormat =
2357
- new HexDumpFormat (
2358
- newIncludeAddressColumn,
2359
- dataColumnCount,
2360
- dataColumnWidthInBytes,
2361
- includeAsciiColumn,
2362
- alphabet,
2363
- ansiEnabled
2364
- )
2365
- def withDataColumnCount (newDataColumnCount : Int ): HexDumpFormat =
2366
- new HexDumpFormat (
2367
- includeAddressColumn,
2368
- newDataColumnCount,
2369
- dataColumnWidthInBytes,
2370
- includeAsciiColumn,
2371
- alphabet,
2372
- ansiEnabled
2373
- )
2374
- def withDataColumnWidthInBytes (newDataColumnWidthInBytes : Int ): HexDumpFormat =
2375
- new HexDumpFormat (
2376
- includeAddressColumn,
2377
- dataColumnCount,
2378
- newDataColumnWidthInBytes,
2379
- includeAsciiColumn,
2380
- alphabet,
2381
- ansiEnabled
2382
- )
2383
- def withIncludeAsciiColumn (newIncludeAsciiColumn : Boolean ): HexDumpFormat =
2384
- new HexDumpFormat (
2385
- includeAddressColumn,
2386
- dataColumnCount,
2387
- dataColumnWidthInBytes,
2388
- newIncludeAsciiColumn,
2389
- alphabet,
2390
- ansiEnabled
2391
- )
2392
- def withAlphabet (newAlphabet : Bases .HexAlphabet ): HexDumpFormat =
2393
- new HexDumpFormat (
2394
- includeAddressColumn,
2395
- dataColumnCount,
2396
- dataColumnWidthInBytes,
2397
- includeAsciiColumn,
2398
- newAlphabet,
2399
- ansiEnabled
2400
- )
2401
- def withAnsi (newAnsiEnabled : Boolean ): HexDumpFormat =
2402
- new HexDumpFormat (
2403
- includeAddressColumn,
2404
- dataColumnCount,
2405
- dataColumnWidthInBytes,
2406
- includeAsciiColumn,
2407
- alphabet,
2408
- newAnsiEnabled
2409
- )
2410
-
2411
- def render (bytes : ByteVector ): String = {
2412
- val bldr = new StringBuilder
2413
- val numBytesPerLine = dataColumnWidthInBytes * dataColumnCount
2414
- val bytesPerLine = bytes.groupedIterator(numBytesPerLine.toLong)
2415
- bytesPerLine.zipWithIndex.foreach { case (bytesInLine, index) =>
2416
- renderLine(bldr, bytesInLine, index * numBytesPerLine)
2417
- }
2418
- bldr.toString
2419
- }
2420
-
2421
- private object Ansi {
2422
- val Faint = " \u001b [;2m"
2423
- val Normal = " \u001b [;22m"
2424
- val Reset = " \u001b [0m"
2425
- def foregroundColor (bldr : StringBuilder , rgb : (Int , Int , Int )): Unit = {
2426
- bldr
2427
- .append(" \u001b [38;2;" )
2428
- .append(rgb._1)
2429
- .append(" ;" )
2430
- .append(rgb._2)
2431
- .append(" ;" )
2432
- .append(rgb._3)
2433
- .append(" m" )
2434
- ()
2435
- }
2436
- }
2437
-
2438
- private def renderLine (bldr : StringBuilder , bytes : ByteVector , address : Int ): Unit = {
2439
- if (includeAddressColumn) {
2440
- if (ansiEnabled) bldr.append(Ansi .Faint )
2441
- bldr.append(ByteVector .fromInt(address).toHex(alphabet))
2442
- if (ansiEnabled) bldr.append(Ansi .Normal )
2443
- bldr.append(" " )
2444
- }
2445
- bytes.groupedIterator(dataColumnWidthInBytes.toLong).foreach { columnBytes =>
2446
- renderHex(bldr, columnBytes)
2447
- bldr.append(" " )
2448
- }
2449
- if (ansiEnabled)
2450
- bldr.append(Ansi .Reset )
2451
- if (includeAsciiColumn) {
2452
- val padding = {
2453
- val bytesOnFullLine = dataColumnWidthInBytes * dataColumnCount
2454
- val bytesOnThisLine = bytes.size.toInt
2455
- val dataBytePadding = (bytesOnFullLine - bytesOnThisLine) * 3 - 1
2456
- val numFullDataColumns = bytesOnThisLine / dataColumnWidthInBytes
2457
- val numAdditionalColumnSpacers = dataColumnCount - numFullDataColumns
2458
- dataBytePadding + numAdditionalColumnSpacers
2459
- }
2460
- bldr.append(" " * padding)
2461
- bldr.append('│' )
2462
- renderAsciiBestEffort(bldr, bytes)
2463
- bldr.append('│' )
2464
- }
2465
- bldr.append('\n ' )
2466
- ()
2467
- }
2468
-
2469
- private def renderHex (bldr : StringBuilder , bytes : ByteVector ): Unit =
2470
- bytes.foreachS {
2471
- new F1BU {
2472
- def apply (b : Byte ) = {
2473
- if (ansiEnabled) Ansi .foregroundColor(bldr, rgbForByte(b))
2474
- bldr
2475
- .append(alphabet.toChar((b >> 4 & 0x0f ).toByte.toInt))
2476
- .append(alphabet.toChar((b & 0x0f ).toByte.toInt))
2477
- .append(' ' )
2478
- ()
2479
- }
2480
- }
2481
- }
2482
-
2483
- private def rgbForByte (b : Byte ): (Int , Int , Int ) = {
2484
- val saturation = 0.4
2485
- val value = 0.75
2486
- val hue = ((b & 0xff ) / 256.0 ) * 360.0
2487
- hsvToRgb(hue, saturation, value)
2488
- }
2489
-
2490
- // From https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
2491
- private def hsvToRgb (hue : Double , saturation : Double , value : Double ): (Int , Int , Int ) = {
2492
- val c = saturation * value
2493
- val h = hue / 60
2494
- val x = c * (1 - (h % 2 - 1 ).abs)
2495
- val z = 0d
2496
- val (r1, g1, b1) = h.toInt match {
2497
- case 0 => (c, x, z)
2498
- case 1 => (x, c, z)
2499
- case 2 => (z, c, x)
2500
- case 3 => (z, x, c)
2501
- case 4 => (x, z, c)
2502
- case 5 => (c, z, x)
2503
- }
2504
- val m = value - c
2505
- val (r, g, b) = (r1 + m, g1 + m, b1 + m)
2506
- def scale (v : Double ) = (v * 256 ).toInt
2507
- (scale(r), scale(g), scale(b))
2508
- }
2509
-
2510
- private val FaintDot = s " ${Ansi .Faint }. ${Ansi .Normal }"
2511
- private val FaintUnmappable = s " ${Ansi .Faint }� ${Ansi .Normal }"
2512
- private val NonPrintablePattern = " [^�\\ p{Print}]" .r
2513
-
2514
- private def renderAsciiBestEffort (bldr : StringBuilder , bytes : ByteVector ): Unit = {
2515
- val decoded = bytes.decodeAsciiLenient
2516
- val nonPrintableReplacement = if (ansiEnabled) FaintDot else " ."
2517
- val printable = NonPrintablePattern .replaceAllIn(decoded, nonPrintableReplacement)
2518
- val colorized = if (ansiEnabled) printable.replaceAll(" �" , FaintUnmappable ) else printable
2519
- bldr.append(colorized)
2520
- ()
2521
- }
2522
- }
2523
-
2524
- object HexDumpFormat {
2525
-
2526
- /** Colorized hex dump that displays 2 columns of 8 bytes each, along with the address column and ASCII column. */
2527
- val Default : HexDumpFormat =
2528
- new HexDumpFormat (true , 2 , 8 , true , Bases .Alphabets .HexLowercase , true )
2529
-
2530
- /** Like [[Default ]] but with ANSI color disabled. */
2531
- val NoAnsi : HexDumpFormat =
2532
- Default .withAnsi(false )
2533
-
2534
- /** Like [[Default ]] but with 3 columns of data and no ASCII column. */
2535
- val NoAscii : HexDumpFormat =
2536
- Default .withIncludeAsciiColumn(false ).withDataColumnCount(3 )
2537
- }
2538
2347
}
0 commit comments