-module(packkit@seven_z).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/seven_z.gleam").
-export([format/0, new/0, lzma/0, copy/0, deflate/0, bzip2/0, encode_with_method/2, encode/1, encode_with_password_and_method/3, encode_with_password/2, encode_with_password_and_header_encryption_and_method/3, encode_with_password_and_header_encryption/2, decode/1, decode_with_limits/2, decode_with_password/2, decode_with_password_and_limits/3]).
-export_type([method/0, encryption_spec/0, folder_encoding/0, parsed_header/0, parsed_folder/0, coder_spec/0, coder_id/0, header_parser/0, header_streams/0, header_files/0, streams_parser/0, sub_streams_acc/0, aes_properties/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(
" 7z archive — minimal pure-Gleam reader.\n"
"\n"
" The reader handles the common case produced by `7z a` on a small\n"
" payload: a single packed stream wrapped in a single folder that\n"
" uses one coder. Recognised single-coder ids:\n"
" - LZMA2 (`0x21`)\n"
" - raw LZMA (`0x03 0x01 0x01`)\n"
" - Copy (`0x00`) — identity passthrough\n"
" - Deflate (`0x04 0x01 0x08`) — raw DEFLATE, delegated to packkit/deflate\n"
" - BZip2 (`0x04 0x02 0x02`) — full BZh stream, delegated to packkit/bzip2\n"
" Multiple files packed into that folder are supported when the\n"
" archive carries a `SubStreamsInfo` block — the parser reads the\n"
" per-substream sizes from `kSize` (0x09), derives the final size\n"
" from the folder's total, and splits the decoded stream\n"
" accordingly. Multi-coder folders (BCJ filters in front of LZMA2,\n"
" AES decryption in front of LZMA2), AES-256-CBC encryption with\n"
" p7zip's SHA-256-based key derivation (`06 F1 07 01`), and multiple\n"
" folders are supported. Header encryption (`-mhe=on`, encrypts the\n"
" next-header itself) is intentionally rejected with\n"
" `ArchiveNotImplemented`. AES-encrypted archives require the\n"
" `decode_with_password` / `decode_with_password_and_limits` entry\n"
" points. The encoder is unaffected — it still emits a single\n"
" LZMA-coded folder regardless of which coders the decoder accepts.\n"
).
-opaque method() :: method_lzma | method_copy | method_deflate | method_bzip2.
-type encryption_spec() :: {encryption_spec,
binary(),
bitstring(),
bitstring(),
integer()}.
-type folder_encoding() :: {folder_encoding, bitstring(), bitstring()}.
-type parsed_header() :: {parsed_header,
integer(),
list(integer()),
list(parsed_folder()),
list(list(integer())),
list(integer()),
list(binary()),
list(boolean()),
list(boolean()),
list(gleam@option:option(integer()))}.
-type parsed_folder() :: {parsed_folder, list(coder_spec()), list(integer())}.
-type coder_spec() :: {coder_spec,
coder_id(),
bitstring(),
integer(),
integer()}.
-type coder_id() :: lzma2 |
lzma |
copy |
deflate |
b_zip2 |
delta |
bcj_x86 |
bcj_ppc |
bcj_ia64 |
bcj_arm |
bcj_arm_t |
bcj_sparc |
aes256_sha256 |
bcj2.
-type header_parser() :: {header_parser,
list(bitstring()),
header_streams(),
header_files()}.
-type header_streams() :: header_streams_none |
{header_streams_parsed,
integer(),
list(integer()),
list(parsed_folder()),
list(list(integer())),
list(integer())}.
-type header_files() :: header_files_none |
{header_files_parsed,
list(binary()),
list(boolean()),
list(boolean()),
list(gleam@option:option(integer()))}.
-type streams_parser() :: {streams_parser,
integer(),
list(integer()),
list(parsed_folder()),
list(list(integer())),
list(integer()),
boolean(),
boolean()}.
-type sub_streams_acc() :: {sub_streams_acc, list(integer()), list(integer())}.
-type aes_properties() :: {aes_properties, integer(), bitstring(), bitstring()}.
-file("src/packkit/seven_z.gleam", 215).
?DOC(" 7z archive format marker.\n").
-spec format() -> packkit@archive:archive_format().
format() ->
packkit@archive:seven_z().
-file("src/packkit/seven_z.gleam", 220).
?DOC(" Create an empty 7z archive value.\n").
-spec new() -> packkit@archive:archive().
new() ->
packkit@archive:new(format()).
-file("src/packkit/seven_z.gleam", 240).
?DOC(
" Default `Method`: raw LZMA1 with the historical `7z a` defaults\n"
" (lc=3 / lp=0 / pb=2, 64 KiB dictionary). Equivalent to passing\n"
" `seven_z.lzma()` to `encode_with_method`.\n"
).
-spec lzma() -> method().
lzma() ->
method_lzma.
-file("src/packkit/seven_z.gleam", 247).
?DOC(
" `Method` constructor: identity (no compression). Equivalent to\n"
" `7z a -m0=Copy`. The packed bytes stored in the folder are the\n"
" concatenated entry bodies verbatim.\n"
).
-spec copy() -> method().
copy() ->
method_copy.
-file("src/packkit/seven_z.gleam", 254).
?DOC(
" `Method` constructor: raw DEFLATE (no zlib / gzip wrapper). The\n"
" concatenated entry bodies go through `packkit/deflate.encode`.\n"
" Equivalent to `7z a -m0=Deflate`.\n"
).
-spec deflate() -> method().
deflate() ->
method_deflate.
-file("src/packkit/seven_z.gleam", 261).
?DOC(
" `Method` constructor: full bzip2 stream (with `BZh` magic and CRCs).\n"
" The concatenated entry bodies go through `packkit/bzip2.encode`.\n"
" Equivalent to `7z a -m0=BZip2`.\n"
).
-spec bzip2() -> method().
bzip2() ->
method_bzip2.
-file("src/packkit/seven_z.gleam", 644).
-spec validate_entries_for_encode(list(packkit@entry:entry())) -> {ok, nil} |
{error, packkit@error:archive_error()}.
validate_entries_for_encode(Entries) ->
case Entries of
[] ->
{ok, nil};
[Head | Rest] ->
case packkit@entry:kind(Head) of
file ->
validate_entries_for_encode(Rest);
_ ->
{error,
{archive_entry_rejected,
packkit@entry:to_string(packkit@entry:path(Head)),
<<"7z encoder currently supports File entries only"/utf8>>}}
end
end.
-file("src/packkit/seven_z.gleam", 901).
-spec drop_last(list(MXD), list(MXD)) -> list(MXD).
drop_last(Values, Acc) ->
case Values of
[] ->
lists:reverse(Acc);
[_] ->
lists:reverse(Acc);
[Head | Rest] ->
drop_last(Rest, [Head | Acc])
end.
-file("src/packkit/seven_z.gleam", 951).
-spec pack_bool_bits_loop(
list(boolean()),
integer(),
integer(),
integer(),
bitstring()
) -> bitstring().
pack_bool_bits_loop(Bits, Remaining, Bit_index, Current_byte, Acc) ->
case Remaining of
0 ->
case Bit_index of
0 ->
Acc;
_ ->
gleam_stdlib:bit_array_concat([Acc, <<Current_byte>>])
end;
_ ->
{Head, Tail} = case Bits of
[B | Rest] ->
{B, Rest};
[] ->
{false, []}
end,
Bit_value = case Head of
true ->
1;
false ->
0
end,
Updated_byte = erlang:'bor'(
Current_byte,
erlang:'bsl'(Bit_value, 7 - Bit_index)
),
case Bit_index =:= 7 of
true ->
pack_bool_bits_loop(
Tail,
Remaining - 1,
0,
0,
gleam_stdlib:bit_array_concat([Acc, <<Updated_byte>>])
);
false ->
pack_bool_bits_loop(
Tail,
Remaining - 1,
Bit_index + 1,
Updated_byte,
Acc
)
end
end.
-file("src/packkit/seven_z.gleam", 947).
-spec pack_bool_bits(list(boolean()), integer()) -> bitstring().
pack_bool_bits(Bits, Count) ->
pack_bool_bits_loop(Bits, Count, 0, 0, <<>>).
-file("src/packkit/seven_z.gleam", 1029).
-spec encode_utf16_le_codepoints(list(integer()), bitstring(), binary()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
encode_utf16_le_codepoints(Codepoints, Acc, Full_name) ->
case Codepoints of
[] ->
{ok, Acc};
[Cp | Rest] ->
Value = gleam_stdlib:identity(Cp),
case Value < 16#10000 of
true ->
Low = erlang:'band'(Value, 16#FF),
High = erlang:'bsr'(Value, 8),
encode_utf16_le_codepoints(
Rest,
<<Acc/bitstring, Low, High>>,
Full_name
);
false ->
{error,
{archive_entry_rejected,
Full_name,
<<"7z encoder requires BMP-only file names (no UTF-16 surrogate pairs yet)"/utf8>>}}
end
end.
-file("src/packkit/seven_z.gleam", 1022).
-spec encode_utf16_le_name(binary()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
encode_utf16_le_name(Name) ->
Codepoints = gleam@string:to_utf_codepoints(Name),
gleam@result:'try'(
encode_utf16_le_codepoints(Codepoints, <<>>, Name),
fun(Body) -> {ok, <<Body/bitstring, 0, 0>>} end
).
-file("src/packkit/seven_z.gleam", 1009).
-spec encode_names_loop(list(binary()), bitstring()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
encode_names_loop(Names, Acc) ->
case Names of
[] ->
{ok, Acc};
[Name | Rest] ->
gleam@result:'try'(
encode_utf16_le_name(Name),
fun(Encoded) ->
encode_names_loop(
Rest,
gleam_stdlib:bit_array_concat([Acc, Encoded])
)
end
)
end.
-file("src/packkit/seven_z.gleam", 1000).
-spec encode_names_block(list(binary())) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
encode_names_block(Names) ->
gleam@result:'try'(
encode_names_loop(Names, <<>>),
fun(Bodies) -> {ok, <<16#00, Bodies/bitstring>>} end
).
-file("src/packkit/seven_z.gleam", 1075).
-spec encode_le_bytes(integer(), integer(), bitstring()) -> bitstring().
encode_le_bytes(Value, Count, Acc) ->
case Count of
0 ->
Acc;
_ ->
Byte = Value - ((Value div 256) * 256),
Shifted = Value div 256,
encode_le_bytes(Shifted, Count - 1, <<Acc/bitstring, Byte>>)
end.
-file("src/packkit/seven_z.gleam", 1086).
-spec int_pow(integer(), integer()) -> integer().
int_pow(Base, Exp) ->
case Exp of
0 ->
1;
_ ->
Base * int_pow(Base, Exp - 1)
end.
-file("src/packkit/seven_z.gleam", 1058).
?DOC(
" 7z-style 1..5 byte varint. The first byte's leading 1-bits encode\n"
" the total length; the trailing bytes carry the lower bytes of the\n"
" value little-endian. Cap is 2^35 - 1 which comfortably covers\n"
" every size field the encoder will produce in practice.\n"
).
-spec write_varint(integer()) -> bitstring().
write_varint(Value) ->
{Num_bytes, Header_top} = case Value of
N when N < 16#80 ->
{1, 16#00};
N@1 when N@1 < 16#4000 ->
{2, 16#80};
N@2 when N@2 < 16#200000 ->
{3, 16#C0};
N@3 when N@3 < 16#10000000 ->
{4, 16#E0};
_ ->
{5, 16#F0}
end,
Trailers = Num_bytes - 1,
Divisor = int_pow(256, Trailers),
High_value = case Divisor of
0 -> 0;
Gleam@denominator -> Value div Gleam@denominator
end,
Low_value = Value - (High_value * Divisor),
First_byte = erlang:'bor'(Header_top, High_value),
Trailer_bytes = encode_le_bytes(Low_value, Trailers, <<>>),
<<First_byte, Trailer_bytes/bitstring>>.
-file("src/packkit/seven_z.gleam", 1237).
-spec parse_signature_header(bitstring()) -> {ok,
{integer(), integer(), integer()}} |
{error, packkit@error:archive_error()}.
parse_signature_header(Bytes) ->
case Bytes of
<<16#37,
16#7A,
16#BC,
16#AF,
16#27,
16#1C,
_,
_,
_:4/binary,
Next_offset_lo:32/little-unsigned,
Next_offset_hi:32/little-unsigned,
Next_size_lo:32/little-unsigned,
Next_size_hi:32/little-unsigned,
Next_crc:32/little-unsigned,
_/binary>> ->
Next_offset = begin
_pipe = erlang:'bsl'(Next_offset_hi, 32),
erlang:'bor'(_pipe, Next_offset_lo)
end,
Next_size = begin
_pipe@1 = erlang:'bsl'(Next_size_hi, 32),
erlang:'bor'(_pipe@1, Next_size_lo)
end,
{ok, {Next_offset, Next_size, Next_crc}};
_ ->
{error, {archive_invalid, <<"invalid 7z signature header"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1491).
-spec finalize_parsed_header(header_parser()) -> {ok, parsed_header()} |
{error, packkit@error:archive_error()}.
finalize_parsed_header(Parser) ->
case {erlang:element(3, Parser), erlang:element(4, Parser)} of
{{header_streams_parsed,
Pack_pos,
Pack_sizes,
Folders,
Folder_unpack_sizes,
Sub},
{header_files_parsed,
Names,
Empty_streams,
Empty_files,
Mtimes_unix}} ->
{ok,
{parsed_header,
Pack_pos,
Pack_sizes,
Folders,
Folder_unpack_sizes,
Sub,
Names,
Empty_streams,
Empty_files,
Mtimes_unix}};
{{header_streams_parsed,
Pack_pos@1,
Pack_sizes@1,
Folders@1,
Folder_unpack_sizes@1,
Sub@1},
header_files_none} ->
{ok,
{parsed_header,
Pack_pos@1,
Pack_sizes@1,
Folders@1,
Folder_unpack_sizes@1,
Sub@1,
[],
[],
[],
[]}};
{_, _} ->
{error,
{archive_invalid, <<"7z header missing MainStreamsInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1888).
-spec get_additional_stream(list(bitstring()), integer()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
get_additional_stream(Streams, Index) ->
case {Streams, Index} of
{[Head | _], 0} ->
{ok, Head};
{[_ | Rest], _} when Index > 0 ->
get_additional_stream(Rest, Index - 1);
{_, _} ->
{error,
{archive_invalid,
<<<<<<<<"7z external DataIndex "/utf8,
(erlang:integer_to_binary(Index))/binary>>/binary,
" out of bounds (AdditionalStreamsInfo holds "/utf8>>/binary,
(erlang:integer_to_binary(erlang:length(Streams)))/binary>>/binary,
" stream(s))"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1923).
-spec split_unpack_sizes_by_folder(
list(integer()),
list(parsed_folder()),
list(list(integer()))
) -> list(list(integer())).
split_unpack_sizes_by_folder(Flat, Folders, Acc) ->
case Folders of
[] ->
lists:reverse(Acc);
[Folder | Rest] ->
Count = erlang:length(erlang:element(2, Folder)),
Group = gleam@list:take(Flat, Count),
Leftover = gleam@list:drop(Flat, Count),
split_unpack_sizes_by_folder(Leftover, Rest, [Group | Acc])
end.
-file("src/packkit/seven_z.gleam", 2011).
-spec sum_coder_in_streams(list(coder_spec()), integer()) -> integer().
sum_coder_in_streams(Coders, Acc) ->
case Coders of
[] ->
Acc;
[Head | Rest] ->
sum_coder_in_streams(Rest, Acc + erlang:element(4, Head))
end.
-file("src/packkit/seven_z.gleam", 2018).
-spec sum_coder_out_streams(list(coder_spec()), integer()) -> integer().
sum_coder_out_streams(Coders, Acc) ->
case Coders of
[] ->
Acc;
[Head | Rest] ->
sum_coder_out_streams(Rest, Acc + erlang:element(5, Head))
end.
-file("src/packkit/seven_z.gleam", 2229).
-spec describe_bit_array_hex(bitstring(), binary()) -> binary().
describe_bit_array_hex(Bytes, Acc) ->
case Bytes of
<<B, Rest/binary>> ->
describe_bit_array_hex(
Rest,
<<Acc/binary, (gleam@int:to_base16(B))/binary>>
);
_ ->
Acc
end.
-file("src/packkit/seven_z.gleam", 2436).
-spec count_true(list(boolean())) -> integer().
count_true(Bits) ->
case Bits of
[] ->
0;
[true | Rest] ->
1 + count_true(Rest);
[false | Rest@1] ->
count_true(Rest@1)
end.
-file("src/packkit/seven_z.gleam", 2558).
-spec build_dummy_names(integer(), integer(), list(binary())) -> list(binary()).
build_dummy_names(Count, Index, Acc) ->
case Index >= Count of
true ->
lists:reverse(Acc);
false ->
build_dummy_names(
Count,
Index + 1,
[<<"file"/utf8, (erlang:integer_to_binary(Index))/binary>> |
Acc]
)
end.
-file("src/packkit/seven_z.gleam", 2554).
-spec dummy_names(integer()) -> list(binary()).
dummy_names(Count) ->
build_dummy_names(Count, 0, []).
-file("src/packkit/seven_z.gleam", 2630).
-spec encode_utf8_code(integer(), bitstring()) -> bitstring().
encode_utf8_code(Code, Acc) ->
case Code of
C when C < 16#80 ->
<<Acc/bitstring, C>>;
C@1 when C@1 < 16#800 ->
B1 = 16#C0 + erlang:'bsr'(C@1, 6),
B2 = 16#80 + erlang:'band'(C@1, 16#3F),
<<Acc/bitstring, B1, B2>>;
C@2 ->
B1@1 = 16#E0 + erlang:'bsr'(C@2, 12),
B2@1 = 16#80 + erlang:'band'(erlang:'bsr'(C@2, 6), 16#3F),
B3 = 16#80 + erlang:'band'(C@2, 16#3F),
<<Acc/bitstring, B1@1, B2@1, B3>>
end.
-file("src/packkit/seven_z.gleam", 2623).
-spec codepoints_to_bit_array(list(integer()), bitstring()) -> bitstring().
codepoints_to_bit_array(Codes, Acc) ->
case Codes of
[] ->
Acc;
[Code | Rest] ->
codepoints_to_bit_array(Rest, encode_utf8_code(Code, Acc))
end.
-file("src/packkit/seven_z.gleam", 2594).
-spec decode_utf16_names(
bitstring(),
integer(),
list(integer()),
list(binary())
) -> {ok, list(binary())} | {error, packkit@error:archive_error()}.
decode_utf16_names(Bytes, Remaining, Current, Acc) ->
case Remaining of
0 ->
{ok, lists:reverse(Acc)};
_ ->
case Bytes of
<<Lo, Hi, Rest/binary>> ->
Code = erlang:'bor'(erlang:'bsl'(Hi, 8), Lo),
case Code of
0 ->
Name@1 = case gleam@bit_array:to_string(
codepoints_to_bit_array(
lists:reverse(Current),
<<>>
)
) of
{ok, Name} -> Name;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"decode_utf16_names"/utf8>>,
line => 2608,
value => _assert_fail,
start => 83799,
'end' => 83947,
pattern_start => 83810,
pattern_end => 83818})
end,
decode_utf16_names(
Rest,
Remaining - 1,
[],
[Name@1 | Acc]
);
_ ->
decode_utf16_names(
Rest,
Remaining,
[Code | Current],
Acc
)
end;
_ ->
{error,
{archive_invalid,
<<"truncated 7z UTF-16 file name"/utf8>>}}
end
end.
-file("src/packkit/seven_z.gleam", 2665).
-spec unpack_bits(integer(), integer(), list(boolean())) -> list(boolean()).
unpack_bits(Byte, Remaining, Acc) ->
case Remaining of
0 ->
lists:reverse(Acc);
_ ->
Bit = erlang:'band'(erlang:'bsr'(Byte, Remaining - 1), 1),
unpack_bits(Byte, Remaining - 1, [Bit =:= 1 | Acc])
end.
-file("src/packkit/seven_z.gleam", 2712).
-spec drop_bytes(bitstring(), integer(), binary()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
drop_bytes(Bytes, Count, Label) ->
case gleam_stdlib:bit_array_slice(
Bytes,
Count,
erlang:byte_size(Bytes) - Count
) of
{ok, Rest} ->
{ok, Rest};
{error, _} ->
{error, {archive_invalid, <<"truncated "/utf8, Label/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 2690).
-spec skip_crc_block(bitstring(), integer()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
skip_crc_block(Bytes, Count) ->
case Bytes of
<<All_defined, Rest/binary>> ->
case All_defined of
1 ->
drop_bytes(Rest, Count * 4, <<"7z CRC table"/utf8>>);
_ ->
Byte_count = (Count + 7) div 8,
gleam@result:'try'(
drop_bytes(
Rest,
Byte_count,
<<"7z CRC flag bits"/utf8>>
),
fun(After_flags) ->
drop_bytes(
After_flags,
Count * 4,
<<"7z CRC values"/utf8>>
)
end
)
end;
_ ->
{error, {archive_invalid, <<"truncated 7z CRC block"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2827).
-spec repeat_one_per_folder(integer(), list(integer())) -> list(integer()).
repeat_one_per_folder(N, Acc) ->
case N of
0 ->
Acc;
_ ->
repeat_one_per_folder(N - 1, [1 | Acc])
end.
-file("src/packkit/seven_z.gleam", 2867).
-spec list_take(list(NEE), integer(), list(NEE)) -> {list(NEE), list(NEE)}.
list_take(Values, N, Acc) ->
case {Values, N} of
{_, 0} ->
{lists:reverse(Acc), Values};
{[], _} ->
{lists:reverse(Acc), []};
{[Head | Rest], _} ->
list_take(Rest, N - 1, [Head | Acc])
end.
-file("src/packkit/seven_z.gleam", 2875).
-spec sum_list(list(integer()), integer()) -> integer().
sum_list(Values, Acc) ->
case Values of
[] ->
Acc;
[Head | Rest] ->
sum_list(Rest, Acc + Head)
end.
-file("src/packkit/seven_z.gleam", 2834).
-spec derive_substream_sizes(
list(integer()),
list(integer()),
list(integer()),
list(integer())
) -> list(integer()).
derive_substream_sizes(Per_folder, Folder_unpack_sizes, Remaining_explicit, Acc) ->
case {Per_folder, Folder_unpack_sizes} of
{[], _} ->
lists:reverse(Acc);
{_, []} ->
lists:reverse(Acc);
{[Count | Rest_counts], [Folder_total | Rest_folder_totals]} ->
Explicit_for_folder = case Count of
0 ->
0;
_ ->
Count - 1
end,
{Explicit, Remaining} = list_take(
Remaining_explicit,
Explicit_for_folder,
[]
),
Explicit_sum = sum_list(Explicit, 0),
Derived = Folder_total - Explicit_sum,
Folder_sizes = case Count of
0 ->
[];
_ ->
lists:append(Explicit, [Derived])
end,
derive_substream_sizes(
Rest_counts,
Rest_folder_totals,
Remaining,
lists:append(lists:reverse(Folder_sizes), Acc)
)
end.
-file("src/packkit/seven_z.gleam", 2988).
-spec folder_packed_stream_count(parsed_folder()) -> integer().
folder_packed_stream_count(Folder) ->
case erlang:element(3, Folder) of
[] ->
1;
List_value ->
erlang:length(List_value)
end.
-file("src/packkit/seven_z.gleam", 3015).
-spec enforce_max_output(list(integer()), packkit@limit:limits()) -> {ok, nil} |
{error, packkit@error:archive_error()}.
enforce_max_output(Unpack_sizes, Limits) ->
Total = sum_list(Unpack_sizes, 0),
case Total > packkit@limit:max_output_bytes(Limits) of
true ->
{error,
{archive_limit_exceeded, <<"max_output_bytes"/utf8>>, Total}};
false ->
{ok, nil}
end.
-file("src/packkit/seven_z.gleam", 3111).
-spec bcj2_error_to_archive(packkit@internal@bcj2:bcj2_error()) -> packkit@error:archive_error().
bcj2_error_to_archive(Err) ->
case Err of
range_coder_header_invalid ->
{archive_invalid,
<<"7z BCJ2: range-coder header invalid (first 5 bytes)"/utf8>>};
{stream_exhausted, Name} ->
{archive_invalid,
<<<<"7z BCJ2: stream \""/utf8, Name/binary>>/binary,
"\" exhausted mid-decode"/utf8>>};
{output_size_mismatch, Declared, Actual} ->
{archive_invalid,
<<<<<<"7z BCJ2: decoded "/utf8,
(erlang:integer_to_binary(Actual))/binary>>/binary,
" bytes, expected "/utf8>>/binary,
(erlang:integer_to_binary(Declared))/binary>>}
end.
-file("src/packkit/seven_z.gleam", 3200).
-spec string_inspect(any()) -> binary().
string_inspect(Value) ->
gleam@string:inspect(Value).
-file("src/packkit/seven_z.gleam", 3179).
-spec maybe_wrap_aes_chain_error(packkit@error:archive_error(), coder_id()) -> packkit@error:archive_error().
maybe_wrap_aes_chain_error(Err, Head_id) ->
case Head_id =:= aes256_sha256 of
false ->
Err;
true ->
Original = case Err of
{archive_invalid, Message} ->
Message;
{archive_not_implemented, Feature} ->
Feature;
Other ->
string_inspect(Other)
end,
{archive_invalid,
<<<<"7z AES decrypt produced invalid plaintext for the "/utf8,
"downstream coder (wrong password or corrupt archive): "/utf8>>/binary,
Original/binary>>}
end.
-file("src/packkit/seven_z.gleam", 3285).
-spec bit_array_to_byte_list_seven_z(bitstring(), list(integer())) -> list(integer()).
bit_array_to_byte_list_seven_z(Bytes, Acc) ->
case Bytes of
<<B, Rest/binary>> ->
bit_array_to_byte_list_seven_z(Rest, [B | Acc]);
_ ->
lists:reverse(Acc)
end.
-file("src/packkit/seven_z.gleam", 3292).
-spec byte_list_to_bit_array_seven_z(list(integer()), bitstring()) -> bitstring().
byte_list_to_bit_array_seven_z(Bytes, Acc) ->
case Bytes of
[] ->
Acc;
[B | Rest] ->
byte_list_to_bit_array_seven_z(Rest, <<Acc/bitstring, B>>)
end.
-file("src/packkit/seven_z.gleam", 3324).
-spec nth_back(list(integer()), integer()) -> integer().
nth_back(Values, Steps) ->
case {Values, Steps} of
{[Head | _], 0} ->
Head;
{[_ | Tail], _} ->
nth_back(Tail, Steps - 1);
{[], _} ->
0
end.
-file("src/packkit/seven_z.gleam", 3299).
-spec delta_decode_seven_z_loop(
list(integer()),
integer(),
list(integer()),
integer()
) -> list(integer()).
delta_decode_seven_z_loop(Input, Distance, Output, Index) ->
case Input of
[] ->
lists:reverse(Output);
[B | Rest] ->
case Index < Distance of
true ->
delta_decode_seven_z_loop(
Rest,
Distance,
[B | Output],
Index + 1
);
false ->
Predecessor = nth_back(Output, Distance - 1),
Sum = erlang:'band'(B + Predecessor, 16#FF),
delta_decode_seven_z_loop(
Rest,
Distance,
[Sum | Output],
Index + 1
)
end
end.
-file("src/packkit/seven_z.gleam", 3279).
-spec delta_decode_seven_z(bitstring(), integer()) -> bitstring().
delta_decode_seven_z(Bytes, Distance) ->
Byte_list = bit_array_to_byte_list_seven_z(Bytes, []),
Decoded = delta_decode_seven_z_loop(Byte_list, Distance, [], 0),
byte_list_to_bit_array_seven_z(Decoded, <<>>).
-file("src/packkit/seven_z.gleam", 3344).
-spec flag_to_int(boolean()) -> integer().
flag_to_int(Flag) ->
case Flag of
true ->
1;
false ->
0
end.
-file("src/packkit/seven_z.gleam", 3506).
-spec aes_kdf_loop(
packkit@checksum:sha256_state(),
bitstring(),
bitstring(),
integer(),
integer()
) -> packkit@checksum:sha256_state().
aes_kdf_loop(State, Salt, Password_utf16le, Counter, Rounds) ->
case gleam@int:compare(Counter, Rounds) of
lt ->
Counter_bytes = <<Counter:64/little>>,
Next_state = begin
_pipe = State,
_pipe@1 = packkit@checksum:sha256_update(_pipe, Salt),
_pipe@2 = packkit@checksum:sha256_update(
_pipe@1,
Password_utf16le
),
packkit@checksum:sha256_update(_pipe@2, Counter_bytes)
end,
aes_kdf_loop(
Next_state,
Salt,
Password_utf16le,
Counter + 1,
Rounds
);
_ ->
State
end.
-file("src/packkit/seven_z.gleam", 3484).
-spec derive_aes_key_hashed(bitstring(), bitstring(), integer()) -> bitstring().
derive_aes_key_hashed(Salt, Password_utf16le, Num_cycles_power) ->
Rounds = erlang:'bsl'(1, Num_cycles_power),
Initial = packkit@checksum:sha256_init(),
Final_state = aes_kdf_loop(Initial, Salt, Password_utf16le, 0, Rounds),
packkit@checksum:sha256_finalize(Final_state).
-file("src/packkit/seven_z.gleam", 3556).
-spec utf16le_append_codepoint(integer(), bitstring()) -> bitstring().
utf16le_append_codepoint(Scalar, Acc) ->
gleam@bool:guard(
Scalar < 16#10000,
<<Acc/bitstring, Scalar:16/little>>,
fun() ->
Adjusted = Scalar - 16#10000,
High = 16#D800 + erlang:'bsr'(Adjusted, 10),
Low = 16#DC00 + erlang:'band'(Adjusted, 16#3FF),
<<Acc/bitstring, High:16/little, Low:16/little>>
end
).
-file("src/packkit/seven_z.gleam", 3549).
-spec utf16le_append_grapheme(binary(), bitstring()) -> bitstring().
utf16le_append_grapheme(Grapheme, Acc) ->
_pipe = gleam@string:to_utf_codepoints(Grapheme),
gleam@list:fold(
_pipe,
Acc,
fun(Running, Codepoint) ->
utf16le_append_codepoint(gleam_stdlib:identity(Codepoint), Running)
end
).
-file("src/packkit/seven_z.gleam", 3538).
-spec utf16le_encode(binary(), bitstring()) -> bitstring().
utf16le_encode(Source, Acc) ->
case gleam_stdlib:string_pop_grapheme(Source) of
{ok, {Grapheme, Rest}} ->
utf16le_encode(Rest, utf16le_append_grapheme(Grapheme, Acc));
_ ->
Acc
end.
-file("src/packkit/seven_z.gleam", 3642).
-spec iv_or_zero(bitstring()) -> bitstring().
iv_or_zero(Iv) ->
Iv_size = erlang:byte_size(Iv),
case Iv_size of
16 ->
Iv;
Size when Size < 16 ->
<<Iv/bitstring, 0:(lists:max([(((16 - Size) * 8)), 0]))>>;
_ ->
_pipe = gleam_stdlib:bit_array_slice(Iv, 0, 16),
gleam@result:unwrap(_pipe, <<0:128>>)
end.
-file("src/packkit/seven_z.gleam", 3683).
-spec xor_bit_arrays_loop(bitstring(), bitstring(), bitstring()) -> bitstring().
xor_bit_arrays_loop(Left, Right, Acc) ->
case {Left, Right} of
{<<Left_byte, Left_rest/binary>>, <<Right_byte, Right_rest/binary>>} ->
xor_bit_arrays_loop(
Left_rest,
Right_rest,
<<Acc/bitstring, (erlang:'bxor'(Left_byte, Right_byte))>>
);
{_, _} ->
Acc
end.
-file("src/packkit/seven_z.gleam", 3679).
-spec xor_bit_arrays(bitstring(), bitstring()) -> bitstring().
xor_bit_arrays(Left, Right) ->
xor_bit_arrays_loop(Left, Right, <<>>).
-file("src/packkit/seven_z.gleam", 3593).
-spec aes_cbc_encrypt_loop(
bitstring(),
packkit@internal@aes:expanded_key(),
bitstring(),
bitstring()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
aes_cbc_encrypt_loop(Plaintext, Key, Prev_block, Acc) ->
case Plaintext of
<<>> ->
{ok, Acc};
<<Block:16/binary, Rest/binary>> ->
Xored = xor_bit_arrays(Block, Prev_block),
gleam@result:'try'(
begin
_pipe = packkit@internal@aes:encrypt_block(Key, Xored),
gleam@result:replace_error(
_pipe,
{archive_invalid,
<<"7z AES encrypt_block rejected a 16-byte plaintext block"/utf8>>}
)
end,
fun(Ciphertext_block) ->
aes_cbc_encrypt_loop(
Rest,
Key,
Ciphertext_block,
<<Acc/bitstring, Ciphertext_block/bitstring>>
)
end
);
_ ->
{error,
{archive_invalid,
<<"7z AES plaintext tail shorter than 16 bytes after padding"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3654).
-spec aes_cbc_decrypt_loop(
bitstring(),
packkit@internal@aes:expanded_key(),
bitstring(),
bitstring()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
aes_cbc_decrypt_loop(Ciphertext, Key, Prev_block, Acc) ->
case Ciphertext of
<<>> ->
{ok, Acc};
<<Block:16/binary, Rest/binary>> ->
gleam@result:'try'(
begin
_pipe = packkit@internal@aes:decrypt_block(Key, Block),
gleam@result:replace_error(
_pipe,
{archive_invalid,
<<"7z AES decrypt_block rejected a 16-byte ciphertext block"/utf8>>}
)
end,
fun(Decrypted) ->
Plaintext_block = xor_bit_arrays(Decrypted, Prev_block),
aes_cbc_decrypt_loop(
Rest,
Key,
Block,
<<Acc/bitstring, Plaintext_block/bitstring>>
)
end
);
_ ->
{error,
{archive_invalid,
<<"7z AES ciphertext tail shorter than 16 bytes"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3698).
-spec folder_unpack_total(list(integer())) -> integer().
folder_unpack_total(Unpack_sizes) ->
case Unpack_sizes of
[Size | _] ->
Size;
[] ->
0
end.
-file("src/packkit/seven_z.gleam", 3711).
-spec decode_copy_coder(bitstring(), list(integer())) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
decode_copy_coder(Packed, Unpack_sizes) ->
Target = folder_unpack_total(Unpack_sizes),
Packed_size = erlang:byte_size(Packed),
case Packed_size >= Target of
true ->
case gleam_stdlib:bit_array_slice(Packed, 0, Target) of
{ok, B} ->
{ok, B};
{error, _} ->
{error,
{archive_invalid, <<"7z Copy coder slice failed"/utf8>>}}
end;
false ->
{error,
{archive_invalid,
<<<<<<"7z Copy coder packed size "/utf8,
(erlang:integer_to_binary(Packed_size))/binary>>/binary,
" < declared unpack size "/utf8>>/binary,
(erlang:integer_to_binary(Target))/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 3770).
-spec verify_unpack_size(bitstring(), integer(), binary()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
verify_unpack_size(Plain, Expected, Coder_name) ->
Actual = erlang:byte_size(Plain),
case Actual =:= Expected of
true ->
{ok, Plain};
false ->
{error,
{archive_invalid,
<<<<<<<<<<"7z "/utf8, Coder_name/binary>>/binary,
" unpacked "/utf8>>/binary,
(erlang:integer_to_binary(Actual))/binary>>/binary,
" bytes but folder declared "/utf8>>/binary,
(erlang:integer_to_binary(Expected))/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 3247).
-spec decode_bcj_coder(
bitstring(),
list(integer()),
fun((bitstring(), integer()) -> bitstring()),
binary()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_bcj_coder(Packed, Unpack_sizes, Decoder, Arch_name) ->
Target = folder_unpack_total(Unpack_sizes),
Decoded = Decoder(Packed, 0),
verify_unpack_size(Decoded, Target, <<"BCJ "/utf8, Arch_name/binary>>).
-file("src/packkit/seven_z.gleam", 3265).
-spec decode_delta_coder(bitstring(), bitstring(), list(integer())) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_delta_coder(Packed, Properties, Unpack_sizes) ->
Target = folder_unpack_total(Unpack_sizes),
Distance = case Properties of
<<D>> ->
D + 1;
_ ->
1
end,
Decoded = delta_decode_seven_z(Packed, Distance),
verify_unpack_size(Decoded, Target, <<"Delta"/utf8>>).
-file("src/packkit/seven_z.gleam", 3948).
-spec codec_to_archive(packkit@error:codec_error()) -> packkit@error:archive_error().
codec_to_archive(Err) ->
case Err of
{codec_not_implemented, Feature} ->
{archive_not_implemented, Feature};
{codec_invalid_data, Message} ->
{archive_invalid, Message};
{codec_limit_exceeded, Limit, Actual} ->
{archive_limit_exceeded, Limit, Actual};
{codec_dictionary_required, Name} ->
{archive_invalid,
<<<<"codec "/utf8, Name/binary>>/binary,
" requires a preset dictionary"/utf8>>};
{codec_dictionary_mismatch, Name@1} ->
{archive_invalid,
<<<<"codec "/utf8, Name@1/binary>>/binary,
" preset dictionary DICT_ID mismatch"/utf8>>};
{codec_option_unsupported, Option, Codec_name} ->
{archive_invalid,
<<<<<<"codec "/utf8, Codec_name/binary>>/binary,
" does not support the requested option: "/utf8>>/binary,
Option/binary>>}
end.
-file("src/packkit/seven_z.gleam", 3739).
-spec decode_deflate_coder(bitstring(), list(integer()), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_deflate_coder(Packed, Unpack_sizes, Limits) ->
Target = folder_unpack_total(Unpack_sizes),
case packkit@deflate:decode_with_limits(Packed, Limits) of
{ok, Plain} ->
verify_unpack_size(Plain, Target, <<"Deflate"/utf8>>);
{error, Err} ->
{error, codec_to_archive(Err)}
end.
-file("src/packkit/seven_z.gleam", 3753).
-spec decode_bzip2_coder(bitstring(), list(integer()), packkit@limit:limits()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_bzip2_coder(Packed, Unpack_sizes, Limits) ->
Target = folder_unpack_total(Unpack_sizes),
case packkit@bzip2:decode_with_limits(Packed, Limits) of
{ok, Plain} ->
verify_unpack_size(Plain, Target, <<"BZip2"/utf8>>);
{error, Err} ->
{error, codec_to_archive(Err)}
end.
-file("src/packkit/seven_z.gleam", 3803).
-spec decode_lzma2_stream(bitstring(), bitstring(), integer()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_lzma2_stream(Payload, Output, Target) ->
case Payload of
<<16#00, _/binary>> ->
{ok, Output};
<<Control, _/binary>> when (Control =:= 16#01) orelse (Control =:= 16#02) ->
case Payload of
<<_, Sh, Sl, Rest/binary>> ->
Size = erlang:'bor'(erlang:'bsl'(Sh, 8), Sl) + 1,
case gleam_stdlib:bit_array_slice(Rest, 0, Size) of
{ok, Chunk} ->
case gleam_stdlib:bit_array_slice(
Rest,
Size,
erlang:byte_size(Rest) - Size
) of
{ok, After} ->
decode_lzma2_stream(
After,
gleam_stdlib:bit_array_concat(
[Output, Chunk]
),
Target
);
{error, _} ->
{error,
{archive_invalid,
<<"truncated 7z LZMA2 uncompressed chunk"/utf8>>}}
end;
{error, _} ->
{error,
{archive_invalid,
<<"truncated 7z LZMA2 chunk body"/utf8>>}}
end;
_ ->
{error,
{archive_invalid,
<<"truncated 7z LZMA2 chunk header"/utf8>>}}
end;
<<Control@1,
Usize_high,
Usize_low,
Csize_high,
Csize_low,
Rest@1/binary>> when Control@1 >= 16#80 ->
_ = Target,
Usize = erlang:'bor'(
erlang:'bsl'(erlang:'band'(Control@1, 16#1F), 16),
erlang:'bor'(erlang:'bsl'(Usize_high, 8), Usize_low)
)
+ 1,
Csize = erlang:'bor'(erlang:'bsl'(Csize_high, 8), Csize_low) + 1,
case Control@1 >= 16#C0 of
true ->
case Rest@1 of
<<Props_byte, Rest_after_props/binary>> ->
case packkit@internal@lzma:properties_of_byte(
Props_byte
) of
{ok, Parsed_props} ->
case gleam_stdlib:bit_array_slice(
Rest_after_props,
0,
Csize
) of
{ok, Lzma_data} ->
case gleam_stdlib:bit_array_slice(
Rest_after_props,
Csize,
erlang:byte_size(
Rest_after_props
)
- Csize
) of
{ok, After_chunk} ->
case packkit@internal@lzma:new(
Lzma_data,
Parsed_props,
32000000
) of
{ok, Dec} ->
case packkit@internal@lzma:decode_into(
Dec,
Usize
) of
{ok,
{Decoded, _}} ->
decode_lzma2_stream(
After_chunk,
gleam_stdlib:bit_array_concat(
[Output,
Decoded]
),
Target
);
{error, Err} ->
{error,
codec_to_archive(
Err
)}
end;
{error, Err@1} ->
{error,
codec_to_archive(
Err@1
)}
end;
{error, _} ->
{error,
{archive_invalid,
<<"truncated 7z LZMA chunk"/utf8>>}}
end;
{error, _} ->
{error,
{archive_invalid,
<<"truncated 7z LZMA chunk body"/utf8>>}}
end;
{error, Err@2} ->
{error, codec_to_archive(Err@2)}
end;
_ ->
{error,
{archive_invalid,
<<"truncated 7z LZMA properties byte"/utf8>>}}
end;
false ->
{error,
{archive_not_implemented,
<<"7z LZMA2 chunks without inline properties"/utf8>>}}
end;
_ ->
{error, {archive_invalid, <<"invalid 7z LZMA2 control byte"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3790).
-spec decode_lzma2_payload(bitstring(), bitstring(), list(integer())) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_lzma2_payload(Packed, _, Unpack_sizes) ->
Total = case Unpack_sizes of
[Size | _] ->
Size;
[] ->
0
end,
gleam@result:'try'(
decode_lzma2_stream(Packed, <<>>, Total),
fun(Bytes) -> {ok, Bytes} end
).
-file("src/packkit/seven_z.gleam", 3912).
-spec decode_raw_lzma(bitstring(), bitstring(), list(integer())) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
decode_raw_lzma(Packed, Props, Unpack_sizes) ->
Target = case Unpack_sizes of
[Size | _] ->
Size;
[] ->
0
end,
case Props of
<<Props_byte, _/binary>> ->
case packkit@internal@lzma:properties_of_byte(Props_byte) of
{ok, Parsed_props} ->
case packkit@internal@lzma:new(
Packed,
Parsed_props,
32000000
) of
{ok, Dec} ->
case packkit@internal@lzma:decode_into(Dec, Target) of
{ok, {Decoded, _}} ->
{ok, Decoded};
{error, Err} ->
{error, codec_to_archive(Err)}
end;
{error, Err@1} ->
{error, codec_to_archive(Err@1)}
end;
{error, Err@2} ->
{error, codec_to_archive(Err@2)}
end;
_ ->
{error,
{archive_invalid,
<<"7z raw LZMA coder missing properties"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 4016).
-spec last_of_list(list(integer())) -> integer().
last_of_list(Values) ->
case Values of
[Last] ->
Last;
[_ | Rest] ->
last_of_list(Rest);
[] ->
0
end.
-file("src/packkit/seven_z.gleam", 4010).
-spec derive_substream_sizes_from_folders(list(list(integer()))) -> list(integer()).
derive_substream_sizes_from_folders(Folder_unpack_sizes) ->
gleam@list:map(Folder_unpack_sizes, fun last_of_list/1).
-file("src/packkit/seven_z.gleam", 4143).
-spec apply_mtime(packkit@entry:entry(), gleam@option:option(integer())) -> packkit@entry:entry().
apply_mtime(E, Mtime) ->
case Mtime of
{some, Unix_seconds} when Unix_seconds > 0 ->
packkit@entry:with_modified_at(E, Unix_seconds);
_ ->
E
end.
-file("src/packkit/seven_z.gleam", 4151).
-spec add_file(
binary(),
bitstring(),
gleam@option:option(integer()),
list(packkit@entry:entry()),
packkit@limit:limits()
) -> {ok, list(packkit@entry:entry())} | {error, packkit@error:archive_error()}.
add_file(Name, Body, Mtime, Acc, Limits) ->
case packkit@entry:file_checked(Name, Body) of
{ok, E} ->
Depth = packkit@entry:depth(packkit@entry:path(E)),
case Depth > packkit@limit:max_entry_depth(Limits) of
true ->
{error,
{archive_limit_exceeded,
<<"max_entry_depth"/utf8>>,
Depth}};
false ->
{ok, [apply_mtime(E, Mtime) | Acc]}
end;
{error, _} ->
{error,
{archive_invalid,
<<"7z file name failed path validation: "/utf8,
Name/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 4177).
-spec add_directory(
binary(),
gleam@option:option(integer()),
list(packkit@entry:entry()),
packkit@limit:limits()
) -> {ok, list(packkit@entry:entry())} | {error, packkit@error:archive_error()}.
add_directory(Name, Mtime, Acc, Limits) ->
case packkit@entry:directory_checked(Name) of
{ok, E} ->
Depth = packkit@entry:depth(packkit@entry:path(E)),
case Depth > packkit@limit:max_entry_depth(Limits) of
true ->
{error,
{archive_limit_exceeded,
<<"max_entry_depth"/utf8>>,
Depth}};
false ->
{ok, [apply_mtime(E, Mtime) | Acc]}
end;
{error, _} ->
{error,
{archive_invalid,
<<"7z directory name failed path validation: "/utf8,
Name/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 4204).
-spec slice_required(bitstring(), integer(), integer(), binary()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
slice_required(Bytes, Offset, Length, Label) ->
case gleam_stdlib:bit_array_slice(Bytes, Offset, Length) of
{ok, Value} ->
{ok, Value};
{error, _} ->
{error, {archive_invalid, <<"truncated "/utf8, Label/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 2995).
-spec slice_folder_streams(
bitstring(),
integer(),
list(integer()),
list(bitstring())
) -> {ok, list(bitstring())} | {error, packkit@error:archive_error()}.
slice_folder_streams(Packed, Cursor, Sizes, Acc) ->
case Sizes of
[] ->
{ok, lists:reverse(Acc)};
[Size | Rest] ->
gleam@result:'try'(
slice_required(
Packed,
Cursor,
Size,
<<"7z per-folder packed stream"/utf8>>
),
fun(Stream) ->
slice_folder_streams(
Packed,
Cursor + Size,
Rest,
[Stream | Acc]
)
end
)
end.
-file("src/packkit/seven_z.gleam", 4223).
-spec read_number_body(integer(), bitstring(), integer(), integer(), integer()) -> {ok,
{integer(), bitstring()}} |
{error, packkit@error:archive_error()}.
read_number_body(First, Rest, Mask, Index, Value) ->
case Index >= 8 of
true ->
{ok, {Value, Rest}};
false ->
case erlang:'band'(First, Mask) of
0 ->
High_part = erlang:'band'(First, Mask - 1),
Final_value = Value + erlang:'bsl'(High_part, Index * 8),
{ok, {Final_value, Rest}};
_ ->
case Rest of
<<Byte, More/binary>> ->
read_number_body(
First,
More,
erlang:'bsr'(Mask, 1),
Index + 1,
Value + erlang:'bsl'(Byte, Index * 8)
);
_ ->
{error,
{archive_invalid,
<<"truncated 7z multi-byte varint"/utf8>>}}
end
end
end.
-file("src/packkit/seven_z.gleam", 4216).
-spec read_number(bitstring()) -> {ok, {integer(), bitstring()}} |
{error, packkit@error:archive_error()}.
read_number(Bytes) ->
case Bytes of
<<First, Rest/binary>> ->
read_number_body(First, Rest, 16#80, 0, 0);
_ ->
{error, {archive_invalid, <<"truncated 7z varint"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2025).
-spec read_bind_pairs(bitstring(), integer(), list({integer(), integer()})) -> {ok,
{list({integer(), integer()}), bitstring()}} |
{error, packkit@error:archive_error()}.
read_bind_pairs(Bytes, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Bytes}};
_ ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{In_idx, After_in} = _use0,
gleam@result:'try'(
read_number(After_in),
fun(_use0@1) ->
{Out_idx, After_out} = _use0@1,
read_bind_pairs(
After_out,
Remaining - 1,
[{In_idx, Out_idx} | Acc]
)
end
)
end
)
end.
-file("src/packkit/seven_z.gleam", 2040).
-spec read_varint_list(bitstring(), integer(), list(integer())) -> {ok,
{list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
read_varint_list(Bytes, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Bytes}};
_ ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Value, After_value} = _use0,
read_varint_list(After_value, Remaining - 1, [Value | Acc])
end
)
end.
-file("src/packkit/seven_z.gleam", 2054).
-spec consume_linear_bind_pairs(bitstring(), integer(), integer()) -> {ok,
{bitstring(), nil}} |
{error, packkit@error:archive_error()}.
consume_linear_bind_pairs(Bytes, Next_in_idx, Remaining) ->
gleam@bool:guard(
Remaining =:= 0,
{ok, {Bytes, nil}},
fun() ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{In_idx, After_in} = _use0,
gleam@result:'try'(
read_number(After_in),
fun(_use0@1) ->
{Out_idx, After_out} = _use0@1,
Expected_out_idx = Next_in_idx - 1,
gleam@bool:guard(
(In_idx /= Next_in_idx) orelse (Out_idx /= Expected_out_idx),
{error,
{archive_not_implemented,
<<<<<<<<<<<<<<<<"7z non-linear coder topology (bind in="/utf8,
(erlang:integer_to_binary(
In_idx
))/binary>>/binary,
" out="/utf8>>/binary,
(erlang:integer_to_binary(
Out_idx
))/binary>>/binary,
", expected linear in="/utf8>>/binary,
(erlang:integer_to_binary(
Next_in_idx
))/binary>>/binary,
" out="/utf8>>/binary,
(erlang:integer_to_binary(
Expected_out_idx
))/binary>>/binary,
")"/utf8>>}},
fun() ->
consume_linear_bind_pairs(
After_out,
Next_in_idx + 1,
Remaining - 1
)
end
)
end
)
end
)
end
).
-file("src/packkit/seven_z.gleam", 2569).
-spec parse_name_block(bitstring(), integer(), list(bitstring())) -> {ok,
list(binary())} |
{error, packkit@error:archive_error()}.
parse_name_block(Payload, Num_files, Additional_streams) ->
case Payload of
<<External, Rest/binary>> ->
case External of
0 ->
decode_utf16_names(Rest, Num_files, [], []);
_ ->
gleam@result:'try'(
read_number(Rest),
fun(_use0) ->
{Data_index, _} = _use0,
gleam@result:'try'(
get_additional_stream(
Additional_streams,
Data_index
),
fun(External_bytes) ->
decode_utf16_names(
External_bytes,
Num_files,
[],
[]
)
end
)
end
)
end;
_ ->
{error,
{archive_invalid, <<"truncated 7z file-name section"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 4265).
-spec read_numbers_loop(bitstring(), integer(), list(integer())) -> {ok,
{list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
read_numbers_loop(Bytes, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Bytes}};
_ ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Value, Rest} = _use0,
read_numbers_loop(Rest, Remaining - 1, [Value | Acc])
end
)
end.
-file("src/packkit/seven_z.gleam", 4258).
-spec read_numbers(bitstring(), integer()) -> {ok,
{list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
read_numbers(Bytes, Count) ->
read_numbers_loop(Bytes, Count, []).
-file("src/packkit/seven_z.gleam", 667).
-spec encode_via_method(bitstring(), method()) -> {ok,
{bitstring(), bitstring()}} |
{error, packkit@error:archive_error()}.
encode_via_method(Bytes, Method) ->
case Method of
method_lzma ->
Props = {properties, 3, 0, 2},
Compressed = packkit@internal@lzma:encode_with_lz77(Bytes, Props),
Prop_byte = packkit@internal@lzma:properties_to_byte(Props),
Dict_size_bytes = <<16#10000:32/little>>,
Coder_def = <<16#23,
16#03,
16#01,
16#01,
(write_varint(5))/bitstring,
Prop_byte,
Dict_size_bytes/bitstring>>,
{ok, {Compressed, Coder_def}};
method_copy ->
Coder_def@1 = <<16#01, 16#00>>,
{ok, {Bytes, Coder_def@1}};
method_deflate ->
gleam@result:'try'(
begin
_pipe = packkit@deflate:encode(Bytes),
gleam@result:map_error(_pipe, fun codec_to_archive/1)
end,
fun(Compressed@1) ->
Coder_def@2 = <<16#03, 16#04, 16#01, 16#08>>,
{ok, {Compressed@1, Coder_def@2}}
end
);
method_bzip2 ->
gleam@result:'try'(
begin
_pipe@1 = packkit@bzip2:encode(Bytes),
gleam@result:map_error(_pipe@1, fun codec_to_archive/1)
end,
fun(Compressed@2) ->
Coder_def@3 = <<16#03, 16#04, 16#02, 16#02>>,
{ok, {Compressed@2, Coder_def@3}}
end
)
end.
-file("src/packkit/seven_z.gleam", 2176).
-spec classify_coder_id(bitstring()) -> {ok, coder_id()} |
{error, packkit@error:archive_error()}.
classify_coder_id(Id_bytes) ->
case Id_bytes of
<<B>> when B =:= 16#00 ->
{ok, copy};
<<B@1>> when B@1 =:= 16#21 ->
{ok, lzma2};
<<B@2>> when B@2 =:= 16#03 ->
{ok, delta};
<<B1, B2, B3>> when ((B1 =:= 16#03) andalso (B2 =:= 16#01)) andalso (B3 =:= 16#01) ->
{ok, lzma};
<<B1@1, B2@1, B3@1>> when ((B1@1 =:= 16#04) andalso (B2@1 =:= 16#01)) andalso (B3@1 =:= 16#08) ->
{ok, deflate};
<<B1@2, B2@2, B3@2>> when ((B1@2 =:= 16#04) andalso (B2@2 =:= 16#02)) andalso (B3@2 =:= 16#02) ->
{ok, b_zip2};
<<B1@3, B2@3, B3@3, B4>> when (((B1@3 =:= 16#06) andalso (B2@3 =:= 16#F1)) andalso (B3@3 =:= 16#07)) andalso (B4 =:= 16#01) ->
{ok, aes256_sha256};
<<B1@4, B2@4, B3@4, B4@1>> when (((B1@4 =:= 16#03) andalso (B2@4 =:= 16#03)) andalso (B3@4 =:= 16#01)) andalso (B4@1 =:= 16#1B) ->
{ok, bcj2};
<<B1@5, B2@5, B3@5, B4@2>> when (B1@5 =:= 16#03) andalso (B2@5 =:= 16#03) ->
case {B3@5, B4@2} of
{V3, V4} when (V3 =:= 16#01) andalso (V4 =:= 16#03) ->
{ok, bcj_x86};
{V3@1, V4@1} when (V3@1 =:= 16#02) andalso (V4@1 =:= 16#05) ->
{ok, bcj_ppc};
{V3@2, V4@2} when (V3@2 =:= 16#04) andalso (V4@2 =:= 16#01) ->
{ok, bcj_ia64};
{V3@3, V4@3} when (V3@3 =:= 16#05) andalso (V4@3 =:= 16#01) ->
{ok, bcj_arm};
{V3@4, V4@4} when (V3@4 =:= 16#07) andalso (V4@4 =:= 16#01) ->
{ok, bcj_arm_t};
{V3@5, V4@5} when (V3@5 =:= 16#08) andalso (V4@5 =:= 16#05) ->
{ok, bcj_sparc};
{_, _} ->
{error,
{archive_not_implemented,
<<"7z coder id "/utf8,
(describe_bit_array_hex(Id_bytes, <<""/utf8>>))/binary>>}}
end;
_ ->
{error,
{archive_not_implemented,
<<"7z coder id "/utf8,
(describe_bit_array_hex(Id_bytes, <<""/utf8>>))/binary>>}}
end.
-file("src/packkit/seven_z.gleam", 2094).
-spec parse_one_coder(bitstring()) -> {ok, {coder_spec(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_one_coder(Bytes) ->
case Bytes of
<<Flags, After_flags/binary>> ->
Id_size = erlang:'band'(Flags, 16#0F),
Is_complex = erlang:'band'(Flags, 16#10) /= 0,
Has_attrs = erlang:'band'(Flags, 16#20) /= 0,
gleam@result:'try'(
slice_required(After_flags, 0, Id_size, <<"7z coder id"/utf8>>),
fun(Coder_id_bytes) ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:bit_array_slice(
After_flags,
Id_size,
erlang:byte_size(After_flags) - Id_size
),
gleam@result:replace_error(
_pipe,
{archive_invalid,
<<"7z coder id slice failed"/utf8>>}
)
end,
fun(After_coder_id) ->
gleam@result:'try'(
classify_coder_id(Coder_id_bytes),
fun(Coder_id) ->
gleam@result:'try'(case Is_complex of
false ->
{ok, {1, 1, After_coder_id}};
true ->
gleam@result:'try'(
read_number(After_coder_id),
fun(_use0) ->
{Num_in_streams, Rest_a} = _use0,
gleam@result:'try'(
read_number(Rest_a),
fun(_use0@1) ->
{Num_out_streams,
Rest_b} = _use0@1,
{ok,
{Num_in_streams,
Num_out_streams,
Rest_b}}
end
)
end
)
end, fun(_use0@2) ->
{Num_in, Num_out, After_streams} = _use0@2,
case Has_attrs of
false ->
{ok,
{{coder_spec,
Coder_id,
<<>>,
Num_in,
Num_out},
After_streams}};
true ->
gleam@result:'try'(
read_number(
After_streams
),
fun(_use0@3) ->
{Attrs_size,
After_attrs_size} = _use0@3,
gleam@result:'try'(
slice_required(
After_attrs_size,
0,
Attrs_size,
<<"7z coder attributes"/utf8>>
),
fun(Attrs) ->
gleam@result:'try'(
begin
_pipe@1 = gleam_stdlib:bit_array_slice(
After_attrs_size,
Attrs_size,
erlang:byte_size(
After_attrs_size
)
- Attrs_size
),
gleam@result:replace_error(
_pipe@1,
{archive_invalid,
<<"7z coder attrs slice failed"/utf8>>}
)
end,
fun(
After_attrs
) ->
{ok,
{{coder_spec,
Coder_id,
Attrs,
Num_in,
Num_out},
After_attrs}}
end
)
end
)
end
)
end
end)
end
)
end
)
end
);
_ ->
{error, {archive_invalid, <<"truncated 7z coder definition"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2080).
-spec parse_coders_loop(bitstring(), integer(), list(coder_spec())) -> {ok,
{list(coder_spec()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_coders_loop(Bytes, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Bytes}};
_ ->
gleam@result:'try'(
parse_one_coder(Bytes),
fun(_use0) ->
{Coder, Rest} = _use0,
parse_coders_loop(Rest, Remaining - 1, [Coder | Acc])
end
)
end.
-file("src/packkit/seven_z.gleam", 1954).
-spec parse_one_folder(bitstring()) -> {ok, {parsed_folder(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_one_folder(Bytes) ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Num_coders, Rest} = _use0,
gleam@bool:guard(
Num_coders < 1,
{error,
{archive_invalid, <<"7z folder declares zero coders"/utf8>>}},
fun() ->
gleam@bool:guard(
Num_coders > 3,
{error,
{archive_not_implemented,
<<<<"7z folders with "/utf8,
(erlang:integer_to_binary(Num_coders))/binary>>/binary,
" coders"/utf8>>}},
fun() ->
gleam@result:'try'(
parse_coders_loop(Rest, Num_coders, []),
fun(_use0@1) ->
{Coders, Rest@1} = _use0@1,
Total_in = sum_coder_in_streams(Coders, 0),
Total_out = sum_coder_out_streams(Coders, 0),
Num_bind_pairs = Total_out - 1,
Num_packed_streams = Total_in - Num_bind_pairs,
case {Num_coders, Total_in =:= Total_out} of
{1, _} ->
{ok,
{{parsed_folder, Coders, []},
Rest@1}};
{_, true} ->
gleam@result:'try'(
consume_linear_bind_pairs(
Rest@1,
1,
Num_bind_pairs
),
fun(_use0@2) ->
{After_bind_pairs, _} = _use0@2,
{ok,
{{parsed_folder,
Coders,
[]},
After_bind_pairs}}
end
);
{_, false} ->
gleam@result:'try'(
read_bind_pairs(
Rest@1,
Num_bind_pairs,
[]
),
fun(_use0@3) ->
{_, After_bind_pairs@1} = _use0@3,
gleam@result:'try'(
case Num_packed_streams
> 1 of
true ->
read_varint_list(
After_bind_pairs@1,
Num_packed_streams,
[]
);
false ->
{ok,
{[],
After_bind_pairs@1}}
end,
fun(_use0@4) ->
{Packed_indices,
After_packed} = _use0@4,
{ok,
{{parsed_folder,
Coders,
Packed_indices},
After_packed}}
end
)
end
)
end
end
)
end
)
end
)
end
).
-file("src/packkit/seven_z.gleam", 1906).
-spec parse_folders_loop(bitstring(), integer(), list(parsed_folder())) -> {ok,
{list(parsed_folder()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_folders_loop(Bytes, Remaining, Acc) ->
case Remaining of
0 ->
{ok, {lists:reverse(Acc), Bytes}};
_ ->
gleam@result:'try'(
parse_one_folder(Bytes),
fun(_use0) ->
{Folder, Rest} = _use0,
parse_folders_loop(Rest, Remaining - 1, [Folder | Acc])
end
)
end.
-file("src/packkit/seven_z.gleam", 1763).
-spec parse_folders(bitstring(), list(bitstring())) -> {ok,
{list(parsed_folder()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_folders(Bytes, Additional_streams) ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Num_folders, Rest} = _use0,
gleam@bool:guard(
Num_folders < 1,
{error,
{archive_invalid,
<<"7z UnPackInfo declares zero folders"/utf8>>}},
fun() -> case Rest of
<<External, After_external/binary>> ->
case External of
0 ->
parse_folders_loop(
After_external,
Num_folders,
[]
);
_ ->
gleam@result:'try'(
read_number(After_external),
fun(_use0@1) ->
{Data_index, After_data_index} = _use0@1,
gleam@result:'try'(
get_additional_stream(
Additional_streams,
Data_index
),
fun(External_bytes) ->
gleam@result:'try'(
parse_folders_loop(
External_bytes,
Num_folders,
[]
),
fun(_use0@2) ->
{Parsed_folders, _} = _use0@2,
{ok,
{Parsed_folders,
After_data_index}}
end
)
end
)
end
)
end;
_ ->
{error,
{archive_invalid,
<<"truncated 7z folder section"/utf8>>}}
end end
)
end
).
-file("src/packkit/seven_z.gleam", 3574).
-spec aes_cbc_encrypt(
bitstring(),
packkit@internal@aes:expanded_key(),
bitstring()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
aes_cbc_encrypt(Plaintext, Key, Iv) ->
Plaintext_size = erlang:byte_size(Plaintext),
Remainder = erlang:'band'(Plaintext_size, 16 - 1),
Padding_bytes = case Remainder of
0 ->
0;
Used ->
16 - Used
end,
Padding = case Padding_bytes of
0 ->
<<>>;
_ ->
<<0:(lists:max([((Padding_bytes * 8)), 0]))>>
end,
Padded = <<Plaintext/bitstring, Padding/bitstring>>,
aes_cbc_encrypt_loop(Padded, Key, iv_or_zero(Iv), <<>>).
-file("src/packkit/seven_z.gleam", 3625).
-spec aes_cbc_decrypt(
bitstring(),
packkit@internal@aes:expanded_key(),
bitstring()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
aes_cbc_decrypt(Ciphertext, Key, Iv) ->
Size = erlang:byte_size(Ciphertext),
case erlang:'band'(Size, 16 - 1) of
0 ->
aes_cbc_decrypt_loop(Ciphertext, Key, iv_or_zero(Iv), <<>>);
_ ->
{error,
{archive_invalid,
<<<<"7z AES ciphertext length "/utf8,
(erlang:integer_to_binary(Size))/binary>>/binary,
" is not a multiple of 16"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 807).
-spec build_aes_props_tail(bitstring(), bitstring(), integer(), integer()) -> bitstring().
build_aes_props_tail(Salt, Iv, Salt_extra, Iv_extra) ->
Second_byte = erlang:'bor'(erlang:'bsl'(Salt_extra, 4), Iv_extra),
<<Second_byte, Salt/bitstring, Iv/bitstring>>.
-file("src/packkit/seven_z.gleam", 821).
-spec build_aes_coder_def(encryption_spec()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
build_aes_coder_def(Spec) ->
Salt_size = erlang:byte_size(erlang:element(3, Spec)),
Iv_size = erlang:byte_size(erlang:element(4, Spec)),
gleam@bool:guard(
(Salt_size > 16) orelse (Iv_size > 16),
{error,
{archive_invalid,
<<"7z AES encoder: salt or iv exceeds 16 bytes"/utf8>>}},
fun() ->
gleam@bool:guard(
(erlang:element(5, Spec) < 0) orelse (erlang:element(5, Spec) >= 16#3F),
{error,
{archive_invalid,
<<"7z AES encoder: numCyclesPower must be in 0..62 (0x3F is reserved)"/utf8>>}},
fun() ->
Salt_flag = Salt_size > 0,
Iv_flag = Iv_size > 0,
First_byte = erlang:'bor'(
erlang:element(5, Spec),
erlang:'bor'(
16#80 * flag_to_int(Salt_flag),
16#40 * flag_to_int(Iv_flag)
)
),
Props_after_first = case Salt_flag orelse Iv_flag of
false ->
<<>>;
true ->
build_aes_props_tail(
erlang:element(3, Spec),
erlang:element(4, Spec),
Salt_size - flag_to_int(Salt_flag),
Iv_size - flag_to_int(Iv_flag)
)
end,
Props = <<First_byte, Props_after_first/bitstring>>,
Props_size = erlang:byte_size(Props),
{ok,
gleam_stdlib:bit_array_concat(
[<<16#24>>,
<<16#06, 16#F1, 16#07, 16#01>>,
write_varint(Props_size),
Props]
)}
end
)
end
).
-file("src/packkit/seven_z.gleam", 3414).
-spec parse_aes_field_sizes(bitstring(), integer(), boolean(), boolean()) -> {ok,
aes_properties()} |
{error, packkit@error:archive_error()}.
parse_aes_field_sizes(After_first_byte, Num_cycles_power, Salt_flag, Iv_flag) ->
case After_first_byte of
<<Second_byte, After_second/binary>> ->
Salt_base = flag_to_int(Salt_flag),
Iv_base = flag_to_int(Iv_flag),
Salt_size = Salt_base + erlang:'bsr'(Second_byte, 4),
Iv_size = Iv_base + erlang:'band'(Second_byte, 16#0F),
gleam@bool:guard(
(Salt_size > 16) orelse (Iv_size > 16),
{error,
{archive_invalid,
<<"7z AES salt or iv size exceeds 16 bytes"/utf8>>}},
fun() ->
gleam@result:'try'(
begin
_pipe = gleam_stdlib:bit_array_slice(
After_second,
0,
Salt_size
),
gleam@result:replace_error(
_pipe,
{archive_invalid,
<<"7z AES salt slice failed"/utf8>>}
)
end,
fun(Salt) ->
gleam@result:'try'(
begin
_pipe@1 = gleam_stdlib:bit_array_slice(
After_second,
Salt_size,
Iv_size
),
gleam@result:replace_error(
_pipe@1,
{archive_invalid,
<<"7z AES iv slice failed"/utf8>>}
)
end,
fun(Iv) ->
{ok,
{aes_properties,
Num_cycles_power,
Salt,
Iv}}
end
)
end
)
end
);
_ ->
{error,
{archive_invalid,
<<"7z AES coder properties truncated before salt/iv sizes"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3393).
-spec parse_aes_properties(bitstring()) -> {ok, aes_properties()} |
{error, packkit@error:archive_error()}.
parse_aes_properties(Properties) ->
case Properties of
<<First_byte, Rest/binary>> ->
Num_cycles_power = erlang:'band'(First_byte, 16#3F),
Iv_flag = erlang:'band'(First_byte, 16#40) /= 0,
Salt_flag = erlang:'band'(First_byte, 16#80) /= 0,
gleam@bool:guard(
not Salt_flag andalso not Iv_flag,
{ok, {aes_properties, Num_cycles_power, <<>>, <<>>}},
fun() ->
parse_aes_field_sizes(
Rest,
Num_cycles_power,
Salt_flag,
Iv_flag
)
end
);
_ ->
{error,
{archive_invalid,
<<"7z AES coder properties are empty or non-byte-aligned"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 381).
-spec default_encryption_spec(binary()) -> encryption_spec().
default_encryption_spec(Password) ->
{encryption_spec, Password, <<>>, <<0:128>>, 19}.
-file("src/packkit/seven_z.gleam", 3495).
-spec derive_aes_key_direct(bitstring(), bitstring()) -> bitstring().
derive_aes_key_direct(Salt, Password_utf16le) ->
Combined = <<Salt/bitstring,
Password_utf16le/bitstring,
0:(lists:max([((32 * 8)), 0]))>>,
_pipe = gleam_stdlib:bit_array_slice(Combined, 0, 32),
gleam@result:unwrap(_pipe, <<0:(lists:max([((32 * 8)), 0]))>>).
-file("src/packkit/seven_z.gleam", 3465).
-spec derive_aes_key(binary(), bitstring(), integer()) -> {ok,
packkit@internal@aes:expanded_key()} |
{error, packkit@error:archive_error()}.
derive_aes_key(Password, Salt, Num_cycles_power) ->
Password_utf16le = utf16le_encode(Password, <<>>),
Digest = case Num_cycles_power =:= 16#3F of
true ->
derive_aes_key_direct(Salt, Password_utf16le);
false ->
derive_aes_key_hashed(Salt, Password_utf16le, Num_cycles_power)
end,
case packkit@internal@aes:expand_key(Digest) of
{ok, Expanded} ->
{ok, Expanded};
{error, nil} ->
{error,
{archive_invalid,
<<"7z AES key expansion rejected the derived 32-byte digest"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 744).
-spec maybe_wrap_with_aes(
bitstring(),
bitstring(),
integer(),
integer(),
gleam@option:option(encryption_spec())
) -> {ok, {bitstring(), folder_encoding()}} |
{error, packkit@error:archive_error()}.
maybe_wrap_with_aes(
Inner_packed,
Inner_coder_def,
Inner_packed_size,
Total_unpack,
Encryption
) ->
case Encryption of
none ->
{ok,
{Inner_packed,
{folder_encoding,
gleam_stdlib:bit_array_concat(
[write_varint(1), Inner_coder_def]
),
write_varint(Total_unpack)}}};
{some, Spec} ->
gleam@result:'try'(
derive_aes_key(
erlang:element(2, Spec),
erlang:element(3, Spec),
erlang:element(5, Spec)
),
fun(Key) ->
gleam@result:'try'(
aes_cbc_encrypt(
Inner_packed,
Key,
erlang:element(4, Spec)
),
fun(Ciphertext) ->
gleam@result:'try'(
build_aes_coder_def(Spec),
fun(Aes_coder_def) ->
Folder_coders_block = gleam_stdlib:bit_array_concat(
[write_varint(2),
Aes_coder_def,
Inner_coder_def,
write_varint(1),
write_varint(0)]
),
Coders_unpack_sizes_block = gleam_stdlib:bit_array_concat(
[write_varint(Inner_packed_size),
write_varint(Total_unpack)]
),
{ok,
{Ciphertext,
{folder_encoding,
Folder_coders_block,
Coders_unpack_sizes_block}}}
end
)
end
)
end
)
end.
-file("src/packkit/seven_z.gleam", 3351).
-spec decode_aes_coder(
bitstring(),
bitstring(),
list(integer()),
gleam@option:option(binary())
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_aes_coder(Packed, Properties, Unpack_sizes, Password) ->
gleam@result:'try'(case Password of
{some, Value} ->
{ok, Value};
none ->
{error,
{archive_invalid,
<<"7z AES folder requires a password — call decode_with_password"/utf8>>}}
end, fun(Password_value) ->
gleam@result:'try'(
parse_aes_properties(Properties),
fun(Props) ->
gleam@result:'try'(
derive_aes_key(
Password_value,
erlang:element(3, Props),
erlang:element(2, Props)
),
fun(Key) ->
gleam@result:'try'(
aes_cbc_decrypt(
Packed,
Key,
erlang:element(4, Props)
),
fun(Plaintext) ->
Target = folder_unpack_total(Unpack_sizes),
Plaintext_size = erlang:byte_size(Plaintext),
gleam@bool:guard(
Plaintext_size < Target,
{error,
{archive_invalid,
<<<<<<"7z AES decrypted "/utf8,
(erlang:integer_to_binary(
Plaintext_size
))/binary>>/binary,
" bytes < declared "/utf8>>/binary,
(erlang:integer_to_binary(
Target
))/binary>>}},
fun() ->
_pipe = gleam_stdlib:bit_array_slice(
Plaintext,
0,
Target
),
gleam@result:replace_error(
_pipe,
{archive_invalid,
<<"7z AES decrypted slice failed"/utf8>>}
)
end
)
end
)
end
)
end
)
end).
-file("src/packkit/seven_z.gleam", 3204).
-spec dispatch_coder(
bitstring(),
coder_spec(),
list(integer()),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
dispatch_coder(Packed, Spec, Unpack_sizes, Password, Limits) ->
case erlang:element(2, Spec) of
lzma2 ->
decode_lzma2_payload(Packed, erlang:element(3, Spec), Unpack_sizes);
lzma ->
decode_raw_lzma(Packed, erlang:element(3, Spec), Unpack_sizes);
copy ->
decode_copy_coder(Packed, Unpack_sizes);
deflate ->
decode_deflate_coder(Packed, Unpack_sizes, Limits);
b_zip2 ->
decode_bzip2_coder(Packed, Unpack_sizes, Limits);
delta ->
decode_delta_coder(Packed, erlang:element(3, Spec), Unpack_sizes);
bcj_x86 ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:x86_decode/2,
<<"x86"/utf8>>
);
bcj_ppc ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:powerpc_decode/2,
<<"PowerPC"/utf8>>
);
bcj_ia64 ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:ia64_decode/2,
<<"IA-64"/utf8>>
);
bcj_arm ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:arm_decode/2,
<<"ARM"/utf8>>
);
bcj_arm_t ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:armthumb_decode/2,
<<"ARM-Thumb"/utf8>>
);
bcj_sparc ->
decode_bcj_coder(
Packed,
Unpack_sizes,
fun packkit@internal@bcj:sparc_decode/2,
<<"SPARC"/utf8>>
);
aes256_sha256 ->
decode_aes_coder(
Packed,
erlang:element(3, Spec),
Unpack_sizes,
Password
);
bcj2 ->
{error,
{archive_not_implemented,
<<"7z BCJ2 outside its canonical [simple, BCJ2(4,1)] folder layout"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3076).
-spec decode_bcj2_folder(
bitstring(),
bitstring(),
bitstring(),
bitstring(),
coder_spec(),
list(integer()),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_bcj2_folder(
Main_packed,
Call_packed,
Jump_packed,
Rc_packed,
Inner_spec,
Unpack_sizes,
Password,
Limits
) ->
{Inner_unpack_size, Bcj2_output_size} = case Unpack_sizes of
[First, Second | _] ->
{First, Second};
[Only] ->
{Only, Only};
[] ->
{0, 0}
end,
gleam@result:'try'(
dispatch_coder(
Main_packed,
Inner_spec,
[Inner_unpack_size],
Password,
Limits
),
fun(Main_stream) ->
_pipe = packkit@internal@bcj2:decode(
Main_stream,
Call_packed,
Jump_packed,
Rc_packed,
Bcj2_output_size
),
gleam@result:map_error(_pipe, fun bcj2_error_to_archive/1)
end
).
-file("src/packkit/seven_z.gleam", 3131).
-spec decode_linear_chain(
bitstring(),
list(coder_spec()),
list(integer()),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_linear_chain(Packed, Coders, Unpack_sizes, Password, Limits) ->
case {Coders, Unpack_sizes} of
{[], _} ->
{error,
{archive_invalid,
<<"7z folder has unsupported coder count"/utf8>>}};
{[Single], _} ->
dispatch_coder(Packed, Single, Unpack_sizes, Password, Limits);
{[Head | Rest_coders], [Head_size | Rest_sizes]} ->
gleam@result:'try'(
dispatch_coder(Packed, Head, [Head_size], Password, Limits),
fun(Intermediate) ->
_pipe = decode_linear_chain(
Intermediate,
Rest_coders,
Rest_sizes,
Password,
Limits
),
gleam@result:map_error(
_pipe,
fun(_capture) ->
maybe_wrap_aes_chain_error(
_capture,
erlang:element(2, Head)
)
end
)
end
);
{_, _} ->
{error,
{archive_invalid,
<<"7z folder coder list longer than CodersUnPackSize block"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 3027).
-spec decode_folder(
list(bitstring()),
parsed_folder(),
list(integer()),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_folder(Packed_streams, Folder, Unpack_sizes, Password, Limits) ->
case {Packed_streams, erlang:element(2, Folder)} of
{[Single_packed], _} ->
decode_linear_chain(
Single_packed,
erlang:element(2, Folder),
Unpack_sizes,
Password,
Limits
);
{[Main_packed, Call_packed, Jump_packed, Rc_packed],
[Inner_spec, Bcj2_spec]} when (erlang:element(2, Bcj2_spec) =:= bcj2) andalso (erlang:element(
4,
Bcj2_spec
) =:= 4) ->
decode_bcj2_folder(
Main_packed,
Call_packed,
Jump_packed,
Rc_packed,
Inner_spec,
Unpack_sizes,
Password,
Limits
);
{_, _} ->
{error,
{archive_not_implemented,
<<<<<<<<"7z folder topology with "/utf8,
(erlang:integer_to_binary(
erlang:length(Packed_streams)
))/binary>>/binary,
" packed streams and "/utf8>>/binary,
(erlang:integer_to_binary(
erlang:length(erlang:element(2, Folder))
))/binary>>/binary,
" coders"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1845).
-spec decode_additional_streams_loop(
bitstring(),
list(parsed_folder()),
list(list(integer())),
list(integer()),
packkit@limit:limits(),
integer(),
list(bitstring())
) -> {ok, list(bitstring())} | {error, packkit@error:archive_error()}.
decode_additional_streams_loop(
Packed,
Folders,
Folder_unpack_sizes,
Pack_sizes,
Limits,
Pack_cursor,
Acc
) ->
case {Folders, Folder_unpack_sizes} of
{[], []} ->
{ok, lists:reverse(Acc)};
{[Folder | Rest_folders], [Unpack_sizes | Rest_unpack]} ->
Stream_count = folder_packed_stream_count(Folder),
Folder_pack_sizes = gleam@list:take(Pack_sizes, Stream_count),
Rest_pack_sizes = gleam@list:drop(Pack_sizes, Stream_count),
gleam@result:'try'(
slice_folder_streams(Packed, Pack_cursor, Folder_pack_sizes, []),
fun(Folder_streams) ->
gleam@result:'try'(
decode_folder(
Folder_streams,
Folder,
Unpack_sizes,
none,
Limits
),
fun(Folder_plain) ->
Next_cursor = Pack_cursor + sum_list(
Folder_pack_sizes,
0
),
decode_additional_streams_loop(
Packed,
Rest_folders,
Rest_unpack,
Rest_pack_sizes,
Limits,
Next_cursor,
[Folder_plain | Acc]
)
end
)
end
);
{_, _} ->
{error,
{archive_invalid,
<<"7z AdditionalStreamsInfo folder/unpack-size lists misaligned"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1813).
-spec decode_additional_streams(
header_streams(),
bitstring(),
packkit@limit:limits()
) -> {ok, list(bitstring())} | {error, packkit@error:archive_error()}.
decode_additional_streams(Streams_info, Full_archive, Limits) ->
case Streams_info of
header_streams_none ->
{error,
{archive_invalid,
<<"7z AdditionalStreamsInfo has no StreamsInfo body"/utf8>>}};
{header_streams_parsed,
Pack_pos,
Pack_sizes,
Folders,
Folder_unpack_sizes,
_} ->
Pack_offset = 32 + Pack_pos,
Total_pack_size = sum_list(Pack_sizes, 0),
gleam@result:'try'(
slice_required(
Full_archive,
Pack_offset,
Total_pack_size,
<<"7z AdditionalStreamsInfo packed bytes"/utf8>>
),
fun(Packed) ->
decode_additional_streams_loop(
Packed,
Folders,
Folder_unpack_sizes,
Pack_sizes,
Limits,
0,
[]
)
end
)
end.
-file("src/packkit/seven_z.gleam", 2940).
-spec decode_all_folders(
bitstring(),
list(parsed_folder()),
list(list(integer())),
list(integer()),
gleam@option:option(binary()),
packkit@limit:limits(),
integer(),
list(bitstring())
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_all_folders(
Packed,
Folders,
Folder_unpack_sizes,
Pack_sizes,
Password,
Limits,
Pack_cursor,
Acc
) ->
case {Folders, Folder_unpack_sizes} of
{[], []} ->
{ok, gleam_stdlib:bit_array_concat(lists:reverse(Acc))};
{[Folder | Rest_folders], [Unpack_sizes | Rest_unpack]} ->
Stream_count = folder_packed_stream_count(Folder),
Folder_pack_sizes = gleam@list:take(Pack_sizes, Stream_count),
Rest_pack_sizes = gleam@list:drop(Pack_sizes, Stream_count),
gleam@result:'try'(
slice_folder_streams(Packed, Pack_cursor, Folder_pack_sizes, []),
fun(Folder_streams) ->
gleam@result:'try'(
decode_folder(
Folder_streams,
Folder,
Unpack_sizes,
Password,
Limits
),
fun(Folder_plain) ->
Next_cursor = Pack_cursor + sum_list(
Folder_pack_sizes,
0
),
decode_all_folders(
Packed,
Rest_folders,
Rest_unpack,
Rest_pack_sizes,
Password,
Limits,
Next_cursor,
[Folder_plain | Acc]
)
end
)
end
);
{_, _} ->
{error,
{archive_invalid,
<<"7z folder / unpack-size lists are misaligned"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 880).
-spec build_sub_streams_info(list(integer())) -> bitstring().
build_sub_streams_info(Unpack_sizes) ->
Explicit_sizes = drop_last(Unpack_sizes, []),
Size_block = gleam@list:fold(
Explicit_sizes,
<<>>,
fun(Acc, N) -> gleam_stdlib:bit_array_concat([Acc, write_varint(N)]) end
),
Num_files = erlang:length(Unpack_sizes),
gleam_stdlib:bit_array_concat(
[<<16#08>>,
<<16#0D>>,
write_varint(Num_files),
<<16#09>>,
Size_block,
<<16#00>>]
).
-file("src/packkit/seven_z.gleam", 1656).
-spec parse_pack_info_body(bitstring(), integer(), integer(), list(integer())) -> {ok,
{integer(), list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_pack_info_body(Bytes, Pack_pos, Num_pack_streams, Sizes) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
{ok, {Pack_pos, Sizes, Rest}};
N@1 when N@1 =:= 16#09 ->
gleam@result:'try'(
read_numbers(Rest, Num_pack_streams),
fun(_use0) ->
{Read_sizes, Rest@1} = _use0,
parse_pack_info_body(
Rest@1,
Pack_pos,
Num_pack_streams,
Read_sizes
)
end
);
N@2 when N@2 =:= 16#0A ->
gleam@result:'try'(
skip_crc_block(Rest, Num_pack_streams),
fun(Rest@2) ->
parse_pack_info_body(
Rest@2,
Pack_pos,
Num_pack_streams,
Sizes
)
end
);
_ ->
{error,
{archive_invalid,
<<"unexpected 7z PackInfo NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{error, {archive_invalid, <<"truncated 7z PackInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1648).
-spec parse_pack_info(bitstring()) -> {ok,
{integer(), list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_pack_info(Bytes) ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Pack_pos, Rest} = _use0,
gleam@result:'try'(
read_number(Rest),
fun(_use0@1) ->
{Num_pack_streams, Rest@1} = _use0@1,
parse_pack_info_body(Rest@1, Pack_pos, Num_pack_streams, [])
end
)
end
).
-file("src/packkit/seven_z.gleam", 2772).
-spec sub_streams_loop_collect(bitstring(), integer(), sub_streams_acc()) -> {ok,
{sub_streams_acc(), bitstring()}} |
{error, packkit@error:archive_error()}.
sub_streams_loop_collect(Bytes, Num_folders, Acc) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
{ok, {Acc, Rest}};
16#0D ->
gleam@result:'try'(
read_numbers(Rest, Num_folders),
fun(_use0) ->
{Counts, Rest@1} = _use0,
sub_streams_loop_collect(
Rest@1,
Num_folders,
{sub_streams_acc,
Counts,
erlang:element(3, Acc)}
)
end
);
N@1 when N@1 =:= 16#09 ->
Per_folder = case erlang:element(2, Acc) of
[] ->
repeat_one_per_folder(Num_folders, []);
Values ->
Values
end,
Explicit_count = sum_list(Per_folder, 0) - erlang:length(
Per_folder
),
Safe_count = case Explicit_count > 0 of
true ->
Explicit_count;
false ->
0
end,
gleam@result:'try'(
read_numbers(Rest, Safe_count),
fun(_use0@1) ->
{Sizes, Rest@2} = _use0@1,
sub_streams_loop_collect(
Rest@2,
Num_folders,
{sub_streams_acc, erlang:element(2, Acc), Sizes}
)
end
);
N@2 when N@2 =:= 16#0A ->
Total = case erlang:element(2, Acc) of
[] ->
Num_folders;
Values@1 ->
sum_list(Values@1, 0)
end,
gleam@result:'try'(
skip_crc_block(Rest, Total),
fun(Rest@3) ->
sub_streams_loop_collect(Rest@3, Num_folders, Acc)
end
);
_ ->
{error,
{archive_invalid,
<<"unexpected 7z SubStreamsInfo NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{error, {archive_invalid, <<"truncated 7z SubStreamsInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2736).
-spec parse_sub_streams_info(bitstring(), integer(), list(integer())) -> {ok,
{list(integer()), list(integer()), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_sub_streams_info(Bytes, Num_folders, Folder_unpack_sizes) ->
Initial = {sub_streams_acc, [], []},
gleam@result:'try'(
sub_streams_loop_collect(Bytes, Num_folders, Initial),
fun(_use0) ->
{Acc, Rest} = _use0,
Per_folder = case erlang:element(2, Acc) of
[] ->
repeat_one_per_folder(Num_folders, []);
Values ->
Values
end,
Total_substreams = sum_list(Per_folder, 0),
Sizes = derive_substream_sizes(
Per_folder,
Folder_unpack_sizes,
erlang:element(3, Acc),
[]
),
case erlang:length(Sizes) =:= Total_substreams of
true ->
{ok, {Per_folder, Sizes, Rest}};
false ->
{error,
{archive_invalid,
<<"7z SubStreamsInfo: derived substream count mismatch"/utf8>>}}
end
end
).
-file("src/packkit/seven_z.gleam", 1698).
-spec parse_unpack_info_body(
bitstring(),
list(parsed_folder()),
list(list(integer())),
list(bitstring())
) -> {ok, {list(parsed_folder()), list(list(integer())), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_unpack_info_body(Bytes, Folders, Folder_unpack_sizes, Additional_streams) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
case Folders of
[] ->
{error,
{archive_invalid,
<<"7z UnPackInfo missing Folder section"/utf8>>}};
_ ->
{ok, {Folders, Folder_unpack_sizes, Rest}}
end;
N@1 when N@1 =:= 16#0B ->
gleam@result:'try'(
parse_folders(Rest, Additional_streams),
fun(_use0) ->
{Parsed_folders, Rest@1} = _use0,
parse_unpack_info_body(
Rest@1,
Parsed_folders,
Folder_unpack_sizes,
Additional_streams
)
end
);
N@2 when N@2 =:= 16#0C ->
Total_size_count = gleam@list:fold(
Folders,
0,
fun(Acc, F) ->
Acc + erlang:length(erlang:element(2, F))
end
),
gleam@result:'try'(
read_numbers(Rest, Total_size_count),
fun(_use0@1) ->
{Flat_sizes, Rest@2} = _use0@1,
Grouped = split_unpack_sizes_by_folder(
Flat_sizes,
Folders,
[]
),
parse_unpack_info_body(
Rest@2,
Folders,
Grouped,
Additional_streams
)
end
);
N@3 when N@3 =:= 16#0A ->
gleam@result:'try'(
skip_crc_block(Rest, erlang:length(Folders)),
fun(Rest@3) ->
parse_unpack_info_body(
Rest@3,
Folders,
Folder_unpack_sizes,
Additional_streams
)
end
);
_ ->
{error,
{archive_invalid,
<<"unexpected 7z UnPackInfo NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{error, {archive_invalid, <<"truncated 7z UnPackInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1688).
-spec parse_unpack_info(bitstring(), list(bitstring())) -> {ok,
{list(parsed_folder()), list(list(integer())), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_unpack_info(Bytes, Additional_streams) ->
parse_unpack_info_body(Bytes, [], [], Additional_streams).
-file("src/packkit/seven_z.gleam", 1561).
-spec parse_streams_loop(bitstring(), streams_parser(), list(bitstring())) -> {ok,
{header_streams(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_streams_loop(Bytes, State, Additional_streams) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
case erlang:element(4, State) of
[] ->
{error,
{archive_invalid,
<<"7z MainStreamsInfo missing UnPackInfo"/utf8>>}};
_ ->
{ok,
{{header_streams_parsed,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State)},
Rest}}
end;
N@1 when N@1 =:= 16#06 ->
gleam@result:'try'(
parse_pack_info(Rest),
fun(_use0) ->
{Pack_pos, Pack_sizes, Rest@1} = _use0,
parse_streams_loop(
Rest@1,
{streams_parser,
Pack_pos,
Pack_sizes,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
true,
erlang:element(8, State)},
Additional_streams
)
end
);
N@2 when N@2 =:= 16#07 ->
gleam@result:'try'(
parse_unpack_info(Rest, Additional_streams),
fun(_use0@1) ->
{Folders, Folder_unpack_sizes, Rest@2} = _use0@1,
parse_streams_loop(
Rest@2,
{streams_parser,
erlang:element(2, State),
erlang:element(3, State),
Folders,
Folder_unpack_sizes,
erlang:element(6, State),
erlang:element(7, State),
true},
Additional_streams
)
end
);
N@3 when N@3 =:= 16#08 ->
Folder_totals = gleam@list:map(
erlang:element(5, State),
fun last_of_list/1
),
gleam@result:'try'(
parse_sub_streams_info(
Rest,
erlang:length(erlang:element(4, State)),
Folder_totals
),
fun(_use0@2) ->
{_, Substream_sizes, Rest@3} = _use0@2,
parse_streams_loop(
Rest@3,
{streams_parser,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Substream_sizes,
erlang:element(7, State),
erlang:element(8, State)},
Additional_streams
)
end
);
_ ->
{error,
{archive_invalid,
<<"unexpected 7z MainStreamsInfo NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{error, {archive_invalid, <<"truncated 7z MainStreamsInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1532).
-spec parse_main_streams_info(bitstring(), list(bitstring())) -> {ok,
{header_streams(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_main_streams_info(Bytes, Additional_streams) ->
State = {streams_parser, 0, [], [], [], [], false, false},
parse_streams_loop(Bytes, State, Additional_streams).
-file("src/packkit/seven_z.gleam", 1175).
-spec decode_encoded_header(
bitstring(),
bitstring(),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
decode_encoded_header(Bytes_after_nid, Full_archive, Password, Limits) ->
gleam@result:'try'(
parse_main_streams_info(Bytes_after_nid, []),
fun(_use0) ->
{Streams, _} = _use0,
case Streams of
header_streams_none ->
{error,
{archive_invalid,
<<"7z encoded next header has no StreamsInfo"/utf8>>}};
{header_streams_parsed,
Pack_pos,
Pack_sizes,
Folders,
Folder_unpack_sizes,
_} ->
Pack_offset = 32 + Pack_pos,
Pack_size = sum_list(Pack_sizes, 0),
gleam@result:'try'(
slice_required(
Full_archive,
Pack_offset,
Pack_size,
<<"7z encoded-header packed bytes"/utf8>>
),
fun(Packed) ->
decode_all_folders(
Packed,
Folders,
Folder_unpack_sizes,
Pack_sizes,
Password,
Limits,
0,
[]
)
end
)
end
end
).
-file("src/packkit/seven_z.gleam", 603).
-spec build_encoded_next_header_for_aes(
integer(),
integer(),
bitstring(),
integer()
) -> bitstring().
build_encoded_next_header_for_aes(
Pack_pos,
Pack_size,
Aes_coder_def,
Plain_header_size
) ->
Pack_info = gleam_stdlib:bit_array_concat(
[<<16#06>>,
write_varint(Pack_pos),
write_varint(1),
<<16#09>>,
write_varint(Pack_size),
<<16#00>>]
),
Folder_def = gleam_stdlib:bit_array_concat(
[write_varint(1), <<16#00>>, write_varint(1), Aes_coder_def]
),
Unpack_info = gleam_stdlib:bit_array_concat(
[<<16#07>>,
<<16#0B>>,
Folder_def,
<<16#0C>>,
write_varint(Plain_header_size),
<<16#00>>]
),
gleam_stdlib:bit_array_concat(
[<<16#17>>, Pack_info, Unpack_info, <<16#00>>]
).
-file("src/packkit/seven_z.gleam", 566).
-spec maybe_encrypt_next_header(
bitstring(),
integer(),
gleam@option:option(encryption_spec())
) -> {ok, {bitstring(), bitstring()}} | {error, packkit@error:archive_error()}.
maybe_encrypt_next_header(
Plain_next_header,
Payload_pack_size,
Header_encryption
) ->
case Header_encryption of
none ->
{ok, {<<>>, Plain_next_header}};
{some, Spec} ->
gleam@result:'try'(
derive_aes_key(
erlang:element(2, Spec),
erlang:element(3, Spec),
erlang:element(5, Spec)
),
fun(Key) ->
gleam@result:'try'(
aes_cbc_encrypt(
Plain_next_header,
Key,
erlang:element(4, Spec)
),
fun(Encrypted_header) ->
Plain_size = erlang:byte_size(Plain_next_header),
Encrypted_size = erlang:byte_size(Encrypted_header),
gleam@result:'try'(
build_aes_coder_def(Spec),
fun(Aes_coder_def) ->
Encoded_next_header = build_encoded_next_header_for_aes(
Payload_pack_size,
Encrypted_size,
Aes_coder_def,
Plain_size
),
{ok,
{Encrypted_header, Encoded_next_header}}
end
)
end
)
end
)
end.
-file("src/packkit/seven_z.gleam", 2461).
-spec unix_to_filetime(integer()) -> integer().
unix_to_filetime(Unix_seconds) ->
(Unix_seconds + 11644473600) * 10000000.
-file("src/packkit/seven_z.gleam", 915).
-spec build_mtime_block(list(integer())) -> bitstring().
build_mtime_block(Mtimes_unix) ->
Defined_flags = gleam@list:map(Mtimes_unix, fun(M) -> M > 0 end),
All_defined = gleam@list:all(Defined_flags, fun(B) -> B end),
Num_files = erlang:length(Mtimes_unix),
Filetime_payload = gleam@list:fold(
Mtimes_unix,
<<>>,
fun(Acc, M@1) -> case M@1 > 0 of
true ->
Ft = unix_to_filetime(M@1),
gleam_stdlib:bit_array_concat([Acc, <<Ft:64/little>>]);
false ->
Acc
end end
),
Body = case All_defined of
true ->
gleam_stdlib:bit_array_concat([<<16#01, 16#00>>, Filetime_payload]);
false ->
Bitmap = pack_bool_bits(Defined_flags, Num_files),
gleam_stdlib:bit_array_concat(
[<<16#00, 16#00>>, Bitmap, Filetime_payload]
)
end,
gleam_stdlib:bit_array_concat(
[<<16#14>>, write_varint(erlang:byte_size(Body)), Body]
).
-file("src/packkit/seven_z.gleam", 416).
-spec encode_entries(
list(packkit@entry:entry()),
method(),
gleam@option:option(encryption_spec()),
gleam@option:option(encryption_spec())
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
encode_entries(Entries, Method, Encryption, Header_encryption) ->
gleam@result:'try'(
validate_entries_for_encode(Entries),
fun(_) ->
Bodies = gleam@list:map(Entries, fun packkit@entry:body/1),
Names = gleam@list:map(
Entries,
fun(E) -> packkit@entry:to_string(packkit@entry:path(E)) end
),
Unpack_sizes = gleam@list:map(Bodies, fun erlang:byte_size/1),
Total_unpack = sum_list(Unpack_sizes, 0),
Concatenated = gleam_stdlib:bit_array_concat(Bodies),
gleam@result:'try'(
encode_via_method(Concatenated, Method),
fun(_use0) ->
{Inner_packed, Inner_coder_def} = _use0,
Inner_packed_size = erlang:byte_size(Inner_packed),
gleam@result:'try'(
maybe_wrap_with_aes(
Inner_packed,
Inner_coder_def,
Inner_packed_size,
Total_unpack,
Encryption
),
fun(_use0@1) ->
{Packed, Folder_inner} = _use0@1,
Pack_size = erlang:byte_size(Packed),
Pack_info_body = gleam_stdlib:bit_array_concat(
[write_varint(0),
write_varint(1),
<<16#09>>,
write_varint(Pack_size),
<<16#00>>]
),
Pack_info = <<16#06, Pack_info_body/bitstring>>,
Folder_def = gleam_stdlib:bit_array_concat(
[write_varint(1),
<<16#00>>,
erlang:element(2, Folder_inner)]
),
Unpack_info_body = gleam_stdlib:bit_array_concat(
[<<16#0B>>,
Folder_def,
<<16#0C>>,
erlang:element(3, Folder_inner),
<<16#00>>]
),
Unpack_info = <<16#07, Unpack_info_body/bitstring>>,
Sub_streams_info = case Entries of
[_] ->
<<>>;
_ ->
build_sub_streams_info(Unpack_sizes)
end,
Main_streams = gleam_stdlib:bit_array_concat(
[<<16#04>>,
Pack_info,
Unpack_info,
Sub_streams_info,
<<16#00>>]
),
gleam@result:'try'(
encode_names_block(Names),
fun(Names_block) ->
Num_files = erlang:length(Entries),
Mtimes_unix = gleam@list:map(
Entries,
fun(E@1) ->
packkit@entry:modified_at_unix(
packkit@entry:metadata(E@1)
)
end
),
Any_mtime_set = gleam@list:any(
Mtimes_unix,
fun(M) -> M > 0 end
),
Mtime_block = case Any_mtime_set of
true ->
build_mtime_block(Mtimes_unix);
false ->
<<>>
end,
Files_info = gleam_stdlib:bit_array_concat(
[<<16#05>>,
write_varint(Num_files),
<<16#11>>,
write_varint(
erlang:byte_size(Names_block)
),
Names_block,
Mtime_block,
<<16#00>>]
),
Plain_next_header = gleam_stdlib:bit_array_concat(
[<<16#01>>,
Main_streams,
Files_info,
<<16#00>>]
),
gleam@result:'try'(
maybe_encrypt_next_header(
Plain_next_header,
Pack_size,
Header_encryption
),
fun(_use0@2) ->
{Post_pack_bytes, Final_next_header} = _use0@2,
Final_next_header_size = erlang:byte_size(
Final_next_header
),
Final_next_header_crc = packkit@checksum:crc32(
Final_next_header
),
Final_next_header_offset = Pack_size
+ erlang:byte_size(Post_pack_bytes),
Post_signature_20 = <<Final_next_header_offset:64/little,
Final_next_header_size:64/little,
Final_next_header_crc:32/little>>,
Start_crc = packkit@checksum:crc32(
Post_signature_20
),
Signature_header = gleam_stdlib:bit_array_concat(
[<<16#37,
16#7A,
16#BC,
16#AF,
16#27,
16#1C>>,
<<16#00, 16#04>>,
<<Start_crc:32/little>>,
Post_signature_20]
),
{ok,
gleam_stdlib:bit_array_concat(
[Signature_header,
Packed,
Post_pack_bytes,
Final_next_header]
)}
end
)
end
)
end
)
end
)
end
).
-file("src/packkit/seven_z.gleam", 399).
-spec do_encode(
packkit@archive:archive(),
method(),
gleam@option:option(encryption_spec()),
gleam@option:option(encryption_spec())
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
do_encode(Archive_value, Method, Encryption, Header_encryption) ->
Entries = packkit@archive:entries(Archive_value),
case Entries of
[] ->
{error,
{archive_entry_rejected,
<<"<archive>"/utf8>>,
<<"7z encoder requires at least one entry"/utf8>>}};
_ ->
encode_entries(Entries, Method, Encryption, Header_encryption)
end.
-file("src/packkit/seven_z.gleam", 292).
?DOC(
" Same as `encode/1` but lets the caller pick the coder. All four\n"
" methods produce a single-folder, single-coder archive — Copy is\n"
" just the raw bytes; Deflate / BZip2 / LZMA dispatch to the\n"
" corresponding packkit codec. Cross-method round-trips work\n"
" because the decoder accepts each of these coder ids.\n"
).
-spec encode_with_method(packkit@archive:archive(), method()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
encode_with_method(Archive_value, Method) ->
do_encode(Archive_value, Method, none, none).
-file("src/packkit/seven_z.gleam", 281).
?DOC(
" Encode a logical archive to a 7z byte stream.\n"
"\n"
" The encoder produces a single-folder, single-coder archive that\n"
" uses a raw LZMA1 coder for the packed stream. All file bodies are\n"
" concatenated into one logical substream which is then fed to\n"
" `packkit/internal/lzma.encode_literal_only`; if the archive holds\n"
" more than one entry, the per-substream sizes are emitted via\n"
" `SubStreamsInfo` so the standard decoder can split the decompressed\n"
" bytes back into individual entries.\n"
"\n"
" Restrictions: only `File` entries are accepted (no directories,\n"
" symlinks, or hardlinks — these would require the `EmptyStream` /\n"
" `Attribute` / `WinAttributes` blocks the reader does not yet\n"
" validate). Empty archives are rejected because the 7z format\n"
" requires `MainStreamsInfo` to be present once a `Header` block\n"
" exists.\n"
).
-spec encode(packkit@archive:archive()) -> {ok, bitstring()} |
{error, packkit@error:archive_error()}.
encode(Archive_value) ->
encode_with_method(Archive_value, lzma()).
-file("src/packkit/seven_z.gleam", 334).
?DOC(
" Same as `encode_with_password` but lets the caller pick the inner\n"
" coder (Copy / Deflate / BZip2 / LZMA). Salt + IV are still empty /\n"
" all-zero — see `encode_with_password` for the determinism caveat.\n"
).
-spec encode_with_password_and_method(
packkit@archive:archive(),
binary(),
method()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
encode_with_password_and_method(Archive_value, Password, Method) ->
do_encode(
Archive_value,
Method,
{some, default_encryption_spec(Password)},
none
).
-file("src/packkit/seven_z.gleam", 320).
?DOC(
" Encode a logical archive to a 7z byte stream with AES-256-CBC\n"
" payload encryption (coder id `06 F1 07 01`). Plumbed into the\n"
" folder as a 2-coder chain `[AES, <method>]` so the existing\n"
" `decode_with_password` path reads it back verbatim.\n"
"\n"
" The encoder uses **empty salt** and **a 16-byte all-zero IV** for\n"
" determinism — without an FFI into a platform CSPRNG there is no\n"
" good source of randomness in pure Gleam. This is fine for\n"
" archives that go to a trusted recipient over an authenticated\n"
" channel, but it is NOT a substitute for randomised encryption —\n"
" two archives encrypted with the same password produce identical\n"
" ciphertext blocks for identical plaintext prefixes, which leaks\n"
" information about the payload. If you need randomised\n"
" encryption, encrypt the payload yourself before passing it in or\n"
" pre-generate a 16-byte IV from a CSPRNG and feed it back through\n"
" a future BYO-IV API.\n"
"\n"
" The inner coder defaults to LZMA — matching what `7z a -p<pw>`\n"
" emits — and the key derivation runs the canonical 2^19 = 524288\n"
" SHA-256 iterations, which on the JS target is slow (multiple\n"
" seconds per archive).\n"
).
-spec encode_with_password(packkit@archive:archive(), binary()) -> {ok,
bitstring()} |
{error, packkit@error:archive_error()}.
encode_with_password(Archive_value, Password) ->
encode_with_password_and_method(Archive_value, Password, lzma()).
-file("src/packkit/seven_z.gleam", 372).
?DOC(
" Like `encode_with_password_and_header_encryption` but lets the\n"
" caller pick the inner coder for the *payload*. The header is\n"
" always wrapped in just AES (no inner method).\n"
).
-spec encode_with_password_and_header_encryption_and_method(
packkit@archive:archive(),
binary(),
method()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
encode_with_password_and_header_encryption_and_method(
Archive_value,
Password,
Method
) ->
Spec = default_encryption_spec(Password),
do_encode(Archive_value, Method, {some, Spec}, {some, Spec}).
-file("src/packkit/seven_z.gleam", 358).
?DOC(
" Encode an archive with both the payload AND the next-header bytes\n"
" AES-encrypted — the on-disk equivalent of `7z a -p<pw> -mhe=on`.\n"
" The signature header points at an \"encoded next header\" (NID 0x17)\n"
" whose StreamsInfo block tells the decoder where the AES-encrypted\n"
" next-header pack lives; the next header itself is plain bytes\n"
" AES-CBC-encrypted with the user's password (no inner compression\n"
" — the header is small enough that LZMA isn't worth the dispatch\n"
" cost).\n"
"\n"
" The same determinism caveat as `encode_with_password` applies: salt\n"
" is empty and IV is all zeros.\n"
).
-spec encode_with_password_and_header_encryption(
packkit@archive:archive(),
binary()
) -> {ok, bitstring()} | {error, packkit@error:archive_error()}.
encode_with_password_and_header_encryption(Archive_value, Password) ->
encode_with_password_and_header_encryption_and_method(
Archive_value,
Password,
lzma()
).
-file("src/packkit/seven_z.gleam", 2465).
-spec filetime_to_unix(integer()) -> integer().
filetime_to_unix(Filetime) ->
(case 10000000 of
0 -> 0;
Gleam@denominator -> Filetime div Gleam@denominator
end) - 11644473600.
-file("src/packkit/seven_z.gleam", 2528).
-spec read_mtime_filetimes(
bitstring(),
list(boolean()),
list(gleam@option:option(integer()))
) -> {ok, list(gleam@option:option(integer()))} |
{error, packkit@error:archive_error()}.
read_mtime_filetimes(Payload, Defined_flags, Acc) ->
case Defined_flags of
[] ->
{ok, lists:reverse(Acc)};
[false | Rest] ->
read_mtime_filetimes(Payload, Rest, [none | Acc]);
[true | Rest@1] ->
case Payload of
<<Filetime:64/little, Tail/binary>> ->
Unix_seconds = filetime_to_unix(Filetime),
Safe = case Unix_seconds < 0 of
true ->
0;
false ->
Unix_seconds
end,
read_mtime_filetimes(Tail, Rest@1, [{some, Safe} | Acc]);
_ ->
{error,
{archive_invalid,
<<"truncated 7z mtime FILETIME entry"/utf8>>}}
end
end.
-file("src/packkit/seven_z.gleam", 4106).
-spec consume_one_file_body(
bitstring(),
binary(),
list(binary()),
list(boolean()),
list(boolean()),
gleam@option:option(integer()),
list(gleam@option:option(integer())),
list(integer()),
integer(),
list(packkit@entry:entry()),
packkit@limit:limits()
) -> {ok, list(packkit@entry:entry())} | {error, packkit@error:archive_error()}.
consume_one_file_body(
Plain,
Name,
Rest_names,
Rest_empties,
Empty_files,
Entry_mtime,
Rest_mtimes,
Sizes,
Consumed,
Acc,
Limits
) ->
{This_size, Next_sizes} = case Sizes of
[S | Rest] ->
{S, Rest};
[] ->
{erlang:byte_size(Plain) - Consumed, []}
end,
Body@1 = case gleam_stdlib:bit_array_slice(Plain, Consumed, This_size) of
{ok, Body} -> Body;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"consume_one_file_body"/utf8>>,
line => 4126,
value => _assert_fail,
start => 133389,
'end' => 133454,
pattern_start => 133400,
pattern_end => 133408})
end,
_pipe = add_file(Name, Body@1, Entry_mtime, Acc, Limits),
gleam@result:'try'(
_pipe,
fun(New_acc) ->
build_entries_loop(
Plain,
Rest_names,
Rest_empties,
Empty_files,
Rest_mtimes,
Next_sizes,
Consumed + This_size,
New_acc,
Limits
)
end
).
-file("src/packkit/seven_z.gleam", 4024).
-spec build_entries_loop(
bitstring(),
list(binary()),
list(boolean()),
list(boolean()),
list(gleam@option:option(integer())),
list(integer()),
integer(),
list(packkit@entry:entry()),
packkit@limit:limits()
) -> {ok, list(packkit@entry:entry())} | {error, packkit@error:archive_error()}.
build_entries_loop(
Plain,
Names,
Empties,
Empty_files,
Mtimes,
Sizes,
Consumed,
Acc,
Limits
) ->
{Entry_mtime, Rest_mtimes} = case Mtimes of
[M | Rest] ->
{M, Rest};
[] ->
{none, []}
end,
case {Names, Empties} of
{[], _} ->
{ok, lists:reverse(Acc)};
{[Name | Rest_names], [Is_empty | Rest_empties]} ->
case Is_empty of
true ->
{Is_file, Rest_empty_files} = case Empty_files of
[Bit | Rest@1] ->
{Bit, Rest@1};
[] ->
{false, []}
end,
Adder = case Is_file of
true ->
add_file(Name, <<>>, Entry_mtime, Acc, Limits);
false ->
add_directory(Name, Entry_mtime, Acc, Limits)
end,
_pipe = Adder,
gleam@result:'try'(
_pipe,
fun(New_acc) ->
build_entries_loop(
Plain,
Rest_names,
Rest_empties,
Rest_empty_files,
Rest_mtimes,
Sizes,
Consumed,
New_acc,
Limits
)
end
);
false ->
consume_one_file_body(
Plain,
Name,
Rest_names,
Rest_empties,
Empty_files,
Entry_mtime,
Rest_mtimes,
Sizes,
Consumed,
Acc,
Limits
)
end;
{[Name@1 | Rest_names@1], []} ->
consume_one_file_body(
Plain,
Name@1,
Rest_names@1,
[],
Empty_files,
Entry_mtime,
Rest_mtimes,
Sizes,
Consumed,
Acc,
Limits
)
end.
-file("src/packkit/seven_z.gleam", 3973).
-spec build_archive_entries(
bitstring(),
parsed_header(),
packkit@limit:limits()
) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}.
build_archive_entries(Plain, Parsed, Limits) ->
Substream_sizes = case erlang:element(6, Parsed) of
[] ->
derive_substream_sizes_from_folders(erlang:element(5, Parsed));
Values ->
Values
end,
_pipe = build_entries_loop(
Plain,
erlang:element(7, Parsed),
erlang:element(8, Parsed),
erlang:element(9, Parsed),
erlang:element(10, Parsed),
Substream_sizes,
0,
[],
Limits
),
gleam@result:map(
_pipe,
fun(Entries) -> packkit@archive:from_entries(format(), Entries) end
).
-file("src/packkit/seven_z.gleam", 2884).
-spec decode_archive(
bitstring(),
parsed_header(),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}.
decode_archive(Packed, Parsed, Password, Limits) ->
gleam@result:'try'(
enforce_max_output(lists:append(erlang:element(5, Parsed)), Limits),
fun(_) ->
Declared_members = erlang:length(erlang:element(7, Parsed)),
gleam@bool:guard(
Declared_members > packkit@limit:max_members(Limits),
{error,
{archive_limit_exceeded,
<<"max_members"/utf8>>,
Declared_members}},
fun() ->
gleam@result:'try'(
decode_all_folders(
Packed,
erlang:element(4, Parsed),
erlang:element(5, Parsed),
erlang:element(3, Parsed),
Password,
Limits,
erlang:element(2, Parsed),
[]
),
fun(Plain) ->
build_archive_entries(Plain, Parsed, Limits)
end
)
end
)
end
).
-file("src/packkit/seven_z.gleam", 2675).
-spec take_bools(list(boolean()), bitstring(), integer(), list(boolean())) -> list(boolean()).
take_bools(Bits, Rest_bytes, Count, Acc) ->
case {Bits, Count} of
{_, 0} ->
lists:reverse(Acc);
{[], _} ->
bit_array_to_bool_list(Rest_bytes, Count, Acc);
{[Head | Tail], _} ->
take_bools(Tail, Rest_bytes, Count - 1, [Head | Acc])
end.
-file("src/packkit/seven_z.gleam", 2647).
-spec bit_array_to_bool_list(bitstring(), integer(), list(boolean())) -> list(boolean()).
bit_array_to_bool_list(Bytes, Count, Acc) ->
case Count of
0 ->
lists:reverse(Acc);
_ ->
case Bytes of
<<B, Rest/binary>> ->
Bits = unpack_bits(B, 8, []),
take_bools(Bits, Rest, Count, Acc);
_ ->
lists:reverse(Acc)
end
end.
-file("src/packkit/seven_z.gleam", 2514).
-spec read_mtime_defined_flags(bitstring(), integer()) -> {ok, list(boolean())} |
{error, packkit@error:archive_error()}.
read_mtime_defined_flags(Payload, Num_files) ->
Bitmap_size = (Num_files + 7) div 8,
gleam@result:'try'(
slice_required(
Payload,
0,
Bitmap_size,
<<"7z mtime defined bitmap"/utf8>>
),
fun(Bits) -> {ok, bit_array_to_bool_list(Bits, Num_files, [])} end
).
-file("src/packkit/seven_z.gleam", 2469).
-spec parse_mtime_block(bitstring(), integer(), list(bitstring())) -> {ok,
list(gleam@option:option(integer()))} |
{error, packkit@error:archive_error()}.
parse_mtime_block(Payload, Num_files, Additional_streams) ->
case Payload of
<<All_defined, External, After_header/binary>> ->
gleam@result:'try'(case External of
0 ->
{ok, After_header};
_ ->
gleam@result:'try'(
read_number(After_header),
fun(_use0) ->
{Data_index, _} = _use0,
get_additional_stream(
Additional_streams,
Data_index
)
end
)
end, fun(External_bytes) ->
gleam@result:'try'(case All_defined of
1 ->
{ok, gleam@list:repeat(true, Num_files)};
_ ->
read_mtime_defined_flags(
External_bytes,
Num_files
)
end, fun(Defined_flags) ->
Body_after_flags = case All_defined of
1 ->
External_bytes;
_ ->
Bitmap_size = (Num_files + 7) div 8,
Rest@1 = case gleam_stdlib:bit_array_slice(
External_bytes,
Bitmap_size,
erlang:byte_size(External_bytes) - Bitmap_size
) of
{ok, Rest} -> Rest;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_mtime_block"/utf8>>,
line => 2499,
value => _assert_fail,
start => 80739,
'end' => 80925,
pattern_start => 80750,
pattern_end => 80758}
)
end,
Rest@1
end,
read_mtime_filetimes(
Body_after_flags,
Defined_flags,
[]
)
end)
end);
_ ->
{error,
{archive_invalid, <<"truncated 7z mtime block header"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2246).
-spec parse_files_loop(
bitstring(),
integer(),
list(binary()),
list(boolean()),
list(boolean()),
list(gleam@option:option(integer())),
list(bitstring())
) -> {ok, {header_files(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_files_loop(
Bytes,
Num_files,
Names,
Empty_streams,
Empty_files,
Mtimes_unix,
Additional_streams
) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
{ok, {{header_files_parsed, case Names of
[] ->
dummy_names(Num_files);
Ns ->
Ns
end, case Empty_streams of
[] ->
gleam@list:repeat(false, Num_files);
Es ->
Es
end, Empty_files, Mtimes_unix}, Rest}};
N@1 when N@1 =:= 16#11 ->
gleam@result:'try'(
read_number(Rest),
fun(_use0) ->
{Size, After_size} = _use0,
gleam@result:'try'(
slice_required(
After_size,
0,
Size,
<<"7z file names payload"/utf8>>
),
fun(Payload) ->
After_payload@1 = case gleam_stdlib:bit_array_slice(
After_size,
Size,
erlang:byte_size(After_size) - Size
) of
{ok, After_payload} -> After_payload;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_files_loop"/utf8>>,
line => 2282,
value => _assert_fail,
start => 73382,
'end' => 73555,
pattern_start => 73393,
pattern_end => 73410}
)
end,
gleam@result:'try'(
parse_name_block(
Payload,
Num_files,
Additional_streams
),
fun(Parsed_names) ->
parse_files_loop(
After_payload@1,
Num_files,
Parsed_names,
Empty_streams,
Empty_files,
Mtimes_unix,
Additional_streams
)
end
)
end
)
end
);
N@2 when N@2 =:= 16#0E ->
gleam@result:'try'(
read_number(Rest),
fun(_use0@1) ->
{Size@1, After_size@1} = _use0@1,
gleam@result:'try'(
slice_required(
After_size@1,
0,
Size@1,
<<"7z empty-stream payload"/utf8>>
),
fun(Payload@1) ->
After_payload@3 = case gleam_stdlib:bit_array_slice(
After_size@1,
Size@1,
erlang:byte_size(After_size@1) - Size@1
) of
{ok, After_payload@2} -> After_payload@2;
_assert_fail@1 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_files_loop"/utf8>>,
line => 2311,
value => _assert_fail@1,
start => 74217,
'end' => 74390,
pattern_start => 74228,
pattern_end => 74245}
)
end,
Flags = bit_array_to_bool_list(
Payload@1,
Num_files,
[]
),
parse_files_loop(
After_payload@3,
Num_files,
Names,
Flags,
Empty_files,
Mtimes_unix,
Additional_streams
)
end
)
end
);
N@3 when N@3 =:= 16#0F ->
gleam@result:'try'(
read_number(Rest),
fun(_use0@2) ->
{Size@2, After_size@2} = _use0@2,
gleam@result:'try'(
slice_required(
After_size@2,
0,
Size@2,
<<"7z empty-file payload"/utf8>>
),
fun(Payload@2) ->
After_payload@5 = case gleam_stdlib:bit_array_slice(
After_size@2,
Size@2,
erlang:byte_size(After_size@2) - Size@2
) of
{ok, After_payload@4} -> After_payload@4;
_assert_fail@2 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_files_loop"/utf8>>,
line => 2343,
value => _assert_fail@2,
start => 75398,
'end' => 75571,
pattern_start => 75409,
pattern_end => 75426}
)
end,
Empty_count = count_true(Empty_streams),
Flags@1 = bit_array_to_bool_list(
Payload@2,
Empty_count,
[]
),
parse_files_loop(
After_payload@5,
Num_files,
Names,
Empty_streams,
Flags@1,
Mtimes_unix,
Additional_streams
)
end
)
end
);
N@4 when N@4 =:= 16#14 ->
gleam@result:'try'(
read_number(Rest),
fun(_use0@3) ->
{Size@3, After_size@3} = _use0@3,
gleam@result:'try'(
slice_required(
After_size@3,
0,
Size@3,
<<"7z mtime block payload"/utf8>>
),
fun(Payload@3) ->
After_payload@7 = case gleam_stdlib:bit_array_slice(
After_size@3,
Size@3,
erlang:byte_size(After_size@3) - Size@3
) of
{ok, After_payload@6} -> After_payload@6;
_assert_fail@3 ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_files_loop"/utf8>>,
line => 2380,
value => _assert_fail@3,
start => 76856,
'end' => 77029,
pattern_start => 76867,
pattern_end => 76884}
)
end,
gleam@result:'try'(
parse_mtime_block(
Payload@3,
Num_files,
Additional_streams
),
fun(Parsed_mtimes) ->
parse_files_loop(
After_payload@7,
Num_files,
Names,
Empty_streams,
Empty_files,
Parsed_mtimes,
Additional_streams
)
end
)
end
)
end
);
N@5 when ((((((N@5 =:= 16#19) orelse (N@5 =:= 16#12)) orelse (N@5 =:= 16#13)) orelse (N@5 =:= 16#15)) orelse (N@5 =:= 16#10)) orelse (N@5 =:= 16#18)) orelse (N@5 =:= 16#16) ->
gleam@result:'try'(
read_number(Rest),
fun(_use0@4) ->
{Size@4, After_size@4} = _use0@4,
After_payload@9 = case gleam_stdlib:bit_array_slice(
After_size@4,
Size@4,
erlang:byte_size(After_size@4) - Size@4
) of
{ok, After_payload@8} -> After_payload@8;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"packkit/seven_z"/utf8>>,
function => <<"parse_files_loop"/utf8>>,
line => 2411,
value => _assert_fail@4,
start => 77720,
'end' => 77893,
pattern_start => 77731,
pattern_end => 77748})
end,
parse_files_loop(
After_payload@9,
Num_files,
Names,
Empty_streams,
Empty_files,
Mtimes_unix,
Additional_streams
)
end
);
_ ->
{error,
{archive_invalid,
<<"unexpected 7z FilesInfo NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{error, {archive_invalid, <<"truncated 7z FilesInfo"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 2238).
-spec parse_files_info(bitstring(), list(bitstring())) -> {ok,
{header_files(), bitstring()}} |
{error, packkit@error:archive_error()}.
parse_files_info(Bytes, Additional_streams) ->
gleam@result:'try'(
read_number(Bytes),
fun(_use0) ->
{Num_files, Rest} = _use0,
parse_files_loop(
Rest,
Num_files,
[],
[],
[],
[],
Additional_streams
)
end
).
-file("src/packkit/seven_z.gleam", 1415).
-spec parse_header_body(
bitstring(),
header_parser(),
bitstring(),
packkit@limit:limits()
) -> {ok, header_parser()} | {error, packkit@error:archive_error()}.
parse_header_body(Bytes, Parser, Full_archive, Limits) ->
case Bytes of
<<Nid, Rest/binary>> ->
case Nid of
N when N =:= 16#00 ->
{ok, Parser};
N@1 when N@1 =:= 16#04 ->
gleam@result:'try'(
parse_main_streams_info(Rest, erlang:element(2, Parser)),
fun(_use0) ->
{Streams, Rest@1} = _use0,
parse_header_body(
Rest@1,
{header_parser,
erlang:element(2, Parser),
Streams,
erlang:element(4, Parser)},
Full_archive,
Limits
)
end
);
N@2 when N@2 =:= 16#05 ->
gleam@result:'try'(
parse_files_info(Rest, erlang:element(2, Parser)),
fun(_use0@1) ->
{Files, Rest@2} = _use0@1,
parse_header_body(
Rest@2,
{header_parser,
erlang:element(2, Parser),
erlang:element(3, Parser),
Files},
Full_archive,
Limits
)
end
);
N@3 when N@3 =:= 16#03 ->
gleam@result:'try'(
parse_main_streams_info(Rest, []),
fun(_use0@2) ->
{Streams_info, Rest@3} = _use0@2,
gleam@result:'try'(
decode_additional_streams(
Streams_info,
Full_archive,
Limits
),
fun(Decoded) ->
parse_header_body(
Rest@3,
{header_parser,
Decoded,
erlang:element(3, Parser),
erlang:element(4, Parser)},
Full_archive,
Limits
)
end
)
end
);
N@4 when N@4 =:= 16#02 ->
{error,
{archive_not_implemented,
<<"7z ArchiveProperties (NID 0x02)"/utf8>>}};
_ ->
{error,
{archive_invalid,
<<"unexpected 7z header NID "/utf8,
(erlang:integer_to_binary(Nid))/binary>>}}
end;
_ ->
{ok, Parser}
end.
-file("src/packkit/seven_z.gleam", 1352).
-spec parse_header(bitstring(), bitstring(), packkit@limit:limits()) -> {ok,
parsed_header()} |
{error, packkit@error:archive_error()}.
parse_header(Header, Full_archive, Limits) ->
case Header of
<<Head_nid, Rest/binary>> when Head_nid =:= 16#01 ->
Parser = {header_parser, [], header_streams_none, header_files_none},
gleam@result:'try'(
parse_header_body(Rest, Parser, Full_archive, Limits),
fun(Parser@1) -> finalize_parsed_header(Parser@1) end
);
_ ->
{error,
{archive_invalid,
<<"7z header must start with the Header NID"/utf8>>}}
end.
-file("src/packkit/seven_z.gleam", 1136).
-spec decode_internal(
bitstring(),
gleam@option:option(binary()),
packkit@limit:limits()
) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}.
decode_internal(Bytes, Password, Limits) ->
gleam@bool:guard(
erlang:byte_size(Bytes) > packkit@limit:max_input_bytes(Limits),
{error,
{archive_limit_exceeded,
<<"max_input_bytes"/utf8>>,
erlang:byte_size(Bytes)}},
fun() ->
gleam@result:'try'(
parse_signature_header(Bytes),
fun(_use0) ->
{Next_offset, Next_size, _} = _use0,
gleam@result:'try'(
slice_required(
Bytes,
32,
Next_offset,
<<"7z packed streams region"/utf8>>
),
fun(Packed_streams) ->
gleam@result:'try'(
slice_required(
Bytes,
32 + Next_offset,
Next_size,
<<"7z next header"/utf8>>
),
fun(Next_header_bytes) ->
gleam@result:'try'(case Next_header_bytes of
<<N, Rest/binary>> when N =:= 16#17 ->
decode_encoded_header(
Rest,
Bytes,
Password,
Limits
);
_ ->
{ok, Next_header_bytes}
end, fun(Header) ->
gleam@result:'try'(
parse_header(
Header,
Bytes,
Limits
),
fun(Parsed) ->
decode_archive(
Packed_streams,
Parsed,
Password,
Limits
)
end
)
end)
end
)
end
)
end
)
end
).
-file("src/packkit/seven_z.gleam", 1094).
?DOC(" Decode a 7z byte stream using the default limits.\n").
-spec decode(bitstring()) -> {ok, packkit@archive:archive()} |
{error, packkit@error:archive_error()}.
decode(Bytes) ->
decode_internal(Bytes, none, packkit@limit:default()).
-file("src/packkit/seven_z.gleam", 1105).
?DOC(
" Decode a 7z byte stream using explicit limits. Enforces\n"
" `max_input_bytes` at entry, `max_output_bytes` against the\n"
" declared unpack size before invoking the LZMA/LZMA2 decoder,\n"
" and `max_members` / `max_entry_depth` while materialising the\n"
" logical entry list.\n"
).
-spec decode_with_limits(bitstring(), packkit@limit:limits()) -> {ok,
packkit@archive:archive()} |
{error, packkit@error:archive_error()}.
decode_with_limits(Bytes, Limits) ->
decode_internal(Bytes, none, Limits).
-file("src/packkit/seven_z.gleam", 1120).
?DOC(
" Decode a 7z byte stream that contains an AES-256 encrypted folder.\n"
" `password` is applied to every AES-coded folder via the SHA-256\n"
" key-derivation routine p7zip uses (`numCyclesPower` rounds of\n"
" `sha256(salt || utf16le(password) || u64_le(counter))`); folders\n"
" without an AES coder decode unchanged. A wrong password produces\n"
" garbage plaintext that the downstream coder (typically LZMA2)\n"
" rejects with the usual typed `ArchiveInvalid` error — there's no\n"
" authentication tag on the AES layer.\n"
).
-spec decode_with_password(bitstring(), binary()) -> {ok,
packkit@archive:archive()} |
{error, packkit@error:archive_error()}.
decode_with_password(Bytes, Password) ->
decode_internal(Bytes, {some, Password}, packkit@limit:default()).
-file("src/packkit/seven_z.gleam", 1128).
?DOC(" Same as `decode_with_password` but with explicit limits.\n").
-spec decode_with_password_and_limits(
bitstring(),
binary(),
packkit@limit:limits()
) -> {ok, packkit@archive:archive()} | {error, packkit@error:archive_error()}.
decode_with_password_and_limits(Bytes, Password, Limits) ->
decode_internal(Bytes, {some, Password}, Limits).