github.com/spi-ca/misc@v1.0.1/dbg/dumper.go (about)

     1  package dbg
     2  
     3  import "bytes"
     4  
     5  import (
     6  	"fmt"
     7  	"golang.org/x/text/width"
     8  	"unicode/utf8"
     9  )
    10  
    11  // HexDump returns hexadecimal data dump data.
    12  func HexDump(by []byte) string {
    13  	n := len(by)
    14  	rowcount := 0
    15  	stop := (n / 16) * 16
    16  	k := 0
    17  	buf := &bytes.Buffer{}
    18  
    19  	for i := 0; i <= stop; i += 16 {
    20  		k++
    21  		if i+16 < n {
    22  			rowcount = 16
    23  		} else {
    24  			rowcount = min(k*16, n) % 16
    25  		}
    26  
    27  		fmt.Fprintf(buf, "%08x ", i)
    28  		for j := 0; j < rowcount; j++ {
    29  			if j%8 == 0 {
    30  				fmt.Fprintf(buf, " %02x ", by[i+j])
    31  			} else {
    32  				fmt.Fprintf(buf, "%02x ", by[i+j])
    33  			}
    34  
    35  		}
    36  
    37  		for j := rowcount; j < 16; j++ {
    38  			if j%8 == 0 {
    39  				fmt.Fprintf(buf, "    ")
    40  			} else {
    41  				fmt.Fprintf(buf, "   ")
    42  			}
    43  		}
    44  		buf.WriteRune('|')
    45  		viewString(by[i:(i+rowcount)], buf)
    46  		buf.WriteRune('|')
    47  		buf.WriteRune('\n')
    48  		buf.WriteRune('\r')
    49  	}
    50  	return buf.String()
    51  }
    52  
    53  func max(a, b int) int {
    54  	if a > b {
    55  		return a
    56  	}
    57  	return b
    58  }
    59  func min(a, b int) int {
    60  	if a < b {
    61  		return a
    62  	}
    63  	return b
    64  }
    65  
    66  // GuessUnicodeWidth returns the size of bytes for a single rune.
    67  func GuessUnicodeWidth(char rune) (realSize int) {
    68  	prop := width.LookupRune(char)
    69  	switch prop.Kind() {
    70  	case width.EastAsianFullwidth:
    71  		fallthrough
    72  	case width.EastAsianWide:
    73  		realSize = 2
    74  	case width.EastAsianHalfwidth:
    75  		fallthrough
    76  	case width.EastAsianNarrow:
    77  		realSize = 2
    78  	case width.EastAsianAmbiguous:
    79  		fallthrough
    80  	case width.Neutral:
    81  		fallthrough
    82  	default:
    83  		realSize = 1
    84  	}
    85  	return
    86  }
    87  
    88  func viewString(b []byte, buf *bytes.Buffer) {
    89  	for {
    90  		if r, size := utf8.DecodeRune(b); size == 0 {
    91  			return
    92  		} else if r == utf8.RuneError {
    93  			for i := 0; i < size; i++ {
    94  				buf.WriteRune('_')
    95  			}
    96  			b = b[size:]
    97  		} else if r < 32 {
    98  			for i := 0; i < size; i++ {
    99  				buf.WriteRune('.')
   100  			}
   101  			b = b[size:]
   102  		} else {
   103  			buf.WriteRune(r)
   104  			pad := max(0, size-GuessUnicodeWidth(r))
   105  			for i := 0; i < pad; i++ {
   106  				buf.WriteRune('.')
   107  			}
   108  			b = b[size:]
   109  		}
   110  	}
   111  }