1 2 /** 3 * Convert binary data to hex and ASCII. 4 * 5 * Copyright: Copyright Digital Mars 2015-2015 6 * License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Authors: $(WEB digitalmars.com, Walter Bright) 8 * Source: $(SARGONSRC src/sargon/_dumphex.d) 9 */ 10 11 module sargon.dumphex; 12 13 private import std.range; 14 15 16 /********************************** 17 Transform ubytes into hex and ASCII. 18 19 Params: 20 r = input range of ubytes 21 startoffset = offset of start of bytes 22 23 Returns: 24 range of chars with r's contents in hex and ASCII 25 */ 26 27 auto dumpHex(Range)(Range r, ulong startoffset = 0) 28 if (isInputRange!Range && is(ElementType!Range == ubyte)) 29 { 30 import core.stdc.ctype; 31 32 struct Result 33 { 34 enum PerLine = 16; 35 enum OffsetDigits = 16; 36 37 this(Range r, ulong startoffset) 38 { 39 this.r = r; 40 this.offset = startoffset; 41 } 42 43 @property bool empty() 44 { 45 return nleft == 0 && r.empty; 46 } 47 48 @property char front() 49 { 50 immutable char[16] hexDigits = "0123456789abcdef"; 51 52 if (!nleft) 53 { 54 line[0 .. $ - 1] = ' '; 55 line[OffsetDigits] = ':'; 56 line[$ - 1] = '\n'; 57 58 size_t ndigits; 59 auto offs = offset; 60 while (ndigits < 4 || offs) 61 { 62 line[OffsetDigits - ndigits - 1] = hexDigits[offs & 0x0F]; 63 offs >>= 4; 64 line[OffsetDigits - ndigits - 2] = hexDigits[offs & 0x0F]; 65 offs >>= 4; 66 ndigits += 2; 67 } 68 69 size_t i; 70 while (!r.empty) 71 { 72 ubyte c = r.front; 73 r.popFront(); 74 75 line[OffsetDigits + 2 + i * 3] = (c >> 4) ? hexDigits[c >> 4] : ' '; 76 line[OffsetDigits + 2 + i * 3 + 1] = hexDigits[c & 0x0F]; 77 line[OffsetDigits + 2 + PerLine * 3 + 3 + i] = core.stdc.ctype.isprint(c) ? c : '.'; 78 if (++i == PerLine) 79 break; 80 } 81 nleft = line.length - OffsetDigits + ndigits; 82 offset += PerLine; 83 } 84 return line[line.length - nleft]; 85 } 86 87 void popFront() 88 { 89 if (!nleft) 90 front(); 91 --nleft; 92 } 93 94 static if (isForwardRange!Range) 95 { 96 @property typeof(this) save() 97 { 98 auto ret = this; 99 ret.r = r.save; 100 return ret; 101 } 102 } 103 104 private: 105 Range r; 106 ulong offset; 107 char[OffsetDigits + 2 + PerLine * 3 + 3 + PerLine + 1] line; 108 size_t nleft; 109 } 110 111 return Result(r, startoffset); 112 } 113 114 unittest 115 { 116 import std.conv; 117 import std.array; 118 119 { 120 ubyte[] data = cast(ubyte[])hexString!"65 74 29 3b 0d 0a 7d 0d 0a"; 121 auto s = data.dumpHex(0x0ad0).array; 122 assert(s == "0ad0: 65 74 29 3b d a 7d d a et);..}.. \n"); 123 } 124 { 125 ubyte[] data = cast(ubyte[])"65 74 29 3b 0d 0a 7d 0d 0a"; 126 auto s = data.dumpHex(0x0ad578).array; 127 assert(s == "0ad578: 36 35 20 37 34 20 32 39 20 33 62 20 30 64 20 30 65 74 29 3b 0d 0 128 0ad588: 61 20 37 64 20 30 64 20 30 61 a 7d 0d 0a \n"); 129 } 130 { 131 ubyte[] data = cast(ubyte[])hexString!"65 74 29 3b 0d 0a 7d 0d 0a"; 132 auto r = data.dumpHex(0x0ad0); 133 auto s = r.save; 134 r.popFront(); 135 assert(s.front == '0'); 136 assert(r.front == 'a'); 137 } 138 }