2 people like it.

hexdump (somewhat fast)

Simple functions to display a hex dump of a byte array using sequence expressions, with ASCII. Rewrote naive version that used string concat, based on optimizations in http://fssnip.net/ht, and cleaned up ASCII formatting.

Hex dump of byte array b, display width w.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
open System
open System.Text

let filterChar (b : byte) = if int b <= 32 || int b > 127 then '.' else char b
        
let hexdump w (b : byte[]) =
    let format = sprintf "{0:X8}  {1,-%i} {2}" (w * 2 + w)

    let mapj (sb : StringBuilder * StringBuilder) x = 
        (fst sb).AppendFormat("{0:X2} ", x :> obj), 
        (snd sb).Append(filterChar x)

    seq { for i in 0 .. w .. (b.Length - 1) ->
            let (hex, asc) = 
                Array.sub b i (min w (b.Length - i))
                |> Array.fold (mapj) (StringBuilder(), StringBuilder())
            String.Format(format, i, hex, asc)
        }

//> [|0uy..100uy|] |> hexdump 16 |> Seq.iter (printfn "%s");;
//00000000  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  ................
//00000010  10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F  ................
//00000020  20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F  .!"#$%&'()*+,-./
//00000030  30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  0123456789:;<=>?
//00000040  40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F  @ABCDEFGHIJKLMNO
//00000050  50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F  PQRSTUVWXYZ[\]^_
//00000060  60 61 62 63 64                                   `abcd
//Real: 00:00:00.013, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0        

//> Array.zeroCreate 1000000
//|> hexdump 16
//|> Seq.iter ignore;;
//Real: 00:00:00.834, CPU: 00:00:00.842, GC gen0: 875, gen1: 2, gen2: 1        

(Naive slow version omitted)
namespace System
namespace System.Text
val filterChar : b:byte -> char

Full name: Script.filterChar
val b : byte
Multiple items
val byte : value:'T -> byte (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.byte

--------------------
type byte = Byte

Full name: Microsoft.FSharp.Core.byte
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Multiple items
val char : value:'T -> char (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.char

--------------------
type char = Char

Full name: Microsoft.FSharp.Core.char
val hexdump : w:int -> b:byte [] -> seq<string>

Full name: Script.hexdump
val w : int
val b : byte []
val format : string
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val mapj : (StringBuilder * StringBuilder -> byte -> StringBuilder * StringBuilder)
val sb : StringBuilder * StringBuilder
Multiple items
type StringBuilder =
  new : unit -> StringBuilder + 5 overloads
  member Append : value:string -> StringBuilder + 18 overloads
  member AppendFormat : format:string * arg0:obj -> StringBuilder + 4 overloads
  member AppendLine : unit -> StringBuilder + 1 overload
  member Capacity : int with get, set
  member Chars : int -> char with get, set
  member Clear : unit -> StringBuilder
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EnsureCapacity : capacity:int -> int
  member Equals : sb:StringBuilder -> bool
  ...

Full name: System.Text.StringBuilder

--------------------
StringBuilder() : unit
StringBuilder(capacity: int) : unit
StringBuilder(value: string) : unit
StringBuilder(value: string, capacity: int) : unit
StringBuilder(capacity: int, maxCapacity: int) : unit
StringBuilder(value: string, startIndex: int, length: int, capacity: int) : unit
val x : byte
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val i : int
property Array.Length: int
val hex : StringBuilder
val asc : StringBuilder
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val sub : array:'T [] -> startIndex:int -> count:int -> 'T []

Full name: Microsoft.FSharp.Collections.Array.sub
val min : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.min
val fold : folder:('State -> 'T -> 'State) -> state:'State -> array:'T [] -> 'State

Full name: Microsoft.FSharp.Collections.Array.fold
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Encoding) : unit
String.Format(format: string, [<ParamArray>] args: obj []) : string
String.Format(format: string, arg0: obj) : string
String.Format(provider: IFormatProvider, format: string, [<ParamArray>] args: obj []) : string
String.Format(format: string, arg0: obj, arg1: obj) : string
String.Format(format: string, arg0: obj, arg1: obj, arg2: obj) : string
// Slow version.
(*
let hexdump w (b : byte[]) =
    seq {
        for i in 0..w..b.Length - 1 ->
            let hex =
                Seq.skip i b
                |> Seq.truncate w
                |> Seq.map (sprintf "%02X ")
                |> Seq.fold ( + ) ""
            sprintf "%08X %s\n" i hex
        }
    |> Seq.iter (printf "%s")

// Filters non-printable characters.
let filterChar (b : byte) = if int b <= 32 || int b > 127 then '.' else char b

// Pads a string based on number (w) of bytes to display.
let pad w (s : string) =
    let t = (w * 2) + w
    if s.Length < t then s + String.replicate (t - s.Length) " " else s

// With ASCII column.

let hexdump' w (b : byte[]) =
    seq {
        for i in 0..w..b.Length - 1 ->
            let byt = Seq.skip i b
                      |> Seq.truncate w
            let hex = Seq.map (sprintf "%02X ") byt
                      |> Seq.fold ( + ) ""
                      |> pad w
            let asc = Seq.map (fun c -> sprintf "%c" (filterChar c)) byt
                      |> Seq.fold ( + ) ""
            sprintf "%08X %s %s\n" i hex asc
        }
    |> Seq.iter (printf "%s")
*)

More information

Link:http://fssnip.net/hq
Posted:4 years ago
Author:Matthew H. Traylor
Tags: hex dump , hex , sequences , conversion