-module(packkit@lz4).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/lz4.gleam").
-export([codec/0, decode_with_limits/2, decode/1, encode/1, encode_with_content_size/1]).
-export_type([legacy_blocks_step/0, blocks_step/0, block_step/0, copy_step/0]).
-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(
" LZ4 frame format codec.\n"
"\n"
" Decodes LZ4 frames (magic `0x184D2204`) as specified in the LZ4\n"
" Frame Format Description. The encoder runs a greedy 4-byte hash-\n"
" chain match-finder over each block and emits the LZ77 sequences\n"
" in the canonical block layout (token byte + optional length\n"
" extensions + literals + 16-bit little-endian offset + optional\n"
" match-length extensions). Blocks that don't shrink are emitted\n"
" in the uncompressed form to guarantee the frame never grows\n"
" beyond `1 + ceil(input_size / block_max) * (4 + block_max)`.\n"
).
-type legacy_blocks_step() :: {legacy_blocks_done, bitstring()} |
{legacy_blocks_continue, bitstring(), bitstring()}.
-type blocks_step() :: {blocks_done, bitstring()} |
{blocks_continue, bitstring(), bitstring()}.
-type block_step() :: {block_done, bitstring()} |
{block_continue, bitstring(), bitstring()}.
-type copy_step() :: {copy_done, bitstring()} |
{copy_continue, bitstring(), integer()}.
-file("src/packkit/lz4.gleam", 58).
?DOC(" LZ4 frame codec smart constructor.\n").
-spec codec() -> packkit@codec:codec().
codec() ->
packkit@codec:lz4().
-file("src/packkit/lz4.gleam", 356).
-spec build_byte_table(
bitstring(),
integer(),
gleam@dict:dict(integer(), integer())
) -> gleam@dict:dict(integer(), integer()).
build_byte_table(Bytes, Index, Acc) ->
case Bytes of
<<B, Rest/binary>> ->
build_byte_table(Rest, Index + 1, gleam@dict:insert(Acc, Index, B));
_ ->
Acc
end.
-file("src/packkit/lz4.gleam", 368).
-spec byte_at(gleam@dict:dict(integer(), integer()), integer()) -> integer().
byte_at(Table, Index) ->
case gleam_stdlib:map_get(Table, Index) of
{ok, B} ->
B;
_ ->
0
end.
-file("src/packkit/lz4.gleam", 375).
-spec hash4(integer(), integer(), integer(), integer()) -> integer().
hash4(B0, B1, B2, B3) ->
Combined = erlang:'bor'(
B0,
erlang:'bor'(
erlang:'bsl'(B1, 8),
erlang:'bor'(erlang:'bsl'(B2, 16), erlang:'bsl'(B3, 24))
)
),
erlang:'band'(Combined * 2654435761, 16#FFFF).
-file("src/packkit/lz4.gleam", 393).
-spec bytes4_equal(gleam@dict:dict(integer(), integer()), integer(), integer()) -> boolean().
bytes4_equal(Table, P1, P2) ->
(((byte_at(Table, P1) =:= byte_at(Table, P2)) andalso (byte_at(
Table,
P1 + 1
)
=:= byte_at(Table, P2 + 1)))
andalso (byte_at(Table, P1 + 2) =:= byte_at(Table, P2 + 2)))
andalso (byte_at(Table, P1 + 3) =:= byte_at(Table, P2 + 3)).
-file("src/packkit/lz4.gleam", 400).
-spec lz4_match_length(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer()
) -> integer().
lz4_match_length(Table, Base, Cursor, Limit_pos, Acc) ->
case (Cursor + Acc) >= Limit_pos of
true ->
Acc;
false ->
case byte_at(Table, Base + Acc) =:= byte_at(Table, Cursor + Acc) of
true ->
lz4_match_length(Table, Base, Cursor, Limit_pos, Acc + 1);
false ->
Acc
end
end.
-file("src/packkit/lz4.gleam", 498).
-spec encode_length_extension(integer()) -> bitstring().
encode_length_extension(N) ->
case N of
N@1 when N@1 < 255 ->
<<N@1>>;
_ ->
gleam_stdlib:bit_array_concat(
[<<16#FF>>, encode_length_extension(N - 255)]
)
end.
-file("src/packkit/lz4.gleam", 505).
-spec collect_bytes(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
bitstring()
) -> bitstring().
collect_bytes(Table, Start, Count, Acc) ->
case Count of
0 ->
Acc;
_ ->
collect_bytes(
Table,
Start + 1,
Count - 1,
<<Acc/bitstring, (byte_at(Table, Start))>>
)
end.
-file("src/packkit/lz4.gleam", 480).
-spec emit_literal_only_chunk(
gleam@dict:dict(integer(), integer()),
integer(),
integer()
) -> bitstring().
emit_literal_only_chunk(Table, Start, Lit_len) ->
Lit_high = case Lit_len >= 15 of
true ->
15;
false ->
Lit_len
end,
Token = erlang:'bsl'(Lit_high, 4),
Lit_ext = case Lit_len >= 15 of
true ->
encode_length_extension(Lit_len - 15);
false ->
<<>>
end,
Literals = collect_bytes(Table, Start, Lit_len, <<>>),
gleam_stdlib:bit_array_concat([<<Token>>, Lit_ext, Literals]).
-file("src/packkit/lz4.gleam", 475).
-spec emit_literal_only_block(bitstring(), integer(), integer()) -> bitstring().
emit_literal_only_block(Bytes, Start, Size) ->
Table = build_byte_table(Bytes, 0, maps:new()),
emit_literal_only_chunk(Table, Start, Size).
-file("src/packkit/lz4.gleam", 703).
-spec finalize(bitstring(), bitstring(), boolean()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
finalize(After_end, Output, Content_checksum) ->
case Content_checksum of
false ->
{ok, Output};
true ->
case erlang:byte_size(After_end) >= 4 of
true ->
{ok, Output};
false ->
{error,
{codec_invalid_data,
<<"lz4: content checksum missing"/utf8>>}}
end
end.
-file("src/packkit/lz4.gleam", 834).
-spec read_extension(bitstring(), integer()) -> {ok, {integer(), bitstring()}} |
{error, packkit@error:codec_error()}.
read_extension(Bytes, Acc) ->
case Bytes of
<<B, Rest/binary>> ->
case B of
16#FF ->
read_extension(Rest, Acc + 16#FF);
_ ->
{ok, {Acc + B, Rest}}
end;
_ ->
{error,
{codec_invalid_data, <<"lz4: length extension truncated"/utf8>>}}
end.
-file("src/packkit/lz4.gleam", 911).
-spec append_with_limit(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
append_with_limit(Output, Chunk, Limits) ->
Projected = erlang:byte_size(Output) + erlang:byte_size(Chunk),
case Projected > packkit@limit:max_output_bytes(Limits) of
true ->
{error,
{codec_limit_exceeded, <<"max_output_bytes"/utf8>>, Projected}};
false ->
{ok, gleam_stdlib:bit_array_concat([Output, Chunk])}
end.
-file("src/packkit/lz4.gleam", 894).
-spec copy_match_byte_step(
bitstring(),
integer(),
integer(),
packkit@limit:limits()
) -> {ok, copy_step()} | {error, packkit@error:codec_error()}.
copy_match_byte_step(Output, Offset, Length, Limits) ->
case Length of
0 ->
{ok, {copy_done, Output}};
_ ->
Size = erlang:byte_size(Output),
Byte_slice@1 = case gleam_stdlib:bit_array_slice(
Output,
Size - Offset,
1
) of
{ok, Byte_slice} -> Byte_slice;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"copy_match_byte_step"/utf8>>,
line => 904,
value => _assert_fail,
start => 26798,
'end' => 26867,
pattern_start => 26809,
pattern_end => 26823})
end,
gleam@result:'try'(
append_with_limit(Output, Byte_slice@1, Limits),
fun(New_output) ->
{ok, {copy_continue, New_output, Length - 1}}
end
)
end.
-file("src/packkit/lz4.gleam", 875).
-spec copy_match_byte_by_byte(
bitstring(),
integer(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
copy_match_byte_by_byte(Output, Offset, Length, Limits) ->
case copy_match_byte_step(Output, Offset, Length, Limits) of
{error, Err} ->
{error, Err};
{ok, {copy_done, Out}} ->
{ok, Out};
{ok, {copy_continue, New_output, New_length}} ->
copy_match_byte_by_byte(New_output, Offset, New_length, Limits)
end.
-file("src/packkit/lz4.gleam", 849).
-spec copy_match(bitstring(), integer(), integer(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
copy_match(Output, Offset, Length, Limits) ->
case Length of
0 ->
{ok, Output};
_ ->
Size = erlang:byte_size(Output),
case Offset >= Length of
true ->
Chunk@1 = case gleam_stdlib:bit_array_slice(
Output,
Size - Offset,
Length
) of
{ok, Chunk} -> Chunk;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"copy_match"/utf8>>,
line => 861,
value => _assert_fail,
start => 25518,
'end' => 25587,
pattern_start => 25529,
pattern_end => 25538})
end,
append_with_limit(Output, Chunk@1, Limits);
false ->
copy_match_byte_by_byte(Output, Offset, Length, Limits)
end
end.
-file("src/packkit/lz4.gleam", 756).
-spec decode_block_step(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
block_step()} |
{error, packkit@error:codec_error()}.
decode_block_step(Block, Output, Limits) ->
case Block of
<<Token, Rest/binary>> ->
Lit_len_base = erlang:'bsr'(Token, 4),
Match_len_base = erlang:'band'(Token, 16#0F),
gleam@result:'try'(case Lit_len_base of
15 ->
read_extension(Rest, 15);
_ ->
{ok, {Lit_len_base, Rest}}
end, fun(_use0) ->
{Lit_len, Rest@1} = _use0,
case erlang:byte_size(Rest@1) < Lit_len of
true ->
{error,
{codec_invalid_data,
<<"lz4: literal length exceeds block payload"/utf8>>}};
false ->
Literals@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
0,
Lit_len
) of
{ok, Literals} -> Literals;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_block_step"/utf8>>,
line => 777,
value => _assert_fail,
start => 22993,
'end' => 23052,
pattern_start => 23004,
pattern_end => 23016})
end,
After_literals@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
Lit_len,
erlang:byte_size(Rest@1) - Lit_len
) of
{ok, After_literals} -> After_literals;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_block_step"/utf8>>,
line => 778,
value => _assert_fail@1,
start => 23063,
'end' => 23174,
pattern_start => 23074,
pattern_end => 23092})
end,
gleam@result:'try'(
append_with_limit(Output, Literals@1, Limits),
fun(Output@1) ->
case erlang:byte_size(After_literals@1) of
0 ->
{ok, {block_done, Output@1}};
_ ->
case After_literals@1 of
<<Offset:16/little,
After_offset/binary>> ->
gleam@bool:guard(
Offset =:= 0,
{error,
{codec_invalid_data,
<<"lz4: zero match offset"/utf8>>}},
fun() ->
gleam@result:'try'(
case Match_len_base of
15 ->
read_extension(
After_offset,
15
);
_ ->
{ok,
{Match_len_base,
After_offset}}
end,
fun(_use0@1) ->
{Match_len_extra,
After_offset@1} = _use0@1,
Match_len = Match_len_extra
+ 4,
gleam@bool:guard(
Offset > erlang:byte_size(
Output@1
),
{error,
{codec_invalid_data,
<<"lz4: match offset exceeds output"/utf8>>}},
fun() ->
gleam@result:'try'(
copy_match(
Output@1,
Offset,
Match_len,
Limits
),
fun(
Output@2
) ->
{ok,
{block_continue,
After_offset@1,
Output@2}}
end
)
end
)
end
)
end
);
_ ->
{error,
{codec_invalid_data,
<<"lz4: match offset truncated"/utf8>>}}
end
end
end
)
end
end);
<<>> ->
{ok, {block_done, Output}};
_ ->
{error, {codec_invalid_data, <<"lz4: malformed block"/utf8>>}}
end.
-file("src/packkit/lz4.gleam", 738).
-spec decode_block_loop(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_block_loop(Block, Output, Limits) ->
case decode_block_step(Block, Output, Limits) of
{error, Err} ->
{error, Err};
{ok, {block_done, Out}} ->
{ok, Out};
{ok, {block_continue, Next_block, Next_output}} ->
decode_block_loop(Next_block, Next_output, Limits)
end.
-file("src/packkit/lz4.gleam", 719).
-spec decode_block(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_block(Block, Output, Limits) ->
case erlang:byte_size(Block) of
0 ->
{ok, Output};
_ ->
decode_block_loop(Block, Output, Limits)
end.
-file("src/packkit/lz4.gleam", 927).
-spec maybe_skip(bitstring(), boolean(), integer(), binary()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
maybe_skip(Bytes, Active, Count, Message) ->
case Active of
false ->
{ok, Bytes};
true ->
case erlang:byte_size(Bytes) < Count of
true ->
{error, {codec_invalid_data, Message}};
false ->
After@1 = case gleam_stdlib:bit_array_slice(
Bytes,
Count,
erlang:byte_size(Bytes) - Count
) of
{ok, After} -> After;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"maybe_skip"/utf8>>,
line => 939,
value => _assert_fail,
start => 27760,
'end' => 27860,
pattern_start => 27771,
pattern_end => 27780})
end,
{ok, After@1}
end
end.
-file("src/packkit/lz4.gleam", 947).
-spec block_max_bytes(integer()) -> integer().
block_max_bytes(Index) ->
case Index of
4 ->
64000;
5 ->
256000;
6 ->
1000000;
7 ->
4000000;
_ ->
4000000
end.
-file("src/packkit/lz4.gleam", 542).
-spec decode_legacy_blocks_step(
bitstring(),
bitstring(),
packkit@limit:limits()
) -> {ok, legacy_blocks_step()} | {error, packkit@error:codec_error()}.
decode_legacy_blocks_step(Bytes, Output, Limits) ->
case Bytes of
<<>> ->
{ok, {legacy_blocks_done, Output}};
<<Block_size:32/little, _/binary>> when Block_size =:= 0 ->
{ok, {legacy_blocks_done, Output}};
<<Block_size@1:32/little, _/binary>> when Block_size@1 > 8388608 ->
{ok, {legacy_blocks_done, Output}};
<<Block_size@2:32/little, Rest/binary>> ->
case erlang:byte_size(Rest) < Block_size@2 of
true ->
{error,
{codec_invalid_data,
<<"lz4 legacy: block payload truncated"/utf8>>}};
false ->
Block@1 = case gleam_stdlib:bit_array_slice(
Rest,
0,
Block_size@2
) of
{ok, Block} -> Block;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_legacy_blocks_step"/utf8>>,
line => 569,
value => _assert_fail,
start => 16860,
'end' => 16919,
pattern_start => 16871,
pattern_end => 16880})
end,
After_block@1 = case gleam_stdlib:bit_array_slice(
Rest,
Block_size@2,
erlang:byte_size(Rest) - Block_size@2
) of
{ok, After_block} -> After_block;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_legacy_blocks_step"/utf8>>,
line => 570,
value => _assert_fail@1,
start => 16930,
'end' => 17101,
pattern_start => 16941,
pattern_end => 16956})
end,
gleam@result:'try'(
decode_block(Block@1, Output, Limits),
fun(New_output) ->
{ok,
{legacy_blocks_continue,
After_block@1,
New_output}}
end
)
end;
_ ->
{error,
{codec_invalid_data,
<<"lz4 legacy: block header truncated"/utf8>>}}
end.
-file("src/packkit/lz4.gleam", 524).
-spec decode_legacy_blocks(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_legacy_blocks(Bytes, Output, Limits) ->
case decode_legacy_blocks_step(Bytes, Output, Limits) of
{error, Err} ->
{error, Err};
{ok, {legacy_blocks_done, Out}} ->
{ok, Out};
{ok, {legacy_blocks_continue, Next_bytes, Next_output}} ->
decode_legacy_blocks(Next_bytes, Next_output, Limits)
end.
-file("src/packkit/lz4.gleam", 630).
-spec decode_blocks_step(
bitstring(),
bitstring(),
boolean(),
boolean(),
integer(),
packkit@limit:limits()
) -> {ok, blocks_step()} | {error, packkit@error:codec_error()}.
decode_blocks_step(
Bytes,
Output,
Block_checksum,
Content_checksum,
Block_max,
Limits
) ->
case Bytes of
<<0:32/little, Rest/binary>> ->
case finalize(Rest, Output, Content_checksum) of
{ok, Out} ->
{ok, {blocks_done, Out}};
{error, Err} ->
{error, Err}
end;
<<Header:32/little, Rest@1/binary>> ->
Uncompressed = erlang:'band'(Header, 16#80000000) /= 0,
Block_size = erlang:'band'(
Header,
erlang:'bxor'(16#FFFFFFFF, 16#80000000)
),
gleam@bool:guard(
Block_size > Block_max,
{error,
{codec_invalid_data,
<<"lz4: block size exceeds frame max block size"/utf8>>}},
fun() -> case erlang:byte_size(Rest@1) < Block_size of
true ->
{error,
{codec_invalid_data,
<<"lz4: block payload truncated"/utf8>>}};
false ->
Block@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
0,
Block_size
) of
{ok, Block} -> Block;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_blocks_step"/utf8>>,
line => 662,
value => _assert_fail,
start => 19471,
'end' => 19530,
pattern_start => 19482,
pattern_end => 19491})
end,
After_block@1 = case gleam_stdlib:bit_array_slice(
Rest@1,
Block_size,
erlang:byte_size(Rest@1) - Block_size
) of
{ok, After_block} -> After_block;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_blocks_step"/utf8>>,
line => 663,
value => _assert_fail@1,
start => 19541,
'end' => 19712,
pattern_start => 19552,
pattern_end => 19567})
end,
gleam@result:'try'(case Block_checksum of
true ->
case erlang:byte_size(After_block@1) < 4 of
true ->
{error,
{codec_invalid_data,
<<"lz4: block checksum missing"/utf8>>}};
false ->
After@1 = case gleam_stdlib:bit_array_slice(
After_block@1,
4,
erlang:byte_size(
After_block@1
)
- 4
) of
{ok, After} -> After;
_assert_fail@2 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_blocks_step"/utf8>>,
line => 678,
value => _assert_fail@2,
start => 20052,
'end' => 20253,
pattern_start => 20063,
pattern_end => 20072}
)
end,
{ok, After@1}
end;
false ->
{ok, After_block@1}
end, fun(After_block@2) ->
gleam@result:'try'(case Uncompressed of
true ->
append_with_limit(
Output,
Block@1,
Limits
);
false ->
decode_block(
Block@1,
Output,
Limits
)
end, fun(New_output) ->
{ok,
{blocks_continue,
After_block@2,
New_output}}
end)
end)
end end
);
_ ->
{error,
{codec_invalid_data, <<"lz4: block header truncated"/utf8>>}}
end.
-file("src/packkit/lz4.gleam", 593).
-spec decode_blocks(
bitstring(),
bitstring(),
boolean(),
boolean(),
integer(),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:codec_error()}.
decode_blocks(
Bytes,
Output,
Block_checksum,
Content_checksum,
Block_max,
Limits
) ->
case decode_blocks_step(
Bytes,
Output,
Block_checksum,
Content_checksum,
Block_max,
Limits
) of
{error, Err} ->
{error, Err};
{ok, {blocks_done, Out}} ->
{ok, Out};
{ok, {blocks_continue, Next_bytes, Next_output}} ->
decode_blocks(
Next_bytes,
Next_output,
Block_checksum,
Content_checksum,
Block_max,
Limits
)
end.
-file("src/packkit/lz4.gleam", 112).
?DOC(" Decode an LZ4 frame using explicit resource limits.\n").
-spec decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:codec_error()}.
decode_with_limits(Bytes, Limits) ->
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
<<M:32/little, _/binary>> when M =:= 16#184C2102 ->
After_magic@1 = case gleam_stdlib:bit_array_slice(
Bytes,
4,
erlang:byte_size(Bytes) - 4
) of
{ok, After_magic} -> After_magic;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"decode_with_limits"/utf8>>,
line => 126,
value => _assert_fail,
start => 4235,
'end' => 4329,
pattern_start => 4246,
pattern_end => 4261})
end,
decode_legacy_blocks(After_magic@1, <<>>, Limits);
<<M@1:32/little, Flg, Bd, Rest/binary>> ->
gleam@bool:guard(
M@1 /= 16#184D2204,
{error,
{codec_invalid_data,
<<"lz4: bad frame magic"/utf8>>}},
fun() ->
gleam@bool:guard(
erlang:'band'(Flg, 16#C0) /= 16#40,
{error,
{codec_invalid_data,
<<"lz4: unsupported frame version"/utf8>>}},
fun() ->
Block_checksum = erlang:'band'(Flg, 16#10)
/= 0,
Content_size_present = erlang:'band'(
Flg,
16#08
)
/= 0,
Content_checksum = erlang:'band'(Flg, 16#04)
/= 0,
Dict_id_present = erlang:'band'(Flg, 16#01)
/= 0,
Bd_block_max_idx = erlang:'band'(
erlang:'bsr'(Bd, 4),
7
),
Block_max = block_max_bytes(
Bd_block_max_idx
),
gleam@result:'try'(
maybe_skip(
Rest,
Content_size_present,
8,
<<"lz4: content size truncated"/utf8>>
),
fun(Rest@1) ->
gleam@result:'try'(
maybe_skip(
Rest@1,
Dict_id_present,
4,
<<"lz4: dictionary id truncated"/utf8>>
),
fun(Rest@2) ->
gleam@result:'try'(
maybe_skip(
Rest@2,
true,
1,
<<"lz4: header checksum missing"/utf8>>
),
fun(Rest@3) ->
decode_blocks(
Rest@3,
<<>>,
Block_checksum,
Content_checksum,
Block_max,
Limits
)
end
)
end
)
end
)
end
)
end
);
_ ->
{error,
{codec_invalid_data,
<<"lz4: frame header truncated"/utf8>>}}
end end
).
-file("src/packkit/lz4.gleam", 107).
?DOC(" Decode an LZ4 frame using the default resource limits.\n").
-spec decode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
decode(Bytes) ->
decode_with_limits(Bytes, packkit@limit:default()).
-file("src/packkit/lz4.gleam", 417).
-spec lz4_insert_hashes(
gleam@dict:dict(integer(), integer()),
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer()
) -> gleam@dict:dict(integer(), integer()).
lz4_insert_hashes(Table, Hashes, From, To, Size) ->
case (From > To) orelse ((From + 4) > Size) of
true ->
Hashes;
false ->
Key = hash4(
byte_at(Table, From),
byte_at(Table, From + 1),
byte_at(Table, From + 2),
byte_at(Table, From + 3)
),
lz4_insert_hashes(
Table,
gleam@dict:insert(Hashes, Key, From),
From + 1,
To,
Size
)
end.
-file("src/packkit/lz4.gleam", 445).
-spec emit_sequence(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer()
) -> bitstring().
emit_sequence(Table, Lit_start, Lit_len, Distance, Match_len) ->
Ml_stored = Match_len - 4,
Lit_high = case Lit_len >= 15 of
true ->
15;
false ->
Lit_len
end,
Ml_high = case Ml_stored >= 15 of
true ->
15;
false ->
Ml_stored
end,
Token = erlang:'bor'(erlang:'bsl'(Lit_high, 4), Ml_high),
Lit_ext = case Lit_len >= 15 of
true ->
encode_length_extension(Lit_len - 15);
false ->
<<>>
end,
Literals = collect_bytes(Table, Lit_start, Lit_len, <<>>),
Offset = <<Distance:16/little>>,
Ml_ext = case Ml_stored >= 15 of
true ->
encode_length_extension(Ml_stored - 15);
false ->
<<>>
end,
gleam_stdlib:bit_array_concat(
[<<Token>>, Lit_ext, Literals, Offset, Ml_ext]
).
-file("src/packkit/lz4.gleam", 268).
-spec step_compress(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
list(bitstring())
) -> bitstring().
step_compress(Table, Size, Pos, Last_lit_start, Hashes, Acc) ->
Key = hash4(
byte_at(Table, Pos),
byte_at(Table, Pos + 1),
byte_at(Table, Pos + 2),
byte_at(Table, Pos + 3)
),
case gleam_stdlib:map_get(Hashes, Key) of
{ok, Prev} ->
Distance = Pos - Prev,
Valid = ((Distance >= 1) andalso (Distance =< 65535)) andalso bytes4_equal(
Table,
Prev,
Pos
),
case Valid of
false ->
compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
);
true ->
Search_end = Size - 5,
Match_len = lz4_match_length(
Table,
Prev,
Pos,
Search_end,
0
),
case Match_len < 4 of
true ->
compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
);
false ->
Lit_len = Pos - Last_lit_start,
Seq = emit_sequence(
Table,
Last_lit_start,
Lit_len,
Distance,
Match_len
),
Next_pos = Pos + Match_len,
New_hashes = lz4_insert_hashes(
Table,
gleam@dict:insert(Hashes, Key, Pos),
Pos + 1,
Next_pos - 1,
Size
),
compress_loop(
Table,
Size,
Next_pos,
Next_pos,
New_hashes,
[Seq | Acc]
)
end
end;
_ ->
compress_loop(
Table,
Size,
Pos + 1,
Last_lit_start,
gleam@dict:insert(Hashes, Key, Pos),
Acc
)
end.
-file("src/packkit/lz4.gleam", 248).
-spec compress_loop(
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
list(bitstring())
) -> bitstring().
compress_loop(Table, Size, Pos, Last_lit_start, Hashes, Acc) ->
Last_search = Size - 12,
case Pos > Last_search of
true ->
Lit_len = Size - Last_lit_start,
Tail = emit_literal_only_chunk(Table, Last_lit_start, Lit_len),
gleam_stdlib:bit_array_concat(lists:reverse([Tail | Acc]));
false ->
step_compress(Table, Size, Pos, Last_lit_start, Hashes, Acc)
end.
-file("src/packkit/lz4.gleam", 238).
-spec compress_block(bitstring(), integer()) -> bitstring().
compress_block(Bytes, Size) ->
case Size =< 12 of
true ->
emit_literal_only_block(Bytes, 0, Size);
false ->
Table = build_byte_table(Bytes, 0, maps:new()),
compress_loop(Table, Size, 0, 0, maps:new(), [])
end.
-file("src/packkit/lz4.gleam", 183).
-spec encode_blocks(bitstring(), list(bitstring())) -> bitstring().
encode_blocks(Remaining, Acc) ->
Total = erlang:byte_size(Remaining),
case Total of
0 ->
gleam_stdlib:bit_array_concat(lists:reverse(Acc));
_ ->
Chunk_size = case Total > 4194304 of
true ->
4194304;
false ->
Total
end,
Chunk@1 = case gleam_stdlib:bit_array_slice(
Remaining,
0,
Chunk_size
) of
{ok, Chunk} -> Chunk;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"encode_blocks"/utf8>>,
line => 192,
value => _assert_fail,
start => 6195,
'end' => 6259,
pattern_start => 6206,
pattern_end => 6215})
end,
After@1 = case gleam_stdlib:bit_array_slice(
Remaining,
Chunk_size,
Total - Chunk_size
) of
{ok, After} -> After;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/lz4"/utf8>>,
function => <<"encode_blocks"/utf8>>,
line => 193,
value => _assert_fail@1,
start => 6266,
'end' => 6355,
pattern_start => 6277,
pattern_end => 6286})
end,
Compressed = compress_block(Chunk@1, Chunk_size),
Compressed_size = erlang:byte_size(Compressed),
Framed = case Compressed_size < Chunk_size of
true ->
<<Compressed_size:32/little, Compressed/bitstring>>;
false ->
<<(erlang:'bor'(16#80000000, Chunk_size)):32/little,
Chunk@1/bitstring>>
end,
encode_blocks(After@1, [Framed | Acc])
end.
-file("src/packkit/lz4.gleam", 82).
-spec encode_internal(bitstring(), boolean()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode_internal(Bytes, Content_size_present) ->
Flg = case Content_size_present of
true ->
16#60 + 16#08;
false ->
16#60
end,
Bd = 16#70,
Descriptor = case Content_size_present of
true ->
<<Flg, Bd, (erlang:byte_size(Bytes)):64/little>>;
false ->
<<Flg, Bd>>
end,
Hc = erlang:'band'(
erlang:'bsr'(packkit@internal@xxh32:digest(Descriptor, 0), 8),
16#FF
),
Header = gleam_stdlib:bit_array_concat(
[<<16#184D2204:32/little>>, Descriptor, <<Hc>>]
),
Blocks = encode_blocks(Bytes, []),
End_mark = <<0:32/little>>,
{ok, gleam_stdlib:bit_array_concat([Header, Blocks, End_mark])}.
-file("src/packkit/lz4.gleam", 66).
?DOC(
" Encode `bytes` as an LZ4 frame. The frame descriptor uses\n"
" independent blocks, the v1 frame version, and a 4 MiB block\n"
" maximum; no content size, block checksum, content checksum, or\n"
" dictionary id is written.\n"
).
-spec encode(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode(Bytes) ->
encode_internal(Bytes, false).
-file("src/packkit/lz4.gleam", 76).
?DOC(
" Encode `bytes` as an LZ4 frame and store the uncompressed\n"
" content size in the frame descriptor. Strict LZ4 decoders use\n"
" the value to pre-allocate the output buffer and reject any\n"
" frame whose payload disagrees with the declared length; our own\n"
" decoder simply skips the field today, so encoding it does not\n"
" change `encode -> decode` round trips.\n"
).
-spec encode_with_content_size(bitstring()) -> {ok, bitstring()} |
{error, packkit@error:codec_error()}.
encode_with_content_size(Bytes) ->
encode_internal(Bytes, true).