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]).
-spec process_backreference(
integer(),
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 create_control_byte(integer()) -> bitstring().
create_control_byte(Count) ->
<<0:1, Count:7>>.
-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 => 241})
end.
-spec print_literal(bitstring(), integer(), integer()) -> nil.
print_literal(Data, Len, Pos) ->
Size = (erlang:byte_size(Data) - Len) * 8,
case Data of
<<_:Size, Chars/bitstring>> ->
_assert_subject = gleam@bit_array:to_string(Chars),
{ok, Chars@1} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"lzf_gleam"/utf8>>,
function => <<"print_literal"/utf8>>,
line => 263})
end,
gleam@io:println(
<<<<<<<<<<"[LITERAL] - pos: "/utf8,
(gleam@string:pad_left(
gleam@int:to_string(Pos),
4,
<<" "/utf8>>
))/binary>>/binary,
", len: "/utf8>>/binary,
(gleam@string:pad_left(
gleam@int:to_string(Len),
3,
<<" "/utf8>>
))/binary>>/binary,
", chars: "/utf8>>/binary,
(gleam@string:inspect(Chars@1))/binary>>
);
_ ->
erlang:error(#{gleam_error => panic,
message => <<"unable to print chars"/utf8>>,
module => <<"lzf_gleam"/utf8>>,
function => <<"print_literal"/utf8>>,
line => 273})
end.
-spec flush_literals(bitstring(), bitstring(), integer(), integer()) -> bitstring().
flush_literals(Output, Buffer, Count, Pos) ->
case Count > 0 of
true ->
print_literal(Buffer, Count, Pos),
Control_byte = create_control_byte(Count),
<<Output/bitstring, Control_byte/bitstring, Buffer/bitstring>>;
false ->
Output
end.
-spec print_backref(internal@back_ref:back_ref(), bitstring(), integer()) -> nil.
print_backref(Ref, Data, Pos) ->
gleam@io:print(
<<<<<<<<<<<<"[BACKREF] - pos: "/utf8,
(gleam@string:pad_left(
gleam@int:to_string(Pos),
4,
<<" "/utf8>>
))/binary>>/binary,
", len: "/utf8>>/binary,
(gleam@string:pad_left(
gleam@int:to_string(erlang:element(2, Ref)),
3,
<<" "/utf8>>
))/binary>>/binary,
", offset: "/utf8>>/binary,
(gleam@string:pad_left(
gleam@int:to_string(erlang:element(3, Ref)),
4,
<<" "/utf8>>
))/binary>>/binary,
", content: "/utf8>>
),
_assert_subject = begin
_pipe = Ref,
internal@back_ref:resolve(_pipe, Data, Pos)
end,
{ok, Token_str} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"lzf_gleam"/utf8>>,
function => <<"print_backref"/utf8>>,
line => 287})
end,
_pipe@1 = Token_str,
_pipe@2 = gleam@string:inspect(_pipe@1),
gleam@io:println(_pipe@2).
-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},
print_backref(Ref, Output, Output_pos),
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,
print_literal(Output@2, Len@1, Output_pos@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, binary()}.
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, <<"Unable to convert bit array to string"/utf8>>}
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,
Current_pos
),
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 => 124})
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,
Current_pos
),
print_backref(Token, Input, Current_pos),
Token@1 = 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.