///|
priv suberror HexdumpError {
HexdumpError(String)
}
///|
struct DumpState {
modes : Array[String]
verbose : Bool
pending : Array[Byte]
mut skip : Int64
mut remaining : Int64?
mut offset : Int64
mut previous : Bytes?
mut squeezed : Bool
}
///|
fn DumpState::row(self : DumpState) -> String {
let data = Bytes::from_array(self.pending)
self.pending.clear()
let out = StringBuilder()
if !self.verbose && data.length() == 16 && self.previous == Some(data) {
if !self.squeezed {
out.write_string("*\n")
self.squeezed = true
}
} else {
self.squeezed = false
for mode in self.modes {
out.write_string(render_row(data, self.offset, mode))
}
}
self.previous = Some(data)
self.offset += data.length().to_int64()
out.to_string()
}
///|
fn DumpState::feed(self : DumpState, chunk : Bytes) -> String {
let out = StringBuilder()
for byte in chunk {
if self.skip > 0L {
self.skip -= 1L
self.offset += 1L
continue
}
if self.remaining == Some(0L) {
break
}
self.pending.push(byte)
if self.remaining is Some(n) {
self.remaining = Some(n - 1L)
}
if self.pending.length() == 16 {
out.write_string(self.row())
}
}
out.to_string()
}
///|
async fn DumpState::read(self : DumpState, reader : &@io.Reader) -> Unit {
let buffer : FixedArray[Byte] = FixedArray::make(65536, 0)
while self.skip > 0L || self.remaining != Some(0L) {
let maximum = match self.remaining {
Some(n) => self.skip.min(65536L) + n.min(65536L)
None => 65536L
}
let count = reader.read(buffer, max_len=maximum.min(65536L).to_int())
if count == 0 {
break
}
@stdio.stdout.write(self.feed(Bytes::from_array(buffer[:count].to_owned())))
}
}
///|
fn parse_count(text : String) -> Int64 raise HexdumpError {
if text == "" || text.has_prefix("-") {
raise HexdumpError("invalid byte count '\{text}'")
}
let mut digits = text
let mut multiplier = 1L
for
(suffix, factor) in [
("KiB", 1024L),
("MiB", 1048576L),
("GiB", 1073741824L),
("KB", 1000L),
("MB", 1000000L),
("GB", 1000000000L),
("K", 1024L),
("M", 1048576L),
("G", 1073741824L),
("k", 1024L),
("m", 1048576L),
("g", 1073741824L),
("b", 512L),
] {
if text.has_suffix(suffix) {
digits = text[:text.length() - suffix.length()].to_owned()
multiplier = factor
break
}
}
let radix = if digits.has_prefix("0x") || digits.has_prefix("0X") {
16
} else if digits.length() > 1 && digits[0] == '0' {
8
} else {
10
}
if radix == 16 {
digits = digits[2:].to_owned()
}
let n = @string.parse_int64(digits, base=radix) catch {
_ => raise HexdumpError("invalid byte count '\{text}'")
}
if n < 0L || n > 9223372036854775807L / multiplier {
raise HexdumpError("byte count out of range")
}
n * multiplier
}