///|
async fn skip_bytes(reader : &@io.Reader, count : Int64) -> Unit {
let buffer : FixedArray[Byte] = FixedArray::make(65536, 0)
let mut remaining = count
while remaining > 0L {
let count = reader.read(buffer, max_len=remaining.min(65536L).to_int())
if count == 0 {
raise CliError(4, "xxd: Sorry, cannot seek.")
}
remaining -= count.to_int64()
}
}
///|
async fn input_offset(file : @fs.File?, seek : Seek?) -> Int64 {
guard seek is Some(seek) else { return 0L }
let amount = if seek.negative { -seek.amount } else { seek.amount }
if !seek.negative {
return amount
}
guard file is Some(file) else {
raise CliError(4, "xxd: Sorry, cannot seek.")
}
if file.kind() != @fs.Regular && file.kind() != @fs.BlockDevice {
raise CliError(4, "xxd: Sorry, cannot seek.")
}
let start = if seek.relative { 0L } else { file.size() }
let position = checked_add(start, amount, 4, "xxd: Sorry, cannot seek.")
if position < 0L {
raise CliError(4, "xxd: Sorry, cannot seek.")
}
position
}
///|
priv struct Output {
file : @fs.File?
mut position : Int64
}
///|
async fn Output::write(self : Output, bytes : Bytes) -> Unit {
let next = checked_add(
self.position,
bytes.length().to_int64(),
3,
"xxd: output offset overflow.",
)
try {
match self.file {
Some(file) => file.write_at(bytes[:], position=self.position)
None => @stdio.stdout.write(bytes)
}
} catch {
error => raise CliError(3, "xxd: \{error}")
}
self.position = next
}
///|
async fn Output::seek(self : Output, position : Int64) -> Unit {
if position < 0L || (self.file is None && position < self.position) {
raise CliError(5, "xxd: Sorry, cannot seek backwards.")
}
if self.file is Some(_) {
self.position = position
return
}
let zeros = Bytes::make(65536, b'\x00')
while self.position < position {
let count = (position - self.position).min(65536L).to_int()
self.write(zeros[:count].to_owned())
}
}