-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), <>. -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 <> -> 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 <> -> 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 => <>, 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 => <>, 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; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, 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() ).