src/packkit@zlib.erl
-module(packkit@zlib).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/zlib.gleam").
-export([codec/0, encode/1, encode_with_dictionary/2, decode_with_limits/2, decode/1, decode_with_dictionary_and_limits/3, decode_with_dictionary/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" RFC 1950 zlib codec.\n"
"\n"
" zlib wraps a DEFLATE stream in a two-byte header and a trailing\n"
" Adler-32 checksum. The encoder delegates to the DEFLATE\n"
" fixed-Huffman writer; the decoder enforces the CMF/FLG check bits\n"
" and the trailing Adler-32, and can resolve the optional `FDICT`\n"
" preset-dictionary path when the caller supplies the dictionary.\n"
).
-file("src/packkit/zlib.gleam", 28).
?DOC(" Zlib codec smart constructor.\n").
-spec codec() -> packkit@codec:codec().
codec() ->
packkit@codec:zlib().
-file("src/packkit/zlib.gleam", 188).
-spec adler_trailer(bitstring()) -> bitstring().
adler_trailer(Payload) ->
Value = packkit@checksum:adler32(Payload),
<<Value:32/big>>.
-file("src/packkit/zlib.gleam", 206).
-spec verify_dict_id(bitstring(), bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
verify_dict_id(Rest, Dictionary) ->
case Rest of
<<Stored_dict_id:32/big, After_dict_id/binary>> ->
Expected = packkit@checksum:adler32(Dictionary),
case Stored_dict_id =:= Expected of
true ->
{ok, After_dict_id};
false ->
{error, {codec_dictionary_mismatch, <<"zlib"/utf8>>}}
end;
_ ->
{error,
{codec_invalid_data,
<<"zlib: FDICT set but DICT_ID truncated"/utf8>>}}
end.
-file("src/packkit/zlib.gleam", 193).
-spec consume_fdict_if_present(bitstring(), boolean(), boolean(), bitstring()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
consume_fdict_if_present(Rest, Has_fdict_bit, Has_dict, Dictionary) ->
case {Has_fdict_bit, Has_dict} of
{false, _} ->
{ok, Rest};
{true, false} ->
{error, {codec_dictionary_required, <<"zlib"/utf8>>}};
{true, true} ->
verify_dict_id(Rest, Dictionary)
end.
-file("src/packkit/zlib.gleam", 36).
?DOC(
" Encode `data` as a zlib byte stream. The DEFLATE body uses the\n"
" dynamic-Huffman encoder (BTYPE=10) for better compression on\n"
" typical inputs; pathologically-skewed payloads fall back to\n"
" fixed Huffman (BTYPE=01) inside `deflate.encode_dynamic`.\n"
).
-spec encode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode(Bytes) ->
gleam@result:'try'(
packkit@deflate:encode_dynamic(Bytes),
fun(Deflated) ->
Header = <<16#78, 16#01>>,
Trailer = adler_trailer(Bytes),
{ok, gleam_stdlib:bit_array_concat([Header, Deflated, Trailer])}
end
).
-file("src/packkit/zlib.gleam", 50).
?DOC(
" Encode `bytes` as a zlib stream carrying the preset-dictionary\n"
" adler ID for `dictionary`. The body is emitted by the\n"
" dynamic-Huffman DEFLATE encoder over `bytes` alone; the receiver\n"
" must already share `dictionary` to verify the four-byte DICT_ID.\n"
" Callers that have the dictionary on both sides can use this to\n"
" round-trip a stream they will later decode with\n"
" `decode_with_dictionary`.\n"
).
-spec encode_with_dictionary(bitstring(), bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode_with_dictionary(Bytes, Dictionary) ->
gleam@result:'try'(
packkit@deflate:encode_dynamic(Bytes),
fun(Deflated) ->
Dict_id = packkit@checksum:adler32(Dictionary),
Header = <<16#78, 16#BB, Dict_id:32/big>>,
Trailer = adler_trailer(Bytes),
{ok, gleam_stdlib:bit_array_concat([Header, Deflated, Trailer])}
end
).
-file("src/packkit/zlib.gleam", 107).
-spec decode_inner(bitstring(), packkit@limit:limits(), bitstring(), boolean()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_inner(Bytes, Limits, Dictionary, Has_dict) ->
gleam@bool:guard(
erlang:byte_size(Bytes) > packkit@limit:max_input_bytes(Limits),
{error,
{codec_limit_exceeded,
<<"max_input_bytes"/utf8>>,
erlang:byte_size(Bytes)}},
fun() -> case Bytes of
<<Cmf, Flg, Rest/binary>> ->
gleam@bool:guard(
erlang:'band'(Cmf, 16#0F) /= 8,
{error,
{codec_invalid_data,
<<"zlib: compression method is not deflate"/utf8>>}},
fun() ->
gleam@bool:guard(
(((Cmf * 256) + Flg) rem 31) /= 0,
{error,
{codec_invalid_data,
<<"zlib: header check bits mismatch"/utf8>>}},
fun() ->
Cinfo = erlang:'bsr'(Cmf, 4),
Window_bits = Cinfo + 8,
gleam@bool:guard(
Window_bits > packkit@limit:max_window_bits(
Limits
),
{error,
{codec_limit_exceeded,
<<"max_window_bits"/utf8>>,
Window_bits}},
fun() ->
Has_fdict_bit = erlang:'band'(
Flg,
16#20
)
/= 0,
gleam@result:'try'(
consume_fdict_if_present(
Rest,
Has_fdict_bit,
Has_dict,
Dictionary
),
fun(Rest@1) ->
Payload_size = erlang:byte_size(
Rest@1
),
gleam@bool:guard(
Payload_size < 4,
{error,
{codec_invalid_data,
<<"zlib: stream missing Adler-32 trailer"/utf8>>}},
fun() ->
Deflate_size = Payload_size
- 4,
Deflate_bits@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
0,
Deflate_size
) of
{ok,
Deflate_bits} -> Deflate_bits;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zlib"/utf8>>,
function => <<"decode_inner"/utf8>>,
line => 166,
value => _assert_fail,
start => 5438,
'end' => 5506,
pattern_start => 5449,
pattern_end => 5465}
)
end,
Checksum_bits@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
Deflate_size,
4
) of
{ok,
Checksum_bits} -> Checksum_bits;
_assert_fail@1 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zlib"/utf8>>,
function => <<"decode_inner"/utf8>>,
line => 167,
value => _assert_fail@1,
start => 5513,
'end' => 5582,
pattern_start => 5524,
pattern_end => 5541}
)
end,
gleam@result:'try'(
packkit@deflate:decode_with_limits(
Deflate_bits@1,
Limits
),
fun(Plain) ->
Expected = packkit@checksum:adler32(
Plain
),
Stored@1 = case Checksum_bits@1 of
<<Stored:32/big>> -> Stored;
_assert_fail@2 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/zlib"/utf8>>,
function => <<"decode_inner"/utf8>>,
line => 175,
value => _assert_fail@2,
start => 5756,
'end' => 5806,
pattern_start => 5767,
pattern_end => 5790}
)
end,
gleam@bool:guard(
Stored@1
/= Expected,
{error,
{codec_invalid_data,
<<"zlib: Adler-32 mismatch"/utf8>>}},
fun() ->
{ok,
Plain}
end
)
end
)
end
)
end
)
end
)
end
)
end
);
_ ->
{error,
{codec_invalid_data,
<<"zlib: input too short for header"/utf8>>}}
end end
).
-file("src/packkit/zlib.gleam", 69).
?DOC(
" Decode a zlib byte stream using explicit limits. Returns\n"
" `CodecDictionaryRequired` when the stream sets the `FDICT` bit;\n"
" use [decode_with_dictionary] in that case.\n"
).
-spec decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_with_limits(Bytes, Limits) ->
decode_inner(Bytes, Limits, <<>>, false).
-file("src/packkit/zlib.gleam", 62).
?DOC(" Decode a zlib byte stream using default limits.\n").
-spec decode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
decode(Bytes) ->
decode_with_limits(Bytes, packkit@limit:default()).
-file("src/packkit/zlib.gleam", 94).
?DOC(
" Like [decode_with_dictionary] but accepts an explicit `Limits`\n"
" value.\n"
).
-spec decode_with_dictionary_and_limits(
bitstring(),
bitstring(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_with_dictionary_and_limits(Bytes, Dictionary, Limits) ->
decode_inner(Bytes, Limits, Dictionary, true).
-file("src/packkit/zlib.gleam", 81).
?DOC(
" Decode a zlib byte stream that uses the FDICT preset-dictionary\n"
" path. Verifies the four-byte DICT_ID against the supplied bytes\n"
" and returns `CodecDictionaryMismatch` when they do not agree. If\n"
" `bytes` does not advertise FDICT this falls through to the regular\n"
" decoder so callers can pass the dictionary defensively.\n"
).
-spec decode_with_dictionary(bitstring(), bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
decode_with_dictionary(Bytes, Dictionary) ->
decode_with_dictionary_and_limits(
Bytes,
Dictionary,
packkit@limit:default()
).