diff --git a/src/CodecZstd.jl b/src/CodecZstd.jl index dffbcc1..9778a43 100644 --- a/src/CodecZstd.jl +++ b/src/CodecZstd.jl @@ -5,7 +5,8 @@ export ZstdCompressorStream, ZstdFrameCompressor, ZstdDecompressor, - ZstdDecompressorStream + ZstdDecompressorStream, + ZstdError import TranscodingStreams: TranscodingStreams, diff --git a/src/compression.jl b/src/compression.jl index cabc3f9..0822064 100644 --- a/src/compression.jl +++ b/src/compression.jl @@ -81,7 +81,7 @@ end function TranscodingStreams.initialize(codec::ZstdCompressor) code = initialize!(codec.cstream, codec.level) if iserror(code) - zstderror(codec.cstream, code) + throw(ZstdError(code)) end reset!(codec.cstream.ibuffer) reset!(codec.cstream.obuffer) @@ -92,7 +92,7 @@ function TranscodingStreams.finalize(codec::ZstdCompressor) if codec.cstream.ptr != C_NULL code = free!(codec.cstream) if iserror(code) - zstderror(codec.cstream, code) + throw(ZstdError(code)) end codec.cstream.ptr = C_NULL end @@ -104,7 +104,7 @@ end function TranscodingStreams.startproc(codec::ZstdCompressor, mode::Symbol, error::Error) code = reset!(codec.cstream, 0 #=unknown source size=#) if iserror(code) - error[] = ErrorException("zstd error") + error[] = ZstdError(code) return :error end return :ok @@ -144,8 +144,7 @@ function TranscodingStreams.process(codec::ZstdCompressor, input::Memory, output Δin = Int(cstream.ibuffer.pos - ibuffer_starting_pos) Δout = Int(cstream.obuffer.pos) if iserror(code) - ptr = LibZstd.ZSTD_getErrorName(code) - error[] = ErrorException("zstd error: " * unsafe_string(ptr)) + error[] = ZstdError(code) return Δin, Δout, :error else return Δin, Δout, input.size == 0 && code == 0 ? :end : :ok diff --git a/src/decompression.jl b/src/decompression.jl index 765ce2c..a169068 100644 --- a/src/decompression.jl +++ b/src/decompression.jl @@ -36,7 +36,7 @@ end function TranscodingStreams.initialize(codec::ZstdDecompressor) code = initialize!(codec.dstream) if iserror(code) - zstderror(codec.dstream, code) + throw(ZstdError(code)) end reset!(codec.dstream.ibuffer) reset!(codec.dstream.obuffer) @@ -47,7 +47,7 @@ function TranscodingStreams.finalize(codec::ZstdDecompressor) if codec.dstream.ptr != C_NULL code = free!(codec.dstream) if iserror(code) - zstderror(codec.dstream, code) + throw(ZstdError(code)) end codec.dstream.ptr = C_NULL end @@ -59,7 +59,7 @@ end function TranscodingStreams.startproc(codec::ZstdDecompressor, mode::Symbol, error::Error) code = reset!(codec.dstream) if iserror(code) - error[] = ErrorException("zstd error") + error[] = ZstdError(code) return :error end return :ok @@ -77,7 +77,7 @@ function TranscodingStreams.process(codec::ZstdDecompressor, input::Memory, outp Δin = Int(dstream.ibuffer.pos) Δout = Int(dstream.obuffer.pos) if iserror(code) - error[] = ErrorException("zstd error") + error[] = ZstdError(code) return Δin, Δout, :error else if code == 0 diff --git a/src/libzstd.jl b/src/libzstd.jl index 79d021d..a145d71 100644 --- a/src/libzstd.jl +++ b/src/libzstd.jl @@ -5,11 +5,24 @@ function iserror(code::Csize_t) return LibZstd.ZSTD_isError(code) != 0 end +# deprecated error reporting function zstderror(stream, code::Csize_t) + zstderror(code) +end +function zstderror(code::Integer) ptr = LibZstd.ZSTD_getErrorName(code) error("zstd error: ", unsafe_string(ptr)) end +# new error reporting +struct ZstdError <: Exception + code::Csize_t +end +ZstdError() = ZstdError(typemax(Csize_t)) +function Base.show(io::IO, e::ZstdError) + print(io, "ZstdError: ", unsafe_string(LibZstd.ZSTD_getErrorName(e.code))) +end + function max_clevel() return LibZstd.ZSTD_maxCLevel() end diff --git a/test/runtests.jl b/test/runtests.jl index 7ca5875..937d5be 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -83,4 +83,5 @@ Random.seed!(1234) end include("compress_endOp.jl") + include("zstderror.jl") end diff --git a/test/zstderror.jl b/test/zstderror.jl new file mode 100644 index 0000000..c85481c --- /dev/null +++ b/test/zstderror.jl @@ -0,0 +1,47 @@ +using Test +using CodecZstd: ZstdError + +@static if VERSION ≥ v"1.8" +@testset "ZSTD Errors" begin + @test_throws "ZstdError: No error detected" throw(ZstdError(0)) + @test_throws "ZstdError: Error (generic)" throw(ZstdError(18446744073709551615)) + @test_throws "ZstdError: Unknown frame descriptor" throw(ZstdError(18446744073709551606)) + @test_throws "ZstdError: Version not supported" throw(ZstdError(18446744073709551604)) + @test_throws "ZstdError: Unsupported frame parameter" throw(ZstdError(18446744073709551602)) + @test_throws "ZstdError: Frame requires too much memory for decoding" throw(ZstdError(18446744073709551600)) + @test_throws "ZstdError: Data corruption detected" throw(ZstdError(18446744073709551596)) + @test_throws "ZstdError: Restored data doesn't match checksum" throw(ZstdError(18446744073709551594)) + @test_throws "ZstdError: Header of Literals' block doesn't respect format specification" throw(ZstdError(18446744073709551592)) + @test_throws "ZstdError: Dictionary is corrupted" throw(ZstdError(18446744073709551586)) + @test_throws "ZstdError: Dictionary mismatch" throw(ZstdError(18446744073709551584)) + @test_throws "ZstdError: Cannot create Dictionary from provided samples" throw(ZstdError(18446744073709551582)) + @test_throws "ZstdError: Unsupported parameter" throw(ZstdError(18446744073709551576)) + @test_throws "ZstdError: Unsupported combination of parameters" throw(ZstdError(18446744073709551575)) + @test_throws "ZstdError: Parameter is out of bound" throw(ZstdError(18446744073709551574)) + @test_throws "ZstdError: tableLog requires too much memory : unsupported" throw(ZstdError(18446744073709551572)) + @test_throws "ZstdError: Unsupported max Symbol Value : too large" throw(ZstdError(18446744073709551570)) + @test_throws "ZstdError: Specified maxSymbolValue is too small" throw(ZstdError(18446744073709551568)) + @test_throws "ZstdError: pledged buffer stability condition is not respected" throw(ZstdError(18446744073709551566)) + @test_throws "ZstdError: Operation not authorized at current processing stage" throw(ZstdError(18446744073709551556)) + @test_throws "ZstdError: Context should be init first" throw(ZstdError(18446744073709551554)) + @test_throws "ZstdError: Allocation error : not enough memory" throw(ZstdError(18446744073709551552)) + @test_throws "ZstdError: workSpace buffer is not large enough" throw(ZstdError(18446744073709551550)) + @test_throws "ZstdError: Destination buffer is too small" throw(ZstdError(18446744073709551546)) + @test_throws "ZstdError: Src size is incorrect" throw(ZstdError(18446744073709551544)) + @test_throws "ZstdError: Operation on NULL destination buffer" throw(ZstdError(18446744073709551542)) + @test_throws "ZstdError: Operation made no progress over multiple calls, due to output buffer being full" throw(ZstdError(18446744073709551536)) + @test_throws "ZstdError: Operation made no progress over multiple calls, due to input being empty" throw(ZstdError(18446744073709551534)) +end +end + +# Use the following function to print the tests above +function print_error_tests() + err_codes = [0, 1, 10, 12, 14, 16, 20, 22, 24, 30, 32, 34, 40, 41, 42, 44, 46, 48, 50, 60, 62, 64, 66, 70, 72, 74, 80, 82]; + println("@testset \"ZSTD Errors\" begin") + for err_code in err_codes + code = typemax(Csize_t)-err_code+1 + println(" @test_throws \"" * string(CodecZstd.ZstdError(typemax(Csize_t) - err_code + 1)) * "\" throw(ZstdError($code))") + end + println("end") +end +