Init with the basics

This commit is contained in:
Colby Russell committed 2026-09-24 11:16:57 -05:00
commit 800161fd6d
6 files changed
+3919

No files matched your search

+299
View File
@@ -0,0 +1,299 @@
/*
* A port of xxd as distributed with Vim 8.2 (on Ubuntu 22.04 LTS).
*
* That utility's source code is distributed with the following notice:
*
* (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
*
* I hereby grant permission to distribute and use xxd
* under X11-MIT or GPL-2.0 (at the user's choice).
*
* Contributions by Bram Moolenaar et al.
*
* Only the defaults are supported at this time. The argument processing
* logic is mostly absent.
*
* The choices made here (and there are few--we primarily aim for the source
* to correspond to the routines just as they appear in xxd-8.2.3995.c) are
* done with the main aim being to reconcile the impedance mismatch between
* the C implementation and the dialect used here for the programming
* environment we are targeting. Modifications have been made where necessary
* with the foremost goal being to get the code to work. It is not meant to
* be efficient nor to satisfy some other measure of good. This is bad code.
*
* This class doesn't actually output anything (or read anything, for that
* matter). It does its work with the `input` and `output` buffers. There is
* a `toString` implementation to reify the completed dump as a string.
*/
export
class XXD {
exec() {
const _static = new XXD.Keeps;
const { EOF } = XXD;
const { HEX_NORMAL } = XXD;
const { HEX_POSTSCRIPT } = XXD;
const { HEX_CINCLUDE } = XXD;
const { HEX_BITS } = XXD;
const { HEX_LITTLEENDIAN } = XXD;
const { COLS } = XXD;
const { LLEN } = XXD;
const $ = ((c) => (c.charCodeAt(0)));
const $$ = ((s) => (Uint8Array.from(s, $)));
const $puts = ((...args) => (this._putOrDie(...args)));
const $exit = ((...args) => (this._exit(...args)));
const hexx = $$("0123456789abcdef0123456789ABCDEF");
let fp = this.input;
let fpo = this.output;
let c, e, p = 0;
let relseek = 1;
let negseek = 0;
let revert = 0;
let cols = 0;
let nonzero = 0;
let autoskip = 0;
let hextype = HEX_NORMAL;
let capitalize, decimaloff = 0;
let ebcdic = 0;
let octspergrp = -1;
let grplen;
let length = -1, n = 0, seekoff = 0;
let displayoff = 0;
let l = new Uint8Array(LLEN + 1);
let pp;
let addrlen = 9;
if (!cols) {
switch (hextype) {
case HEX_POSTSCRIPT: cols = 30; break;
case HEX_CINCLUDE: cols = 12; break;
case HEX_BITS: cols = 6; break;
case HEX_NORMAL:
case HEX_LITTLENDIAN:
default: cols = 16; break;
}
}
if (octspergrp < 0) {
switch (hextype) {
case HEX_BITS: octspergrp = 1; break;
case HEX_NORMAL: octspergrp = 2; break;
case HEX_LITTLENDIAN: octspergrp = 4; break;
case HEX_POSTSCRIPT:
case HEX_CINCLUDE:
default: octspergrp = 0; break;
}
}
if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS ||
hextype == HEX_LITTLEENDIAN) && (cols > COLS))) {
return void this._exit(
1, null, pname + ": invalid number of columns (max. " + COLS + ")"
);
}
if (octspergrp < 1 || octspergrp > cols) {
octspergrp = cols;
} else if (hextype == HEX_LITTLEENDIAN) {
if (octspergrp & (octspergrp - 1)) {
return void this._exit(
1, "number of octets per group must be a power of 2 with -e."
);
}
}
if (revert) {
if (hextype && hextype != HEX_POSTSCRIPT) {
return void this._exit(-1, "Sorry, cannot revert this type of hexdump");
}
return void this._exit(XXD.UNIMPLEMENTED); // XXX
}
if (seekoff || negseek || !relseek) {
if (relseek) {
e = _fseek(fp, (negseek) ? -seekoff : seekoff, SEEK_CUR);
} else {
e = _fseek(fp, (negseek) ? -seekoff : seekoff,
(negseek) ? SEEK_END : SEEK_SET);
}
if (e < 0 && negseek) {
return void this._exit(4, "Sorry, cannot seek.");
} else if (e >= 0) {
seekoff = _ftell(fp);
} else {
let s = seekoff;
while (s--) {
let e = this._getOrDie(fp);
if (e == EOF) return void this._exit(4, "Sorry, cannot seek.");
}
}
}
if (hextype == HEX_CINCLUDE) {
return void this._exit(XXD.UNIMPLEMENTED); // XXX
} else if (hextype == HEX_POSTSCRIPT) {
return void this._exit(XXD.UNIMPLEMENTED); // XXX
}
if (hextype != HEX_BITS) {
grplen = octspergrp + octspergrp + 1;
} else {
grplen = 8 * octspergrp + 1;
}
while (length < 0 || n < length) {
e = this._getOrDie(fp);
if (e == EOF) break;
let x;
if (p == 0) {
addrlen = _sprintf(
l, (decimaloff) ? "%08ld:" : "%08lx:",
n + seekoff + displayoff
);
for (c = addrlen; c < LLEN; l[c++] = $(' '));
}
x = (hextype == HEX_LITTLEENDIAN) ? (p ^ (octspergrp - 1)) : p;
c = addrlen + 1 + ~~((grplen * x) / octspergrp);
if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN) {
l[c+0] = hexx[(e >> 4) & 0x0F];
l[++c] = hexx[(e >> 0) & 0x0F];
} else { // HEX_BITS
for (let i = 7; i >= 0; --i) {
l[c++] = (e & (1 << i)) ? $('1') : $('0');
}
}
if (e) nonzero++;
if (ebcdic) return void this._exit(XXD.UNIMPLEMENTED); // XXX
c = addrlen + 3 + ~~((grplen * cols - 1) / octspergrp) + p;
if (31 < e && e < 127) {
l[c++] = e;
} else {
l[c++] = $('.');
}
++n;
if (++p == cols) {
l[c+0] = $('\n');
l[++c] = $('\0');
_xxdline(fpo, l , (autoskip) ? nonzero : 1);
nonzero = 0;
p = 0;
}
}
if (p) {
l[c+0] = $('\n');
l[++c] = $('\0');
_xxdline(fpo, l, 1);
} else if (autoskip) {
_xxdline(fpo, l, -1);
}
function _xxdline(fp, l, nz, _ = _static) {
if (!nz && _.s == 1) {
_strcpy(_.z, l);
}
if (nz || !_.s++) {
if (nz) {
if (nz < 0) _.s--;
if (_.s == 2) $puts(_.z, fp);
if (_.s > 2) $puts($$("*\n"), fp);
}
if (nz >= 0 || _.s > 0) $puts(l, fp);
if (nz) _.s = 0;
}
}
function _strcpy(dest, src) {
let stop = src.indexOf(0);
if (stop >= 0) {
dest.set(new Uint8Array(src.buffer, 0, stop));
} else {
return void $exit(XXD.IMPLEMENTATION_ERROR); // XXX
}
}
function _sprintf(bytes, format, ...args) {
if (args.length == 1 && format == "%08lx:") {
let what = args[0].toString(16).padStart(8, "0") + ":";
bytes.set($$(what));
return what.length;
}
return void $exit(XXD.UNIMPLEMENTED); // XXX
}
}
constructor(input, output = []) {
this.input = input;
this.output = output;
this._place = 0;
}
toString() {
return this.output.map((x) => (String.fromCharCode(x))).join("");
}
_getOrDie(fp) {
if (fp == this.input) {
if (this._place < this.input.length) {
return this.input[this._place++];
}
return XXD.EOF;
}
return void this._exit(XXD.UNIMPLEMENTED); // XXX
}
_putOrDie(bytes, fp) {
if (fp == this.output) {
for (let i = 0, n = bytes.length; i < n; ++i) {
if (bytes[i] == 0) return;
this.output.push(bytes[i]);
}
}
return void this._exit(XXD.UNIMPLEMENTED); // XXX
}
}
XXD.Keeps = class {
constructor() {
this.s = 0; // was `zero_seen` in C
this.z = new Uint8Array(XXD.LLEN + 1);
}
}
XXD.HEX_NORMAL = 0;
XXD.HEX_POSTSCRIPT = 1;
XXD.HEX_CINCLUDE = 2;
XXD.HEX_BITS = 3;
XXD.HEX_LITTLEENDIAN = 4;
XXD.COLS = 256;
XXD.LLEN = 2573; // XXX (2 * 4) + 4 + (9 * COLS - 1) + COLS + 2
XXD.EOF = -1;
XXD.UNIMPLEMENTED = 90;
XXD.IMPLEMENTATION_ERROR = 91;