///|
/// Error categories reported by fzip operations.
///
/// Most public decompression and archive-reading APIs raise `FzipError` with
/// one of these codes. The code is intended for programmatic handling while the
/// error message gives a human-readable explanation.
pub(all) enum FzipErrorCode {
/// The input ended before the current format could be fully decoded.
UnexpectedEOF
/// A DEFLATE block used an invalid block type.
InvalidBlockType
/// A DEFLATE length or literal code was invalid.
InvalidLengthLiteral
/// A DEFLATE back-reference distance was invalid.
InvalidDistance
/// Reserved for stream state errors after a stream has finished.
StreamFinished
/// Reserved for stream APIs that require an `ondata` handler.
NoStreamHandler
/// A container header, such as GZIP or Zlib, is malformed or unsupported.
InvalidHeader
/// Reserved for APIs that require a callback.
NoCallback
/// Byte data could not be decoded as valid UTF-8.
InvalidUTF8
/// Reserved for ZIP extra fields that exceed supported lengths.
ExtraFieldTooLong
/// Reserved for ZIP timestamps outside the supported date range.
InvalidDate
/// Reserved for filenames that exceed supported lengths.
FilenameTooLong
/// Reserved for stream state errors while finishing.
StreamFinishing
/// ZIP data is malformed, unsafe, or violates configured safety limits.
InvalidZipData
/// A ZIP entry uses a compression method fzip does not support.
UnknownCompressionMethod
/// A checksum footer does not match the decompressed data.
InvalidChecksum
/// Well-formed ZIP64 metadata whose size, offset, count, or layout cannot be
/// represented or safely indexed by the current `Int`/`FixedArray`-based
/// sync APIs. The archive may be structurally valid; the sync API just
/// cannot process it.
Zip64ValueTooLarge
} derive(Eq, Debug)
///|
/// Write the symbolic error-code name, such as `"InvalidHeader"`.
pub impl Show for FzipErrorCode with fn output(self, logger) {
match self {
UnexpectedEOF => logger.write_string("UnexpectedEOF")
InvalidBlockType => logger.write_string("InvalidBlockType")
InvalidLengthLiteral => logger.write_string("InvalidLengthLiteral")
InvalidDistance => logger.write_string("InvalidDistance")
StreamFinished => logger.write_string("StreamFinished")
NoStreamHandler => logger.write_string("NoStreamHandler")
InvalidHeader => logger.write_string("InvalidHeader")
NoCallback => logger.write_string("NoCallback")
InvalidUTF8 => logger.write_string("InvalidUTF8")
ExtraFieldTooLong => logger.write_string("ExtraFieldTooLong")
InvalidDate => logger.write_string("InvalidDate")
FilenameTooLong => logger.write_string("FilenameTooLong")
StreamFinishing => logger.write_string("StreamFinishing")
InvalidZipData => logger.write_string("InvalidZipData")
UnknownCompressionMethod => logger.write_string("UnknownCompressionMethod")
InvalidChecksum => logger.write_string("InvalidChecksum")
Zip64ValueTooLarge => logger.write_string("Zip64ValueTooLarge")
}
}
///|
let error_messages : Array[String] = [
"unexpected EOF", "invalid block type", "invalid length/literal", "invalid distance",
"stream finished", "no stream handler", "invalid header", "no callback", "invalid UTF-8 data",
"extra field too long", "date not in range 1980-2099", "filename too long", "stream finishing",
"invalid zip data", "unknown compression method", "invalid checksum", "zip64 value too large for sync API",
]
///|
/// Error raised by fzip decoding, decompression, and archive-reading APIs.
///
/// `code` is stable enough for branching in callers. `message` may include
/// additional context such as the failed format check or violated safety limit.
pub(all) suberror FzipError {
FzipError(code~ : FzipErrorCode, message~ : String)
}
///|
fn fzip_error_code_to_int(code : FzipErrorCode) -> Int {
match code {
UnexpectedEOF => 0
InvalidBlockType => 1
InvalidLengthLiteral => 2
InvalidDistance => 3
StreamFinished => 4
NoStreamHandler => 5
InvalidHeader => 6
NoCallback => 7
InvalidUTF8 => 8
ExtraFieldTooLong => 9
InvalidDate => 10
FilenameTooLong => 11
StreamFinishing => 12
InvalidZipData => 13
UnknownCompressionMethod => 14
InvalidChecksum => 15
Zip64ValueTooLarge => 16
}
}
///|
fn fzip_err(code : FzipErrorCode, msg? : String = "") -> FzipError {
let message = if msg != "" {
msg
} else {
error_messages[fzip_error_code_to_int(code)]
}
FzipError(code~, message~)
}
///|
fn[T] fzip_result(f : () -> T raise FzipError) -> Result[T, FzipError] {
try f() catch {
err => Err(err)
} noraise {
value => Ok(value)
}
}