-module(packkit@internal@bcj2).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/internal/bcj2.gleam").
-export([decode/5]).
-export_type([bcj2_error/0, state/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(false).
-type bcj2_error() :: range_coder_header_invalid |
{stream_exhausted, binary()} |
{output_size_mismatch, integer(), integer()}.
-type state() :: {state,
bitstring(),
bitstring(),
bitstring(),
bitstring(),
gleam@dict:dict(integer(), integer()),
integer(),
integer(),
integer(),
integer(),
bitstring(),
integer()}.
-file("src/packkit/internal/bcj2.gleam", 143).
?DOC(false).
-spec init_range_coder(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, bcj2_error()}.
init_range_coder(Rc) ->
case Rc of
<<First, C1, C2, C3, C4, Rest/binary>> ->
case First =:= 0 of
true ->
Code = erlang:'bor'(
erlang:'bor'(erlang:'bsl'(C1, 24), erlang:'bsl'(C2, 16)),
erlang:'bor'(erlang:'bsl'(C3, 8), C4)
),
{ok, {Code, Rest}};
false ->
{error, range_coder_header_invalid}
end;
_ ->
{error, range_coder_header_invalid}
end.
-file("src/packkit/internal/bcj2.gleam", 209).
?DOC(false).
-spec consume_main_byte(state(), integer(), bitstring()) -> state().
consume_main_byte(State, Byte, Main_rest) ->
{state,
Main_rest,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State) + 1,
Byte,
<<(erlang:element(11, State))/bitstring, Byte>>,
erlang:element(12, State)}.
-file("src/packkit/internal/bcj2.gleam", 223).
?DOC(false).
-spec is_branch_candidate(integer(), integer()) -> boolean().
is_branch_candidate(Byte, Prev_byte) ->
case Byte of
16#E8 ->
true;
16#E9 ->
true;
_ ->
case (Prev_byte =:= 16#0F) andalso (erlang:'band'(Byte, 16#F0) =:= 16#80) of
true ->
true;
false ->
false
end
end.
-file("src/packkit/internal/bcj2.gleam", 269).
?DOC(false).
-spec prev_byte_for_call(state()) -> integer().
prev_byte_for_call(State) ->
Output_size = erlang:byte_size(erlang:element(11, State)),
case Output_size < 2 of
true ->
0;
false ->
case gleam_stdlib:bit_array_slice(
erlang:element(11, State),
Output_size - 2,
1
) of
{ok, <<Single>>} ->
Single;
_ ->
0
end
end.
-file("src/packkit/internal/bcj2.gleam", 283).
?DOC(false).
-spec range_decode_bit(integer(), integer(), integer()) -> {integer(),
integer(),
integer(),
integer()}.
range_decode_bit(Range, Code, Prob) ->
Bound = begin
_pipe = erlang:'bsr'(Range, 11),
_pipe@1 = gleam@int:multiply(_pipe, Prob),
erlang:'band'(_pipe@1, 16#FFFFFFFF)
end,
case Code < Bound of
true ->
New_prob = Prob + erlang:'bsr'(16#800 - Prob, 5),
{0, Bound, Code, New_prob};
false ->
New_range = erlang:'band'(Range - Bound, 16#FFFFFFFF),
New_code = erlang:'band'(Code - Bound, 16#FFFFFFFF),
New_prob@1 = Prob - erlang:'bsr'(Prob, 5),
{1, New_range, New_code, New_prob@1}
end.
-file("src/packkit/internal/bcj2.gleam", 336).
?DOC(false).
-spec emit_branch_target(state(), integer()) -> {ok, state()} |
{error, bcj2_error()}.
emit_branch_target(State, Opcode) ->
{Dest_stream, Dest_label} = case Opcode =:= 16#E8 of
true ->
{erlang:element(3, State), <<"call"/utf8>>};
false ->
{erlang:element(4, State), <<"jump"/utf8>>}
end,
case Dest_stream of
<<B0, B1, B2, B3, Dest_rest/binary>> ->
Target = erlang:'bor'(
erlang:'bor'(erlang:'bsl'(B0, 24), erlang:'bsl'(B1, 16)),
erlang:'bor'(erlang:'bsl'(B2, 8), B3)
),
New_ip = erlang:element(9, State) + 4,
Relative = erlang:'band'(Target - New_ip, 16#FFFFFFFF),
R0 = erlang:'band'(Relative, 16#FF),
R1 = erlang:'band'(erlang:'bsr'(Relative, 8), 16#FF),
R2 = erlang:'band'(erlang:'bsr'(Relative, 16), 16#FF),
R3 = erlang:'band'(erlang:'bsr'(Relative, 24), 16#FF),
New_output = <<(erlang:element(11, State))/bitstring,
R0,
R1,
R2,
R3>>,
Next_state = {state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
New_ip,
R3,
New_output,
erlang:element(12, State)},
case Opcode =:= 16#E8 of
true ->
{ok,
{state,
erlang:element(2, Next_state),
Dest_rest,
erlang:element(4, Next_state),
erlang:element(5, Next_state),
erlang:element(6, Next_state),
erlang:element(7, Next_state),
erlang:element(8, Next_state),
erlang:element(9, Next_state),
erlang:element(10, Next_state),
erlang:element(11, Next_state),
erlang:element(12, Next_state)}};
false ->
{ok,
{state,
erlang:element(2, Next_state),
erlang:element(3, Next_state),
Dest_rest,
erlang:element(5, Next_state),
erlang:element(6, Next_state),
erlang:element(7, Next_state),
erlang:element(8, Next_state),
erlang:element(9, Next_state),
erlang:element(10, Next_state),
erlang:element(11, Next_state),
erlang:element(12, Next_state)}}
end;
_ ->
{error, {stream_exhausted, Dest_label}}
end.
-file("src/packkit/internal/bcj2.gleam", 129).
?DOC(false).
-spec init_probs(integer(), gleam@dict:dict(integer(), integer())) -> gleam@dict:dict(integer(), integer()).
init_probs(Index, Acc) ->
case gleam@int:compare(Index, 258) of
lt ->
init_probs(Index + 1, gleam@dict:insert(Acc, Index, 16#800 div 2));
_ ->
Acc
end.
-file("src/packkit/internal/bcj2.gleam", 178).
?DOC(false).
-spec decode_loop_step(state()) -> {ok, state()} | {error, bcj2_error()}.
decode_loop_step(State) ->
case erlang:element(2, State) of
<<>> ->
{ok, State};
<<Byte, Main_rest/binary>> ->
After_consume = consume_main_byte(State, Byte, Main_rest),
gleam@result:'try'(
decode_main_byte(After_consume, Byte, erlang:element(10, State)),
fun(Stepped) -> decode_loop(Stepped) end
);
_ ->
{error, {stream_exhausted, <<"main"/utf8>>}}
end.
-file("src/packkit/internal/bcj2.gleam", 166).
?DOC(false).
-spec decode_loop(state()) -> {ok, state()} | {error, bcj2_error()}.
decode_loop(State) ->
case gleam@int:compare(
erlang:byte_size(erlang:element(11, State)),
erlang:element(12, State)
) of
lt ->
decode_loop_step(State);
_ ->
{ok, State}
end.
-file("src/packkit/internal/bcj2.gleam", 80).
?DOC(false).
-spec decode(bitstring(), bitstring(), bitstring(), bitstring(), integer()) -> {ok,
bitstring()} |
{error, bcj2_error()}.
decode(Main, Call, Jump, Rc, Output_size) ->
gleam@result:'try'(
init_range_coder(Rc),
fun(_use0) ->
{Code, Rc_rest} = _use0,
Probs = init_probs(0, maps:new()),
Initial = {state,
Main,
Call,
Jump,
Rc_rest,
Probs,
16#FFFFFFFF,
Code,
0,
0,
<<>>,
Output_size},
gleam@result:'try'(
decode_loop(Initial),
fun(Final_state) ->
Actual = erlang:byte_size(erlang:element(11, Final_state)),
case Actual =:= Output_size of
true ->
{ok, erlang:element(11, Final_state)};
false ->
{error, {output_size_mismatch, Output_size, Actual}}
end
end
)
end
).
-file("src/packkit/internal/bcj2.gleam", 317).
?DOC(false).
-spec refill_rc_step(state()) -> {ok, state()} | {error, bcj2_error()}.
refill_rc_step(State) ->
case erlang:element(5, State) of
<<Next, Rc_rest/binary>> ->
New_range = begin
_pipe = erlang:'bsl'(erlang:element(7, State), 8),
erlang:'band'(_pipe, 16#FFFFFFFF)
end,
New_code = begin
_pipe@1 = erlang:'bor'(
erlang:'bsl'(erlang:element(8, State), 8),
Next
),
erlang:'band'(_pipe@1, 16#FFFFFFFF)
end,
maybe_refill_rc(
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
Rc_rest,
erlang:element(6, State),
New_range,
New_code,
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
erlang:element(12, State)}
);
_ ->
{error, {stream_exhausted, <<"range_coder"/utf8>>}}
end.
-file("src/packkit/internal/bcj2.gleam", 308).
?DOC(false).
-spec maybe_refill_rc(state()) -> {ok, state()} | {error, bcj2_error()}.
maybe_refill_rc(State) ->
case gleam@int:compare(erlang:element(7, State), 16#1000000) of
lt ->
refill_rc_step(State);
_ ->
{ok, State}
end.
-file("src/packkit/internal/bcj2.gleam", 239).
?DOC(false).
-spec decode_branch(state(), integer()) -> {ok, state()} | {error, bcj2_error()}.
decode_branch(State, Opcode) ->
Prob_index = case Opcode of
16#E8 ->
2 + prev_byte_for_call(State);
16#E9 ->
1;
_ ->
0
end,
Prob = begin
_pipe = gleam_stdlib:map_get(erlang:element(6, State), Prob_index),
gleam@result:unwrap(_pipe, 16#800 div 2)
end,
{Bit, Range_after, Code_after, Prob_after} = range_decode_bit(
erlang:element(7, State),
erlang:element(8, State),
Prob
),
Probs_after = gleam@dict:insert(
erlang:element(6, State),
Prob_index,
Prob_after
),
Intermediate = {state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Probs_after,
Range_after,
Code_after,
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
erlang:element(12, State)},
gleam@result:'try'(
maybe_refill_rc(Intermediate),
fun(Refilled) -> case Bit of
0 ->
{ok, Refilled};
_ ->
emit_branch_target(Refilled, Opcode)
end end
).
-file("src/packkit/internal/bcj2.gleam", 194).
?DOC(false).
-spec decode_main_byte(state(), integer(), integer()) -> {ok, state()} |
{error, bcj2_error()}.
decode_main_byte(State, Byte, Prev_byte_before_consume) ->
gleam@bool:guard(
not is_branch_candidate(Byte, Prev_byte_before_consume),
{ok, State},
fun() -> decode_branch(State, Byte) end
).