-module(packkit@bzip2). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/packkit/bzip2.gleam"). -export([codec/0, decode_with_limits/2, decode/1, encode_with_level/2, encode/1]). -export_type([huffman_table/0, build_acc/0, huffman_stream_step/0, reader/0, huff_node/0, writer/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( " bzip2 codec — pure Gleam decoder for `.bz2` streams.\n" "\n" " The decoder consumes the `\"BZh\"` magic, a single-character\n" " block-size label (1..9), one or more compressed blocks, and the\n" " stream end-marker plus 32-bit combined CRC. Each block is\n" " reversed through Huffman decoding, MTF inversion, inverse\n" " Burrows-Wheeler, and the RLE1 expansion that bzip2 applies to the\n" " raw input before transformation. The encoder is intentionally\n" " deferred.\n" ). -type huffman_table() :: {huffman_table, integer(), integer(), gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer())}. -type build_acc() :: {build_acc, gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()), integer(), integer(), integer()}. -type huffman_stream_step() :: {huffman_stream_done, list(integer()), integer(), reader()} | {huffman_stream_continue, reader(), list(integer()), integer(), integer(), integer(), list(integer()), integer()}. -type reader() :: {reader, integer(), integer(), bitstring(), boolean()}. -type huff_node() :: {huff_leaf, integer(), integer()} | {huff_internal, integer(), huff_node(), huff_node()}. -type writer() :: {writer, list(integer()), integer(), integer()}. -file("src/packkit/bzip2.gleam", 38). ?DOC(" bzip2 codec smart constructor.\n"). -spec codec() -> packkit@codec:codec(). codec() -> packkit@codec:bzip2(). -file("src/packkit/bzip2.gleam", 145). -spec parse_stream_header(bitstring()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. parse_stream_header(Bytes) -> case Bytes of <<16#42, 16#5A, 16#68, Level, Rest/binary>> when (Level >= 16#31) andalso (Level =< 16#39) -> {ok, Rest}; _ -> {error, {codec_invalid_data, <<"invalid bzip2 stream header"/utf8>>}} end. -file("src/packkit/bzip2.gleam", 196). ?DOC( " Recover the byte-aligned tail of the bit reader so the caller can\n" " look for another stream's `\"BZh\"` magic. bzip2 streams pad to\n" " the next byte boundary after the stream CRC, so any partial bits\n" " still sitting in `reader.buffer` are padding and we discard them.\n" ). -spec byte_aligned_remainder(reader()) -> bitstring(). byte_aligned_remainder(Reader) -> _ = erlang:element(3, Reader), erlang:element(4, Reader). -file("src/packkit/bzip2.gleam", 201). -spec combine_block_crc(integer(), integer()) -> integer(). combine_block_crc(Combined, Block_crc) -> Rotated = erlang:'bor'( erlang:'band'(erlang:'bsl'(Combined, 1), 16#FFFFFFFF), erlang:'bsr'(Combined, 31) ), erlang:'band'(erlang:'bxor'(Rotated, Block_crc), 16#FFFFFFFF). -file("src/packkit/bzip2.gleam", 210). -spec verify_block_crc(bitstring(), integer()) -> {ok, nil} | {error, packkit@error:codec_error()}. verify_block_crc(Data, Expected) -> case packkit@checksum:bzip2_crc32(Data) =:= Expected of true -> {ok, nil}; false -> {error, {codec_invalid_data, <<"bzip2 block CRC mismatch"/utf8>>}} end. -file("src/packkit/bzip2.gleam", 220). -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/bzip2.gleam", 350). -spec collect_group_bytes(integer(), integer(), integer(), list(integer())) -> list(integer()). collect_group_bytes(Bits, Group, Offset, Acc) -> case Offset >= 16 of true -> Acc; false -> Mask = erlang:'bsl'(1, 15 - Offset), Acc@1 = case erlang:'band'(Bits, Mask) of 0 -> Acc; _ -> [(Group * 16) + Offset | Acc] end, collect_group_bytes(Bits, Group, Offset + 1, Acc@1) end. -file("src/packkit/bzip2.gleam", 380). -spec init_selector_stack(integer(), integer(), list(integer())) -> list(integer()). init_selector_stack(Num, Index, Acc) -> case Index >= Num of true -> lists:reverse(Acc); false -> init_selector_stack(Num, Index + 1, [Index | Acc]) end. -file("src/packkit/bzip2.gleam", 421). -spec pick_at(list(integer()), integer(), list(integer())) -> {integer(), list(integer())}. pick_at(Stack, Index, Prefix) -> case {Stack, Index} of {[Head | Rest], 0} -> {Head, lists:append(lists:reverse(Prefix), Rest)}; {[Head@1 | Rest@1], _} -> pick_at(Rest@1, Index - 1, [Head@1 | Prefix]); {[], _} -> {0, lists:reverse(Prefix)} end. -file("src/packkit/bzip2.gleam", 557). -spec canonical_loop(list({integer(), integer()}), build_acc()) -> build_acc(). canonical_loop(Sorted, Acc) -> case Sorted of [] -> Acc; [{Sym, Length} | Rest] -> {Code, Base, Limit} = case Length =:= erlang:element(7, Acc) of true -> {erlang:element(6, Acc), erlang:element(2, Acc), erlang:element(3, Acc)}; false -> case erlang:element(7, Acc) of 0 -> {0, gleam@dict:insert( erlang:element(2, Acc), Length, erlang:element(5, Acc) ), erlang:element(3, Acc)}; _ -> Shift = Length - erlang:element(7, Acc), Prev_limit = gleam@dict:insert( erlang:element(3, Acc), erlang:element(7, Acc), erlang:element(6, Acc) - 1 ), New_code = erlang:'bsl'( erlang:element(6, Acc), Shift ), {New_code, gleam@dict:insert( erlang:element(2, Acc), Length, erlang:element(5, Acc) - New_code ), Prev_limit} end end, Symbols = gleam@dict:insert( erlang:element(4, Acc), erlang:element(5, Acc), Sym ), canonical_loop( Rest, {build_acc, Base, Limit, Symbols, erlang:element(5, Acc) + 1, Code + 1, Length} ) end. -file("src/packkit/bzip2.gleam", 599). -spec enumerate_lengths( list(integer()), integer(), list({integer(), integer()}) ) -> list({integer(), integer()}). enumerate_lengths(Lengths, Index, Acc) -> case Lengths of [] -> lists:reverse(Acc); [Head | Rest] -> enumerate_lengths(Rest, Index + 1, [{Index, Head} | Acc]) end. -file("src/packkit/bzip2.gleam", 611). -spec find_min_length(list(integer()), integer()) -> integer(). find_min_length(Lengths, Best) -> case Lengths of [] -> case Best of 21 -> 1; _ -> Best end; [Head | Rest] -> Best@1 = case Head < Best of true -> Head; false -> Best end, find_min_length(Rest, Best@1) end. -file("src/packkit/bzip2.gleam", 628). -spec find_max_length(list(integer()), integer()) -> integer(). find_max_length(Lengths, Best) -> case Lengths of [] -> Best; [Head | Rest] -> Best@1 = case Head > Best of true -> Head; false -> Best end, find_max_length(Rest, Best@1) end. -file("src/packkit/bzip2.gleam", 661). -spec prepend_reversed( list({integer(), integer()}), list({integer(), integer()}) ) -> list({integer(), integer()}). prepend_reversed(Values, Acc) -> case Values of [] -> Acc; [Head | Rest] -> prepend_reversed(Rest, [Head | Acc]) end. -file("src/packkit/bzip2.gleam", 641). -spec sort_pairs_by_length( list({integer(), integer()}), integer(), integer(), list({integer(), integer()}) ) -> list({integer(), integer()}). sort_pairs_by_length(Pairs, Length, Max_length, Acc) -> case Length > Max_length of true -> lists:reverse(Acc); false -> Bucket = gleam@list:filter( Pairs, fun(Pair) -> erlang:element(2, Pair) =:= Length end ), sort_pairs_by_length( Pairs, Length + 1, Max_length, prepend_reversed(Bucket, Acc) ) end. -file("src/packkit/bzip2.gleam", 673). -spec list_to_dict(list(GXM), integer(), gleam@dict:dict(integer(), GXM)) -> gleam@dict:dict(integer(), GXM). list_to_dict(Values, Index, Acc) -> case Values of [] -> Acc; [Head | Rest] -> list_to_dict(Rest, Index + 1, gleam@dict:insert(Acc, Index, Head)) end. -file("src/packkit/bzip2.gleam", 885). -spec emit_byte(list(integer()), integer(), integer(), packkit@limit:limits()) -> {ok, {list(integer()), integer()}} | {error, packkit@error:codec_error()}. emit_byte(Out_rev, Out_len, Byte, Limits) -> gleam@bool:guard( (Out_len + 1) > packkit@limit:max_output_bytes(Limits), {error, {codec_limit_exceeded, <<"max_output_bytes"/utf8>>, Out_len + 1}}, fun() -> {ok, {[Byte | Out_rev], Out_len + 1}} end ). -file("src/packkit/bzip2.gleam", 901). -spec repeat_prepend(integer(), integer(), list(integer())) -> list(integer()). repeat_prepend(Value, Count, Acc) -> case Count of 0 -> Acc; _ -> repeat_prepend(Value, Count - 1, [Value | Acc]) end. -file("src/packkit/bzip2.gleam", 858). -spec flush_run( list(integer()), integer(), list(integer()), integer(), packkit@limit:limits() ) -> {ok, {list(integer()), integer()}} | {error, packkit@error:codec_error()}. flush_run(Out_rev, Out_len, Mtf, Pending, Limits) -> case Pending of 0 -> {ok, {Out_rev, Out_len}}; _ -> Front = case Mtf of [Head | _] -> Head; [] -> 0 end, gleam@bool:guard( (Out_len + Pending) > packkit@limit:max_output_bytes(Limits), {error, {codec_limit_exceeded, <<"max_output_bytes"/utf8>>, Out_len + Pending}}, fun() -> Out_rev@1 = repeat_prepend(Front, Pending, Out_rev), {ok, {Out_rev@1, Out_len + Pending}} end ) end. -file("src/packkit/bzip2.gleam", 920). -spec mtf_pick_loop(list(integer()), integer(), list(integer())) -> {ok, {integer(), list(integer()), list(integer())}} | {error, nil}. mtf_pick_loop(Mtf, Index, Prefix) -> case {Mtf, Index} of {[Head | Rest], 0} -> {ok, {Head, Prefix, Rest}}; {[Head@1 | Rest@1], _} -> mtf_pick_loop(Rest@1, Index - 1, [Head@1 | Prefix]); {[], _} -> {error, nil} end. -file("src/packkit/bzip2.gleam", 908). -spec mtf_pick_byte(list(integer()), integer()) -> {ok, {integer(), list(integer())}} | {error, packkit@error:codec_error()}. mtf_pick_byte(Mtf, Index) -> case mtf_pick_loop(Mtf, Index, []) of {ok, {Byte, Prefix, Rest}} -> {ok, {Byte, [Byte | lists:append(lists:reverse(Prefix), Rest)]}}; {error, _} -> {error, {codec_invalid_data, <<"bzip2 MTF index out of range"/utf8>>}} end. -file("src/packkit/bzip2.gleam", 932). -spec list_to_indexed_dict( list(integer()), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). list_to_indexed_dict(Values, Index, Acc) -> case Values of [] -> Acc; [Head | Rest] -> list_to_indexed_dict( Rest, Index + 1, gleam@dict:insert(Acc, Index, Head) ) end. -file("src/packkit/bzip2.gleam", 1012). -spec count_bytes( gleam@dict:dict(integer(), integer()), integer(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). count_bytes(L_string, Index, Length, Acc) -> case Index >= Length of true -> Acc; false -> Byte = case gleam_stdlib:map_get(L_string, Index) of {ok, V} -> V; {error, _} -> 0 end, Current = case gleam_stdlib:map_get(Acc, Byte) of {ok, V@1} -> V@1; {error, _} -> 0 end, count_bytes( L_string, Index + 1, Length, gleam@dict:insert(Acc, Byte, Current + 1) ) end. -file("src/packkit/bzip2.gleam", 1039). -spec build_cumulative( gleam@dict:dict(integer(), integer()), integer(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). build_cumulative(Counts, Symbol, Acc, Out) -> case Symbol >= 256 of true -> Out; false -> Out@1 = gleam@dict:insert(Out, Symbol, Acc), N = case gleam_stdlib:map_get(Counts, Symbol) of {ok, V} -> V; {error, _} -> 0 end, build_cumulative(Counts, Symbol + 1, Acc + N, Out@1) end. -file("src/packkit/bzip2.gleam", 1058). -spec build_t( gleam@dict:dict(integer(), integer()), integer(), integer(), gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). build_t(L_string, Index, Length, Cumulative, T) -> case Index >= Length of true -> T; false -> Byte = case gleam_stdlib:map_get(L_string, Index) of {ok, V} -> V; {error, _} -> 0 end, Slot = case gleam_stdlib:map_get(Cumulative, Byte) of {ok, V@1} -> V@1; {error, _} -> 0 end, Cumulative@1 = gleam@dict:insert(Cumulative, Byte, Slot + 1), build_t( L_string, Index + 1, Length, Cumulative@1, gleam@dict:insert(T, Slot, Index) ) end. -file("src/packkit/bzip2.gleam", 1088). -spec walk_bwt( gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()), integer(), integer(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). walk_bwt(L_string, T, Pos, Index, Length, Out) -> case Index >= Length of true -> Out; false -> Next = case gleam_stdlib:map_get(T, Pos) of {ok, V} -> V; {error, _} -> 0 end, Byte = case gleam_stdlib:map_get(L_string, Next) of {ok, V@1} -> V@1; {error, _} -> 0 end, walk_bwt( L_string, T, Next, Index + 1, Length, gleam@dict:insert(Out, Index, Byte) ) end. -file("src/packkit/bzip2.gleam", 1001). -spec inverse_bwt(gleam@dict:dict(integer(), integer()), integer(), integer()) -> gleam@dict:dict(integer(), integer()). inverse_bwt(L_string, Length, Orig_ptr) -> Counts = count_bytes(L_string, 0, Length, maps:new()), Cumulative = build_cumulative(Counts, 0, 0, maps:new()), T = build_t(L_string, 0, Length, Cumulative, maps:new()), walk_bwt(L_string, T, Orig_ptr, 0, Length, maps:new()). -file("src/packkit/bzip2.gleam", 1127). -spec rle1_decode_loop( gleam@dict:dict(integer(), integer()), integer(), integer(), integer(), integer(), list(integer()) ) -> list(integer()). rle1_decode_loop(Input, Index, Length, Last_byte, Run, Acc) -> case Index >= Length of true -> Acc; false -> Byte = case gleam_stdlib:map_get(Input, Index) of {ok, V} -> V; {error, _} -> 0 end, case Run =:= 4 of true -> Acc@1 = repeat_prepend(Last_byte, Byte, Acc), rle1_decode_loop(Input, Index + 1, Length, -1, 0, Acc@1); false -> case Byte =:= Last_byte of true -> rle1_decode_loop( Input, Index + 1, Length, Byte, Run + 1, [Byte | Acc] ); false -> rle1_decode_loop( Input, Index + 1, Length, Byte, 1, [Byte | Acc] ) end end end. -file("src/packkit/bzip2.gleam", 1163). -spec bytes_list_to_bit_array(list(integer()), bitstring()) -> bitstring(). bytes_list_to_bit_array(Bytes, Acc) -> case Bytes of [] -> Acc; [Head | Rest] -> bytes_list_to_bit_array(Rest, <>) end. -file("src/packkit/bzip2.gleam", 1121). -spec rle1_decode(gleam@dict:dict(integer(), integer()), integer()) -> bitstring(). rle1_decode(Input, Length) -> _pipe = rle1_decode_loop(Input, 0, Length, -1, 0, []), _pipe@1 = lists:reverse(_pipe), bytes_list_to_bit_array(_pipe@1, <<>>). -file("src/packkit/bzip2.gleam", 1176). -spec new_reader(bitstring()) -> reader(). new_reader(Source) -> {reader, 0, 0, Source, false}. -file("src/packkit/bzip2.gleam", 1180). -spec refill(reader(), integer()) -> reader(). refill(Reader, Needed) -> case (erlang:element(2, Reader) >= Needed) orelse erlang:element(5, Reader) of true -> Reader; false -> case erlang:element(4, Reader) of <> -> refill( {reader, erlang:element(2, Reader) + 8, erlang:'bor'( erlang:'bsl'(erlang:element(3, Reader), 8), B ), Rest, false}, Needed ); _ -> {reader, erlang:element(2, Reader), erlang:element(3, Reader), <<>>, true} end end. -file("src/packkit/bzip2.gleam", 1209). -spec read_bits(reader(), integer()) -> {ok, {integer(), reader()}} | {error, packkit@error:codec_error()}. read_bits(Reader, Count) -> Reader@1 = refill(Reader, Count), case erlang:element(2, Reader@1) < Count of true -> {error, {codec_invalid_data, <<"truncated bzip2 stream"/utf8>>}}; false -> New_bits = erlang:element(2, Reader@1) - Count, Mask = erlang:'bsl'(1, Count) - 1, Value = erlang:'band'( erlang:'bsr'(erlang:element(3, Reader@1), New_bits), Mask ), Buffer_mask = erlang:'bsl'(1, New_bits) - 1, New_buffer = erlang:'band'(erlang:element(3, Reader@1), Buffer_mask), {ok, {Value, {reader, New_bits, New_buffer, erlang:element(4, Reader@1), erlang:element(5, Reader@1)}}} end. -file("src/packkit/bzip2.gleam", 328). -spec read_symbol_groups(reader(), integer(), integer(), list(integer())) -> {ok, {list(integer()), reader()}} | {error, packkit@error:codec_error()}. read_symbol_groups(Reader, Presence, Group, Acc) -> case Group >= 16 of true -> {ok, {lists:reverse(Acc), Reader}}; false -> Bit_mask = erlang:'bsl'(1, 15 - Group), case erlang:'band'(Presence, Bit_mask) of 0 -> read_symbol_groups(Reader, Presence, Group + 1, Acc); _ -> gleam@result:'try'( read_bits(Reader, 16), fun(_use0) -> {Bits, Reader@1} = _use0, Acc@1 = collect_group_bytes(Bits, Group, 0, Acc), read_symbol_groups( Reader@1, Presence, Group + 1, Acc@1 ) end ) end end. -file("src/packkit/bzip2.gleam", 321). -spec read_symbol_map(reader()) -> {ok, {list(integer()), reader()}} | {error, packkit@error:codec_error()}. read_symbol_map(Reader) -> gleam@result:'try'( read_bits(Reader, 16), fun(_use0) -> {Present_groups, Reader@1} = _use0, read_symbol_groups(Reader@1, Present_groups, 0, []) end ). -file("src/packkit/bzip2.gleam", 410). -spec read_unary(reader(), integer()) -> {ok, {integer(), reader()}} | {error, packkit@error:codec_error()}. read_unary(Reader, Acc) -> gleam@result:'try'( read_bits(Reader, 1), fun(_use0) -> {Bit, Reader@1} = _use0, case Bit of 0 -> {ok, {Acc, Reader@1}}; _ -> read_unary(Reader@1, Acc + 1) end end ). -file("src/packkit/bzip2.gleam", 387). -spec read_selectors_loop(reader(), integer(), list(integer()), list(integer())) -> {ok, {list(integer()), reader()}} | {error, packkit@error:codec_error()}. read_selectors_loop(Reader, Remaining, Stack, Acc) -> case Remaining of 0 -> {ok, {lists:reverse(Acc), Reader}}; _ -> gleam@result:'try'( read_unary(Reader, 0), fun(_use0) -> {Index, Reader@1} = _use0, gleam@bool:guard( Index >= erlang:length(Stack), {error, {codec_invalid_data, <<"bzip2 selector out of range"/utf8>>}}, fun() -> {Picked, Remaining_stack} = pick_at( Stack, Index, [] ), Stack@1 = [Picked | Remaining_stack], read_selectors_loop( Reader@1, Remaining - 1, Stack@1, [Picked | Acc] ) end ) end ) end. -file("src/packkit/bzip2.gleam", 371). -spec read_selectors(reader(), integer(), integer()) -> {ok, {list(integer()), reader()}} | {error, packkit@error:codec_error()}. read_selectors(Reader, Remaining, Num_tables) -> Stack = init_selector_stack(Num_tables, 0, []), read_selectors_loop(Reader, Remaining, Stack, []). -file("src/packkit/bzip2.gleam", 492). -spec adjust_length(reader(), integer()) -> {ok, {integer(), reader()}} | {error, packkit@error:codec_error()}. adjust_length(Reader, Current) -> gleam@result:'try'( read_bits(Reader, 1), fun(_use0) -> {Flag, Reader@1} = _use0, case Flag of 0 -> {ok, {Current, Reader@1}}; _ -> gleam@result:'try'( read_bits(Reader@1, 1), fun(_use0@1) -> {Direction, Reader@2} = _use0@1, Updated = case Direction of 0 -> Current + 1; _ -> Current - 1 end, adjust_length(Reader@2, Updated) end ) end end ). -file("src/packkit/bzip2.gleam", 952). -spec walk_huffman(reader(), huffman_table(), integer(), integer()) -> {ok, {integer(), reader()}} | {error, packkit@error:codec_error()}. walk_huffman(Reader, Table, Length, Code) -> case Length > erlang:element(3, Table) of true -> {error, {codec_invalid_data, <<"bzip2 huffman code overflow"/utf8>>}}; false -> Limit_value = case gleam_stdlib:map_get( erlang:element(5, Table), Length ) of {ok, V} -> V; {error, _} -> -1 end, case Code =< Limit_value of true -> Base_value = case gleam_stdlib:map_get( erlang:element(4, Table), Length ) of {ok, V@1} -> V@1; {error, _} -> 0 end, Index = Base_value + Code, Symbol = case gleam_stdlib:map_get( erlang:element(6, Table), Index ) of {ok, V@2} -> V@2; {error, _} -> -1 end, case Symbol < 0 of true -> {error, {codec_invalid_data, <<"bzip2 huffman symbol lookup failed"/utf8>>}}; false -> {ok, {Symbol, Reader}} end; false -> gleam@result:'try'( read_bits(Reader, 1), fun(_use0) -> {Bit, Reader@1} = _use0, walk_huffman( Reader@1, Table, Length + 1, erlang:'bor'(erlang:'bsl'(Code, 1), Bit) ) end ) end end. -file("src/packkit/bzip2.gleam", 944). -spec decode_one_symbol(reader(), huffman_table()) -> {ok, {integer(), reader()}} | {error, packkit@error:codec_error()}. decode_one_symbol(Reader, Table) -> gleam@result:'try'( read_bits(Reader, erlang:element(2, Table)), fun(_use0) -> {Code, Reader@1} = _use0, walk_huffman(Reader@1, Table, erlang:element(2, Table), Code) end ). -file("src/packkit/bzip2.gleam", 1274). -spec rle1_loop(bitstring(), integer(), integer(), list(integer())) -> list(integer()). rle1_loop(Bytes, Last, Run, Acc) -> case Bytes of <> -> case B =:= Last of true -> case Run of R when R < 4 -> rle1_loop(Rest, Last, Run + 1, [B | Acc]); R@1 when R@1 < 259 -> case R@1 >= (4 + 254) of true -> rle1_loop(Rest, -1, 0, [255 | Acc]); false -> rle1_loop(Rest, Last, Run + 1, Acc) end; _ -> rle1_loop(Rest, Last, Run + 1, Acc) end; false -> case Run >= 4 of true -> Extra = Run - 4, rle1_loop(Rest, B, 1, [B, Extra | Acc]); false -> rle1_loop(Rest, B, 1, [B | Acc]) end end; _ -> case Run >= 4 of true -> Extra@1 = Run - 4, lists:reverse([Extra@1 | Acc]); false -> lists:reverse(Acc) end end. -file("src/packkit/bzip2.gleam", 1270). -spec rle1_encode(bitstring()) -> list(integer()). rle1_encode(Bytes) -> rle1_loop(Bytes, -1, 0, []). -file("src/packkit/bzip2.gleam", 1326). -spec list_range(integer(), integer(), list(integer())) -> list(integer()). list_range(Low, High, Acc) -> case Low > High of true -> lists:reverse(Acc); false -> list_range(Low + 1, High, [Low | Acc]) end. -file("src/packkit/bzip2.gleam", 1362). -spec byte_at_index(gleam@dict:dict(integer(), integer()), integer()) -> integer(). byte_at_index(Table, Index) -> case gleam_stdlib:map_get(Table, Index) of {ok, V} -> V; {error, _} -> 0 end. -file("src/packkit/bzip2.gleam", 1369). -spec mod_index(integer(), integer()) -> integer(). mod_index(Value, N) -> case N of 0 -> 0; _ -> R = Value - ((case N of 0 -> 0; Gleam@denominator -> Value div Gleam@denominator end) * N), case R < 0 of true -> R + N; false -> R end end. -file("src/packkit/bzip2.gleam", 1342). -spec compare_loop( gleam@dict:dict(integer(), integer()), integer(), integer(), integer(), integer() ) -> gleam@order:order(). compare_loop(Table, N, A, B, Offset) -> case Offset >= N of true -> eq; false -> Ba = byte_at_index(Table, mod_index(A + Offset, N)), Bb = byte_at_index(Table, mod_index(B + Offset, N)), case Ba =:= Bb of true -> compare_loop(Table, N, A, B, Offset + 1); false -> gleam@int:compare(Ba, Bb) end end. -file("src/packkit/bzip2.gleam", 1333). -spec compare_rotations( gleam@dict:dict(integer(), integer()), integer(), integer(), integer() ) -> gleam@order:order(). compare_rotations(Table, N, A, B) -> compare_loop(Table, N, A, B, 0). -file("src/packkit/bzip2.gleam", 1382). -spec build_l_dict( list(integer()), gleam@dict:dict(integer(), integer()), integer(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). build_l_dict(Sorted, Table, N, Index, Acc) -> case Sorted of [] -> Acc; [Head | Rest] -> Byte = byte_at_index(Table, mod_index((Head + N) - 1, N)), build_l_dict( Rest, Table, N, Index + 1, gleam@dict:insert(Acc, Index, Byte) ) end. -file("src/packkit/bzip2.gleam", 1398). -spec find_index(list(integer()), integer(), integer()) -> integer(). find_index(Values, Target, Index) -> case Values of [Head | _] when Head =:= Target -> Index; [_ | Rest] -> find_index(Rest, Target, Index + 1); [] -> 0 end. -file("src/packkit/bzip2.gleam", 1316). -spec bwt_forward(list(integer()), integer()) -> {gleam@dict:dict(integer(), integer()), integer()}. bwt_forward(Input, N) -> Table = list_to_dict(Input, 0, maps:new()), Indices = list_range(0, N - 1, []), Sorted = gleam@list:sort( Indices, fun(A, B) -> compare_rotations(Table, N, A, B) end ), L_dict = build_l_dict(Sorted, Table, N, 0, maps:new()), Orig_ptr = find_index(Sorted, 0, 0), {L_dict, Orig_ptr}. -file("src/packkit/bzip2.gleam", 1408). -spec sorted_unique_bytes(gleam@dict:dict(integer(), integer())) -> list(integer()). sorted_unique_bytes(L_string) -> Unique_dict = gleam@dict:fold( L_string, maps:new(), fun(Acc, _, Value) -> gleam@dict:insert(Acc, Value, true) end ), Bytes = maps:keys(Unique_dict), gleam@list:sort(Bytes, fun gleam@int:compare/2). -file("src/packkit/bzip2.gleam", 1441). -spec find_and_pop(list(integer()), integer(), integer(), list(integer())) -> {integer(), list(integer())}. find_and_pop(Stack, Target, Pos, Prefix) -> case Stack of [Head | Rest] when Head =:= Target -> {Pos, lists:append(lists:reverse(Prefix), Rest)}; [Head@1 | Rest@1] -> find_and_pop(Rest@1, Target, Pos + 1, [Head@1 | Prefix]); [] -> {Pos, lists:reverse(Prefix)} end. -file("src/packkit/bzip2.gleam", 1421). -spec mtf_forward_loop( gleam@dict:dict(integer(), integer()), integer(), integer(), list(integer()), list(integer()) ) -> list(integer()). mtf_forward_loop(L_string, Index, Length, Stack, Acc) -> case Index >= Length of true -> lists:reverse(Acc); false -> Byte = byte_at_index(L_string, Index), {Pos, New_stack} = find_and_pop(Stack, Byte, 0, []), mtf_forward_loop( L_string, Index + 1, Length, [Byte | New_stack], [Pos | Acc] ) end. -file("src/packkit/bzip2.gleam", 1417). -spec mtf_forward(gleam@dict:dict(integer(), integer()), list(integer())) -> list(integer()). mtf_forward(L_string, Unique) -> mtf_forward_loop(L_string, 0, maps:size(L_string), Unique, []). -file("src/packkit/bzip2.gleam", 1487). -spec emit_runa_runb(integer(), list(integer())) -> list(integer()). emit_runa_runb(Value, Acc) -> case Value of 1 -> Acc; _ -> Bit = erlang:'band'(Value, 1), Next = erlang:'bsr'(Value, 1), emit_runa_runb(Next, [Bit | Acc]) end. -file("src/packkit/bzip2.gleam", 1480). -spec flush_zero_run(integer(), list(integer())) -> list(integer()). flush_zero_run(Count, Acc) -> case Count of 0 -> Acc; _ -> emit_runa_runb(Count + 1, Acc) end. -file("src/packkit/bzip2.gleam", 1461). -spec rle2_loop(list(integer()), integer(), integer(), list(integer())) -> list(integer()). rle2_loop(Mtf, Zero_run, Eob, Acc) -> case Mtf of [0 | Rest] -> rle2_loop(Rest, Zero_run + 1, Eob, Acc); [N | Rest@1] -> Acc@1 = flush_zero_run(Zero_run, Acc), rle2_loop(Rest@1, 0, Eob, [N + 1 | Acc@1]); [] -> Acc@2 = flush_zero_run(Zero_run, Acc), lists:reverse([Eob | Acc@2]) end. -file("src/packkit/bzip2.gleam", 1457). -spec rle2_encode(list(integer()), integer()) -> list(integer()). rle2_encode(Mtf, Eob) -> rle2_loop(Mtf, 0, Eob, []). -file("src/packkit/bzip2.gleam", 1511). -spec count_frequencies(list(integer()), gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()). count_frequencies(Symbols, Acc) -> case Symbols of [] -> Acc; [Head | Rest] -> Current = case gleam_stdlib:map_get(Acc, Head) of {ok, V} -> V; {error, _} -> 0 end, count_frequencies(Rest, gleam@dict:insert(Acc, Head, Current + 1)) end. -file("src/packkit/bzip2.gleam", 1527). -spec pad_min_frequencies( gleam@dict:dict(integer(), integer()), integer(), integer() ) -> gleam@dict:dict(integer(), integer()). pad_min_frequencies(Freq, Symbol, Alphabet_size) -> case Symbol >= Alphabet_size of true -> Freq; false -> Freq@1 = case gleam_stdlib:map_get(Freq, Symbol) of {ok, _} -> Freq; {error, _} -> gleam@dict:insert(Freq, Symbol, 1) end, pad_min_frequencies(Freq@1, Symbol + 1, Alphabet_size) end. -file("src/packkit/bzip2.gleam", 1564). -spec flatten_frequencies(gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()). flatten_frequencies(Freq) -> gleam@dict:fold( Freq, maps:new(), fun(Acc, Sym, Count) -> New_count = case Count of N when N =< 1 -> 1; N@1 -> ((N@1 + 1) div 2) + 1 end, gleam@dict:insert(Acc, Sym, New_count) end ). -file("src/packkit/bzip2.gleam", 1577). -spec max_length_in_dict( gleam@dict:dict(integer(), integer()), integer(), integer(), integer() ) -> integer(). max_length_in_dict(Lengths, Symbol, Alphabet_size, Best) -> case Symbol >= Alphabet_size of true -> Best; false -> Len = case gleam_stdlib:map_get(Lengths, Symbol) of {ok, V} -> V; {error, _} -> 0 end, Best@1 = case Len > Best of true -> Len; false -> Best end, max_length_in_dict(Lengths, Symbol + 1, Alphabet_size, Best@1) end. -file("src/packkit/bzip2.gleam", 1614). -spec build_leaves( gleam@dict:dict(integer(), integer()), integer(), integer(), list(huff_node()) ) -> list(huff_node()). build_leaves(Freq, Symbol, Alphabet_size, Acc) -> case Symbol >= Alphabet_size of true -> Acc; false -> Weight = case gleam_stdlib:map_get(Freq, Symbol) of {ok, V} -> V; {error, _} -> 0 end, build_leaves( Freq, Symbol + 1, Alphabet_size, [{huff_leaf, Symbol, Weight} | Acc] ) end. -file("src/packkit/bzip2.gleam", 1659). -spec node_weight(huff_node()) -> integer(). node_weight(Node) -> case Node of {huff_leaf, _, W} -> W; {huff_internal, W@1, _, _} -> W@1 end. -file("src/packkit/bzip2.gleam", 1635). -spec merge_nodes(list(huff_node())) -> huff_node(). merge_nodes(Nodes) -> case Nodes of [Single] -> Single; _ -> Sorted = gleam@list:sort( Nodes, fun(A, B) -> gleam@int:compare(node_weight(A), node_weight(B)) end ), case Sorted of [A@1, B@1 | Rest] -> merge_nodes( [{huff_internal, node_weight(A@1) + node_weight(B@1), A@1, B@1} | Rest] ); _ -> {huff_leaf, 0, 0} end end. -file("src/packkit/bzip2.gleam", 1666). -spec collect_lengths( huff_node(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). collect_lengths(Node, Depth, Acc) -> case Node of {huff_leaf, Symbol, _} -> Depth@1 = case Depth of 0 -> 1; _ -> Depth end, gleam@dict:insert(Acc, Symbol, Depth@1); {huff_internal, _, Left, Right} -> Acc@1 = collect_lengths(Left, Depth + 1, Acc), collect_lengths(Right, Depth + 1, Acc@1) end. -file("src/packkit/bzip2.gleam", 1600). -spec compute_huffman_lengths(gleam@dict:dict(integer(), integer()), integer()) -> gleam@dict:dict(integer(), integer()). compute_huffman_lengths(Freq, Alphabet_size) -> Nodes = build_leaves(Freq, 0, Alphabet_size, []), Merged_root = merge_nodes(Nodes), collect_lengths(Merged_root, 0, maps:new()). -file("src/packkit/bzip2.gleam", 1547). -spec package_merge_lengths( gleam@dict:dict(integer(), integer()), integer(), integer() ) -> gleam@dict:dict(integer(), integer()). package_merge_lengths(Freq, Alphabet_size, Max_length) -> Lengths = compute_huffman_lengths(Freq, Alphabet_size), case max_length_in_dict(Lengths, 0, Alphabet_size, 0) > Max_length of false -> Lengths; true -> package_merge_lengths( flatten_frequencies(Freq), Alphabet_size, Max_length ) end. -file("src/packkit/bzip2.gleam", 1502). -spec build_huffman_lengths(list(integer()), integer()) -> gleam@dict:dict(integer(), integer()). build_huffman_lengths(Symbols, Alphabet_size) -> Freq = count_frequencies(Symbols, maps:new()), Freq@1 = pad_min_frequencies(Freq, 0, Alphabet_size), package_merge_lengths(Freq@1, Alphabet_size, 17). -file("src/packkit/bzip2.gleam", 1700). -spec assign_codes( list({integer(), integer()}), integer(), integer(), gleam@dict:dict(integer(), integer()) ) -> gleam@dict:dict(integer(), integer()). assign_codes(Pairs, Code, Prev_length, Acc) -> case Pairs of [] -> Acc; [{Sym, Length} | Rest] -> Code@1 = case Prev_length of 0 -> 0; _ -> erlang:'bsl'(Code, Length - Prev_length) end, assign_codes( Rest, Code@1 + 1, Length, gleam@dict:insert(Acc, Sym, Code@1) ) end. -file("src/packkit/bzip2.gleam", 1688). -spec canonical_codes(gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()). canonical_codes(Lengths) -> Pairs = maps:to_list(Lengths), Sorted = gleam@list:sort( Pairs, fun(A, B) -> case gleam@int:compare(erlang:element(2, A), erlang:element(2, B)) of eq -> gleam@int:compare( erlang:element(1, A), erlang:element(1, B) ); Other -> Other end end ), assign_codes(Sorted, 0, 0, maps:new()). -file("src/packkit/bzip2.gleam", 1727). -spec bytes_to_group_dict( list(integer()), gleam@dict:dict(integer(), list(integer())) ) -> gleam@dict:dict(integer(), list(integer())). bytes_to_group_dict(Bytes, Acc) -> case Bytes of [] -> Acc; [B | Rest] -> Group = B div 16, Existing = case gleam_stdlib:map_get(Acc, Group) of {ok, V} -> V; {error, _} -> [] end, bytes_to_group_dict( Rest, gleam@dict:insert(Acc, Group, [B | Existing]) ) end. -file("src/packkit/bzip2.gleam", 1744). -spec compute_group_used( gleam@dict:dict(integer(), list(integer())), integer(), gleam@dict:dict(integer(), boolean()) ) -> gleam@dict:dict(integer(), boolean()). compute_group_used(Group_dict, Group, Acc) -> case Group >= 16 of true -> Acc; false -> Used = case gleam_stdlib:map_get(Group_dict, Group) of {ok, _} -> true; {error, _} -> false end, compute_group_used( Group_dict, Group + 1, gleam@dict:insert(Acc, Group, Used) ) end. -file("src/packkit/bzip2.gleam", 1935). -spec new_writer() -> writer(). new_writer() -> {writer, [], 0, 0}. -file("src/packkit/bzip2.gleam", 1955). -spec mask_for(integer()) -> integer(). mask_for(Count) -> erlang:'bsl'(1, Count) - 1. -file("src/packkit/bzip2.gleam", 1959). -spec flush_writer_full_bytes(writer()) -> writer(). flush_writer_full_bytes(Writer) -> case erlang:element(4, Writer) >= 8 of false -> Writer; true -> Shift = erlang:element(4, Writer) - 8, Byte = erlang:'band'( erlang:'bsr'(erlang:element(3, Writer), Shift), 16#FF ), New_buffer = erlang:'band'( erlang:element(3, Writer), mask_for(Shift) ), flush_writer_full_bytes( {writer, [Byte | erlang:element(2, Writer)], New_buffer, Shift} ) end. -file("src/packkit/bzip2.gleam", 1939). -spec write_bits_msb(writer(), integer(), integer()) -> writer(). write_bits_msb(Writer, Value, Count) -> case Count of 0 -> Writer; _ -> Masked = erlang:'band'(Value, mask_for(Count)), Buffer = erlang:'bor'( erlang:'bsl'(erlang:element(3, Writer), Count), Masked ), flush_writer_full_bytes( {writer, erlang:element(2, Writer), Buffer, erlang:element(4, Writer) + Count} ) end. -file("src/packkit/bzip2.gleam", 1761). -spec emit_group_high( writer(), gleam@dict:dict(integer(), boolean()), integer() ) -> writer(). emit_group_high(Writer, Group_used, Group) -> case Group >= 16 of true -> Writer; false -> Bit = case gleam_stdlib:map_get(Group_used, Group) of {ok, true} -> 1; _ -> 0 end, emit_group_high( write_bits_msb(Writer, Bit, 1), Group_used, Group + 1 ) end. -file("src/packkit/bzip2.gleam", 1801). -spec emit_bitmap_for_group(writer(), list(integer()), integer(), integer()) -> writer(). emit_bitmap_for_group(Writer, Bytes, Group, Offset) -> case Offset >= 16 of true -> Writer; false -> Target = (Group * 16) + Offset, Bit = case gleam@list:contains(Bytes, Target) of true -> 1; false -> 0 end, emit_bitmap_for_group( write_bits_msb(Writer, Bit, 1), Bytes, Group, Offset + 1 ) end. -file("src/packkit/bzip2.gleam", 1778). -spec emit_group_bitmaps( writer(), gleam@dict:dict(integer(), boolean()), gleam@dict:dict(integer(), list(integer())), integer() ) -> writer(). emit_group_bitmaps(Writer, Group_used, Group_dict, Group) -> case Group >= 16 of true -> Writer; false -> case gleam_stdlib:map_get(Group_used, Group) of {ok, true} -> Bytes = case gleam_stdlib:map_get(Group_dict, Group) of {ok, V} -> V; {error, _} -> [] end, Writer@1 = emit_bitmap_for_group(Writer, Bytes, Group, 0), emit_group_bitmaps( Writer@1, Group_used, Group_dict, Group + 1 ); _ -> emit_group_bitmaps( Writer, Group_used, Group_dict, Group + 1 ) end end. -file("src/packkit/bzip2.gleam", 1720). -spec emit_symbol_map(writer(), list(integer())) -> writer(). emit_symbol_map(Writer, Unique) -> Group_dict = bytes_to_group_dict(Unique, maps:new()), Group_used = compute_group_used(Group_dict, 0, maps:new()), Writer@1 = emit_group_high(Writer, Group_used, 0), emit_group_bitmaps(Writer@1, Group_used, Group_dict, 0). -file("src/packkit/bzip2.gleam", 1831). -spec emit_selectors_loop(writer(), integer()) -> writer(). emit_selectors_loop(Writer, Remaining) -> case Remaining of 0 -> Writer; _ -> emit_selectors_loop(write_bits_msb(Writer, 0, 1), Remaining - 1) end. -file("src/packkit/bzip2.gleam", 1825). -spec emit_selectors(writer(), integer()) -> writer(). emit_selectors(Writer, Num_groups) -> emit_selectors_loop(Writer, Num_groups). -file("src/packkit/bzip2.gleam", 1883). -spec emit_length_diff(writer(), integer(), integer()) -> writer(). emit_length_diff(Writer, Previous, Target) -> case Target =:= Previous of true -> write_bits_msb(Writer, 0, 1); false -> case Target > Previous of true -> Writer@1 = write_bits_msb(Writer, 1, 1), Writer@2 = write_bits_msb(Writer@1, 0, 1), emit_length_diff(Writer@2, Previous + 1, Target); false -> Writer@3 = write_bits_msb(Writer, 1, 1), Writer@4 = write_bits_msb(Writer@3, 1, 1), emit_length_diff(Writer@4, Previous - 1, Target) end end. -file("src/packkit/bzip2.gleam", 1863). -spec emit_lengths_diff( writer(), gleam@dict:dict(integer(), integer()), integer(), integer(), integer() ) -> writer(). emit_lengths_diff(Writer, Lengths, Symbol, Alphabet_size, Previous) -> case Symbol >= Alphabet_size of true -> Writer; false -> Target = case gleam_stdlib:map_get(Lengths, Symbol) of {ok, V} -> V; {error, _} -> Previous end, Writer@1 = emit_length_diff(Writer, Previous, Target), emit_lengths_diff( Writer@1, Lengths, Symbol + 1, Alphabet_size, Target ) end. -file("src/packkit/bzip2.gleam", 1847). -spec emit_table_lengths( writer(), gleam@dict:dict(integer(), integer()), integer() ) -> writer(). emit_table_lengths(Writer, Lengths, Alphabet_size) -> First = case gleam_stdlib:map_get(Lengths, 0) of {ok, V} -> V; {error, _} -> 1 end, Writer@1 = write_bits_msb(Writer, First, 5), emit_lengths_diff(Writer@1, Lengths, 0, Alphabet_size, First). -file("src/packkit/bzip2.gleam", 1838). -spec emit_two_tables( writer(), gleam@dict:dict(integer(), integer()), integer() ) -> writer(). emit_two_tables(Writer, Lengths, Alphabet_size) -> Writer@1 = emit_table_lengths(Writer, Lengths, Alphabet_size), emit_table_lengths(Writer@1, Lengths, Alphabet_size). -file("src/packkit/bzip2.gleam", 1902). -spec emit_huffman_data( writer(), list(integer()), gleam@dict:dict(integer(), integer()), gleam@dict:dict(integer(), integer()) ) -> writer(). emit_huffman_data(Writer, Symbols, Lengths, Codes) -> case Symbols of [] -> Writer; [Head | Rest] -> Code = case gleam_stdlib:map_get(Codes, Head) of {ok, V} -> V; {error, _} -> 0 end, Length = case gleam_stdlib:map_get(Lengths, Head) of {ok, V@1} -> V@1; {error, _} -> 1 end, emit_huffman_data( write_bits_msb(Writer, Code, Length), Rest, Lengths, Codes ) end. -file("src/packkit/bzip2.gleam", 1989). -spec list_to_bit_array(list(integer()), bitstring()) -> bitstring(). list_to_bit_array(Values, Acc) -> case Values of [] -> Acc; [Head | Rest] -> list_to_bit_array(Rest, <>) end. -file("src/packkit/bzip2.gleam", 1976). -spec flush_writer_msb(writer()) -> bitstring(). flush_writer_msb(Writer) -> Writer@1 = case erlang:element(4, Writer) of 0 -> Writer; _ -> Pad = 8 - erlang:element(4, Writer), Shifted = erlang:'bsl'(erlang:element(3, Writer), Pad), Byte = erlang:'band'(Shifted, 16#FF), {writer, [Byte | erlang:element(2, Writer)], 0, 0} end, list_to_bit_array(lists:reverse(erlang:element(2, Writer@1)), <<>>). -file("src/packkit/bzip2.gleam", 79). -spec write_eos_marker(writer(), integer()) -> writer(). write_eos_marker(Writer, Stream_crc) -> _pipe = Writer, _pipe@1 = write_bits_msb(_pipe, 16#177245, 24), _pipe@2 = write_bits_msb(_pipe@1, 16#385090, 24), write_bits_msb(_pipe@2, Stream_crc, 32). -file("src/packkit/bzip2.gleam", 471). -spec read_table_lengths(reader(), integer(), integer(), list(integer())) -> {ok, {list(integer()), reader()}} | {error, packkit@error:codec_error()}. read_table_lengths(Reader, Remaining, Current, Acc) -> case Remaining of 0 -> {ok, {lists:reverse(Acc), Reader}}; _ -> gleam@result:'try'( adjust_length(Reader, Current), fun(_use0) -> {Current@1, Reader@1} = _use0, gleam@bool:guard( (Current@1 < 1) orelse (Current@1 > 20), {error, {codec_invalid_data, <<"bzip2 huffman length out of range"/utf8>>}}, fun() -> read_table_lengths( Reader@1, Remaining - 1, Current@1, [Current@1 | Acc] ) end ) end ) end. -file("src/packkit/bzip2.gleam", 510). -spec build_huffman_table(list(integer())) -> {ok, huffman_table()} | {error, packkit@error:codec_error()}. build_huffman_table(Lengths) -> Pairs = enumerate_lengths(Lengths, 0, []), Min_length = find_min_length(Lengths, 21), Max_length = find_max_length(Lengths, 0), gleam@bool:guard( ((Min_length < 1) orelse (Max_length > 20)) orelse (Max_length < 1), {error, {codec_invalid_data, <<"bzip2 huffman length out of range"/utf8>>}}, fun() -> Sorted = sort_pairs_by_length(Pairs, Min_length, Max_length, []), Acc = {build_acc, maps:new(), maps:new(), maps:new(), 0, 0, 0}, Acc@1 = canonical_loop(Sorted, Acc), Final_limit = case erlang:element(7, Acc@1) of 0 -> erlang:element(3, Acc@1); _ -> gleam@dict:insert( erlang:element(3, Acc@1), erlang:element(7, Acc@1), erlang:element(6, Acc@1) - 1 ) end, {ok, {huffman_table, Min_length, Max_length, erlang:element(2, Acc@1), Final_limit, erlang:element(4, Acc@1)}} end ). -file("src/packkit/bzip2.gleam", 449). -spec read_huffman_tables_loop( reader(), integer(), integer(), list(huffman_table()) ) -> {ok, {list(huffman_table()), reader()}} | {error, packkit@error:codec_error()}. read_huffman_tables_loop(Reader, Remaining, Alphabet_size, Acc) -> case Remaining of 0 -> {ok, {lists:reverse(Acc), Reader}}; _ -> gleam@result:'try'( read_bits(Reader, 5), fun(_use0) -> {Initial, Reader@1} = _use0, gleam@result:'try'( read_table_lengths(Reader@1, Alphabet_size, Initial, []), fun(_use0@1) -> {Lengths, Reader@2} = _use0@1, gleam@result:'try'( build_huffman_table(Lengths), fun(Table) -> read_huffman_tables_loop( Reader@2, Remaining - 1, Alphabet_size, [Table | Acc] ) end ) end ) end ) end. -file("src/packkit/bzip2.gleam", 441). -spec read_huffman_tables(reader(), integer(), integer()) -> {ok, {list(huffman_table()), reader()}} | {error, packkit@error:codec_error()}. read_huffman_tables(Reader, Count, Alphabet_size) -> read_huffman_tables_loop(Reader, Count, Alphabet_size, []). -file("src/packkit/bzip2.gleam", 768). -spec decode_huffman_step( reader(), gleam@dict:dict(integer(), huffman_table()), gleam@dict:dict(integer(), integer()), integer(), list(integer()), integer(), integer(), integer(), list(integer()), integer(), packkit@limit:limits() ) -> {ok, huffman_stream_step()} | {error, packkit@error:codec_error()}. decode_huffman_step( Reader, Tables, Selectors, Eob, Mtf, Symbol_count, Pending_run, Run_weight, Out_rev, Out_len, Limits ) -> Group_index = case 50 of 0 -> 0; Gleam@denominator -> Symbol_count div Gleam@denominator end, Selector = case gleam_stdlib:map_get(Selectors, Group_index) of {ok, V} -> V; {error, _} -> 0 end, Table = case gleam_stdlib:map_get(Tables, Selector) of {ok, V@1} -> V@1; {error, _} -> {huffman_table, 1, 1, maps:new(), maps:new(), maps:new()} end, gleam@result:'try'( decode_one_symbol(Reader, Table), fun(_use0) -> {Symbol, Reader@1} = _use0, case Symbol of S when S =:= Eob -> gleam@result:'try'( flush_run(Out_rev, Out_len, Mtf, Pending_run, Limits), fun(_use0@1) -> {Out_rev@1, Out_len@1} = _use0@1, {ok, {huffman_stream_done, Out_rev@1, Out_len@1, Reader@1}} end ); 0 -> {ok, {huffman_stream_continue, Reader@1, Mtf, Symbol_count + 1, Pending_run + Run_weight, Run_weight * 2, Out_rev, Out_len}}; 1 -> {ok, {huffman_stream_continue, Reader@1, Mtf, Symbol_count + 1, Pending_run + (2 * Run_weight), Run_weight * 2, Out_rev, Out_len}}; Other -> gleam@result:'try'( flush_run(Out_rev, Out_len, Mtf, Pending_run, Limits), fun(_use0@2) -> {Out_rev@2, Out_len@2} = _use0@2, Mtf_index = Other - 1, gleam@result:'try'( mtf_pick_byte(Mtf, Mtf_index), fun(_use0@3) -> {Byte, New_mtf} = _use0@3, gleam@result:'try'( emit_byte( Out_rev@2, Out_len@2, Byte, Limits ), fun(_use0@4) -> {Out_rev@3, Out_len@3} = _use0@4, {ok, {huffman_stream_continue, Reader@1, New_mtf, Symbol_count + 1, 0, 1, Out_rev@3, Out_len@3}} end ) end ) end ) end end ). -file("src/packkit/bzip2.gleam", 693). -spec decode_huffman_stream( reader(), gleam@dict:dict(integer(), huffman_table()), gleam@dict:dict(integer(), integer()), integer(), list(integer()), integer(), integer(), integer(), integer(), list(integer()), integer(), packkit@limit:limits() ) -> {ok, {gleam@dict:dict(integer(), integer()), integer(), reader()}} | {error, packkit@error:codec_error()}. decode_huffman_stream( Reader, Tables, Selectors, Eob, Mtf, Num_syms, Symbol_count, Pending_run, Run_weight, Out_rev, Out_len, Limits ) -> case decode_huffman_step( Reader, Tables, Selectors, Eob, Mtf, Symbol_count, Pending_run, Run_weight, Out_rev, Out_len, Limits ) of {error, Err} -> {error, Err}; {ok, {huffman_stream_done, Final_out_rev, Final_out_len, Final_reader}} -> _ = Num_syms, L_string = list_to_indexed_dict( lists:reverse(Final_out_rev), 0, maps:new() ), {ok, {L_string, Final_out_len, Final_reader}}; {ok, {huffman_stream_continue, Next_reader, Next_mtf, Next_symbol_count, Next_pending_run, Next_run_weight, Next_out_rev, Next_out_len}} -> decode_huffman_stream( Next_reader, Tables, Selectors, Eob, Next_mtf, Num_syms, Next_symbol_count, Next_pending_run, Next_run_weight, Next_out_rev, Next_out_len, Limits ) end. -file("src/packkit/bzip2.gleam", 238). -spec decode_block(reader(), packkit@limit:limits()) -> {ok, {bitstring(), integer(), reader()}} | {error, packkit@error:codec_error()}. decode_block(Reader, Limits) -> gleam@result:'try'( read_bits(Reader, 32), fun(_use0) -> {Crc, Reader@1} = _use0, gleam@result:'try'( read_bits(Reader@1, 1), fun(_use0@1) -> {Randomized, Reader@2} = _use0@1, gleam@bool:guard( Randomized /= 0, {error, {codec_invalid_data, <<"randomized bzip2 blocks are not supported"/utf8>>}}, fun() -> gleam@result:'try'( read_bits(Reader@2, 24), fun(_use0@2) -> {Orig_ptr, Reader@3} = _use0@2, gleam@result:'try'( read_symbol_map(Reader@3), fun(_use0@3) -> {Symbols, Reader@4} = _use0@3, Num_syms = erlang:length(Symbols), gleam@bool:guard( Num_syms =:= 0, {error, {codec_invalid_data, <<"empty bzip2 symbol map"/utf8>>}}, fun() -> Alphabet_size = Num_syms + 2, gleam@result:'try'( read_bits(Reader@4, 3), fun(_use0@4) -> {Num_tables, Reader@5} = _use0@4, gleam@bool:guard( (Num_tables < 2) orelse (Num_tables > 6), {error, {codec_invalid_data, <<"invalid bzip2 huffman table count"/utf8>>}}, fun() -> gleam@result:'try'( read_bits( Reader@5, 15 ), fun( _use0@5 ) -> {Num_selectors, Reader@6} = _use0@5, gleam@bool:guard( (Num_selectors =< 0) orelse (Num_selectors > 18002), {error, {codec_invalid_data, <<"invalid bzip2 selector count"/utf8>>}}, fun( ) -> gleam@result:'try'( read_selectors( Reader@6, Num_selectors, Num_tables ), fun( _use0@6 ) -> {Selectors, Reader@7} = _use0@6, gleam@result:'try'( read_huffman_tables( Reader@7, Num_tables, Alphabet_size ), fun( _use0@7 ) -> {Tables, Reader@8} = _use0@7, Tables_arr = list_to_dict( Tables, 0, maps:new( ) ), Selectors_arr = list_to_dict( Selectors, 0, maps:new( ) ), Eob = Alphabet_size - 1, gleam@result:'try'( decode_huffman_stream( Reader@8, Tables_arr, Selectors_arr, Eob, Symbols, Num_syms, 0, 0, 1, [], 0, Limits ), fun( _use0@8 ) -> {L_string, L_len, Reader@9} = _use0@8, gleam@bool:guard( Orig_ptr >= L_len, {error, {codec_invalid_data, <<"bzip2 BWT origin out of range"/utf8>>}}, fun( ) -> Bwt_dict = inverse_bwt( L_string, L_len, Orig_ptr ), Plain = rle1_decode( Bwt_dict, L_len ), {ok, {Plain, Crc, Reader@9}} end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ) end ). -file("src/packkit/bzip2.gleam", 155). -spec decode_blocks_with_remainder( reader(), bitstring(), integer(), packkit@limit:limits() ) -> {ok, {bitstring(), bitstring()}} | {error, packkit@error:codec_error()}. decode_blocks_with_remainder(Reader, Output, Combined_crc, Limits) -> gleam@result:'try'( read_bits(Reader, 24), fun(_use0) -> {Magic_high, Reader@1} = _use0, gleam@result:'try'( read_bits(Reader@1, 24), fun(_use0@1) -> {Magic_low, Reader@2} = _use0@1, case {Magic_high, Magic_low} of {H, L} when (H =:= 16#314159) andalso (L =:= 16#265359) -> gleam@result:'try'( decode_block(Reader@2, Limits), fun(_use0@2) -> {Block_bytes, Block_crc, Reader@3} = _use0@2, gleam@result:'try'( verify_block_crc(Block_bytes, Block_crc), fun(_) -> Combined_crc@1 = combine_block_crc( Combined_crc, Block_crc ), gleam@result:'try'( append_with_limit( Output, Block_bytes, Limits ), fun(New_output) -> decode_blocks_with_remainder( Reader@3, New_output, Combined_crc@1, Limits ) end ) end ) end ); {H@1, L@1} when (H@1 =:= 16#177245) andalso (L@1 =:= 16#385090) -> gleam@result:'try'( read_bits(Reader@2, 32), fun(_use0@3) -> {Stream_crc, Reader@4} = _use0@3, case Stream_crc =:= Combined_crc of true -> {ok, {Output, byte_aligned_remainder( Reader@4 )}}; false -> {error, {codec_invalid_data, <<"bzip2 stream CRC mismatch"/utf8>>}} end end ); {_, _} -> {error, {codec_invalid_data, <<"unexpected bzip2 block marker"/utf8>>}} end end ) end ). -file("src/packkit/bzip2.gleam", 113). -spec decode_streams_loop( bitstring(), bitstring(), integer(), packkit@limit:limits() ) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. decode_streams_loop(Bytes, Acc, Accumulated_size, Limits) -> gleam@result:'try'( parse_stream_header(Bytes), fun(Rest) -> gleam@result:'try'( decode_blocks_with_remainder(new_reader(Rest), <<>>, 0, Limits), fun(_use0) -> {Payload, After} = _use0, Next_size = Accumulated_size + erlang:byte_size(Payload), case Next_size > packkit@limit:max_output_bytes(Limits) of true -> {error, {codec_limit_exceeded, <<"max_output_bytes"/utf8>>, Next_size}}; false -> Acc@1 = gleam_stdlib:bit_array_concat( [Acc, Payload] ), case erlang:byte_size(After) of 0 -> {ok, Acc@1}; _ -> decode_streams_loop( After, Acc@1, Next_size, Limits ) end end end ) end ). -file("src/packkit/bzip2.gleam", 98). ?DOC( " Decode a bzip2 stream using explicit `Limits`.\n" "\n" " Handles multi-stream `.bz2` files (the `bzcat`-style concatenation\n" " of independent bzip2 streams). When the end-of-stream marker for\n" " one stream is reached, the decoder aligns to the next byte\n" " boundary and looks for another `\"BZh\"` magic; if present, the\n" " next stream's payload is appended to the accumulated output.\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() -> decode_streams_loop(Bytes, <<>>, 0, Limits) end ). -file("src/packkit/bzip2.gleam", 87). ?DOC(" Decode a bzip2 stream using the shared 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/bzip2.gleam", 1238). -spec encode_block(writer(), bitstring()) -> writer(). encode_block(Writer, Bytes) -> Block_crc = packkit@checksum:bzip2_crc32(Bytes), Rle1 = rle1_encode(Bytes), N = erlang:length(Rle1), {L_string, Orig_ptr} = bwt_forward(Rle1, N), Unique = sorted_unique_bytes(L_string), Mtf_indices = mtf_forward(L_string, Unique), Symbols = rle2_encode(Mtf_indices, erlang:length(Unique) + 1), Alphabet_size = erlang:length(Unique) + 2, Lengths = build_huffman_lengths(Symbols, Alphabet_size), Codes = canonical_codes(Lengths), Num_groups = case erlang:length(Symbols) of 0 -> 1; Sn -> case 50 of 0 -> 0; Gleam@denominator -> ((Sn + 50) - 1) div Gleam@denominator end end, Writer@1 = begin _pipe = Writer, _pipe@1 = write_bits_msb(_pipe, 16#314159, 24), _pipe@2 = write_bits_msb(_pipe@1, 16#265359, 24), _pipe@3 = write_bits_msb(_pipe@2, Block_crc, 32), _pipe@4 = write_bits_msb(_pipe@3, 0, 1), write_bits_msb(_pipe@4, Orig_ptr, 24) end, Writer@2 = emit_symbol_map(Writer@1, Unique), Writer@3 = write_bits_msb(Writer@2, 2, 3), Writer@4 = write_bits_msb(Writer@3, Num_groups, 15), Writer@5 = emit_selectors(Writer@4, Num_groups), Writer@6 = emit_two_tables(Writer@5, Lengths, Alphabet_size), emit_huffman_data(Writer@6, Symbols, Lengths, Codes). -file("src/packkit/bzip2.gleam", 55). ?DOC( " Encode `bytes` as a bzip2 stream with an explicit block-size\n" " level (1..9). The level only affects the stream header byte; the\n" " encoder always emits a single block so the level mostly carries\n" " over for round-trip tooling.\n" ). -spec encode_with_level(bitstring(), integer()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. encode_with_level(Bytes, Level) -> gleam@bool:guard( (Level < 1) orelse (Level > 9), {error, {codec_invalid_data, <<"bzip2 level must be in 1..9"/utf8>>}}, fun() -> Level_byte = 16#30 + Level, Header = <<16#42, 16#5A, 16#68, Level_byte>>, case erlang:byte_size(Bytes) of 0 -> Writer = write_eos_marker(new_writer(), 0), {ok, gleam_stdlib:bit_array_concat( [Header, flush_writer_msb(Writer)] )}; _ -> Stream_crc = packkit@checksum:bzip2_crc32(Bytes), Writer@1 = encode_block(new_writer(), Bytes), Writer@2 = write_eos_marker(Writer@1, Stream_crc), {ok, gleam_stdlib:bit_array_concat( [Header, flush_writer_msb(Writer@2)] )} end end ). -file("src/packkit/bzip2.gleam", 47). ?DOC( " Encode `bytes` as a bzip2 stream using the default block size 9\n" " (900 KiB). The encoder emits a single block plus the stream\n" " trailer with the combined CRC; large inputs that exceed the\n" " block size will still be packed into one block, so a naive\n" " forward BWT may dominate the running time.\n" ). -spec encode(bitstring()) -> {ok, bitstring()} | {error, packkit@error:codec_error()}. encode(Bytes) -> encode_with_level(Bytes, 9).