Current section
Files
Jump to
Current section
Files
src/lzf_gleam.erl
-module(lzf_gleam).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([decompress/1, compress/1]).
-export_type([decompress_error/0]).
-type decompress_error() :: decompress_error.
-spec process_backreference(
integer(),
lzf_gleam@internal@back_ref:back_ref(),
bitstring()
) -> {ok, bitstring()} | {error, nil}.
process_backreference(Current_pos, Ref, Output) ->
Cursor = (Current_pos - erlang:element(3, Ref)) * 8,
Len_bits = erlang:element(2, Ref) * 8,
case Output of
<<_:Cursor, Literals:Len_bits, _/bitstring>> ->
{ok, <<Output/bitstring, Literals:(lists:max([(Len_bits), 0]))>>};
_ ->
{error, nil}
end.
-spec process_literals(bitstring(), integer(), integer(), bitstring()) -> {ok,
bitstring()} |
{error, nil}.
process_literals(Data, Current_pos, Len, Output) ->
Cursor = Current_pos * 8,
Len_bits = Len * 8,
case Data of
<<_:Cursor, Literals:Len_bits, _/bitstring>> ->
{ok, <<Output/bitstring, Literals:(lists:max([(Len_bits), 0]))>>};
_ ->
{error, nil}
end.
-spec process_decompress(bitstring(), integer(), integer(), bitstring()) -> {ok,
bitstring()} |
{error, nil}.
process_decompress(Data, Input_pos, Output_pos, Output) ->
Cursor = Input_pos * 8,
case Data of
<<_:Cursor, Control:1, Len:3, Offset:12, _/bitstring>> when Control =:= 1 ->
Ref = {back_ref, Len, Offset},
case process_backreference(Output_pos, Ref, Output) of
{ok, Output@1} ->
process_decompress(
Data,
Input_pos + 2,
Output_pos + erlang:element(2, Ref),
Output@1
);
{error, _} ->
{error, nil}
end;
<<_:Cursor, Control@1:1, Len@1:7, _/bitstring>> when Control@1 =:= 0 ->
case process_literals(Data, Input_pos + 1, Len@1, Output) of
{ok, Output@2} ->
Output_pos@1 = Output_pos + Len@1,
process_decompress(
Data,
(Input_pos + Len@1) + 1,
Output_pos@1,
Output@2
);
{error, _} ->
{error, nil}
end;
_ ->
{ok, Output}
end.
-spec decompress(bitstring()) -> {ok, binary()} | {error, decompress_error()}.
decompress(Data) ->
Result = begin
_pipe = Data,
_pipe@1 = process_decompress(_pipe, 0, 0, <<>>),
gleam@result:'try'(_pipe@1, fun gleam@bit_array:to_string/1)
end,
case Result of
{ok, Data@1} ->
{ok, Data@1};
{error, _} ->
{error, decompress_error}
end.
-spec create_control_byte(integer()) -> bitstring().
create_control_byte(Count) ->
<<0:1, Count:7>>.
-spec flush_literals(bitstring(), bitstring(), integer()) -> bitstring().
flush_literals(Output, Buffer, Count) ->
case Count > 0 of
true ->
Control_byte = create_control_byte(Count),
<<Output/bitstring, Control_byte/bitstring, Buffer/bitstring>>;
false ->
Output
end.
-spec match_len_recursive(bitstring(), bitstring(), integer()) -> integer().
match_len_recursive(Seq1, Seq2, Acc) ->
case {Seq1, Seq2} of
{<<First1:8, Rest1/bitstring>>, <<First2:8, Rest2/bitstring>>} when (First1 =:= First2) andalso (Acc < 7) ->
match_len_recursive(Rest1, Rest2, Acc + 1);
{_, _} ->
Acc
end.
-spec get_match_len(bitstring(), integer(), integer()) -> integer().
get_match_len(Input, Match_pos, Current_pos) ->
Len = erlang:byte_size(Input),
S1_result = gleam_stdlib:bit_array_slice(Input, Match_pos, Len - Match_pos),
S2_result = gleam_stdlib:bit_array_slice(
Input,
Current_pos,
Len - Current_pos
),
case {S1_result, S2_result} of
{{ok, S1}, {ok, S2}} ->
match_len_recursive(S1, S2, 0);
{_, _} ->
erlang:error(#{gleam_error => panic,
message => <<"Something went wrong slicing the arrays, this shouldn't happen"/utf8>>,
module => <<"lzf_gleam"/utf8>>,
function => <<"get_match_len"/utf8>>,
line => 234})
end.
-spec process_current(
bitstring(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
bitstring(),
bitstring(),
integer()
) -> bitstring().
process_current(
Input,
Current,
Current_pos,
Hash_map,
Output,
Literal_buffer,
Literal_count
) ->
case gleam@dict:get(Hash_map, Current) of
{ok, Match_pos} ->
process_match(
Input,
Current,
Current_pos,
Match_pos,
Hash_map,
Output,
Literal_buffer,
Literal_count
);
_ ->
Hash_map@1 = gleam@dict:insert(Hash_map, Current, Current_pos),
First = begin
_pipe = Current,
erlang:'bsr'(_pipe, 16)
end,
process_input(
Input,
Current_pos + 1,
Hash_map@1,
Output,
<<Literal_buffer/bitstring, First:8>>,
Literal_count + 1
)
end.
-spec process_input(
bitstring(),
integer(),
gleam@dict:dict(integer(), integer()),
bitstring(),
bitstring(),
integer()
) -> bitstring().
process_input(
Input,
Current_pos,
Hash_map,
Output,
Literal_buffer,
Literal_count
) ->
Cursor = Current_pos * 8,
case Input of
<<_:Cursor>> ->
Output;
<<_:Cursor, Current:24, _/bitstring>> ->
process_current(
Input,
Current,
Current_pos,
Hash_map,
Output,
Literal_buffer,
Literal_count
);
<<_:Cursor, Rest/bitstring>> ->
Output@1 = flush_literals(Output, Literal_buffer, Literal_count),
Size = erlang:byte_size(Rest),
<<Output@1/bitstring, Size:8, Rest/bitstring>>;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"shouldn't get here"/utf8>>,
module => <<"lzf_gleam"/utf8>>,
function => <<"process_input"/utf8>>,
line => 126})
end.
-spec compress(binary()) -> bitstring().
compress(Input) ->
_pipe = Input,
_pipe@1 = gleam_stdlib:identity(_pipe),
process_input(_pipe@1, 0, gleam@dict:new(), <<>>, <<>>, 0).
-spec process_match(
bitstring(),
integer(),
integer(),
integer(),
gleam@dict:dict(integer(), integer()),
bitstring(),
bitstring(),
integer()
) -> bitstring().
process_match(
Input,
Current,
Current_pos,
Match_pos,
Hash_map,
Output,
Literal_buffer,
Literal_count
) ->
case Current_pos - Match_pos of
Diff when Diff < 8191 ->
Match_len = get_match_len(Input, Match_pos, Current_pos),
Token = {back_ref, Match_len, Diff},
Output@1 = flush_literals(Output, Literal_buffer, Literal_count),
Token@1 = lzf_gleam@internal@back_ref:to_bit_array(Token),
process_input(
Input,
Current_pos + Match_len,
Hash_map,
<<Output@1/bitstring, Token@1/bitstring>>,
<<>>,
0
);
_ ->
Hash_map@1 = gleam@dict:insert(Hash_map, Current, Current_pos),
process_input(
Input,
Current_pos + 1,
Hash_map@1,
Output,
<<Literal_buffer/bitstring, Current:8>>,
Literal_count + 1
)
end.