Comparing version 0.3.2 to 0.3.3
@@ -6,13 +6,16 @@ #!/usr/bin/env node | ||
function usage (mes) { | ||
console.log(mes) | ||
console.log("usage bla bal bal"); | ||
function usage(mes) { | ||
console.log(mes || "usage: " + /[^/\\]*$/.exec(process.argv[1]) + " [options] <filename>"); | ||
console.log("--width [(16)] how many bytes per line") | ||
console.log("--numbering [(hex_bytes)|none] prefix current byte count") | ||
console.log("--format [eights|(fours)|twos|none] how many nibbles per group") | ||
console.log("--radix [2|8|10|(16)] radix to use") | ||
console.log("--format [sixteens|eights|(fours)|twos|none] how many nibbles per group") | ||
console.log("--littleEndian the data is littleEndian") | ||
console.log("--extendedChs show more characters as-is") | ||
console.log("--caps [(lower)|upper] case of hex chars") | ||
console.log("--html render the output in HTML format") | ||
console.log("--annotate [(ascii)|none] provide ascii annotation") | ||
console.log("--prefix [(\"\")|<prefix>] printed in front of each line") | ||
console.log("--indent [(0)|<num>] number of spaces to indent output") | ||
console.log("parameter in (parens) are default") | ||
console.log("parameters in (parens) are default") | ||
process.exit(1) | ||
@@ -26,12 +29,16 @@ } | ||
return; | ||
} | ||
} | ||
} catch (e) {} | ||
usage("not a file: "+fn) | ||
} | ||
function handleArgs () { | ||
var format = {}, | ||
var format = {}, | ||
ARGS = [ | ||
"--width", | ||
"--numbering", | ||
"--radix", | ||
"--format", | ||
"--littleEndian", | ||
"--extendedChs", | ||
"--caps", | ||
@@ -43,4 +50,3 @@ "--annotate", | ||
var args = process.argv, | ||
last = -1 | ||
var args = process.argv | ||
@@ -52,6 +58,6 @@ for (var i=2; i<args.length; ++i) { | ||
} | ||
if ( -1 === ARGS.indexOf(arg) ) { | ||
if (-1 === ARGS.indexOf(arg)) { | ||
// not a valid flag | ||
if (args.length-1 === i) { | ||
//last arg, could be filename | ||
// last arg, could be filename | ||
existsFatal(arg) | ||
@@ -65,4 +71,3 @@ format.filename = arg | ||
arg = arg.substr(2, arg.length) | ||
format[arg] = args[++i] | ||
format[arg] = args[++i] | ||
} | ||
@@ -76,2 +81,10 @@ | ||
} | ||
if (format.radix) { | ||
format.radix = parseInt(format.radix, 10) | ||
} | ||
if (format.html) { | ||
format.html = true | ||
} | ||
format.littleEndian = format.littleEndian == "true" | ||
format.extendedChs = format.extendedChs == "true" | ||
return format | ||
@@ -85,4 +98,3 @@ } | ||
var format = handleArgs(), | ||
buffer = null, | ||
str = null | ||
buffer = null | ||
@@ -94,20 +106,18 @@ if (format.filename) { | ||
var stdin = process.openStdin() | ||
stdin.on("data", function(data) { | ||
var offset = 0 | ||
if (buffer) { | ||
offset = buffer.length | ||
buffer_ = new Buffer(buffer.length + data.length) | ||
buffer.copy(buffer_,0,0) | ||
buffer = buffer_ | ||
data.copy(buffer, offset, data.length) | ||
} else { | ||
buffer = data | ||
} | ||
}) | ||
stdin.on("data", function(data) { | ||
var offset = 0 | ||
if (buffer) { | ||
offset = buffer.length | ||
buffer_ = new Buffer(buffer.length + data.length) | ||
buffer.copy(buffer_,0,0) | ||
buffer = buffer_ | ||
data.copy(buffer, offset, data.length) | ||
} else { | ||
buffer = data | ||
} | ||
}) | ||
stdin.on("end", function(){ | ||
console.log(hexy.hexy(buffer, format)) | ||
}) | ||
stdin.on("end", function(){ | ||
console.log(hexy.hexy(buffer, format)) | ||
}) | ||
} | ||
365
hexy.js
@@ -68,12 +68,21 @@ "use strict"; | ||
// format.numbering = n // ["hex_bytes" | "none"], default "hex_bytes" | ||
// format.format = f // ["eights"|"fours"|"twos"|"none"], how many nibbles per group | ||
// format.radix = b // [2, 8, 10, 16], the radix for numeral representation | ||
// // for the right column, default 16 | ||
// format.format = f // ["twos"|"fours"|"eights"|"sixteens"|"none"], number of nibbles per group | ||
// // default "fours" | ||
// format.littleEndian = true | ||
// // endiannes of data, default false | ||
// // counts when number of nibbles is more than "twos", | ||
// // i.e. displaying groups bigger than one byte | ||
// format.extendedChs = true | ||
// // allow displaying more characters in the text column | ||
// // default false | ||
// format.caps = c // ["lower"|"upper"], default lower | ||
// format.annotate=a // ["ascii"|"none"], ascii annotation at end of line? | ||
// format.annotate = a // ["ascii"|"none"], ascii annotation at end of line? | ||
// // default "ascii" | ||
// format.prefix=p // <string> something pretty to put in front of each line | ||
// format.prefix = p // <string> something pretty to put in front of each line | ||
// // default "" | ||
// format.indent=i // <num> number of spaces to indent | ||
// format.indent = i // <num> number of spaces to indent | ||
// // default 0 | ||
// format.html=true // funky html divs 'n stuff! experimental. | ||
// format.html = true // funky html divs 'n stuff! experimental. | ||
// // default: false | ||
@@ -90,3 +99,3 @@ // format.offset = X // generate hexdump based on X byte offset | ||
// // is started at 0) | ||
// // default 0 | ||
// // default 0 | ||
// | ||
@@ -101,3 +110,3 @@ //console.log(hexy.hexy(buffer, format)) | ||
// | ||
// Either use `npm` (or whatever caompatible npm thingie people are using | ||
// Either use `npm` (or whatever compatible npm thingie people are using | ||
// these days) : | ||
@@ -187,2 +196,19 @@ // | ||
// | ||
// ### 0.3.3 | ||
// | ||
// * added endianness (BE and LE) | ||
// * added radix (HEX, DEC, OCT and BIN) | ||
// * added 16-nibble (8 byte) groups | ||
// * added option to display more non-lower-ascii chars | ||
// * toString() can now accept Uint8Array -- the natural way | ||
// of reading files and streams in browsers | ||
// * implemented and exported `maxnumberlen()` | ||
// * performance += { 15-30% } | ||
// * Node.js tests ++ | ||
// * created browser tests | ||
// * created static html demo page (view.html) | ||
// * restricted the set of node.js versions and browsers: | ||
// (now require support of `BigInt`: Node.JS 10.4+, browsers since 2018-2020) | ||
// * the travis is passing now | ||
// | ||
// ### 0.3.2 | ||
@@ -211,10 +237,11 @@ // | ||
var hexy = function (buffer, config) { | ||
var h = new Hexy(buffer, config) | ||
var hexy = function(buffer, config) { | ||
const h = new Hexy(buffer, config) | ||
return h.toString() | ||
} | ||
var Hexy = function (buffer, config) { | ||
var self = this | ||
var Hexy = function(buffer, config) { | ||
const self = this | ||
const MAX_ADDRESS_LENGTH = 8 // TODO: might want to calculate | ||
// if we have a Buffer class, convert | ||
@@ -230,24 +257,32 @@ if (typeof Buffer !== 'undefined') { | ||
self.buffer = buffer // magic string conversion here? | ||
self.width = parseInt(config.width) || 16 | ||
self.numbering = config.numbering == "none" ? "none" : "hex_bytes" | ||
self.buffer = buffer // magic string conversion here? | ||
self.bytes_per_line = parseInt(config.width) || 16 // formerly `width` | ||
self.numbering = config.numbering == "none" ? "none" : "hex_bytes" | ||
self.bytes_per_group = 2 // by default (not handled below) "fours" will fold into `bytes_per_group == 2` | ||
switch (config.format) { | ||
case "none": | ||
self.bytes_per_group = 0 // one byte per group, but no delimiters | ||
break | ||
case "twos": | ||
self.bytes_per_group = 1 | ||
break | ||
case "eights": | ||
self.format = config.format | ||
self.bytes_per_group = 4 | ||
break | ||
default: | ||
self.format = "fours" | ||
case "sixteens": | ||
self.bytes_per_group = 8 | ||
break | ||
} | ||
self.caps = config.caps == "upper" ? "upper" : "lower" | ||
self.annotate = config.annotate == "none" ? "none" : "ascii" | ||
self.prefix = config.prefix || "" | ||
self.indent = config.indent || 0 | ||
self.html = config.html || false | ||
self.offset = config.offset || 0 | ||
self.length = config.length || -1 | ||
self.littleEndian = config.littleEndian || false | ||
self.radix = config.radix || 16 | ||
self.caps = config.caps == "upper" ? "upper" : "lower" | ||
self.annotate = config.annotate == "none" ? "none" : "ascii" | ||
self.prefix = config.prefix || "" | ||
self.indent = config.indent || 0 | ||
self.html = config.html || false | ||
self.offset = config.offset || 0 | ||
self.length = config.length || -1 | ||
self.extendedChs = config.extendedChs || false | ||
self.display_offset = config.display_offset || 0 | ||
@@ -263,135 +298,126 @@ | ||
if (self.length <= self.buffer.length) { | ||
self.buffer = self.buffer.slice(0,self.length) | ||
self.buffer = self.buffer.slice(0, self.length) | ||
} | ||
} | ||
for (var i = 0; i!=self.indent; ++i) { | ||
self.prefix = " "+self.prefix | ||
self.prefix = (self.html ? " " : " ").repeat(self.indent) + self.prefix | ||
self.hex_line_length = (maxnumberlen(self.bytes_per_group, self.radix)) * self.bytes_per_line | ||
/ Math.max(self.bytes_per_group, 1) | ||
switch (self.bytes_per_group) { // the original code (now documented in the tests), | ||
case 8: // some modes had mode-dependent number of extra spaces at the end of the line | ||
case 4: | ||
case 2: | ||
self.hex_line_length += Math.floor(self.bytes_per_line / self.bytes_per_group) | ||
break | ||
case 1: | ||
self.hex_line_length += self.bytes_per_line + 3 | ||
break | ||
case 0: | ||
self.hex_line_length += 2 | ||
break | ||
} | ||
self.bytes_per_group = Math.min(self.bytes_per_group, self.bytes_per_line) | ||
var pos = 0 | ||
this.toString = function () { | ||
this.toString = function() { | ||
var str = "" | ||
if (self.html) { str += "<div class='hexy'>\n"} | ||
//split up into line of max `self.width` | ||
var line_arr = lines() | ||
//lines().forEach(function(hex_raw, i) | ||
for (var i = 0; i!= line_arr.length; ++i) { | ||
var hex_raw = line_arr[i], | ||
hex = hex_raw[0], | ||
raw = hex_raw[1] | ||
//insert spaces every `self.format.twos`, fours or eights | ||
var howMany = hex.length | ||
if (self.format === "eights") { | ||
howMany = 8 | ||
} else if (self.format === "fours") { | ||
howMany = 4 | ||
} else if (self.format === "twos") { | ||
howMany = 2 | ||
} | ||
var addr = self.offset + self.display_offset | ||
var odd = false | ||
var hex_formatted = "" | ||
if (self.html) { str += "<div class='hexy'>\n" } | ||
// each `slice` is a single output line: | ||
for (var start = 0; start < self.buffer.length; start += self.bytes_per_line) { | ||
const end = Math.min(start + self.bytes_per_line, self.buffer.length) | ||
const slice = self.buffer.slice(start, end) | ||
for (var j =0; j< hex.length; j+=howMany) { | ||
var s = hex.substr(j, howMany) | ||
hex_formatted += s + " " | ||
} | ||
var addr = (i*self.width)+self.offset+self.display_offset; | ||
if (self.html) { | ||
var odd = i%2 == 0 ? " even" : " odd" | ||
str += "<div class='"+pad(addr, 8)+odd+"'>" | ||
str += "<div class='" + num2str(addr, MAX_ADDRESS_LENGTH, 16) + (odd ? " odd" : " even") + "'>" | ||
odd = !odd | ||
} | ||
str += self.prefix | ||
str += self.prefix | ||
// the address column: | ||
if (self.numbering === "hex_bytes") { | ||
str += pad(addr, 8) // padding... | ||
str += ": " | ||
str += num2str(addr, MAX_ADDRESS_LENGTH, 16) + ": " | ||
} | ||
var padlen = 0 | ||
switch(self.format) { | ||
case "eights": | ||
padlen = self.width*2 + Math.floor(self.width/4) | ||
// the binary representation column: | ||
str += hex(slice, self.bytes_per_line, self.bytes_per_group, self.radix, self.littleEndian) | ||
// the text representation column: | ||
if (self.annotate === "ascii") { | ||
var text = "" | ||
switch (slice.constructor) { | ||
case Array: | ||
text = String.fromCharCode.apply(self, slice) | ||
break | ||
case "fours": | ||
padlen = self.width*2 + Math.floor(self.width/2) | ||
case Uint8Array: | ||
slice.forEach(ch => text += String.fromCharCode(ch)) | ||
break | ||
case "twos": | ||
padlen = self.width*3 + 2 | ||
break | ||
default: | ||
padlen = self.width * 2 + 1 | ||
text = slice.toString('latin1') | ||
} | ||
str += " " + (self.html ? html_escape(text) : ascii_escape(text)) | ||
} | ||
str += self.html ? "</div>\n" : "\n" | ||
addr += self.bytes_per_line | ||
} | ||
str += rpad(hex_formatted, padlen) | ||
if (self.annotate === "ascii") { | ||
str+=" " | ||
var ascii = raw.replace(/[\000-\040\177-\377]/g, ".") | ||
if (self.html) {str += escape(ascii)} | ||
else { str += ascii } | ||
} | ||
if (self.html) { | ||
str += "</div>\n" | ||
} else { | ||
str += "\n" | ||
} | ||
} | ||
if (self.html) { str += "</div>\n"} | ||
if (self.html) { str += "</div>\n" } | ||
return str | ||
} | ||
var lines = function() { | ||
var hex_raw = [] | ||
for (var i = 0; i<self.buffer.length ; i+=self.width) { | ||
var begin = i, | ||
end = i+self.width >= self.buffer.length ? self.buffer.length : i+self.width, | ||
slice = self.buffer.slice(begin, end), | ||
hex = self.caps === "upper" ? hexu(slice) : hexl(slice), | ||
raw = slice.toString('ascii') | ||
if (self.buffer.constructor == Array) { | ||
raw = String.fromCharCode.apply(self, slice) | ||
} | ||
hex_raw.push([hex,raw]) | ||
// renders the binary representation of individual line | ||
var hex = function(buffer, bytes_per_line, bytes_per_group, radix, littleEndian) { | ||
var str = "" | ||
const delimiter = bytes_per_group == 0 ? "" : " " | ||
const group_len = maxnumberlen(bytes_per_group, radix) | ||
const padlen = (bytes_per_line - buffer.length) * (bytes_per_group == 0 ? group_len: (group_len + 1) / bytes_per_group) | ||
if (bytes_per_group == 0) { | ||
bytes_per_group = 1 | ||
} | ||
return hex_raw | ||
} | ||
var hexl = function (buffer) { | ||
var str = "" | ||
for (var i=0; i!=buffer.length; ++i) { | ||
if (buffer.constructor == String) { | ||
str += pad(buffer.charCodeAt(i), 2) | ||
} else { | ||
str += pad(buffer[i], 2) | ||
const start = littleEndian ? bytes_per_group - 1 : 0 | ||
const end = littleEndian ? -1 : bytes_per_group | ||
const step = littleEndian ? -1 : 1 | ||
for (var group = 0; group < buffer.length / bytes_per_group; ++group) { | ||
var val = bytes_per_group < 4 ? 0 : BigInt(0) | ||
for (var ii = start; ii != end; ii += step) { | ||
const i = group * bytes_per_group + ii | ||
if (i >= buffer.length) { // not rendering dangling bytes. TODO: render them as smaller grouping | ||
break | ||
} | ||
if (bytes_per_group < 4) { | ||
val = val * 256 + ((buffer.constructor == String ? buffer.codePointAt(i) : buffer[i]) & 0xff) | ||
} else { | ||
val = val * 256n + BigInt((buffer.constructor == String ? buffer.codePointAt(i) : buffer[i]) & 0xff) | ||
} | ||
} | ||
const text = val.toString(radix) | ||
for (var c = 0; c < group_len - text.length; c++) { | ||
str += "0" | ||
} | ||
str += text | ||
str += delimiter | ||
if (self.caps === "upper") { | ||
str = str.toUpperCase() | ||
} | ||
} | ||
if (buffer.length < bytes_per_line) { | ||
str += (self.html ? " ": " ").repeat(padlen) | ||
} | ||
str = rpad(str, self.hex_line_length) | ||
return str | ||
} | ||
var hexu = function (buffer) { | ||
return hexl(buffer).toUpperCase() | ||
// converts a number to a string and pads it with '0' on the left, up to requested length | ||
var num2str = function(b, len, radix) { | ||
const s = b.toString(radix) | ||
return "0".repeat(len - s.length) + s | ||
} | ||
var pad = function(b, len) { | ||
var s = b.toString(16) | ||
while (s.length < len) { | ||
s = "0" + s | ||
} | ||
return s | ||
} | ||
var rpad = function(s, len) { | ||
for (var n = len - s.length; n>0; --n) { | ||
if (self.html) { | ||
s += " " | ||
} else { | ||
s += " " | ||
} | ||
const to_add = len - s.length - 1 | ||
if (to_add > 0) { | ||
s += (self.html ? " " : " ").repeat(to_add) | ||
} | ||
@@ -401,13 +427,77 @@ return s | ||
var escape = function (str) { | ||
str = str.split("&").join("&") | ||
str = str.split("<").join("<") | ||
str = str.split(">").join(">") | ||
const ALL_EXCEPT_PRINTABLE_LATIN = /[^\x20-\x7f]/g | ||
const CONTROL_CHARACTERS_ONLY = /[\x00-\x1f]/g | ||
var ascii_escape = function(str) { | ||
return str.replace(self.extendedChs ? CONTROL_CHARACTERS_ONLY : ALL_EXCEPT_PRINTABLE_LATIN, ".") | ||
} | ||
var html_escape = function(str) { | ||
str = str.replace(/&/g, "&") // `replace()` is measurably faster than `split().join()` in Node.js v.* | ||
str = str.replace(/</g, "<") | ||
str = str.replace(/>/g, ">") | ||
if (self.extendedChs) { | ||
str = str.replace(/\'/g, "'") | ||
str = str.replace(/\"/g, """) | ||
str = str.replace(ALL_EXCEPT_PRINTABLE_LATIN, function(ch) { | ||
ch = ch.codePointAt(0) | ||
return "&#x" + ch.toString(16) + ";" | ||
}) | ||
} else { | ||
str = str.replace(ALL_EXCEPT_PRINTABLE_LATIN, ".") | ||
} | ||
return str | ||
} | ||
} | ||
Hexy.VERSION = "0.3.3" | ||
var maxnumberlen = function(bytes, radix) { | ||
var result = 2 | ||
if (bytes == 0) { | ||
bytes = 1 | ||
} | ||
switch (radix) { | ||
case 2: // BIN: 8, 16, 32, 64 | ||
result = bytes * 8 | ||
break | ||
case 8: // OCT: 3, 6, 11, 22 | ||
switch (bytes) { | ||
case 1: | ||
result = 3 | ||
break | ||
case 2: | ||
result = 6 | ||
break | ||
case 4: | ||
result = 11 | ||
break | ||
case 8: | ||
result = 22 | ||
break | ||
} | ||
break | ||
case 10: // DEC: 3, 6, 10, 20 | ||
switch (bytes) { | ||
case 1: | ||
result = 3 | ||
break | ||
case 2: | ||
result = 6 | ||
break | ||
case 4: | ||
result = 10 | ||
break | ||
case 8: | ||
result = 20 | ||
break | ||
} | ||
break | ||
case 16: // HEX: 2, 4, 8, 16 | ||
result = 2 * bytes | ||
break | ||
} | ||
return result | ||
} | ||
Hexy.VERSION = "0.3.2" | ||
@@ -432,3 +522,4 @@ // This is probably not the prettiest or coolest way to to determine runtime | ||
_exp.Hexy = Hexy | ||
_exp.maxnumberlen = maxnumberlen | ||
})(this) |
@@ -5,2 +5,4 @@ | ||
width?: number; | ||
littleEndian?: boolean; | ||
radix?: number; | ||
numbering?: "hex_bytes" | "none"; | ||
@@ -13,2 +15,3 @@ format?: "eights" | "fours" | "twos" | "none"; | ||
html?: boolean; | ||
extendedChs?: boolean; | ||
offset?: number; | ||
@@ -19,2 +22,3 @@ length?: number; | ||
export const hexy: (arg: Buffer | string | number[], format?: FormatOptions) => string; | ||
export const maxnumberlen: (bytes: number, radix: number) => number; | ||
} |
{ | ||
"name": "hexy", | ||
"version": "0.3.2", | ||
"version": "0.3.3", | ||
"description": "hexdump, binary pretty-printing", | ||
@@ -12,2 +12,6 @@ "author": "Tim Becker <tim.becker@kuriositaet.de>", | ||
}, | ||
"engines": { | ||
"node": ">=10.4" | ||
}, | ||
"browserslist": ["> 1%", "last 4 versions"], | ||
"scripts": { | ||
@@ -14,0 +18,0 @@ "test": "node ./test.js" |
@@ -68,12 +68,21 @@ [![build status](https://api.travis-ci.com/a2800276/hexy.js.svg)](https://app.travis-ci.com/github/a2800276/hexy.js) | ||
format.numbering = n // ["hex_bytes" | "none"], default "hex_bytes" | ||
format.format = f // ["eights"|"fours"|"twos"|"none"], how many nibbles per group | ||
format.radix = b // [2, 8, 10, 16], the radix for numeral representation | ||
// for the right column, default 16 | ||
format.format = f // ["twos"|"fours"|"eights"|"sixteens"|"none"], number of nibbles per group | ||
// default "fours" | ||
format.littleEndian = true | ||
// endiannes of data, default false | ||
// counts when number of nibbles is more than "twos", | ||
// i.e. displaying groups bigger than one byte | ||
format.extendedChs = true | ||
// allow displaying more characters in the text column | ||
// default false | ||
format.caps = c // ["lower"|"upper"], default lower | ||
format.annotate=a // ["ascii"|"none"], ascii annotation at end of line? | ||
format.annotate = a // ["ascii"|"none"], ascii annotation at end of line? | ||
// default "ascii" | ||
format.prefix=p // <string> something pretty to put in front of each line | ||
format.prefix = p // <string> something pretty to put in front of each line | ||
// default "" | ||
format.indent=i // <num> number of spaces to indent | ||
format.indent = i // <num> number of spaces to indent | ||
// default 0 | ||
format.html=true // funky html divs 'n stuff! experimental. | ||
format.html = true // funky html divs 'n stuff! experimental. | ||
// default: false | ||
@@ -90,3 +99,3 @@ format.offset = X // generate hexdump based on X byte offset | ||
// is started at 0) | ||
// default 0 | ||
// default 0 | ||
@@ -101,3 +110,3 @@ console.log(hexy.hexy(buffer, format)) | ||
Either use `npm` (or whatever caompatible npm thingie people are using | ||
Either use `npm` (or whatever compatible npm thingie people are using | ||
these days) : | ||
@@ -134,18 +143,5 @@ | ||
## Browser Support | ||
Browser support is fixed (now supports `Array` and `Uint8Array`) in 0.3.3. | ||
Please refer to `test.html` for examples. | ||
Basically eveything should work fine in the browser as well, just | ||
include hexy.js in a script tag, and you'll get `hexy` and `Hexy` stuck | ||
to the global object (window). | ||
Some caveats: "Works fine on my system™". Browser support is 'new' and | ||
not thoroughly tested (... eh, only on chrome [Version: whatever I'm | ||
currently running]). Under node, I can generally assume that binary data | ||
is passed in in a sane fashion using buffers, but plain old Javascript | ||
doesn't really have any datatypes that can handle bytes gracefully. | ||
Currently only Strings and arrays containing Number'ish values are | ||
supported, I'd like to add numeric and typed arrays more explicitly. | ||
Let me know in case you run into any issues, I'd be happy to find out | ||
about them. | ||
## TODOS | ||
@@ -164,3 +160,3 @@ | ||
Better testing for browser use. | ||
**DONE** Better testing for browser use. | ||
@@ -189,2 +185,31 @@ | ||
### 0.3.3 | ||
* introduced the concept of endiannes (googleable and wikiable). Before this change, the code assumed that the displayed data is big-endian. | ||
However, most file formats and most CPU architectures are little-endian. So, introduced the support for it. | ||
The endiannes can be controlled by passing bool via `littleEndian`, which defaults to `false` to support the behavior of the previous versions | ||
* introduced ability to group 8 bytes (16 nibbles). With prevalence of 64-bit computing, the 64-bit (i.e. 8-byte) data is getting more and more popular. | ||
The 8-byte grouping is enabled by passing "sixteens" into `config.format` | ||
* introduced ability to display the binary data in bases (radixes) other than hexadecimal: binary, octal, decimal and hexadecimal | ||
The radix is controlled by passing 2, 8, 10 or 16 into `config.radix` | ||
* introduced ability to control if non-printable characters are displayed or replaced with `'.'`. | ||
To display extended characters, pass `config.extendedChs: true`. The exact behavior of this flag depends on the output type, html or not: | ||
In `config.html: true` mode, all the characters can be displayed, even 0-0x20 have visual represenation. | ||
In `config.html: false` mode, only the extended characters beyond the end of standard ASCII are displayed. | ||
* implemented and exported `maxnumberlen()` -- calculates how many characters can a number occupy given bittness and radix | ||
* several tweaks improved performance by ~15-30%, depending on the platform (compared to v.0.3.2). | ||
* a bit more order in the node.js tests: | ||
* the tests are read from an uniform table. This allows enumerating the testcases, as well as sharing them with browser tests | ||
* added ability to do performance tests -- just run `time node test perf` | ||
* enabled browser tests: | ||
* visual summary with details of all the tests, collapsable and color-coded | ||
* same set of testcases as in node.js | ||
* all tests pass now. Found and fixed a bug that was present in all browsers where they handle bigger-than-byte data differently compared to node.js | ||
* created a static html page to hex display files (view.html) | ||
* restricted the set of node.js versions and browsers (now requires support of `BigInt`: Node.JS 10.4+, browsers since 2018-2020) | ||
* the Travis-ci is passing now | ||
* nits: | ||
* removed some of unused variables | ||
* increased formating consistency | ||
### 0.3.2 | ||
@@ -191,0 +216,0 @@ |
227
test.js
var hexy = require("./hexy.js") | ||
const testcases = require("./test/testcases.js") | ||
var buf = Buffer.from("0123456789abcdefghijklmnopqrstuvwxzy") | ||
var str = "0123456789abcdefghijklmnopqrstuvwxzy" | ||
var nums = [ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, | ||
101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, | ||
115, 116, 117, 118, 119, 120, 122, 121 ] | ||
var testcase_id = [ 0, 0 ] // some tests have multiple variants (distinguished by the intput). To make the navigation easier, the tests are numbered as [line.subtest] | ||
var failed = 0 | ||
var executed = 0 | ||
var iterations = 1 | ||
if (process.argv.includes("perf")) { | ||
iterations = 100000 | ||
} | ||
var execute_first_X_tests = null | ||
if (process.argv.includes("baseline")) { // baselining against version 0.3.2, which | ||
execute_first_X_tests = 29 // had 29 test lines (65 testcases total), that | ||
} // are preserved at the top of the list of tests | ||
var verbose = false | ||
if (process.argv.includes("-v")) { | ||
verbose = true | ||
} | ||
var results = [ | ||
"00000000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
"00000010: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
"00000020: 7778 7a79 wxzy\n", | ||
"00000000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
"00000010: 6768 696A 6B6C 6D6E 6F70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
"00000020: 7778 7A79 wxzy\n", | ||
"00000000: 3031 3233 3435 3637 01234567\n"+ | ||
"00000008: 3839 6162 6364 6566 89abcdef\n"+ | ||
"00000010: 6768 696a 6b6c 6d6e ghijklmn\n"+ | ||
"00000018: 6f70 7172 7374 7576 opqrstuv\n"+ | ||
"00000020: 7778 7a79 wxzy\n", | ||
"00000000: 3031 3233 3435 3637 01234567\n"+ | ||
"00000008: 3839 6162 6364 6566 89abcdef\n"+ | ||
"00000010: 6768 696A 6B6C 6D6E ghijklmn\n"+ | ||
"00000018: 6F70 7172 7374 7576 opqrstuv\n"+ | ||
"00000020: 7778 7A79 wxzy\n", | ||
"3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
"6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
"7778 7a79 wxzy\n", | ||
"00000000: 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 0123456789abcdef\n"+ | ||
"00000010: 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 ghijklmnopqrstuv\n"+ | ||
"00000020: 77 78 7a 79 wxzy\n", | ||
"00000000: 30313233 34353637 38396162 63646566 0123456789abcdef\n" + | ||
"00000010: 6768696a 6b6c6d6e 6f707172 73747576 ghijklmnopqrstuv\n" + | ||
"00000020: 77787a79 wxzy\n", | ||
"00000000: 30313233343536373839616263646566 0123456789abcdef\n"+ | ||
"00000010: 6768696a6b6c6d6e6f70717273747576 ghijklmnopqrstuv\n"+ | ||
"00000020: 77787a79 wxzy\n", | ||
"00000000: 3031 3233 3435 3637 3839 6162 6364 6566 \n"+ | ||
"00000010: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 \n"+ | ||
"00000020: 7778 7a79 \n", | ||
"-00000000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
"-00000010: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
"-00000020: 7778 7a79 wxzy\n", | ||
" 00000000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
" 00000010: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
" 00000020: 7778 7a79 wxzy\n", | ||
"dingdong30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 \n"+ | ||
"dingdong67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 \n"+ | ||
"dingdong77 78 7A 79 \n"+ | ||
"", | ||
"<div class='hexy'>\n"+ | ||
"<div class='00000000 even'>00000000: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef</div>\n"+ | ||
"<div class='00000010 odd'>00000010: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv</div>\n"+ | ||
"<div class='00000020 even'>00000020: 7778 7a79 wxzy</div>\n"+ | ||
"</div>\n", | ||
"0000000a: 6162 6364 6566 6768 696a 6b6c 6d6e 6f70 abcdefghijklmnop\n"+ | ||
"0000001a: 7172 7374 7576 7778 7a79 qrstuvwxzy\n", | ||
"0000000a: 6162 6364 6566 6768 696a abcdefghij\n", | ||
"<div class='hexy'>\n"+ | ||
"<div class='0000000a even'>0000000a: 6162 6364 6566 6768 696a abcdefghij</div>\n"+ | ||
"</div>\n", | ||
"0000000a: 3031 3233 3435 3637 3839 6162 6364 6566 0123456789abcdef\n"+ | ||
"0000001a: 6768 696a 6b6c 6d6e 6f70 7172 7374 7576 ghijklmnopqrstuv\n"+ | ||
"0000002a: 7778 7a79 wxzy\n", | ||
"00000014: 6162 6364 6566 6768 696a abcdefghij\n", | ||
] | ||
var format = [ | ||
{}, | ||
{caps:"upper"}, | ||
{width:8}, | ||
{width:8, caps:"upper"}, | ||
{numbering:"none"}, | ||
{format:"twos"}, | ||
{format:"eights"}, | ||
{format:"none"}, | ||
{annotate:"none"}, | ||
{prefix:"-"}, | ||
{indent:"5"}, | ||
{caps:"upper", numbering:"none", annotate:"none", prefix:"dingdong", format:"twos"}, | ||
{html:true}, | ||
{offset:10}, | ||
{offset:10, length:10}, | ||
{offset:10, length:10, html:true}, | ||
{display_offset: 10}, | ||
{display_offset: 10, offset:10, length:10}, | ||
] | ||
function check (should, is) { | ||
function check(should, is) { | ||
if (should !== is) { | ||
console.log("failed:") | ||
console.log("\x1b[31m FAILED testcase # " + testcase_id + "\x1b[0m") | ||
console.log(" EXPECTED") | ||
console.log(should) | ||
console.log(" ACTUALLY RETURNED") | ||
console.log(is) | ||
console.log("more detailed view of EXPECTED:") | ||
console.log(hexy.hexy(should)) | ||
console.log("more detailed view of ACTUALLY RETURNED:") | ||
console.log(hexy.hexy(is)) | ||
console.log("==") | ||
console.log(should) | ||
failed++ | ||
} else if (verbose) { | ||
console.log(is) | ||
return 1 | ||
} | ||
return 0 | ||
executed++ | ||
} | ||
check (results[0], hexy.hexy(buf)) | ||
function p (o) {console.log(o)} | ||
var total, failed; | ||
total = failed = 0 | ||
for (var i = 0; i!= format.length ; ++i) { | ||
failed += check(results[i], hexy.hexy(buf, format[i])) | ||
++total | ||
failed += check(results[i], hexy.hexy(str, format[i])) | ||
++total | ||
failed += check(results[i], hexy.hexy(nums, format[i])) | ||
++total | ||
for (var rep = 0; rep < iterations; rep++) { | ||
for (var tc = 0; tc < (execute_first_X_tests || testcases.length); tc++) { | ||
if ('inputs' in testcases[tc]) { | ||
for (var ii = 0; ii < testcases[tc].inputs.length; ii++) { | ||
testcase_id = [tc, ii] | ||
check(testcases[tc].result, hexy.hexy(testcases[tc].inputs[ii], testcases[tc].params)) | ||
} | ||
} else { | ||
testcase_id = tc | ||
check(testcases[tc].result, hexy.hexy(testcases[tc].input, testcases[tc].params)) | ||
} | ||
} | ||
} | ||
_00 = String.fromCharCode(0) | ||
_0000 = _00 + _00 | ||
_08 = String.fromCharCode(8) | ||
_40 = "@" | ||
_53 = "S" | ||
_5100 = "Q"+_00 | ||
var str2 = _00 + _00 + _08 + _40 + _53 + _00 + _0000 + _5100 + _0000 + _5100 + _0000 | ||
var xxd2 = "00000000: 0000 0840 5300 0000 5100 0000 5100 0000 ...@S...Q...Q...\n" | ||
failed += check(xxd2, hexy.hexy(str2)) | ||
++total | ||
str3 = "#include<stdio.h>\n" | ||
xxd3 = "00000000: 2369 6e63 6c75 6465 3c73 7464 696f 2e68 #include<stdio.h\n"+ | ||
"00000010: 3e0a >.\n" | ||
failed += check(xxd3, hexy.hexy(str3)) | ||
++total | ||
xxd4 = "<div class='hexy'>\n"+ | ||
"<div class='00000000 even'>00000000: 2369 6e63 6c75 6465 3c73 7464 696f 2e68 #include<stdio.h</div>\n"+ | ||
"<div class='00000010 odd'>00000010: 3e0a >.</div>\n"+ | ||
"</div>\n" | ||
failed += check(xxd4, hexy.hexy(str3, {html:true})) | ||
++total | ||
// empty string/buffer/nil etc should return empty string, as does xxd | ||
var empties = ["", undefined, null] | ||
empties.forEach( function (empty) { | ||
failed += check("", hexy.hexy(empty)) | ||
++total | ||
}) | ||
// Number arrays with bytes work, arrays containing values larger that | ||
// 0xff are truncated ( val & 0xff ) | ||
var arr = [0x1001, 0x2002, 0x3003, 0xf00f] | ||
var arr_e = "00000000: 0102 030f ....\n" | ||
failed += check(arr_e, hexy.hexy(arr)) | ||
++total | ||
// non numerical width | ||
failed += check(arr_e, hexy.hexy(arr, {width: "something"})) | ||
++total | ||
arr_e = "00000000: 0102 ..\n00000002: 030f ..\n" | ||
failed += check(arr_e, hexy.hexy(arr, {width: "2"})) | ||
++total | ||
arr_e = "00000000: 01 .\n00000001: 02 .\n00000002: 03 .\n00000003: 0f .\n" | ||
failed += check(arr_e, hexy.hexy(arr, {width: 1})) | ||
++total | ||
function checkVersion () { | ||
@@ -195,14 +57,13 @@ const fs = require("fs") | ||
failed += check(version, hexy.Hexy.VERSION) | ||
++total | ||
check(version, hexy.Hexy.VERSION) | ||
} | ||
checkVersion() | ||
console.log("Executed: " + executed + ", Failed: " + failed) | ||
if (iterations > 1) { | ||
console.log("This was a perf run over " + iterations + " iterations") | ||
} | ||
p("failed: "+failed+" of "+total) | ||
if (failed != 0) { | ||
process.exit(1) | ||
} | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
54787
16
806
230