- vendor in hex_core at v0.5.0 - Change where repo_name should be the org and not the parent - Changed rebar_utils:url_append_path/2 to not explicitly add a '?', this is returned in the Query chunk by http_uri:parse/1 (e.g., "?foo=bar") - update organization_merging test to expect the sub-repo as the repo_name - Add tests for rebar_utils:url_append_path/2 - Stop referencing/setting "organization" in config and use new organization settings (api_repository and repo_organization) - Do not set (assume) the read key is valid for any/every repo - Set repo_organization and api_repository to org - Update tests to check for new config optspull/2028/head
@ -0,0 +1,120 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% @hidden | |||||
-module(r3_hex_api). | |||||
-export([ | |||||
delete/2, | |||||
get/2, | |||||
post/3, | |||||
put/3, | |||||
encode_query_string/1, | |||||
build_repository_path/2, | |||||
build_organization_path/2, | |||||
join_path_segments/1 | |||||
]). | |||||
-define(ERL_CONTENT_TYPE, <<"application/vnd.hex+erlang">>). | |||||
get(Config, Path) -> | |||||
request(Config, get, Path, undefined). | |||||
post(Config, Path, Body) -> | |||||
request(Config, post, Path, encode_body(Body)). | |||||
put(Config, Path, Body) -> | |||||
request(Config, put, Path, encode_body(Body)). | |||||
delete(Config, Path) -> | |||||
request(Config, delete, Path, undefined). | |||||
%% @private | |||||
encode_query_string(List) -> | |||||
QueryString = | |||||
join("&", | |||||
lists:map(fun | |||||
({K, V}) when is_atom(V) -> | |||||
atom_to_list(K) ++ "=" ++ atom_to_list(V); | |||||
({K, V}) when is_binary(V) -> | |||||
atom_to_list(K) ++ "=" ++ binary_to_list(V); | |||||
({K, V}) when is_integer(V) -> | |||||
atom_to_list(K) ++ "=" ++ integer_to_list(V) | |||||
end, List)), | |||||
Encoded = http_uri:encode(QueryString), | |||||
list_to_binary(Encoded). | |||||
%% @private | |||||
build_repository_path(#{api_repository := Repo}, Path) when is_binary(Repo) -> | |||||
["repos", Repo | Path]; | |||||
build_repository_path(#{api_repository := undefined}, Path) -> | |||||
Path. | |||||
%% @private | |||||
build_organization_path(#{api_organization := Org}, Path) when is_binary(Org) -> | |||||
["orgs", Org | Path]; | |||||
build_organization_path(#{api_organization := undefined}, Path) -> | |||||
Path. | |||||
%% @private | |||||
join_path_segments(Segments) -> | |||||
erlang:iolist_to_binary(join(<<"/">>, lists:map(fun encode/1, Segments))). | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
request(Config, Method, PathSegments, Body) when is_list(PathSegments) -> | |||||
Path = join_path_segments(PathSegments), | |||||
request(Config, Method, Path, Body); | |||||
request(Config, Method, Path, Body) when is_binary(Path) and is_map(Config) -> | |||||
DefaultHeaders = make_headers(Config), | |||||
ReqHeaders = maps:merge(maps:get(http_headers, Config, #{}), DefaultHeaders), | |||||
ReqHeaders2 = put_new(<<"accept">>, ?ERL_CONTENT_TYPE, ReqHeaders), | |||||
case r3_hex_http:request(Config, Method, build_url(Path, Config), ReqHeaders2, Body) of | |||||
{ok, {Status, RespHeaders, RespBody}} = Response -> | |||||
ContentType = maps:get(<<"content-type">>, RespHeaders, <<"">>), | |||||
case binary:match(ContentType, ?ERL_CONTENT_TYPE) of | |||||
{_, _} -> | |||||
{ok, {Status, RespHeaders, binary_to_term(RespBody)}}; | |||||
nomatch -> | |||||
Response | |||||
end; | |||||
Other -> | |||||
Other | |||||
end. | |||||
encode(Binary) when is_binary(Binary) -> | |||||
encode(binary_to_list(Binary)); | |||||
encode(String) when is_list(String) -> | |||||
http_uri:encode(String). | |||||
build_url(Path, #{api_url := URI}) -> | |||||
<<URI/binary, "/", Path/binary>>. | |||||
encode_body({_ContentType, _Body} = Body) -> | |||||
Body; | |||||
encode_body(Body) -> | |||||
{binary_to_list(?ERL_CONTENT_TYPE), term_to_binary(Body)}. | |||||
%% TODO: copy-pasted from r3_hex_repo | |||||
make_headers(Config) -> | |||||
maps:fold(fun set_header/3, #{}, Config). | |||||
set_header(api_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers); | |||||
set_header(_, _, Headers) -> Headers. | |||||
put_new(Key, Value, Map) -> | |||||
case maps:find(Key, Map) of | |||||
{ok, _} -> Map; | |||||
error -> maps:put(Key, Value, Map) | |||||
end. | |||||
%% https://github.com/erlang/otp/blob/OTP-20.3/lib/stdlib/src/lists.erl#L1449:L1453 | |||||
join(_Sep, []) -> []; | |||||
join(Sep, [H|T]) -> [H|join_prepend(Sep, T)]. | |||||
join_prepend(_Sep, []) -> []; | |||||
join_prepend(Sep, [H|T]) -> [Sep,H|join_prepend(Sep,T)]. |
@ -0,0 +1,31 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_api_key). | |||||
-export([ | |||||
list/1, | |||||
get/2, | |||||
add/3, | |||||
delete/2, | |||||
delete_all/1 | |||||
]). | |||||
list(Config) when is_map(Config) -> | |||||
Path = r3_hex_api:build_organization_path(Config, ["keys"]), | |||||
r3_hex_api:get(Config, Path). | |||||
get(Config, Name) when is_map(Config) -> | |||||
Path = r3_hex_api:build_organization_path(Config, ["keys", Name]), | |||||
r3_hex_api:get(Config, Path). | |||||
add(Config, Name, Permissions) when is_map(Config) -> | |||||
Path = r3_hex_api:build_organization_path(Config, ["keys"]), | |||||
Params = #{<<"name">> => Name, <<"permissions">> => Permissions}, | |||||
r3_hex_api:post(Config, Path, Params). | |||||
delete(Config, Name) when is_map(Config) -> | |||||
Path = r3_hex_api:build_organization_path(Config, ["keys", Name]), | |||||
r3_hex_api:delete(Config, Path). | |||||
delete_all(Config) when is_map(Config) -> | |||||
Path = r3_hex_api:build_organization_path(Config, ["keys"]), | |||||
r3_hex_api:delete(Config, Path). |
@ -0,0 +1,49 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_api_package). | |||||
-export([get/2, search/3]). | |||||
%% @doc | |||||
%% Gets package. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_api_package:get(r3_hex_core:default_config(), <<"package">>). | |||||
%% {ok, {200, ..., #{ | |||||
%% <<"name">> => <<"package1">>, | |||||
%% <<"meta">> => #{ | |||||
%% <<"description">> => ..., | |||||
%% <<"licenses">> => ..., | |||||
%% <<"links">> => ..., | |||||
%% <<"maintainers">> => ... | |||||
%% }, | |||||
%% ..., | |||||
%% <<"releases">> => [ | |||||
%% #{<<"url">> => ..., <<"version">> => <<"0.5.0">>}], | |||||
%% #{<<"url">> => ..., <<"version">> => <<"1.0.0">>}], | |||||
%% ... | |||||
%% ]}}} | |||||
%% ''' | |||||
%% @end | |||||
get(Config, Name) when is_binary(Name) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", Name]), | |||||
r3_hex_api:get(Config, Path). | |||||
%% @doc | |||||
%% Searches packages. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_api_package:search(r3_hex_core:default_config(), <<"package">>, []). | |||||
%% {ok, {200, ..., [ | |||||
%% #{<<"name">> => <<"package1">>, ...}, | |||||
%% ... | |||||
%% ]}} | |||||
%% ''' | |||||
search(Config, Query, SearchParams) when is_binary(Query) and is_list(SearchParams) and is_map(Config) -> | |||||
QueryString = r3_hex_api:encode_query_string([{search, Query} | SearchParams]), | |||||
Path = r3_hex_api:join_path_segments(r3_hex_api:build_repository_path(Config, ["packages"])), | |||||
PathQuery = <<Path/binary, "?", QueryString/binary>>, | |||||
r3_hex_api:get(Config, PathQuery). |
@ -0,0 +1,34 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_api_package_owner). | |||||
-export([ | |||||
add/3, | |||||
delete/3, | |||||
get/3, | |||||
list/2 | |||||
]). | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_api_owner:list(r3_hex_core:default_config(), <<"package">>). | |||||
%% {ok, {200, ..., [ | |||||
%% #{<<"username">> => <<"alice">>, ...}, | |||||
%% ... | |||||
%% ]}} | |||||
%% ''' | |||||
list(Config, PackageName) when is_binary(PackageName) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners"]), | |||||
r3_hex_api:get(Config, Path). | |||||
get(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]), | |||||
r3_hex_api:get(Config, Path). | |||||
add(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]), | |||||
r3_hex_api:put(Config, Path, #{}). | |||||
delete(Config, PackageName, UsernameOrEmail) when is_binary(PackageName) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", PackageName, "owners", UsernameOrEmail]), | |||||
r3_hex_api:delete(Config, Path). |
@ -0,0 +1,60 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_api_release). | |||||
-export([ | |||||
delete/3, | |||||
get/3, | |||||
publish/2, | |||||
retire/4, | |||||
unretire/3 | |||||
]). | |||||
%% @doc | |||||
%% Gets package release. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_api:get_release(<<"package">>, <<"1.0.0">>, r3_hex_core:default_config()). | |||||
%% {ok, {200, ..., #{ | |||||
%% <<"version">> => <<"1.0.0">>, | |||||
%% <<"meta">> => #{ | |||||
%% <<"description">> => ..., | |||||
%% <<"licenses">> => ..., | |||||
%% <<"links">> => ..., | |||||
%% <<"maintainers">> => ... | |||||
%% }, | |||||
%% ...}}} | |||||
%% ''' | |||||
%% @end | |||||
get(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version]), | |||||
r3_hex_api:get(Config, Path). | |||||
publish(Config, Tarball) when is_binary(Tarball) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["publish"]), | |||||
TarballContentType = "application/octet-stream", | |||||
Config2 = put_header(<<"content-length">>, integer_to_binary(byte_size(Tarball)), Config), | |||||
Body = {TarballContentType, Tarball}, | |||||
r3_hex_api:post(Config2, Path, Body). | |||||
delete(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version]), | |||||
r3_hex_api:delete(Config, Path). | |||||
retire(Config, Name, Version, Params) when is_binary(Name) and is_binary(Version) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version, "retire"]), | |||||
r3_hex_api:post(Config, Path, Params). | |||||
unretire(Config, Name, Version) when is_binary(Name) and is_binary(Version) and is_map(Config) -> | |||||
Path = r3_hex_api:build_repository_path(Config, ["packages", Name, "releases", Version, "retire"]), | |||||
r3_hex_api:delete(Config, Path). | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
put_header(Name, Value, Config) -> | |||||
Headers = maps:get(http_headers, Config, #{}), | |||||
Headers2 = maps:put(Name, Value, Headers), | |||||
maps:put(http_headers, Headers2, Config). |
@ -0,0 +1,46 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_api_user). | |||||
-export([ | |||||
create/4, | |||||
get/2, | |||||
me/1, | |||||
reset_password/2 | |||||
]). | |||||
me(Config) when is_map(Config) -> | |||||
r3_hex_api:get(Config, ["users", "me"]). | |||||
create(Config, Username, Password, Email) -> | |||||
Params = #{ | |||||
<<"username">> => Username, | |||||
<<"password">> => Password, | |||||
<<"email">> => Email | |||||
}, | |||||
r3_hex_api:post(Config, ["users"], Params). | |||||
reset_password(Username, Config) when is_binary(Username) and is_map(Config) -> | |||||
r3_hex_api:post(Config, ["users", Username, "reset"], #{}). | |||||
%% @doc | |||||
%% Gets user. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_api_user:get(<<"user">>, r3_hex_core:default_config()). | |||||
%% {ok, {200, ..., #{ | |||||
%% <<"username">> => <<"user">>, | |||||
%% <<"packages">> => [ | |||||
%% #{ | |||||
%% <<"name">> => ..., | |||||
%% <<"url">> => ..., | |||||
%% ... | |||||
%% }, | |||||
%% ... | |||||
%% ], | |||||
%% ...}}} | |||||
%% ''' | |||||
%% @end | |||||
get(Config, Username) when is_binary(Username) and is_map(Config) -> | |||||
r3_hex_api:get(Config, ["users", Username]). |
@ -0,0 +1,92 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% @doc | |||||
%% hex_core entrypoint module. | |||||
%% | |||||
%% ### Config | |||||
%% | |||||
%% Most functions in the hex_core API takes a configuration. The configuration sets things | |||||
%% like HTTP client to use, and API and repository URL. Some of these configuration options | |||||
%% will likely be static for your application and some may change depending on the function | |||||
%% you call. | |||||
%% | |||||
%% ##### Options | |||||
%% | |||||
%% * `api_key' - Authentication key used when accessing the HTTP API. | |||||
%% * `api_organization' - Name of the organization endpoint in the API, this should | |||||
%% for example be set when accessing key for a specific organization. | |||||
%% * `api_repository' - Name of the repository endpoint in the API, this should | |||||
%% for example be set when accessing packages from a specific repository. | |||||
%% * `api_url' - URL to the HTTP API (default: `https://hex.pm/api'). | |||||
%% * `http_adapter' - Callback module used for HTTP requests, see [`r3_hex_http'](r3_hex_http.html) | |||||
%% (default: `r3_hex_http_httpc'). | |||||
%% * `http_etag' - Sets the `if-none-match' HTTP header with the given value to do a | |||||
%% conditional HTTP request. | |||||
%% * `http_adapter_config' - Configuration to pass to the HTTP adapter. | |||||
%% * `http_user_agent_fragment' - Will be appended to the `user-agent` HTTP header (default: `(httpc)'). | |||||
%% * `repo_key' - Authentication key used when accessing the repository. | |||||
%% * `repo_name' - Name of the repository, used for verifying the repository signature | |||||
%% authenticity (default: `hexpm'). | |||||
%% * `repo_public_key' - Public key used to verify the repository signature | |||||
%% (defaults to hexpm public key `https://hex.pm/docs/public_keys'). | |||||
%% * `repo_url' - URL to the repository (default: `https://repo.hex.pm'). | |||||
%% * `repo_organization' - Name of the organization repository, appends `/repos/:name' | |||||
%% to the repository URL and overrides the `repo_name' option. | |||||
%% * `repo_verify' - If `true' will verify the repository signature (default: `true'). | |||||
%% * `repo_verify_origin' - If `true' will verify the repository signature origin, | |||||
%% requires protobuf messages as of hex_core v0.4.0 (default: `true'). | |||||
-module(r3_hex_core). | |||||
-export([default_config/0]). | |||||
-export_type([config/0]). | |||||
%% https://hex.pm/docs/public_keys | |||||
-define(HEXPM_PUBLIC_KEY, <<"-----BEGIN PUBLIC KEY----- | |||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB | |||||
Edvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+ | |||||
IqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM | |||||
3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW | |||||
XgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ | |||||
J1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4 | |||||
0wIDAQAB | |||||
-----END PUBLIC KEY-----">>). | |||||
-type config() :: #{ | |||||
api_key => binary() | undefined, | |||||
api_organization => binary() | undefined, | |||||
api_repository => binary() | undefined, | |||||
api_url => binary(), | |||||
http_adapter => module(), | |||||
http_etag => binary() | undefined, | |||||
http_adapter_config => map(), | |||||
http_user_agent_fragment => binary(), | |||||
repo_key => binary() | undefined, | |||||
repo_name => binary(), | |||||
repo_public_key => binary(), | |||||
repo_url => binary(), | |||||
repo_organization => binary() | undefined, | |||||
repo_verify => boolean(), | |||||
repo_verify_origin => boolean() | |||||
}. | |||||
-spec default_config() -> config(). | |||||
default_config() -> | |||||
#{ | |||||
api_key => undefined, | |||||
api_organization => undefined, | |||||
api_repository => undefined, | |||||
api_url => <<"https://hex.pm/api">>, | |||||
http_adapter => r3_hex_http_httpc, | |||||
http_adapter_config => #{profile => default}, | |||||
http_etag => undefined, | |||||
http_user_agent_fragment => <<"(httpc)">>, | |||||
repo_key => undefined, | |||||
repo_name => <<"hexpm">>, | |||||
repo_public_key => ?HEXPM_PUBLIC_KEY, | |||||
repo_url => <<"https://repo.hex.pm">>, | |||||
repo_organization => undefined, | |||||
repo_verify => true, | |||||
repo_verify_origin => true | |||||
}. |
@ -0,0 +1,3 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-define(HEX_CORE_VERSION, "0.5.0"). |
@ -0,0 +1,405 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
% Copied from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/erl_tar.hrl | |||||
%% | |||||
%% %CopyrightBegin% | |||||
%% | |||||
%% Copyright Ericsson AB 2017. All Rights Reserved. | |||||
%% | |||||
%% Licensed under the Apache License, Version 2.0 (the "License"); | |||||
%% you may not use this file except in compliance with the License. | |||||
%% You may obtain a copy of the License at | |||||
%% | |||||
%% http://www.apache.org/licenses/LICENSE-2.0 | |||||
%% | |||||
%% Unless required by applicable law or agreed to in writing, software | |||||
%% distributed under the License is distributed on an "AS IS" BASIS, | |||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
%% See the License for the specific language governing permissions and | |||||
%% limitations under the License. | |||||
%% | |||||
%% %CopyrightEnd% | |||||
%% Options used when adding files to a tar archive. | |||||
-record(add_opts, { | |||||
read_info, %% Fun to use for read file/link info. | |||||
chunk_size = 0, %% For file reading when sending to sftp. 0=do not chunk | |||||
verbose = false, %% Verbose on/off. | |||||
atime = undefined, | |||||
mtime = undefined, | |||||
ctime = undefined, | |||||
uid = 0, | |||||
gid = 0}). | |||||
-type add_opts() :: #add_opts{}. | |||||
%% Options used when reading a tar archive. | |||||
-record(read_opts, { | |||||
cwd :: string(), %% Current working directory. | |||||
keep_old_files = false :: boolean(), %% Owerwrite or not. | |||||
files = all, %% Set of files to extract (or all) | |||||
output = file :: 'file' | 'memory', | |||||
open_mode = [], %% Open mode options. | |||||
verbose = false :: boolean()}). %% Verbose on/off. | |||||
-type read_opts() :: #read_opts{}. | |||||
-type add_opt() :: dereference | | |||||
verbose | | |||||
{chunks, pos_integer()}. | |||||
-type extract_opt() :: {cwd, string()} | | |||||
{files, [string()]} | | |||||
compressed | | |||||
cooked | | |||||
memory | | |||||
keep_old_files | | |||||
verbose. | |||||
-type create_opt() :: compressed | | |||||
cooked | | |||||
dereference | | |||||
verbose. | |||||
-type filelist() :: [file:filename() | | |||||
{string(), binary()} | | |||||
{string(), file:filename()}]. | |||||
-type tar_time() :: non_neg_integer(). | |||||
%% The tar header, once fully parsed. | |||||
-record(tar_header, { | |||||
name = "" :: string(), %% name of header file entry | |||||
mode = 8#100644 :: non_neg_integer(), %% permission and mode bits | |||||
uid = 0 :: non_neg_integer(), %% user id of owner | |||||
gid = 0 :: non_neg_integer(), %% group id of owner | |||||
size = 0 :: non_neg_integer(), %% length in bytes | |||||
mtime :: tar_time(), %% modified time | |||||
typeflag :: char(), %% type of header entry | |||||
linkname = "" :: string(), %% target name of link | |||||
uname = "" :: string(), %% user name of owner | |||||
gname = "" :: string(), %% group name of owner | |||||
devmajor = 0 :: non_neg_integer(), %% major number of character or block device | |||||
devminor = 0 :: non_neg_integer(), %% minor number of character or block device | |||||
atime :: tar_time(), %% access time | |||||
ctime :: tar_time() %% status change time | |||||
}). | |||||
-type tar_header() :: #tar_header{}. | |||||
%% Metadata for a sparse file fragment | |||||
-record(sparse_entry, { | |||||
offset = 0 :: non_neg_integer(), | |||||
num_bytes = 0 :: non_neg_integer()}). | |||||
-type sparse_entry() :: #sparse_entry{}. | |||||
%% Contains metadata about fragments of a sparse file | |||||
-record(sparse_array, { | |||||
entries = [] :: [sparse_entry()], | |||||
is_extended = false :: boolean(), | |||||
max_entries = 0 :: non_neg_integer()}). | |||||
-type sparse_array() :: #sparse_array{}. | |||||
%% A subset of tar header fields common to all tar implementations | |||||
-record(header_v7, { | |||||
name :: binary(), | |||||
mode :: binary(), %% octal | |||||
uid :: binary(), %% integer | |||||
gid :: binary(), %% integer | |||||
size :: binary(), %% integer | |||||
mtime :: binary(), %% integer | |||||
checksum :: binary(), %% integer | |||||
typeflag :: byte(), %% char | |||||
linkname :: binary()}). | |||||
-type header_v7() :: #header_v7{}. | |||||
%% The set of fields specific to GNU tar formatted archives | |||||
-record(header_gnu, { | |||||
header_v7 :: header_v7(), | |||||
magic :: binary(), | |||||
version :: binary(), | |||||
uname :: binary(), | |||||
gname :: binary(), | |||||
devmajor :: binary(), %% integer | |||||
devminor :: binary(), %% integer | |||||
atime :: binary(), %% integer | |||||
ctime :: binary(), %% integer | |||||
sparse :: sparse_array(), | |||||
real_size :: binary()}). %% integer | |||||
-type header_gnu() :: #header_gnu{}. | |||||
%% The set of fields specific to STAR-formatted archives | |||||
-record(header_star, { | |||||
header_v7 :: header_v7(), | |||||
magic :: binary(), | |||||
version :: binary(), | |||||
uname :: binary(), | |||||
gname :: binary(), | |||||
devmajor :: binary(), %% integer | |||||
devminor :: binary(), %% integer | |||||
prefix :: binary(), | |||||
atime :: binary(), %% integer | |||||
ctime :: binary(), %% integer | |||||
trailer :: binary()}). | |||||
-type header_star() :: #header_star{}. | |||||
%% The set of fields specific to USTAR-formatted archives | |||||
-record(header_ustar, { | |||||
header_v7 :: header_v7(), | |||||
magic :: binary(), | |||||
version :: binary(), | |||||
uname :: binary(), | |||||
gname :: binary(), | |||||
devmajor :: binary(), %% integer | |||||
devminor :: binary(), %% integer | |||||
prefix :: binary()}). | |||||
-type header_ustar() :: #header_ustar{}. | |||||
-type header_fields() :: header_v7() | | |||||
header_gnu() | | |||||
header_star() | | |||||
header_ustar(). | |||||
%% The overall tar reader, it holds the low-level file handle, | |||||
%% its access, position, and the I/O primitives wrapper. | |||||
-record(reader, { | |||||
handle :: file:io_device() | term(), | |||||
access :: read | write | ram, | |||||
pos = 0 :: non_neg_integer(), | |||||
func :: file_op() | |||||
}). | |||||
-type reader() :: #reader{}. | |||||
%% A reader for a regular file within the tar archive, | |||||
%% It tracks its current state relative to that file. | |||||
-record(reg_file_reader, { | |||||
handle :: reader(), | |||||
num_bytes = 0, | |||||
pos = 0, | |||||
size = 0 | |||||
}). | |||||
-type reg_file_reader() :: #reg_file_reader{}. | |||||
%% A reader for a sparse file within the tar archive, | |||||
%% It tracks its current state relative to that file. | |||||
-record(sparse_file_reader, { | |||||
handle :: reader(), | |||||
num_bytes = 0, %% bytes remaining | |||||
pos = 0, %% pos | |||||
size = 0, %% total size of file | |||||
sparse_map = #sparse_array{} | |||||
}). | |||||
-type sparse_file_reader() :: #sparse_file_reader{}. | |||||
%% Types for the readers | |||||
-type reader_type() :: reader() | reg_file_reader() | sparse_file_reader(). | |||||
-type handle() :: file:io_device() | term(). | |||||
%% Type for the I/O primitive wrapper function | |||||
-type file_op() :: fun((write | close | read2 | position, | |||||
{handle(), iodata()} | handle() | {handle(), non_neg_integer()} | |||||
| {handle(), non_neg_integer()}) -> | |||||
ok | eof | {ok, string() | binary()} | {ok, non_neg_integer()} | |||||
| {error, term()}). | |||||
%% These constants (except S_IFMT) are | |||||
%% used to determine what type of device | |||||
%% a file is. Namely, `S_IFMT band file_info.mode` | |||||
%% will equal one of these contants, and tells us | |||||
%% which type it is. The stdlib file_info record | |||||
%% does not differentiate between device types, and | |||||
%% will not allow us to differentiate between sockets | |||||
%% and named pipes. These constants are pulled from libc. | |||||
-define(S_IFMT, 61440). | |||||
-define(S_IFSOCK, 49152). %% socket | |||||
-define(S_FIFO, 4096). %% fifo/named pipe | |||||
-define(S_IFBLK, 24576). %% block device | |||||
-define(S_IFCHR, 8192). %% character device | |||||
%% Typeflag constants for the tar header | |||||
-define(TYPE_REGULAR, $0). %% regular file | |||||
-define(TYPE_REGULAR_A, 0). %% regular file | |||||
-define(TYPE_LINK, $1). %% hard link | |||||
-define(TYPE_SYMLINK, $2). %% symbolic link | |||||
-define(TYPE_CHAR, $3). %% character device node | |||||
-define(TYPE_BLOCK, $4). %% block device node | |||||
-define(TYPE_DIR, $5). %% directory | |||||
-define(TYPE_FIFO, $6). %% fifo node | |||||
-define(TYPE_CONT, $7). %% reserved | |||||
-define(TYPE_X_HEADER, $x). %% extended header | |||||
-define(TYPE_X_GLOBAL_HEADER, $g). %% global extended header | |||||
-define(TYPE_GNU_LONGNAME, $L). %% next file has a long name | |||||
-define(TYPE_GNU_LONGLINK, $K). %% next file symlinks to a file with a long name | |||||
-define(TYPE_GNU_SPARSE, $S). %% sparse file | |||||
%% Mode constants from tar spec | |||||
-define(MODE_ISUID, 4000). %% set uid | |||||
-define(MODE_ISGID, 2000). %% set gid | |||||
-define(MODE_ISVTX, 1000). %% save text (sticky bit) | |||||
-define(MODE_ISDIR, 40000). %% directory | |||||
-define(MODE_ISFIFO, 10000). %% fifo | |||||
-define(MODE_ISREG, 100000). %% regular file | |||||
-define(MODE_ISLNK, 120000). %% symbolic link | |||||
-define(MODE_ISBLK, 60000). %% block special file | |||||
-define(MODE_ISCHR, 20000). %% character special file | |||||
-define(MODE_ISSOCK, 140000). %% socket | |||||
%% Keywords for PAX extended header | |||||
-define(PAX_ATIME, <<"atime">>). | |||||
-define(PAX_CHARSET, <<"charset">>). | |||||
-define(PAX_COMMENT, <<"comment">>). | |||||
-define(PAX_CTIME, <<"ctime">>). %% ctime is not a valid pax header | |||||
-define(PAX_GID, <<"gid">>). | |||||
-define(PAX_GNAME, <<"gname">>). | |||||
-define(PAX_LINKPATH, <<"linkpath">>). | |||||
-define(PAX_MTIME, <<"mtime">>). | |||||
-define(PAX_PATH, <<"path">>). | |||||
-define(PAX_SIZE, <<"size">>). | |||||
-define(PAX_UID, <<"uid">>). | |||||
-define(PAX_UNAME, <<"uname">>). | |||||
-define(PAX_XATTR, <<"SCHILY.xattr.">>). | |||||
-define(PAX_XATTR_STR, "SCHILY.xattr."). | |||||
-define(PAX_NONE, <<"">>). | |||||
%% Tar format constants | |||||
%% Unknown format | |||||
-define(FORMAT_UNKNOWN, 0). | |||||
%% The format of the original Unix V7 tar tool prior to standardization | |||||
-define(FORMAT_V7, 1). | |||||
%% The old and new GNU formats, incompatible with USTAR. | |||||
%% This covers the old GNU sparse extension, but it does | |||||
%% not cover the GNU sparse extensions using PAX headers, | |||||
%% versions 0.0, 0.1, and 1.0; these fall under the PAX format. | |||||
-define(FORMAT_GNU, 2). | |||||
%% Schily's tar format, which is incompatible with USTAR. | |||||
%% This does not cover STAR extensions to the PAX format; these | |||||
%% fall under the PAX format. | |||||
-define(FORMAT_STAR, 3). | |||||
%% USTAR is the former standardization of tar defined in POSIX.1-1988, | |||||
%% it is incompatible with the GNU and STAR formats. | |||||
-define(FORMAT_USTAR, 4). | |||||
%% PAX is the latest standardization of tar defined in POSIX.1-2001. | |||||
%% This is an extension of USTAR and is "backwards compatible" with it. | |||||
%% | |||||
%% Some newer formats add their own extensions to PAX, such as GNU sparse | |||||
%% files and SCHILY extended attributes. Since they are backwards compatible | |||||
%% with PAX, they will be labelled as "PAX". | |||||
-define(FORMAT_PAX, 5). | |||||
%% Magic constants | |||||
-define(MAGIC_GNU, <<"ustar ">>). | |||||
-define(VERSION_GNU, <<" \x00">>). | |||||
-define(MAGIC_USTAR, <<"ustar\x00">>). | |||||
-define(VERSION_USTAR, <<"00">>). | |||||
-define(TRAILER_STAR, <<"tar\x00">>). | |||||
%% Size constants | |||||
-define(BLOCK_SIZE, 512). %% size of each block in a tar stream | |||||
-define(NAME_SIZE, 100). %% max length of the name field in USTAR format | |||||
-define(PREFIX_SIZE, 155). %% max length of the prefix field in USTAR format | |||||
%% Maximum size of a nanosecond value as an integer | |||||
-define(MAX_NANO_INT_SIZE, 9). | |||||
%% Maximum size of a 64-bit signed integer | |||||
-define(MAX_INT64, (1 bsl 63 - 1)). | |||||
-define(PAX_GNU_SPARSE_NUMBLOCKS, <<"GNU.sparse.numblocks">>). | |||||
-define(PAX_GNU_SPARSE_OFFSET, <<"GNU.sparse.offset">>). | |||||
-define(PAX_GNU_SPARSE_NUMBYTES, <<"GNU.sparse.numbytes">>). | |||||
-define(PAX_GNU_SPARSE_MAP, <<"GNU.sparse.map">>). | |||||
-define(PAX_GNU_SPARSE_NAME, <<"GNU.sparse.name">>). | |||||
-define(PAX_GNU_SPARSE_MAJOR, <<"GNU.sparse.major">>). | |||||
-define(PAX_GNU_SPARSE_MINOR, <<"GNU.sparse.minor">>). | |||||
-define(PAX_GNU_SPARSE_SIZE, <<"GNU.sparse.size">>). | |||||
-define(PAX_GNU_SPARSE_REALSIZE, <<"GNU.sparse.realsize">>). | |||||
-define(V7_NAME, 0). | |||||
-define(V7_NAME_LEN, 100). | |||||
-define(V7_MODE, 100). | |||||
-define(V7_MODE_LEN, 8). | |||||
-define(V7_UID, 108). | |||||
-define(V7_UID_LEN, 8). | |||||
-define(V7_GID, 116). | |||||
-define(V7_GID_LEN, 8). | |||||
-define(V7_SIZE, 124). | |||||
-define(V7_SIZE_LEN, 12). | |||||
-define(V7_MTIME, 136). | |||||
-define(V7_MTIME_LEN, 12). | |||||
-define(V7_CHKSUM, 148). | |||||
-define(V7_CHKSUM_LEN, 8). | |||||
-define(V7_TYPE, 156). | |||||
-define(V7_TYPE_LEN, 1). | |||||
-define(V7_LINKNAME, 157). | |||||
-define(V7_LINKNAME_LEN, 100). | |||||
-define(STAR_TRAILER, 508). | |||||
-define(STAR_TRAILER_LEN, 4). | |||||
-define(USTAR_MAGIC, 257). | |||||
-define(USTAR_MAGIC_LEN, 6). | |||||
-define(USTAR_VERSION, 263). | |||||
-define(USTAR_VERSION_LEN, 2). | |||||
-define(USTAR_UNAME, 265). | |||||
-define(USTAR_UNAME_LEN, 32). | |||||
-define(USTAR_GNAME, 297). | |||||
-define(USTAR_GNAME_LEN, 32). | |||||
-define(USTAR_DEVMAJ, 329). | |||||
-define(USTAR_DEVMAJ_LEN, 8). | |||||
-define(USTAR_DEVMIN, 337). | |||||
-define(USTAR_DEVMIN_LEN, 8). | |||||
-define(USTAR_PREFIX, 345). | |||||
-define(USTAR_PREFIX_LEN, 155). | |||||
-define(GNU_MAGIC, 257). | |||||
-define(GNU_MAGIC_LEN, 6). | |||||
-define(GNU_VERSION, 263). | |||||
-define(GNU_VERSION_LEN, 2). | |||||
%% ?BLOCK_SIZE of zero-bytes. | |||||
%% Two of these in a row mark the end of an archive. | |||||
-define(ZERO_BLOCK, <<0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0, | |||||
0,0,0,0,0,0,0,0,0,0,0,0>>). | |||||
-define(BILLION, 1000000000). | |||||
-define(EPOCH, {{1970,1,1}, {0,0,0}}). |
@ -0,0 +1,60 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
% @private | |||||
% Excerpt from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/filename.erl#L761-L788 | |||||
% with modifications for changing local function calls to remote function calls | |||||
% to the `filename` module, for the functions `pathtype/1`, `split/1`, and `join/1` | |||||
% | |||||
% safe_relative_path/1 was not present in earlier OTP releases. | |||||
%% | |||||
%% %CopyrightBegin% | |||||
%% | |||||
%% Copyright Ericsson AB 1997-2017. All Rights Reserved. | |||||
%% | |||||
%% Licensed under the Apache License, Version 2.0 (the "License"); | |||||
%% you may not use this file except in compliance with the License. | |||||
%% You may obtain a copy of the License at | |||||
%% | |||||
%% http://www.apache.org/licenses/LICENSE-2.0 | |||||
%% | |||||
%% Unless required by applicable law or agreed to in writing, software | |||||
%% distributed under the License is distributed on an "AS IS" BASIS, | |||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
%% See the License for the specific language governing permissions and | |||||
%% limitations under the License. | |||||
%% | |||||
%% %CopyrightEnd% | |||||
%% | |||||
-module(r3_hex_filename). | |||||
-export([safe_relative_path/1]). | |||||
safe_relative_path(Path) -> | |||||
case filename:pathtype(Path) of | |||||
relative -> | |||||
Cs0 = filename:split(Path), | |||||
safe_relative_path_1(Cs0, []); | |||||
_ -> | |||||
unsafe | |||||
end. | |||||
safe_relative_path_1(["."|T], Acc) -> | |||||
safe_relative_path_1(T, Acc); | |||||
safe_relative_path_1([<<".">>|T], Acc) -> | |||||
safe_relative_path_1(T, Acc); | |||||
safe_relative_path_1([".."|T], Acc) -> | |||||
climb(T, Acc); | |||||
safe_relative_path_1([<<"..">>|T], Acc) -> | |||||
climb(T, Acc); | |||||
safe_relative_path_1([H|T], Acc) -> | |||||
safe_relative_path_1(T, [H|Acc]); | |||||
safe_relative_path_1([], []) -> | |||||
[]; | |||||
safe_relative_path_1([], Acc) -> | |||||
filename:join(lists:reverse(Acc)). | |||||
climb(_, []) -> | |||||
unsafe; | |||||
climb(T, [_|Acc]) -> | |||||
safe_relative_path_1(T, Acc). |
@ -0,0 +1,43 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_http). | |||||
-export([request/5]). | |||||
-ifdef(TEST). | |||||
-export([user_agent/1]). | |||||
-endif. | |||||
-include_lib("r3_hex_core.hrl"). | |||||
-type method() :: get | post | put | patch | delete. | |||||
-type status() :: non_neg_integer(). | |||||
-type headers() :: #{binary() => binary()}. | |||||
-type body() :: {ContentType :: binary(), Body :: binary()} | undefined. | |||||
-type adapter_config() :: map(). | |||||
-callback request(method(), URI :: binary(), headers(), body(), adapter_config()) -> | |||||
{ok, status(), headers(), binary()} | | |||||
{error, term()}. | |||||
-spec request(r3_hex_core:config(), method(), URI :: binary(), headers(), body()) -> | |||||
{ok, {status(), headers(), binary()}} | {error, term()}. | |||||
request(Config, Method, URI, Headers, Body) when is_binary(URI) and is_map(Headers) -> | |||||
Adapter = maps:get(http_adapter, Config), | |||||
UserAgentFragment = maps:get(http_user_agent_fragment, Config), | |||||
Headers2 = put_new(<<"user-agent">>, user_agent(UserAgentFragment), Headers), | |||||
AdapterConfig = maps:get(http_adapter_config, Config, #{}), | |||||
Adapter:request(Method, URI, Headers2, Body, AdapterConfig). | |||||
user_agent(UserAgentFragment) -> | |||||
OTPRelease = erlang:system_info(otp_release), | |||||
ERTSVersion = erlang:system_info(version), | |||||
OTPString = " (OTP/" ++ OTPRelease ++ ") (erts/" ++ ERTSVersion ++ ")", | |||||
iolist_to_binary(["hex_core/", ?HEX_CORE_VERSION, " ", UserAgentFragment, OTPString]). | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
put_new(Key, Value, Map) -> | |||||
case maps:find(Key, Map) of | |||||
{ok, _} -> Map; | |||||
error -> maps:put(Key, Value, Map) | |||||
end. |
@ -0,0 +1,39 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% @hidden | |||||
-module(r3_hex_http_httpc). | |||||
-behaviour(r3_hex_http). | |||||
-export([request/5]). | |||||
%%==================================================================== | |||||
%% API functions | |||||
%%==================================================================== | |||||
request(Method, URI, ReqHeaders, Body, AdapterConfig) -> | |||||
Profile = maps:get(profile, AdapterConfig, default), | |||||
Request = build_request(URI, ReqHeaders, Body), | |||||
{ok, {{_, StatusCode, _}, RespHeaders, RespBody}} = | |||||
httpc:request(Method, Request, [], [{body_format, binary}], Profile), | |||||
RespHeaders2 = load_headers(RespHeaders), | |||||
{ok, {StatusCode, RespHeaders2, RespBody}}. | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
build_request(URI, ReqHeaders, Body) -> | |||||
build_request2(binary_to_list(URI), dump_headers(ReqHeaders), Body). | |||||
build_request2(URI, ReqHeaders, undefined) -> | |||||
{URI, ReqHeaders}; | |||||
build_request2(URI, ReqHeaders, {ContentType, Body}) -> | |||||
{URI, ReqHeaders, ContentType, Body}. | |||||
dump_headers(Map) -> | |||||
maps:fold(fun(K, V, Acc) -> | |||||
[{binary_to_list(K), binary_to_list(V)} | Acc] end, [], Map). | |||||
load_headers(List) -> | |||||
lists:foldl(fun({K, V}, Acc) -> | |||||
maps:put(list_to_binary(K), list_to_binary(V), Acc) end, #{}, List). |
@ -0,0 +1,735 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% -*- coding: utf-8 -*- | |||||
%% Automatically generated, do not edit | |||||
%% Generated by gpb_compile version 4.3.1 | |||||
-module(r3_hex_pb_names). | |||||
-export([encode_msg/2, encode_msg/3]). | |||||
-export([decode_msg/2, decode_msg/3]). | |||||
-export([merge_msgs/3, merge_msgs/4]). | |||||
-export([verify_msg/2, verify_msg/3]). | |||||
-export([get_msg_defs/0]). | |||||
-export([get_msg_names/0]). | |||||
-export([get_group_names/0]). | |||||
-export([get_msg_or_group_names/0]). | |||||
-export([get_enum_names/0]). | |||||
-export([find_msg_def/1, fetch_msg_def/1]). | |||||
-export([find_enum_def/1, fetch_enum_def/1]). | |||||
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]). | |||||
-export([get_service_names/0]). | |||||
-export([get_service_def/1]). | |||||
-export([get_rpc_names/1]). | |||||
-export([find_rpc_def/2, fetch_rpc_def/2]). | |||||
-export([get_package_name/0]). | |||||
-export([gpb_version_as_string/0, gpb_version_as_list/0]). | |||||
%% enumerated types | |||||
-export_type([]). | |||||
%% message types | |||||
-type 'Names'() :: | |||||
#{packages => ['Package'()], % = 1 | |||||
repository => iodata() % = 2 | |||||
}. | |||||
-type 'Package'() :: | |||||
#{name => iodata() % = 1 | |||||
}. | |||||
-export_type(['Names'/0, 'Package'/0]). | |||||
-spec encode_msg('Names'() | 'Package'(), atom()) -> binary(). | |||||
encode_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
encode_msg(Msg, MsgName, []). | |||||
-spec encode_msg('Names'() | 'Package'(), atom(), list()) -> binary(). | |||||
encode_msg(Msg, MsgName, Opts) -> | |||||
verify_msg(Msg, MsgName, Opts), | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Names' -> e_msg_Names(id(Msg, TrUserData), TrUserData); | |||||
'Package' -> | |||||
e_msg_Package(id(Msg, TrUserData), TrUserData) | |||||
end. | |||||
e_msg_Names(Msg, TrUserData) -> | |||||
e_msg_Names(Msg, <<>>, TrUserData). | |||||
e_msg_Names(#{repository := F2} = M, Bin, TrUserData) -> | |||||
B1 = case M of | |||||
#{packages := F1} -> | |||||
TrF1 = id(F1, TrUserData), | |||||
if TrF1 == [] -> Bin; | |||||
true -> e_field_Names_packages(TrF1, Bin, TrUserData) | |||||
end; | |||||
_ -> Bin | |||||
end, | |||||
begin | |||||
TrF2 = id(F2, TrUserData), | |||||
e_type_string(TrF2, <<B1/binary, 18>>, TrUserData) | |||||
end. | |||||
e_msg_Package(Msg, TrUserData) -> | |||||
e_msg_Package(Msg, <<>>, TrUserData). | |||||
e_msg_Package(#{name := F1}, Bin, TrUserData) -> | |||||
begin | |||||
TrF1 = id(F1, TrUserData), | |||||
e_type_string(TrF1, <<Bin/binary, 10>>, TrUserData) | |||||
end. | |||||
e_mfield_Names_packages(Msg, Bin, TrUserData) -> | |||||
SubBin = e_msg_Package(Msg, <<>>, TrUserData), | |||||
Bin2 = e_varint(byte_size(SubBin), Bin), | |||||
<<Bin2/binary, SubBin/binary>>. | |||||
e_field_Names_packages([Elem | Rest], Bin, | |||||
TrUserData) -> | |||||
Bin2 = <<Bin/binary, 10>>, | |||||
Bin3 = e_mfield_Names_packages(id(Elem, TrUserData), | |||||
Bin2, TrUserData), | |||||
e_field_Names_packages(Rest, Bin3, TrUserData); | |||||
e_field_Names_packages([], Bin, _TrUserData) -> Bin. | |||||
-compile({nowarn_unused_function,e_type_sint/3}). | |||||
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> | |||||
e_varint(Value * 2, Bin); | |||||
e_type_sint(Value, Bin, _TrUserData) -> | |||||
e_varint(Value * -2 - 1, Bin). | |||||
-compile({nowarn_unused_function,e_type_int32/3}). | |||||
e_type_int32(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int32(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_int64/3}). | |||||
e_type_int64(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int64(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_bool/3}). | |||||
e_type_bool(true, Bin, _TrUserData) -> | |||||
<<Bin/binary, 1>>; | |||||
e_type_bool(false, Bin, _TrUserData) -> | |||||
<<Bin/binary, 0>>; | |||||
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>; | |||||
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>. | |||||
-compile({nowarn_unused_function,e_type_string/3}). | |||||
e_type_string(S, Bin, _TrUserData) -> | |||||
Utf8 = unicode:characters_to_binary(S), | |||||
Bin2 = e_varint(byte_size(Utf8), Bin), | |||||
<<Bin2/binary, Utf8/binary>>. | |||||
-compile({nowarn_unused_function,e_type_bytes/3}). | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_binary(Bytes) -> | |||||
Bin2 = e_varint(byte_size(Bytes), Bin), | |||||
<<Bin2/binary, Bytes/binary>>; | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_list(Bytes) -> | |||||
BytesBin = iolist_to_binary(Bytes), | |||||
Bin2 = e_varint(byte_size(BytesBin), Bin), | |||||
<<Bin2/binary, BytesBin/binary>>. | |||||
-compile({nowarn_unused_function,e_type_fixed32/3}). | |||||
e_type_fixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed32/3}). | |||||
e_type_sfixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_fixed64/3}). | |||||
e_type_fixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed64/3}). | |||||
e_type_sfixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_float/3}). | |||||
e_type_float(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:32/little-float>>; | |||||
e_type_float(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 127>>; | |||||
e_type_float('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 255>>; | |||||
e_type_float(nan, Bin, _) -> | |||||
<<Bin/binary, 0:16, 192, 127>>. | |||||
-compile({nowarn_unused_function,e_type_double/3}). | |||||
e_type_double(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:64/little-float>>; | |||||
e_type_double(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 127>>; | |||||
e_type_double('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 255>>; | |||||
e_type_double(nan, Bin, _) -> | |||||
<<Bin/binary, 0:48, 248, 127>>. | |||||
-compile({nowarn_unused_function,e_varint/3}). | |||||
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_varint/2}). | |||||
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>; | |||||
e_varint(N, Bin) -> | |||||
Bin2 = <<Bin/binary, (N band 127 bor 128)>>, | |||||
e_varint(N bsr 7, Bin2). | |||||
decode_msg(Bin, MsgName) when is_binary(Bin) -> | |||||
decode_msg(Bin, MsgName, []). | |||||
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData). | |||||
-ifdef('OTP_RELEASE'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
-ifdef('GPB_PATTERN_STACK'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason -> | |||||
StackTrace = erlang:get_stacktrace(), | |||||
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-endif. | |||||
-endif. | |||||
decode_msg_2_doit('Names', Bin, TrUserData) -> | |||||
id(d_msg_Names(Bin, TrUserData), TrUserData); | |||||
decode_msg_2_doit('Package', Bin, TrUserData) -> | |||||
id(d_msg_Package(Bin, TrUserData), TrUserData). | |||||
d_msg_Names(Bin, TrUserData) -> | |||||
dfp_read_field_def_Names(Bin, 0, 0, id([], TrUserData), | |||||
id('$undef', TrUserData), TrUserData). | |||||
dfp_read_field_def_Names(<<10, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Names_packages(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Names(<<18, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Names_repository(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Names(<<>>, 0, 0, R1, F@_2, | |||||
TrUserData) -> | |||||
S1 = #{repository => F@_2}, | |||||
if R1 == '$undef' -> S1; | |||||
true -> S1#{packages => lists_reverse(R1, TrUserData)} | |||||
end; | |||||
dfp_read_field_def_Names(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
dg_read_field_def_Names(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
dg_read_field_def_Names(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 32 - 7 -> | |||||
dg_read_field_def_Names(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
dg_read_field_def_Names(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) -> | |||||
Key = X bsl N + Acc, | |||||
case Key of | |||||
10 -> | |||||
d_field_Names_packages(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
18 -> | |||||
d_field_Names_repository(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
_ -> | |||||
case Key band 7 of | |||||
0 -> | |||||
skip_varint_Names(Rest, 0, 0, F@_1, F@_2, TrUserData); | |||||
1 -> skip_64_Names(Rest, 0, 0, F@_1, F@_2, TrUserData); | |||||
2 -> | |||||
skip_length_delimited_Names(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
3 -> | |||||
skip_group_Names(Rest, Key bsr 3, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
5 -> skip_32_Names(Rest, 0, 0, F@_1, F@_2, TrUserData) | |||||
end | |||||
end; | |||||
dg_read_field_def_Names(<<>>, 0, 0, R1, F@_2, | |||||
TrUserData) -> | |||||
S1 = #{repository => F@_2}, | |||||
if R1 == '$undef' -> S1; | |||||
true -> S1#{packages => lists_reverse(R1, TrUserData)} | |||||
end. | |||||
d_field_Names_packages(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Names_packages(Rest, N + 7, X bsl N + Acc, F@_1, | |||||
F@_2, TrUserData); | |||||
d_field_Names_packages(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, Prev, F@_2, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bs:Len/binary, Rest2/binary>> = Rest, | |||||
{id(d_msg_Package(Bs, TrUserData), TrUserData), | |||||
Rest2} | |||||
end, | |||||
dfp_read_field_def_Names(RestF, 0, 0, | |||||
cons(NewFValue, Prev, TrUserData), F@_2, | |||||
TrUserData). | |||||
d_field_Names_repository(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Names_repository(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
d_field_Names_repository(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, _, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Names(RestF, 0, 0, F@_1, NewFValue, | |||||
TrUserData). | |||||
skip_varint_Names(<<1:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
skip_varint_Names(Rest, Z1, Z2, F@_1, F@_2, TrUserData); | |||||
skip_varint_Names(<<0:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_length_delimited_Names(<<1:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
skip_length_delimited_Names(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
skip_length_delimited_Names(<<0:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) -> | |||||
Length = X bsl N + Acc, | |||||
<<_:Length/binary, Rest2/binary>> = Rest, | |||||
dfp_read_field_def_Names(Rest2, 0, 0, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_group_Names(Bin, FNum, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
{_, Rest} = read_group(Bin, FNum), | |||||
dfp_read_field_def_Names(Rest, 0, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_32_Names(<<_:32, Rest/binary>>, Z1, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_64_Names(<<_:64, Rest/binary>>, Z1, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
dfp_read_field_def_Names(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
d_msg_Package(Bin, TrUserData) -> | |||||
dfp_read_field_def_Package(Bin, 0, 0, | |||||
id('$undef', TrUserData), TrUserData). | |||||
dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, | |||||
F@_1, TrUserData) -> | |||||
d_field_Package_name(Rest, Z1, Z2, F@_1, TrUserData); | |||||
dfp_read_field_def_Package(<<>>, 0, 0, F@_1, _) -> | |||||
#{name => F@_1}; | |||||
dfp_read_field_def_Package(Other, Z1, Z2, F@_1, | |||||
TrUserData) -> | |||||
dg_read_field_def_Package(Other, Z1, Z2, F@_1, | |||||
TrUserData). | |||||
dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, TrUserData) | |||||
when N < 32 - 7 -> | |||||
dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, TrUserData); | |||||
dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, TrUserData) -> | |||||
Key = X bsl N + Acc, | |||||
case Key of | |||||
10 -> | |||||
d_field_Package_name(Rest, 0, 0, F@_1, TrUserData); | |||||
_ -> | |||||
case Key band 7 of | |||||
0 -> skip_varint_Package(Rest, 0, 0, F@_1, TrUserData); | |||||
1 -> skip_64_Package(Rest, 0, 0, F@_1, TrUserData); | |||||
2 -> | |||||
skip_length_delimited_Package(Rest, 0, 0, F@_1, | |||||
TrUserData); | |||||
3 -> | |||||
skip_group_Package(Rest, Key bsr 3, 0, F@_1, | |||||
TrUserData); | |||||
5 -> skip_32_Package(Rest, 0, 0, F@_1, TrUserData) | |||||
end | |||||
end; | |||||
dg_read_field_def_Package(<<>>, 0, 0, F@_1, _) -> | |||||
#{name => F@_1}. | |||||
d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, | |||||
F@_1, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Package_name(Rest, N + 7, X bsl N + Acc, F@_1, | |||||
TrUserData); | |||||
d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, | |||||
_, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Package(RestF, 0, 0, NewFValue, | |||||
TrUserData). | |||||
skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, TrUserData) -> | |||||
skip_varint_Package(Rest, Z1, Z2, F@_1, TrUserData); | |||||
skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, | |||||
TrUserData). | |||||
skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, TrUserData) | |||||
when N < 57 -> | |||||
skip_length_delimited_Package(Rest, N + 7, | |||||
X bsl N + Acc, F@_1, TrUserData); | |||||
skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, TrUserData) -> | |||||
Length = X bsl N + Acc, | |||||
<<_:Length/binary, Rest2/binary>> = Rest, | |||||
dfp_read_field_def_Package(Rest2, 0, 0, F@_1, | |||||
TrUserData). | |||||
skip_group_Package(Bin, FNum, Z2, F@_1, TrUserData) -> | |||||
{_, Rest} = read_group(Bin, FNum), | |||||
dfp_read_field_def_Package(Rest, 0, Z2, F@_1, | |||||
TrUserData). | |||||
skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F@_1, | |||||
TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, | |||||
TrUserData). | |||||
skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F@_1, | |||||
TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, | |||||
TrUserData). | |||||
read_group(Bin, FieldNum) -> | |||||
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), | |||||
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin, | |||||
{Group, Rest}. | |||||
%% Like skipping over fields, but record the total length, | |||||
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue> | |||||
%% Record the length because varints may be non-optimally encoded. | |||||
%% | |||||
%% Groups can be nested, but assume the same FieldNum cannot be nested | |||||
%% because group field numbers are shared with the rest of the fields | |||||
%% numbers. Thus we can search just for an group-end with the same | |||||
%% field number. | |||||
%% | |||||
%% (The only time the same group field number could occur would | |||||
%% be in a nested sub message, but then it would be inside a | |||||
%% length-delimited entry, which we skip-read by length.) | |||||
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) | |||||
when N < (32-7) -> | |||||
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); | |||||
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, | |||||
FieldNum) -> | |||||
Key = X bsl N + Acc, | |||||
TagLen1 = TagLen + 1, | |||||
case {Key bsr 3, Key band 7} of | |||||
{FieldNum, 4} -> % 4 = group_end | |||||
{NumBytes, TagLen1}; | |||||
{_, 0} -> % 0 = varint | |||||
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 1} -> % 1 = bits64 | |||||
<<_:64, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); | |||||
{_, 2} -> % 2 = length_delimited | |||||
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 3} -> % 3 = group_start | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 4} -> % 4 = group_end | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 5} -> % 5 = bits32 | |||||
<<_:32, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) | |||||
end. | |||||
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); | |||||
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> | |||||
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). | |||||
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); | |||||
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> | |||||
Len = X bsl N + Acc, | |||||
NumBytes1 = NumBytes + 1, | |||||
<<_:Len/binary, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). | |||||
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> | |||||
merge_msgs(Prev, New, MsgName, []). | |||||
merge_msgs(Prev, New, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Names' -> merge_msg_Names(Prev, New, TrUserData); | |||||
'Package' -> merge_msg_Package(Prev, New, TrUserData) | |||||
end. | |||||
-compile({nowarn_unused_function,merge_msg_Names/3}). | |||||
merge_msg_Names(#{} = PMsg, | |||||
#{repository := NFrepository} = NMsg, TrUserData) -> | |||||
S1 = #{repository => NFrepository}, | |||||
case {PMsg, NMsg} of | |||||
{#{packages := PFpackages}, | |||||
#{packages := NFpackages}} -> | |||||
S1#{packages => | |||||
'erlang_++'(PFpackages, NFpackages, TrUserData)}; | |||||
{_, #{packages := NFpackages}} -> | |||||
S1#{packages => NFpackages}; | |||||
{#{packages := PFpackages}, _} -> | |||||
S1#{packages => PFpackages}; | |||||
{_, _} -> S1 | |||||
end. | |||||
-compile({nowarn_unused_function,merge_msg_Package/3}). | |||||
merge_msg_Package(#{}, #{name := NFname}, _) -> | |||||
#{name => NFname}. | |||||
verify_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
verify_msg(Msg, MsgName, []). | |||||
verify_msg(Msg, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Names' -> v_msg_Names(Msg, [MsgName], TrUserData); | |||||
'Package' -> v_msg_Package(Msg, [MsgName], TrUserData); | |||||
_ -> mk_type_error(not_a_known_message, Msg, []) | |||||
end. | |||||
-compile({nowarn_unused_function,v_msg_Names/3}). | |||||
v_msg_Names(#{repository := F2} = M, Path, | |||||
TrUserData) -> | |||||
case M of | |||||
#{packages := F1} -> | |||||
if is_list(F1) -> | |||||
_ = [v_msg_Package(Elem, [packages | Path], TrUserData) | |||||
|| Elem <- F1], | |||||
ok; | |||||
true -> | |||||
mk_type_error({invalid_list_of, {msg, 'Package'}}, F1, | |||||
[packages | Path]) | |||||
end; | |||||
_ -> ok | |||||
end, | |||||
v_type_string(F2, [repository | Path], TrUserData), | |||||
lists:foreach(fun (packages) -> ok; | |||||
(repository) -> ok; | |||||
(OtherKey) -> | |||||
mk_type_error({extraneous_key, OtherKey}, M, Path) | |||||
end, | |||||
maps:keys(M)), | |||||
ok; | |||||
v_msg_Names(M, Path, _TrUserData) when is_map(M) -> | |||||
mk_type_error({missing_fields, | |||||
[repository] -- maps:keys(M), 'Names'}, | |||||
M, Path); | |||||
v_msg_Names(X, Path, _TrUserData) -> | |||||
mk_type_error({expected_msg, 'Names'}, X, Path). | |||||
-compile({nowarn_unused_function,v_msg_Package/3}). | |||||
v_msg_Package(#{name := F1} = M, Path, TrUserData) -> | |||||
v_type_string(F1, [name | Path], TrUserData), | |||||
lists:foreach(fun (name) -> ok; | |||||
(OtherKey) -> | |||||
mk_type_error({extraneous_key, OtherKey}, M, Path) | |||||
end, | |||||
maps:keys(M)), | |||||
ok; | |||||
v_msg_Package(M, Path, _TrUserData) when is_map(M) -> | |||||
mk_type_error({missing_fields, [name] -- maps:keys(M), | |||||
'Package'}, | |||||
M, Path); | |||||
v_msg_Package(X, Path, _TrUserData) -> | |||||
mk_type_error({expected_msg, 'Package'}, X, Path). | |||||
-compile({nowarn_unused_function,v_type_string/3}). | |||||
v_type_string(S, Path, _TrUserData) | |||||
when is_list(S); is_binary(S) -> | |||||
try unicode:characters_to_binary(S) of | |||||
B when is_binary(B) -> ok; | |||||
{error, _, _} -> | |||||
mk_type_error(bad_unicode_string, S, Path) | |||||
catch | |||||
error:badarg -> | |||||
mk_type_error(bad_unicode_string, S, Path) | |||||
end; | |||||
v_type_string(X, Path, _TrUserData) -> | |||||
mk_type_error(bad_unicode_string, X, Path). | |||||
-compile({nowarn_unused_function,mk_type_error/3}). | |||||
-spec mk_type_error(_, _, list()) -> no_return(). | |||||
mk_type_error(Error, ValueSeen, Path) -> | |||||
Path2 = prettify_path(Path), | |||||
erlang:error({gpb_type_error, | |||||
{Error, [{value, ValueSeen}, {path, Path2}]}}). | |||||
-compile({nowarn_unused_function,prettify_path/1}). | |||||
prettify_path([]) -> top_level; | |||||
prettify_path(PathR) -> | |||||
list_to_atom(string:join(lists:map(fun atom_to_list/1, | |||||
lists:reverse(PathR)), | |||||
".")). | |||||
-compile({nowarn_unused_function,id/2}). | |||||
-compile({inline,id/2}). | |||||
id(X, _TrUserData) -> X. | |||||
-compile({nowarn_unused_function,v_ok/3}). | |||||
-compile({inline,v_ok/3}). | |||||
v_ok(_Value, _Path, _TrUserData) -> ok. | |||||
-compile({nowarn_unused_function,m_overwrite/3}). | |||||
-compile({inline,m_overwrite/3}). | |||||
m_overwrite(_Prev, New, _TrUserData) -> New. | |||||
-compile({nowarn_unused_function,cons/3}). | |||||
-compile({inline,cons/3}). | |||||
cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. | |||||
-compile({nowarn_unused_function,lists_reverse/2}). | |||||
-compile({inline,lists_reverse/2}). | |||||
'lists_reverse'(L, _TrUserData) -> lists:reverse(L). | |||||
-compile({nowarn_unused_function,'erlang_++'/3}). | |||||
-compile({inline,'erlang_++'/3}). | |||||
'erlang_++'(A, B, _TrUserData) -> A ++ B. | |||||
get_msg_defs() -> | |||||
[{{msg, 'Names'}, | |||||
[#{name => packages, fnum => 1, rnum => 2, | |||||
type => {msg, 'Package'}, occurrence => repeated, | |||||
opts => []}, | |||||
#{name => repository, fnum => 2, rnum => 3, | |||||
type => string, occurrence => required, opts => []}]}, | |||||
{{msg, 'Package'}, | |||||
[#{name => name, fnum => 1, rnum => 2, type => string, | |||||
occurrence => required, opts => []}]}]. | |||||
get_msg_names() -> ['Names', 'Package']. | |||||
get_group_names() -> []. | |||||
get_msg_or_group_names() -> ['Names', 'Package']. | |||||
get_enum_names() -> []. | |||||
fetch_msg_def(MsgName) -> | |||||
case find_msg_def(MsgName) of | |||||
Fs when is_list(Fs) -> Fs; | |||||
error -> erlang:error({no_such_msg, MsgName}) | |||||
end. | |||||
-spec fetch_enum_def(_) -> no_return(). | |||||
fetch_enum_def(EnumName) -> | |||||
erlang:error({no_such_enum, EnumName}). | |||||
find_msg_def('Names') -> | |||||
[#{name => packages, fnum => 1, rnum => 2, | |||||
type => {msg, 'Package'}, occurrence => repeated, | |||||
opts => []}, | |||||
#{name => repository, fnum => 2, rnum => 3, | |||||
type => string, occurrence => required, opts => []}]; | |||||
find_msg_def('Package') -> | |||||
[#{name => name, fnum => 1, rnum => 2, type => string, | |||||
occurrence => required, opts => []}]; | |||||
find_msg_def(_) -> error. | |||||
find_enum_def(_) -> error. | |||||
-spec enum_symbol_by_value(_, _) -> no_return(). | |||||
enum_symbol_by_value(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
-spec enum_value_by_symbol(_, _) -> no_return(). | |||||
enum_value_by_symbol(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
get_service_names() -> []. | |||||
get_service_def(_) -> error. | |||||
get_rpc_names(_) -> error. | |||||
find_rpc_def(_, _) -> error. | |||||
-spec fetch_rpc_def(_, _) -> no_return(). | |||||
fetch_rpc_def(ServiceName, RpcName) -> | |||||
erlang:error({no_such_rpc, ServiceName, RpcName}). | |||||
get_package_name() -> undefined. | |||||
gpb_version_as_string() -> | |||||
"4.3.1". | |||||
gpb_version_as_list() -> | |||||
[4,3,1]. |
@ -0,0 +1,564 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% -*- coding: utf-8 -*- | |||||
%% Automatically generated, do not edit | |||||
%% Generated by gpb_compile version 4.3.1 | |||||
-module(r3_hex_pb_signed). | |||||
-export([encode_msg/2, encode_msg/3]). | |||||
-export([decode_msg/2, decode_msg/3]). | |||||
-export([merge_msgs/3, merge_msgs/4]). | |||||
-export([verify_msg/2, verify_msg/3]). | |||||
-export([get_msg_defs/0]). | |||||
-export([get_msg_names/0]). | |||||
-export([get_group_names/0]). | |||||
-export([get_msg_or_group_names/0]). | |||||
-export([get_enum_names/0]). | |||||
-export([find_msg_def/1, fetch_msg_def/1]). | |||||
-export([find_enum_def/1, fetch_enum_def/1]). | |||||
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]). | |||||
-export([get_service_names/0]). | |||||
-export([get_service_def/1]). | |||||
-export([get_rpc_names/1]). | |||||
-export([find_rpc_def/2, fetch_rpc_def/2]). | |||||
-export([get_package_name/0]). | |||||
-export([gpb_version_as_string/0, gpb_version_as_list/0]). | |||||
%% enumerated types | |||||
-export_type([]). | |||||
%% message types | |||||
-type 'Signed'() :: | |||||
#{payload => iodata() % = 1 | |||||
%% signature => iodata() % = 2 | |||||
}. | |||||
-export_type(['Signed'/0]). | |||||
-spec encode_msg('Signed'(), atom()) -> binary(). | |||||
encode_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
encode_msg(Msg, MsgName, []). | |||||
-spec encode_msg('Signed'(), atom(), list()) -> binary(). | |||||
encode_msg(Msg, MsgName, Opts) -> | |||||
verify_msg(Msg, MsgName, Opts), | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Signed' -> | |||||
e_msg_Signed(id(Msg, TrUserData), TrUserData) | |||||
end. | |||||
e_msg_Signed(Msg, TrUserData) -> | |||||
e_msg_Signed(Msg, <<>>, TrUserData). | |||||
e_msg_Signed(#{payload := F1} = M, Bin, TrUserData) -> | |||||
B1 = begin | |||||
TrF1 = id(F1, TrUserData), | |||||
e_type_bytes(TrF1, <<Bin/binary, 10>>, TrUserData) | |||||
end, | |||||
case M of | |||||
#{signature := F2} -> | |||||
begin | |||||
TrF2 = id(F2, TrUserData), | |||||
e_type_bytes(TrF2, <<B1/binary, 18>>, TrUserData) | |||||
end; | |||||
_ -> B1 | |||||
end. | |||||
-compile({nowarn_unused_function,e_type_sint/3}). | |||||
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> | |||||
e_varint(Value * 2, Bin); | |||||
e_type_sint(Value, Bin, _TrUserData) -> | |||||
e_varint(Value * -2 - 1, Bin). | |||||
-compile({nowarn_unused_function,e_type_int32/3}). | |||||
e_type_int32(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int32(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_int64/3}). | |||||
e_type_int64(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int64(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_bool/3}). | |||||
e_type_bool(true, Bin, _TrUserData) -> | |||||
<<Bin/binary, 1>>; | |||||
e_type_bool(false, Bin, _TrUserData) -> | |||||
<<Bin/binary, 0>>; | |||||
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>; | |||||
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>. | |||||
-compile({nowarn_unused_function,e_type_string/3}). | |||||
e_type_string(S, Bin, _TrUserData) -> | |||||
Utf8 = unicode:characters_to_binary(S), | |||||
Bin2 = e_varint(byte_size(Utf8), Bin), | |||||
<<Bin2/binary, Utf8/binary>>. | |||||
-compile({nowarn_unused_function,e_type_bytes/3}). | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_binary(Bytes) -> | |||||
Bin2 = e_varint(byte_size(Bytes), Bin), | |||||
<<Bin2/binary, Bytes/binary>>; | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_list(Bytes) -> | |||||
BytesBin = iolist_to_binary(Bytes), | |||||
Bin2 = e_varint(byte_size(BytesBin), Bin), | |||||
<<Bin2/binary, BytesBin/binary>>. | |||||
-compile({nowarn_unused_function,e_type_fixed32/3}). | |||||
e_type_fixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed32/3}). | |||||
e_type_sfixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_fixed64/3}). | |||||
e_type_fixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed64/3}). | |||||
e_type_sfixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_float/3}). | |||||
e_type_float(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:32/little-float>>; | |||||
e_type_float(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 127>>; | |||||
e_type_float('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 255>>; | |||||
e_type_float(nan, Bin, _) -> | |||||
<<Bin/binary, 0:16, 192, 127>>. | |||||
-compile({nowarn_unused_function,e_type_double/3}). | |||||
e_type_double(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:64/little-float>>; | |||||
e_type_double(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 127>>; | |||||
e_type_double('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 255>>; | |||||
e_type_double(nan, Bin, _) -> | |||||
<<Bin/binary, 0:48, 248, 127>>. | |||||
-compile({nowarn_unused_function,e_varint/3}). | |||||
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_varint/2}). | |||||
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>; | |||||
e_varint(N, Bin) -> | |||||
Bin2 = <<Bin/binary, (N band 127 bor 128)>>, | |||||
e_varint(N bsr 7, Bin2). | |||||
decode_msg(Bin, MsgName) when is_binary(Bin) -> | |||||
decode_msg(Bin, MsgName, []). | |||||
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData). | |||||
-ifdef('OTP_RELEASE'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
-ifdef('GPB_PATTERN_STACK'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason -> | |||||
StackTrace = erlang:get_stacktrace(), | |||||
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-endif. | |||||
-endif. | |||||
decode_msg_2_doit('Signed', Bin, TrUserData) -> | |||||
id(d_msg_Signed(Bin, TrUserData), TrUserData). | |||||
d_msg_Signed(Bin, TrUserData) -> | |||||
dfp_read_field_def_Signed(Bin, 0, 0, | |||||
id('$undef', TrUserData), | |||||
id('$undef', TrUserData), TrUserData). | |||||
dfp_read_field_def_Signed(<<10, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Signed_payload(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Signed(<<18, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Signed_signature(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Signed(<<>>, 0, 0, F@_1, F@_2, _) -> | |||||
S1 = #{payload => F@_1}, | |||||
if F@_2 == '$undef' -> S1; | |||||
true -> S1#{signature => F@_2} | |||||
end; | |||||
dfp_read_field_def_Signed(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
dg_read_field_def_Signed(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
dg_read_field_def_Signed(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 32 - 7 -> | |||||
dg_read_field_def_Signed(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
dg_read_field_def_Signed(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) -> | |||||
Key = X bsl N + Acc, | |||||
case Key of | |||||
10 -> | |||||
d_field_Signed_payload(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
18 -> | |||||
d_field_Signed_signature(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
_ -> | |||||
case Key band 7 of | |||||
0 -> | |||||
skip_varint_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData); | |||||
1 -> skip_64_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData); | |||||
2 -> | |||||
skip_length_delimited_Signed(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
3 -> | |||||
skip_group_Signed(Rest, Key bsr 3, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
5 -> skip_32_Signed(Rest, 0, 0, F@_1, F@_2, TrUserData) | |||||
end | |||||
end; | |||||
dg_read_field_def_Signed(<<>>, 0, 0, F@_1, F@_2, _) -> | |||||
S1 = #{payload => F@_1}, | |||||
if F@_2 == '$undef' -> S1; | |||||
true -> S1#{signature => F@_2} | |||||
end. | |||||
d_field_Signed_payload(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Signed_payload(Rest, N + 7, X bsl N + Acc, F@_1, | |||||
F@_2, TrUserData); | |||||
d_field_Signed_payload(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, _, F@_2, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Signed(RestF, 0, 0, NewFValue, F@_2, | |||||
TrUserData). | |||||
d_field_Signed_signature(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Signed_signature(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
d_field_Signed_signature(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, _, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Signed(RestF, 0, 0, F@_1, NewFValue, | |||||
TrUserData). | |||||
skip_varint_Signed(<<1:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
skip_varint_Signed(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
skip_varint_Signed(<<0:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_length_delimited_Signed(<<1:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
skip_length_delimited_Signed(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
skip_length_delimited_Signed(<<0:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) -> | |||||
Length = X bsl N + Acc, | |||||
<<_:Length/binary, Rest2/binary>> = Rest, | |||||
dfp_read_field_def_Signed(Rest2, 0, 0, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_group_Signed(Bin, FNum, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
{_, Rest} = read_group(Bin, FNum), | |||||
dfp_read_field_def_Signed(Rest, 0, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_32_Signed(<<_:32, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, TrUserData) -> | |||||
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_64_Signed(<<_:64, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, TrUserData) -> | |||||
dfp_read_field_def_Signed(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
read_group(Bin, FieldNum) -> | |||||
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), | |||||
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin, | |||||
{Group, Rest}. | |||||
%% Like skipping over fields, but record the total length, | |||||
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue> | |||||
%% Record the length because varints may be non-optimally encoded. | |||||
%% | |||||
%% Groups can be nested, but assume the same FieldNum cannot be nested | |||||
%% because group field numbers are shared with the rest of the fields | |||||
%% numbers. Thus we can search just for an group-end with the same | |||||
%% field number. | |||||
%% | |||||
%% (The only time the same group field number could occur would | |||||
%% be in a nested sub message, but then it would be inside a | |||||
%% length-delimited entry, which we skip-read by length.) | |||||
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) | |||||
when N < (32-7) -> | |||||
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); | |||||
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, | |||||
FieldNum) -> | |||||
Key = X bsl N + Acc, | |||||
TagLen1 = TagLen + 1, | |||||
case {Key bsr 3, Key band 7} of | |||||
{FieldNum, 4} -> % 4 = group_end | |||||
{NumBytes, TagLen1}; | |||||
{_, 0} -> % 0 = varint | |||||
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 1} -> % 1 = bits64 | |||||
<<_:64, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); | |||||
{_, 2} -> % 2 = length_delimited | |||||
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 3} -> % 3 = group_start | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 4} -> % 4 = group_end | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 5} -> % 5 = bits32 | |||||
<<_:32, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) | |||||
end. | |||||
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); | |||||
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> | |||||
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). | |||||
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); | |||||
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> | |||||
Len = X bsl N + Acc, | |||||
NumBytes1 = NumBytes + 1, | |||||
<<_:Len/binary, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). | |||||
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> | |||||
merge_msgs(Prev, New, MsgName, []). | |||||
merge_msgs(Prev, New, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Signed' -> merge_msg_Signed(Prev, New, TrUserData) | |||||
end. | |||||
-compile({nowarn_unused_function,merge_msg_Signed/3}). | |||||
merge_msg_Signed(#{} = PMsg, | |||||
#{payload := NFpayload} = NMsg, _) -> | |||||
S1 = #{payload => NFpayload}, | |||||
case {PMsg, NMsg} of | |||||
{_, #{signature := NFsignature}} -> | |||||
S1#{signature => NFsignature}; | |||||
{#{signature := PFsignature}, _} -> | |||||
S1#{signature => PFsignature}; | |||||
_ -> S1 | |||||
end. | |||||
verify_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
verify_msg(Msg, MsgName, []). | |||||
verify_msg(Msg, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Signed' -> v_msg_Signed(Msg, [MsgName], TrUserData); | |||||
_ -> mk_type_error(not_a_known_message, Msg, []) | |||||
end. | |||||
-compile({nowarn_unused_function,v_msg_Signed/3}). | |||||
v_msg_Signed(#{payload := F1} = M, Path, TrUserData) -> | |||||
v_type_bytes(F1, [payload | Path], TrUserData), | |||||
case M of | |||||
#{signature := F2} -> | |||||
v_type_bytes(F2, [signature | Path], TrUserData); | |||||
_ -> ok | |||||
end, | |||||
lists:foreach(fun (payload) -> ok; | |||||
(signature) -> ok; | |||||
(OtherKey) -> | |||||
mk_type_error({extraneous_key, OtherKey}, M, Path) | |||||
end, | |||||
maps:keys(M)), | |||||
ok; | |||||
v_msg_Signed(M, Path, _TrUserData) when is_map(M) -> | |||||
mk_type_error({missing_fields, | |||||
[payload] -- maps:keys(M), 'Signed'}, | |||||
M, Path); | |||||
v_msg_Signed(X, Path, _TrUserData) -> | |||||
mk_type_error({expected_msg, 'Signed'}, X, Path). | |||||
-compile({nowarn_unused_function,v_type_bytes/3}). | |||||
v_type_bytes(B, _Path, _TrUserData) when is_binary(B) -> | |||||
ok; | |||||
v_type_bytes(B, _Path, _TrUserData) when is_list(B) -> | |||||
ok; | |||||
v_type_bytes(X, Path, _TrUserData) -> | |||||
mk_type_error(bad_binary_value, X, Path). | |||||
-compile({nowarn_unused_function,mk_type_error/3}). | |||||
-spec mk_type_error(_, _, list()) -> no_return(). | |||||
mk_type_error(Error, ValueSeen, Path) -> | |||||
Path2 = prettify_path(Path), | |||||
erlang:error({gpb_type_error, | |||||
{Error, [{value, ValueSeen}, {path, Path2}]}}). | |||||
-compile({nowarn_unused_function,prettify_path/1}). | |||||
prettify_path([]) -> top_level; | |||||
prettify_path(PathR) -> | |||||
list_to_atom(string:join(lists:map(fun atom_to_list/1, | |||||
lists:reverse(PathR)), | |||||
".")). | |||||
-compile({nowarn_unused_function,id/2}). | |||||
-compile({inline,id/2}). | |||||
id(X, _TrUserData) -> X. | |||||
-compile({nowarn_unused_function,v_ok/3}). | |||||
-compile({inline,v_ok/3}). | |||||
v_ok(_Value, _Path, _TrUserData) -> ok. | |||||
-compile({nowarn_unused_function,m_overwrite/3}). | |||||
-compile({inline,m_overwrite/3}). | |||||
m_overwrite(_Prev, New, _TrUserData) -> New. | |||||
-compile({nowarn_unused_function,cons/3}). | |||||
-compile({inline,cons/3}). | |||||
cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. | |||||
-compile({nowarn_unused_function,lists_reverse/2}). | |||||
-compile({inline,lists_reverse/2}). | |||||
'lists_reverse'(L, _TrUserData) -> lists:reverse(L). | |||||
-compile({nowarn_unused_function,'erlang_++'/3}). | |||||
-compile({inline,'erlang_++'/3}). | |||||
'erlang_++'(A, B, _TrUserData) -> A ++ B. | |||||
get_msg_defs() -> | |||||
[{{msg, 'Signed'}, | |||||
[#{name => payload, fnum => 1, rnum => 2, type => bytes, | |||||
occurrence => required, opts => []}, | |||||
#{name => signature, fnum => 2, rnum => 3, | |||||
type => bytes, occurrence => optional, opts => []}]}]. | |||||
get_msg_names() -> ['Signed']. | |||||
get_group_names() -> []. | |||||
get_msg_or_group_names() -> ['Signed']. | |||||
get_enum_names() -> []. | |||||
fetch_msg_def(MsgName) -> | |||||
case find_msg_def(MsgName) of | |||||
Fs when is_list(Fs) -> Fs; | |||||
error -> erlang:error({no_such_msg, MsgName}) | |||||
end. | |||||
-spec fetch_enum_def(_) -> no_return(). | |||||
fetch_enum_def(EnumName) -> | |||||
erlang:error({no_such_enum, EnumName}). | |||||
find_msg_def('Signed') -> | |||||
[#{name => payload, fnum => 1, rnum => 2, type => bytes, | |||||
occurrence => required, opts => []}, | |||||
#{name => signature, fnum => 2, rnum => 3, | |||||
type => bytes, occurrence => optional, opts => []}]; | |||||
find_msg_def(_) -> error. | |||||
find_enum_def(_) -> error. | |||||
-spec enum_symbol_by_value(_, _) -> no_return(). | |||||
enum_symbol_by_value(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
-spec enum_value_by_symbol(_, _) -> no_return(). | |||||
enum_value_by_symbol(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
get_service_names() -> []. | |||||
get_service_def(_) -> error. | |||||
get_rpc_names(_) -> error. | |||||
find_rpc_def(_, _) -> error. | |||||
-spec fetch_rpc_def(_, _) -> no_return(). | |||||
fetch_rpc_def(ServiceName, RpcName) -> | |||||
erlang:error({no_such_rpc, ServiceName, RpcName}). | |||||
get_package_name() -> undefined. | |||||
gpb_version_as_string() -> | |||||
"4.3.1". | |||||
gpb_version_as_list() -> | |||||
[4,3,1]. |
@ -0,0 +1,958 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%% -*- coding: utf-8 -*- | |||||
%% Automatically generated, do not edit | |||||
%% Generated by gpb_compile version 4.3.1 | |||||
-module(r3_hex_pb_versions). | |||||
-export([encode_msg/2, encode_msg/3]). | |||||
-export([decode_msg/2, decode_msg/3]). | |||||
-export([merge_msgs/3, merge_msgs/4]). | |||||
-export([verify_msg/2, verify_msg/3]). | |||||
-export([get_msg_defs/0]). | |||||
-export([get_msg_names/0]). | |||||
-export([get_group_names/0]). | |||||
-export([get_msg_or_group_names/0]). | |||||
-export([get_enum_names/0]). | |||||
-export([find_msg_def/1, fetch_msg_def/1]). | |||||
-export([find_enum_def/1, fetch_enum_def/1]). | |||||
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]). | |||||
-export([get_service_names/0]). | |||||
-export([get_service_def/1]). | |||||
-export([get_rpc_names/1]). | |||||
-export([find_rpc_def/2, fetch_rpc_def/2]). | |||||
-export([get_package_name/0]). | |||||
-export([gpb_version_as_string/0, gpb_version_as_list/0]). | |||||
%% enumerated types | |||||
-export_type([]). | |||||
%% message types | |||||
-type 'Versions'() :: | |||||
#{packages => ['Package'()], % = 1 | |||||
repository => iodata() % = 2 | |||||
}. | |||||
-type 'Package'() :: | |||||
#{name => iodata(), % = 1 | |||||
versions => [iodata()], % = 2 | |||||
retired => [integer()] % = 3, 32 bits | |||||
}. | |||||
-export_type(['Versions'/0, 'Package'/0]). | |||||
-spec encode_msg('Versions'() | 'Package'(), atom()) -> binary(). | |||||
encode_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
encode_msg(Msg, MsgName, []). | |||||
-spec encode_msg('Versions'() | 'Package'(), atom(), list()) -> binary(). | |||||
encode_msg(Msg, MsgName, Opts) -> | |||||
verify_msg(Msg, MsgName, Opts), | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Versions' -> | |||||
e_msg_Versions(id(Msg, TrUserData), TrUserData); | |||||
'Package' -> | |||||
e_msg_Package(id(Msg, TrUserData), TrUserData) | |||||
end. | |||||
e_msg_Versions(Msg, TrUserData) -> | |||||
e_msg_Versions(Msg, <<>>, TrUserData). | |||||
e_msg_Versions(#{repository := F2} = M, Bin, | |||||
TrUserData) -> | |||||
B1 = case M of | |||||
#{packages := F1} -> | |||||
TrF1 = id(F1, TrUserData), | |||||
if TrF1 == [] -> Bin; | |||||
true -> e_field_Versions_packages(TrF1, Bin, TrUserData) | |||||
end; | |||||
_ -> Bin | |||||
end, | |||||
begin | |||||
TrF2 = id(F2, TrUserData), | |||||
e_type_string(TrF2, <<B1/binary, 18>>, TrUserData) | |||||
end. | |||||
e_msg_Package(Msg, TrUserData) -> | |||||
e_msg_Package(Msg, <<>>, TrUserData). | |||||
e_msg_Package(#{name := F1} = M, Bin, TrUserData) -> | |||||
B1 = begin | |||||
TrF1 = id(F1, TrUserData), | |||||
e_type_string(TrF1, <<Bin/binary, 10>>, TrUserData) | |||||
end, | |||||
B2 = case M of | |||||
#{versions := F2} -> | |||||
TrF2 = id(F2, TrUserData), | |||||
if TrF2 == [] -> B1; | |||||
true -> e_field_Package_versions(TrF2, B1, TrUserData) | |||||
end; | |||||
_ -> B1 | |||||
end, | |||||
case M of | |||||
#{retired := F3} -> | |||||
TrF3 = id(F3, TrUserData), | |||||
if TrF3 == [] -> B2; | |||||
true -> e_field_Package_retired(TrF3, B2, TrUserData) | |||||
end; | |||||
_ -> B2 | |||||
end. | |||||
e_mfield_Versions_packages(Msg, Bin, TrUserData) -> | |||||
SubBin = e_msg_Package(Msg, <<>>, TrUserData), | |||||
Bin2 = e_varint(byte_size(SubBin), Bin), | |||||
<<Bin2/binary, SubBin/binary>>. | |||||
e_field_Versions_packages([Elem | Rest], Bin, | |||||
TrUserData) -> | |||||
Bin2 = <<Bin/binary, 10>>, | |||||
Bin3 = e_mfield_Versions_packages(id(Elem, TrUserData), | |||||
Bin2, TrUserData), | |||||
e_field_Versions_packages(Rest, Bin3, TrUserData); | |||||
e_field_Versions_packages([], Bin, _TrUserData) -> Bin. | |||||
e_field_Package_versions([Elem | Rest], Bin, | |||||
TrUserData) -> | |||||
Bin2 = <<Bin/binary, 18>>, | |||||
Bin3 = e_type_string(id(Elem, TrUserData), Bin2, | |||||
TrUserData), | |||||
e_field_Package_versions(Rest, Bin3, TrUserData); | |||||
e_field_Package_versions([], Bin, _TrUserData) -> Bin. | |||||
e_field_Package_retired(Elems, Bin, TrUserData) | |||||
when Elems =/= [] -> | |||||
SubBin = e_pfield_Package_retired(Elems, <<>>, | |||||
TrUserData), | |||||
Bin2 = <<Bin/binary, 26>>, | |||||
Bin3 = e_varint(byte_size(SubBin), Bin2), | |||||
<<Bin3/binary, SubBin/binary>>; | |||||
e_field_Package_retired([], Bin, _TrUserData) -> Bin. | |||||
e_pfield_Package_retired([Value | Rest], Bin, | |||||
TrUserData) -> | |||||
Bin2 = e_type_int32(id(Value, TrUserData), Bin, | |||||
TrUserData), | |||||
e_pfield_Package_retired(Rest, Bin2, TrUserData); | |||||
e_pfield_Package_retired([], Bin, _TrUserData) -> Bin. | |||||
-compile({nowarn_unused_function,e_type_sint/3}). | |||||
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> | |||||
e_varint(Value * 2, Bin); | |||||
e_type_sint(Value, Bin, _TrUserData) -> | |||||
e_varint(Value * -2 - 1, Bin). | |||||
-compile({nowarn_unused_function,e_type_int32/3}). | |||||
e_type_int32(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int32(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_int64/3}). | |||||
e_type_int64(Value, Bin, _TrUserData) | |||||
when 0 =< Value, Value =< 127 -> | |||||
<<Bin/binary, Value>>; | |||||
e_type_int64(Value, Bin, _TrUserData) -> | |||||
<<N:64/unsigned-native>> = <<Value:64/signed-native>>, | |||||
e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_type_bool/3}). | |||||
e_type_bool(true, Bin, _TrUserData) -> | |||||
<<Bin/binary, 1>>; | |||||
e_type_bool(false, Bin, _TrUserData) -> | |||||
<<Bin/binary, 0>>; | |||||
e_type_bool(1, Bin, _TrUserData) -> <<Bin/binary, 1>>; | |||||
e_type_bool(0, Bin, _TrUserData) -> <<Bin/binary, 0>>. | |||||
-compile({nowarn_unused_function,e_type_string/3}). | |||||
e_type_string(S, Bin, _TrUserData) -> | |||||
Utf8 = unicode:characters_to_binary(S), | |||||
Bin2 = e_varint(byte_size(Utf8), Bin), | |||||
<<Bin2/binary, Utf8/binary>>. | |||||
-compile({nowarn_unused_function,e_type_bytes/3}). | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_binary(Bytes) -> | |||||
Bin2 = e_varint(byte_size(Bytes), Bin), | |||||
<<Bin2/binary, Bytes/binary>>; | |||||
e_type_bytes(Bytes, Bin, _TrUserData) | |||||
when is_list(Bytes) -> | |||||
BytesBin = iolist_to_binary(Bytes), | |||||
Bin2 = e_varint(byte_size(BytesBin), Bin), | |||||
<<Bin2/binary, BytesBin/binary>>. | |||||
-compile({nowarn_unused_function,e_type_fixed32/3}). | |||||
e_type_fixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed32/3}). | |||||
e_type_sfixed32(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:32/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_fixed64/3}). | |||||
e_type_fixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little>>. | |||||
-compile({nowarn_unused_function,e_type_sfixed64/3}). | |||||
e_type_sfixed64(Value, Bin, _TrUserData) -> | |||||
<<Bin/binary, Value:64/little-signed>>. | |||||
-compile({nowarn_unused_function,e_type_float/3}). | |||||
e_type_float(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:32/little-float>>; | |||||
e_type_float(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 127>>; | |||||
e_type_float('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:16, 128, 255>>; | |||||
e_type_float(nan, Bin, _) -> | |||||
<<Bin/binary, 0:16, 192, 127>>. | |||||
-compile({nowarn_unused_function,e_type_double/3}). | |||||
e_type_double(V, Bin, _) when is_number(V) -> | |||||
<<Bin/binary, V:64/little-float>>; | |||||
e_type_double(infinity, Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 127>>; | |||||
e_type_double('-infinity', Bin, _) -> | |||||
<<Bin/binary, 0:48, 240, 255>>; | |||||
e_type_double(nan, Bin, _) -> | |||||
<<Bin/binary, 0:48, 248, 127>>. | |||||
-compile({nowarn_unused_function,e_varint/3}). | |||||
e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). | |||||
-compile({nowarn_unused_function,e_varint/2}). | |||||
e_varint(N, Bin) when N =< 127 -> <<Bin/binary, N>>; | |||||
e_varint(N, Bin) -> | |||||
Bin2 = <<Bin/binary, (N band 127 bor 128)>>, | |||||
e_varint(N bsr 7, Bin2). | |||||
decode_msg(Bin, MsgName) when is_binary(Bin) -> | |||||
decode_msg(Bin, MsgName, []). | |||||
decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData). | |||||
-ifdef('OTP_RELEASE'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
-ifdef('GPB_PATTERN_STACK'). | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-else. | |||||
decode_msg_1_catch(Bin, MsgName, TrUserData) -> | |||||
try decode_msg_2_doit(MsgName, Bin, TrUserData) | |||||
catch Class:Reason -> | |||||
StackTrace = erlang:get_stacktrace(), | |||||
error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) | |||||
end. | |||||
-endif. | |||||
-endif. | |||||
decode_msg_2_doit('Versions', Bin, TrUserData) -> | |||||
id(d_msg_Versions(Bin, TrUserData), TrUserData); | |||||
decode_msg_2_doit('Package', Bin, TrUserData) -> | |||||
id(d_msg_Package(Bin, TrUserData), TrUserData). | |||||
d_msg_Versions(Bin, TrUserData) -> | |||||
dfp_read_field_def_Versions(Bin, 0, 0, | |||||
id([], TrUserData), id('$undef', TrUserData), | |||||
TrUserData). | |||||
dfp_read_field_def_Versions(<<10, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Versions_packages(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Versions(<<18, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
d_field_Versions_repository(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
dfp_read_field_def_Versions(<<>>, 0, 0, R1, F@_2, | |||||
TrUserData) -> | |||||
S1 = #{repository => F@_2}, | |||||
if R1 == '$undef' -> S1; | |||||
true -> S1#{packages => lists_reverse(R1, TrUserData)} | |||||
end; | |||||
dfp_read_field_def_Versions(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
dg_read_field_def_Versions(Other, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
dg_read_field_def_Versions(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 32 - 7 -> | |||||
dg_read_field_def_Versions(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
dg_read_field_def_Versions(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) -> | |||||
Key = X bsl N + Acc, | |||||
case Key of | |||||
10 -> | |||||
d_field_Versions_packages(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
18 -> | |||||
d_field_Versions_repository(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
_ -> | |||||
case Key band 7 of | |||||
0 -> | |||||
skip_varint_Versions(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
1 -> | |||||
skip_64_Versions(Rest, 0, 0, F@_1, F@_2, TrUserData); | |||||
2 -> | |||||
skip_length_delimited_Versions(Rest, 0, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
3 -> | |||||
skip_group_Versions(Rest, Key bsr 3, 0, F@_1, F@_2, | |||||
TrUserData); | |||||
5 -> | |||||
skip_32_Versions(Rest, 0, 0, F@_1, F@_2, TrUserData) | |||||
end | |||||
end; | |||||
dg_read_field_def_Versions(<<>>, 0, 0, R1, F@_2, | |||||
TrUserData) -> | |||||
S1 = #{repository => F@_2}, | |||||
if R1 == '$undef' -> S1; | |||||
true -> S1#{packages => lists_reverse(R1, TrUserData)} | |||||
end. | |||||
d_field_Versions_packages(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Versions_packages(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
d_field_Versions_packages(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, Prev, F@_2, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bs:Len/binary, Rest2/binary>> = Rest, | |||||
{id(d_msg_Package(Bs, TrUserData), TrUserData), | |||||
Rest2} | |||||
end, | |||||
dfp_read_field_def_Versions(RestF, 0, 0, | |||||
cons(NewFValue, Prev, TrUserData), F@_2, | |||||
TrUserData). | |||||
d_field_Versions_repository(<<1:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Versions_repository(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, TrUserData); | |||||
d_field_Versions_repository(<<0:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, _, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Versions(RestF, 0, 0, F@_1, | |||||
NewFValue, TrUserData). | |||||
skip_varint_Versions(<<1:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
skip_varint_Versions(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData); | |||||
skip_varint_Versions(<<0:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, TrUserData) -> | |||||
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_length_delimited_Versions(<<1:1, X:7, | |||||
Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) | |||||
when N < 57 -> | |||||
skip_length_delimited_Versions(Rest, N + 7, | |||||
X bsl N + Acc, F@_1, F@_2, TrUserData); | |||||
skip_length_delimited_Versions(<<0:1, X:7, | |||||
Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, TrUserData) -> | |||||
Length = X bsl N + Acc, | |||||
<<_:Length/binary, Rest2/binary>> = Rest, | |||||
dfp_read_field_def_Versions(Rest2, 0, 0, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_group_Versions(Bin, FNum, Z2, F@_1, F@_2, | |||||
TrUserData) -> | |||||
{_, Rest} = read_group(Bin, FNum), | |||||
dfp_read_field_def_Versions(Rest, 0, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_32_Versions(<<_:32, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, TrUserData) -> | |||||
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
skip_64_Versions(<<_:64, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, TrUserData) -> | |||||
dfp_read_field_def_Versions(Rest, Z1, Z2, F@_1, F@_2, | |||||
TrUserData). | |||||
d_msg_Package(Bin, TrUserData) -> | |||||
dfp_read_field_def_Package(Bin, 0, 0, | |||||
id('$undef', TrUserData), id([], TrUserData), | |||||
id([], TrUserData), TrUserData). | |||||
dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
d_field_Package_name(Rest, Z1, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
d_field_Package_versions(Rest, Z1, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
d_pfield_Package_retired(Rest, Z1, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
dfp_read_field_def_Package(<<24, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
d_field_Package_retired(Rest, Z1, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
dfp_read_field_def_Package(<<>>, 0, 0, F@_1, R1, R2, | |||||
TrUserData) -> | |||||
#{name => F@_1, | |||||
versions => lists_reverse(R1, TrUserData), | |||||
retired => lists_reverse(R2, TrUserData)}; | |||||
dfp_read_field_def_Package(Other, Z1, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData) -> | |||||
dg_read_field_def_Package(Other, Z1, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 32 - 7 -> | |||||
dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, F@_3, TrUserData); | |||||
dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, F@_3, TrUserData) -> | |||||
Key = X bsl N + Acc, | |||||
case Key of | |||||
10 -> | |||||
d_field_Package_name(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
18 -> | |||||
d_field_Package_versions(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
26 -> | |||||
d_pfield_Package_retired(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
24 -> | |||||
d_field_Package_retired(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
_ -> | |||||
case Key band 7 of | |||||
0 -> | |||||
skip_varint_Package(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
1 -> | |||||
skip_64_Package(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
2 -> | |||||
skip_length_delimited_Package(Rest, 0, 0, F@_1, F@_2, | |||||
F@_3, TrUserData); | |||||
3 -> | |||||
skip_group_Package(Rest, Key bsr 3, 0, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
5 -> | |||||
skip_32_Package(Rest, 0, 0, F@_1, F@_2, F@_3, | |||||
TrUserData) | |||||
end | |||||
end; | |||||
dg_read_field_def_Package(<<>>, 0, 0, F@_1, R1, R2, | |||||
TrUserData) -> | |||||
#{name => F@_1, | |||||
versions => lists_reverse(R1, TrUserData), | |||||
retired => lists_reverse(R2, TrUserData)}. | |||||
d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, | |||||
F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Package_name(Rest, N + 7, X bsl N + Acc, F@_1, | |||||
F@_2, F@_3, TrUserData); | |||||
d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, | |||||
_, F@_2, F@_3, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Package(RestF, 0, 0, NewFValue, F@_2, | |||||
F@_3, TrUserData). | |||||
d_field_Package_versions(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Package_versions(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, F@_3, TrUserData); | |||||
d_field_Package_versions(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, Prev, F@_3, TrUserData) -> | |||||
{NewFValue, RestF} = begin | |||||
Len = X bsl N + Acc, | |||||
<<Bytes:Len/binary, Rest2/binary>> = Rest, | |||||
{id(binary:copy(Bytes), TrUserData), Rest2} | |||||
end, | |||||
dfp_read_field_def_Package(RestF, 0, 0, F@_1, | |||||
cons(NewFValue, Prev, TrUserData), F@_3, | |||||
TrUserData). | |||||
d_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 57 -> | |||||
d_field_Package_retired(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, F@_3, TrUserData); | |||||
d_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, Prev, TrUserData) -> | |||||
{NewFValue, RestF} = {begin | |||||
<<Res:32/signed-native>> = <<(X bsl N + | |||||
Acc):32/unsigned-native>>, | |||||
id(Res, TrUserData) | |||||
end, | |||||
Rest}, | |||||
dfp_read_field_def_Package(RestF, 0, 0, F@_1, F@_2, | |||||
cons(NewFValue, Prev, TrUserData), TrUserData). | |||||
d_pfield_Package_retired(<<1:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 57 -> | |||||
d_pfield_Package_retired(Rest, N + 7, X bsl N + Acc, | |||||
F@_1, F@_2, F@_3, TrUserData); | |||||
d_pfield_Package_retired(<<0:1, X:7, Rest/binary>>, N, | |||||
Acc, F@_1, F@_2, E, TrUserData) -> | |||||
Len = X bsl N + Acc, | |||||
<<PackedBytes:Len/binary, Rest2/binary>> = Rest, | |||||
NewSeq = d_packed_field_Package_retired(PackedBytes, 0, | |||||
0, E, TrUserData), | |||||
dfp_read_field_def_Package(Rest2, 0, 0, F@_1, F@_2, | |||||
NewSeq, TrUserData). | |||||
d_packed_field_Package_retired(<<1:1, X:7, | |||||
Rest/binary>>, | |||||
N, Acc, AccSeq, TrUserData) | |||||
when N < 57 -> | |||||
d_packed_field_Package_retired(Rest, N + 7, | |||||
X bsl N + Acc, AccSeq, TrUserData); | |||||
d_packed_field_Package_retired(<<0:1, X:7, | |||||
Rest/binary>>, | |||||
N, Acc, AccSeq, TrUserData) -> | |||||
{NewFValue, RestF} = {begin | |||||
<<Res:32/signed-native>> = <<(X bsl N + | |||||
Acc):32/unsigned-native>>, | |||||
id(Res, TrUserData) | |||||
end, | |||||
Rest}, | |||||
d_packed_field_Package_retired(RestF, 0, 0, | |||||
[NewFValue | AccSeq], TrUserData); | |||||
d_packed_field_Package_retired(<<>>, 0, 0, AccSeq, _) -> | |||||
AccSeq. | |||||
skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
skip_varint_Package(Rest, Z1, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData); | |||||
skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, | |||||
F@_1, F@_2, F@_3, TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, F@_3, TrUserData) | |||||
when N < 57 -> | |||||
skip_length_delimited_Package(Rest, N + 7, | |||||
X bsl N + Acc, F@_1, F@_2, F@_3, TrUserData); | |||||
skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, | |||||
N, Acc, F@_1, F@_2, F@_3, TrUserData) -> | |||||
Length = X bsl N + Acc, | |||||
<<_:Length/binary, Rest2/binary>> = Rest, | |||||
dfp_read_field_def_Package(Rest2, 0, 0, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
skip_group_Package(Bin, FNum, Z2, F@_1, F@_2, F@_3, | |||||
TrUserData) -> | |||||
{_, Rest} = read_group(Bin, FNum), | |||||
dfp_read_field_def_Package(Rest, 0, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, F@_3, TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F@_1, | |||||
F@_2, F@_3, TrUserData) -> | |||||
dfp_read_field_def_Package(Rest, Z1, Z2, F@_1, F@_2, | |||||
F@_3, TrUserData). | |||||
read_group(Bin, FieldNum) -> | |||||
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), | |||||
<<Group:NumBytes/binary, _:EndTagLen/binary, Rest/binary>> = Bin, | |||||
{Group, Rest}. | |||||
%% Like skipping over fields, but record the total length, | |||||
%% Each field is <(FieldNum bsl 3) bor FieldType> ++ <FieldValue> | |||||
%% Record the length because varints may be non-optimally encoded. | |||||
%% | |||||
%% Groups can be nested, but assume the same FieldNum cannot be nested | |||||
%% because group field numbers are shared with the rest of the fields | |||||
%% numbers. Thus we can search just for an group-end with the same | |||||
%% field number. | |||||
%% | |||||
%% (The only time the same group field number could occur would | |||||
%% be in a nested sub message, but then it would be inside a | |||||
%% length-delimited entry, which we skip-read by length.) | |||||
read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) | |||||
when N < (32-7) -> | |||||
read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); | |||||
read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, | |||||
FieldNum) -> | |||||
Key = X bsl N + Acc, | |||||
TagLen1 = TagLen + 1, | |||||
case {Key bsr 3, Key band 7} of | |||||
{FieldNum, 4} -> % 4 = group_end | |||||
{NumBytes, TagLen1}; | |||||
{_, 0} -> % 0 = varint | |||||
read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 1} -> % 1 = bits64 | |||||
<<_:64, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); | |||||
{_, 2} -> % 2 = length_delimited | |||||
read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); | |||||
{_, 3} -> % 3 = group_start | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 4} -> % 4 = group_end | |||||
read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); | |||||
{_, 5} -> % 5 = bits32 | |||||
<<_:32, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) | |||||
end. | |||||
read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); | |||||
read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> | |||||
read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). | |||||
read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) | |||||
when N < (64-7) -> | |||||
read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); | |||||
read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> | |||||
Len = X bsl N + Acc, | |||||
NumBytes1 = NumBytes + 1, | |||||
<<_:Len/binary, Tl2/binary>> = Tl, | |||||
read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). | |||||
merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> | |||||
merge_msgs(Prev, New, MsgName, []). | |||||
merge_msgs(Prev, New, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Versions' -> merge_msg_Versions(Prev, New, TrUserData); | |||||
'Package' -> merge_msg_Package(Prev, New, TrUserData) | |||||
end. | |||||
-compile({nowarn_unused_function,merge_msg_Versions/3}). | |||||
merge_msg_Versions(#{} = PMsg, | |||||
#{repository := NFrepository} = NMsg, TrUserData) -> | |||||
S1 = #{repository => NFrepository}, | |||||
case {PMsg, NMsg} of | |||||
{#{packages := PFpackages}, | |||||
#{packages := NFpackages}} -> | |||||
S1#{packages => | |||||
'erlang_++'(PFpackages, NFpackages, TrUserData)}; | |||||
{_, #{packages := NFpackages}} -> | |||||
S1#{packages => NFpackages}; | |||||
{#{packages := PFpackages}, _} -> | |||||
S1#{packages => PFpackages}; | |||||
{_, _} -> S1 | |||||
end. | |||||
-compile({nowarn_unused_function,merge_msg_Package/3}). | |||||
merge_msg_Package(#{} = PMsg, #{name := NFname} = NMsg, | |||||
TrUserData) -> | |||||
S1 = #{name => NFname}, | |||||
S2 = case {PMsg, NMsg} of | |||||
{#{versions := PFversions}, | |||||
#{versions := NFversions}} -> | |||||
S1#{versions => | |||||
'erlang_++'(PFversions, NFversions, TrUserData)}; | |||||
{_, #{versions := NFversions}} -> | |||||
S1#{versions => NFversions}; | |||||
{#{versions := PFversions}, _} -> | |||||
S1#{versions => PFversions}; | |||||
{_, _} -> S1 | |||||
end, | |||||
case {PMsg, NMsg} of | |||||
{#{retired := PFretired}, #{retired := NFretired}} -> | |||||
S2#{retired => | |||||
'erlang_++'(PFretired, NFretired, TrUserData)}; | |||||
{_, #{retired := NFretired}} -> | |||||
S2#{retired => NFretired}; | |||||
{#{retired := PFretired}, _} -> | |||||
S2#{retired => PFretired}; | |||||
{_, _} -> S2 | |||||
end. | |||||
verify_msg(Msg, MsgName) when is_atom(MsgName) -> | |||||
verify_msg(Msg, MsgName, []). | |||||
verify_msg(Msg, MsgName, Opts) -> | |||||
TrUserData = proplists:get_value(user_data, Opts), | |||||
case MsgName of | |||||
'Versions' -> | |||||
v_msg_Versions(Msg, [MsgName], TrUserData); | |||||
'Package' -> v_msg_Package(Msg, [MsgName], TrUserData); | |||||
_ -> mk_type_error(not_a_known_message, Msg, []) | |||||
end. | |||||
-compile({nowarn_unused_function,v_msg_Versions/3}). | |||||
v_msg_Versions(#{repository := F2} = M, Path, | |||||
TrUserData) -> | |||||
case M of | |||||
#{packages := F1} -> | |||||
if is_list(F1) -> | |||||
_ = [v_msg_Package(Elem, [packages | Path], TrUserData) | |||||
|| Elem <- F1], | |||||
ok; | |||||
true -> | |||||
mk_type_error({invalid_list_of, {msg, 'Package'}}, F1, | |||||
[packages | Path]) | |||||
end; | |||||
_ -> ok | |||||
end, | |||||
v_type_string(F2, [repository | Path], TrUserData), | |||||
lists:foreach(fun (packages) -> ok; | |||||
(repository) -> ok; | |||||
(OtherKey) -> | |||||
mk_type_error({extraneous_key, OtherKey}, M, Path) | |||||
end, | |||||
maps:keys(M)), | |||||
ok; | |||||
v_msg_Versions(M, Path, _TrUserData) when is_map(M) -> | |||||
mk_type_error({missing_fields, | |||||
[repository] -- maps:keys(M), 'Versions'}, | |||||
M, Path); | |||||
v_msg_Versions(X, Path, _TrUserData) -> | |||||
mk_type_error({expected_msg, 'Versions'}, X, Path). | |||||
-compile({nowarn_unused_function,v_msg_Package/3}). | |||||
v_msg_Package(#{name := F1} = M, Path, TrUserData) -> | |||||
v_type_string(F1, [name | Path], TrUserData), | |||||
case M of | |||||
#{versions := F2} -> | |||||
if is_list(F2) -> | |||||
_ = [v_type_string(Elem, [versions | Path], TrUserData) | |||||
|| Elem <- F2], | |||||
ok; | |||||
true -> | |||||
mk_type_error({invalid_list_of, string}, F2, | |||||
[versions | Path]) | |||||
end; | |||||
_ -> ok | |||||
end, | |||||
case M of | |||||
#{retired := F3} -> | |||||
if is_list(F3) -> | |||||
_ = [v_type_int32(Elem, [retired | Path], TrUserData) | |||||
|| Elem <- F3], | |||||
ok; | |||||
true -> | |||||
mk_type_error({invalid_list_of, int32}, F3, | |||||
[retired | Path]) | |||||
end; | |||||
_ -> ok | |||||
end, | |||||
lists:foreach(fun (name) -> ok; | |||||
(versions) -> ok; | |||||
(retired) -> ok; | |||||
(OtherKey) -> | |||||
mk_type_error({extraneous_key, OtherKey}, M, Path) | |||||
end, | |||||
maps:keys(M)), | |||||
ok; | |||||
v_msg_Package(M, Path, _TrUserData) when is_map(M) -> | |||||
mk_type_error({missing_fields, [name] -- maps:keys(M), | |||||
'Package'}, | |||||
M, Path); | |||||
v_msg_Package(X, Path, _TrUserData) -> | |||||
mk_type_error({expected_msg, 'Package'}, X, Path). | |||||
-compile({nowarn_unused_function,v_type_int32/3}). | |||||
v_type_int32(N, _Path, _TrUserData) | |||||
when -2147483648 =< N, N =< 2147483647 -> | |||||
ok; | |||||
v_type_int32(N, Path, _TrUserData) when is_integer(N) -> | |||||
mk_type_error({value_out_of_range, int32, signed, 32}, | |||||
N, Path); | |||||
v_type_int32(X, Path, _TrUserData) -> | |||||
mk_type_error({bad_integer, int32, signed, 32}, X, | |||||
Path). | |||||
-compile({nowarn_unused_function,v_type_string/3}). | |||||
v_type_string(S, Path, _TrUserData) | |||||
when is_list(S); is_binary(S) -> | |||||
try unicode:characters_to_binary(S) of | |||||
B when is_binary(B) -> ok; | |||||
{error, _, _} -> | |||||
mk_type_error(bad_unicode_string, S, Path) | |||||
catch | |||||
error:badarg -> | |||||
mk_type_error(bad_unicode_string, S, Path) | |||||
end; | |||||
v_type_string(X, Path, _TrUserData) -> | |||||
mk_type_error(bad_unicode_string, X, Path). | |||||
-compile({nowarn_unused_function,mk_type_error/3}). | |||||
-spec mk_type_error(_, _, list()) -> no_return(). | |||||
mk_type_error(Error, ValueSeen, Path) -> | |||||
Path2 = prettify_path(Path), | |||||
erlang:error({gpb_type_error, | |||||
{Error, [{value, ValueSeen}, {path, Path2}]}}). | |||||
-compile({nowarn_unused_function,prettify_path/1}). | |||||
prettify_path([]) -> top_level; | |||||
prettify_path(PathR) -> | |||||
list_to_atom(string:join(lists:map(fun atom_to_list/1, | |||||
lists:reverse(PathR)), | |||||
".")). | |||||
-compile({nowarn_unused_function,id/2}). | |||||
-compile({inline,id/2}). | |||||
id(X, _TrUserData) -> X. | |||||
-compile({nowarn_unused_function,v_ok/3}). | |||||
-compile({inline,v_ok/3}). | |||||
v_ok(_Value, _Path, _TrUserData) -> ok. | |||||
-compile({nowarn_unused_function,m_overwrite/3}). | |||||
-compile({inline,m_overwrite/3}). | |||||
m_overwrite(_Prev, New, _TrUserData) -> New. | |||||
-compile({nowarn_unused_function,cons/3}). | |||||
-compile({inline,cons/3}). | |||||
cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. | |||||
-compile({nowarn_unused_function,lists_reverse/2}). | |||||
-compile({inline,lists_reverse/2}). | |||||
'lists_reverse'(L, _TrUserData) -> lists:reverse(L). | |||||
-compile({nowarn_unused_function,'erlang_++'/3}). | |||||
-compile({inline,'erlang_++'/3}). | |||||
'erlang_++'(A, B, _TrUserData) -> A ++ B. | |||||
get_msg_defs() -> | |||||
[{{msg, 'Versions'}, | |||||
[#{name => packages, fnum => 1, rnum => 2, | |||||
type => {msg, 'Package'}, occurrence => repeated, | |||||
opts => []}, | |||||
#{name => repository, fnum => 2, rnum => 3, | |||||
type => string, occurrence => required, opts => []}]}, | |||||
{{msg, 'Package'}, | |||||
[#{name => name, fnum => 1, rnum => 2, type => string, | |||||
occurrence => required, opts => []}, | |||||
#{name => versions, fnum => 2, rnum => 3, | |||||
type => string, occurrence => repeated, opts => []}, | |||||
#{name => retired, fnum => 3, rnum => 4, type => int32, | |||||
occurrence => repeated, opts => [packed]}]}]. | |||||
get_msg_names() -> ['Versions', 'Package']. | |||||
get_group_names() -> []. | |||||
get_msg_or_group_names() -> ['Versions', 'Package']. | |||||
get_enum_names() -> []. | |||||
fetch_msg_def(MsgName) -> | |||||
case find_msg_def(MsgName) of | |||||
Fs when is_list(Fs) -> Fs; | |||||
error -> erlang:error({no_such_msg, MsgName}) | |||||
end. | |||||
-spec fetch_enum_def(_) -> no_return(). | |||||
fetch_enum_def(EnumName) -> | |||||
erlang:error({no_such_enum, EnumName}). | |||||
find_msg_def('Versions') -> | |||||
[#{name => packages, fnum => 1, rnum => 2, | |||||
type => {msg, 'Package'}, occurrence => repeated, | |||||
opts => []}, | |||||
#{name => repository, fnum => 2, rnum => 3, | |||||
type => string, occurrence => required, opts => []}]; | |||||
find_msg_def('Package') -> | |||||
[#{name => name, fnum => 1, rnum => 2, type => string, | |||||
occurrence => required, opts => []}, | |||||
#{name => versions, fnum => 2, rnum => 3, | |||||
type => string, occurrence => repeated, opts => []}, | |||||
#{name => retired, fnum => 3, rnum => 4, type => int32, | |||||
occurrence => repeated, opts => [packed]}]; | |||||
find_msg_def(_) -> error. | |||||
find_enum_def(_) -> error. | |||||
-spec enum_symbol_by_value(_, _) -> no_return(). | |||||
enum_symbol_by_value(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
-spec enum_value_by_symbol(_, _) -> no_return(). | |||||
enum_value_by_symbol(E, V) -> | |||||
erlang:error({no_enum_defs, E, V}). | |||||
get_service_names() -> []. | |||||
get_service_def(_) -> error. | |||||
get_rpc_names(_) -> error. | |||||
find_rpc_def(_, _) -> error. | |||||
-spec fetch_rpc_def(_, _) -> no_return(). | |||||
fetch_rpc_def(ServiceName, RpcName) -> | |||||
erlang:error({no_such_rpc, ServiceName, RpcName}). | |||||
get_package_name() -> undefined. | |||||
gpb_version_as_string() -> | |||||
"4.3.1". | |||||
gpb_version_as_list() -> | |||||
[4,3,1]. |
@ -0,0 +1,133 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_registry). | |||||
-export([ | |||||
encode_names/1, | |||||
decode_names/2, | |||||
encode_versions/1, | |||||
decode_versions/2, | |||||
encode_package/1, | |||||
decode_package/3, | |||||
sign_protobuf/2, | |||||
decode_signed/1, | |||||
decode_and_verify_signed/2, | |||||
sign/2, | |||||
verify/3 | |||||
]). | |||||
-include_lib("public_key/include/public_key.hrl"). | |||||
-type private_key() :: public_key:rsa_private_key() | binary(). | |||||
-type public_key() :: public_key:rsa_public_key() | binary(). | |||||
%%==================================================================== | |||||
%% API functions | |||||
%%==================================================================== | |||||
%% @doc | |||||
%% Encode Names message. | |||||
encode_names(Names) -> | |||||
r3_hex_pb_names:encode_msg(Names, 'Names'). | |||||
%% @doc | |||||
%% Decode message created with encode_names/1. | |||||
decode_names(Payload, no_verify) -> | |||||
#{packages := Packages} = r3_hex_pb_names:decode_msg(Payload, 'Names'), | |||||
{ok, Packages}; | |||||
decode_names(Payload, Repository) -> | |||||
case r3_hex_pb_names:decode_msg(Payload, 'Names') of | |||||
#{repository := Repository, packages := Packages} -> | |||||
{ok, Packages}; | |||||
_ -> | |||||
{error, unverified} | |||||
end. | |||||
%% @doc | |||||
%% Encode Versions message. | |||||
encode_versions(Versions) -> | |||||
r3_hex_pb_versions:encode_msg(Versions, 'Versions'). | |||||
%% @doc | |||||
%% Decode message created with encode_versions/1. | |||||
decode_versions(Payload, no_verify) -> | |||||
#{packages := Packages} = r3_hex_pb_versions:decode_msg(Payload, 'Versions'), | |||||
{ok, Packages}; | |||||
decode_versions(Payload, Repository) -> | |||||
case r3_hex_pb_versions:decode_msg(Payload, 'Versions') of | |||||
#{repository := Repository, packages := Packages} -> | |||||
{ok, Packages}; | |||||
_ -> | |||||
{error, unverified} | |||||
end. | |||||
%% @doc | |||||
%% Encode Package message. | |||||
encode_package(Package) -> | |||||
r3_hex_pb_package:encode_msg(Package, 'Package'). | |||||
%% @doc | |||||
%% Decode message created with encode_package/1. | |||||
decode_package(Payload, no_verify, no_verify) -> | |||||
#{releases := Releases} = r3_hex_pb_package:decode_msg(Payload, 'Package'), | |||||
{ok, Releases}; | |||||
decode_package(Payload, Repository, Package) -> | |||||
case r3_hex_pb_package:decode_msg(Payload, 'Package') of | |||||
#{repository := Repository, name := Package, releases := Releases} -> | |||||
{ok, Releases}; | |||||
_ -> | |||||
{error, unverified} | |||||
end. | |||||
%% @doc | |||||
%% Encode Signed message. | |||||
sign_protobuf(Payload, PrivateKey) -> | |||||
Signature = sign(Payload, PrivateKey), | |||||
r3_hex_pb_signed:encode_msg(#{payload => Payload, signature => Signature}, 'Signed'). | |||||
%% @doc | |||||
%% Decode message created with sign_protobuf/2 without verification. | |||||
decode_signed(Signed) -> | |||||
r3_hex_pb_signed:decode_msg(Signed, 'Signed'). | |||||
%% @doc | |||||
%% Decode message created with sign_protobuf/2 and verify it against public key. | |||||
-spec decode_and_verify_signed(map(), public_key()) -> {ok, binary()} | {error, term()}. | |||||
decode_and_verify_signed(Signed, PublicKey) -> | |||||
#{payload := Payload, signature := Signature} = decode_signed(Signed), | |||||
case verify(Payload, Signature, PublicKey) of | |||||
true -> {ok, Payload}; | |||||
false -> {error, unverified}; | |||||
{error, Reason} -> {error, Reason} | |||||
end. | |||||
%% @doc | |||||
%% Signs binary with given private key. | |||||
-spec sign(binary(), private_key()) -> binary(). | |||||
sign(Binary, PrivateKey) -> | |||||
{ok, RSAPrivateKey} = key(PrivateKey), | |||||
public_key:sign(Binary, sha512, RSAPrivateKey). | |||||
%% @doc | |||||
%% Verifies binary against signature and a public key. | |||||
-spec verify(binary(), binary(), public_key()) -> boolean() | {error, term()}. | |||||
verify(Binary, Signature, PublicKey) -> | |||||
case key(PublicKey) of | |||||
{ok, RSAPublicKey} -> public_key:verify(Binary, sha512, Signature, RSAPublicKey); | |||||
{error, Reason} -> {error, Reason} | |||||
end. | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
key(#'RSAPublicKey'{} = Key) -> | |||||
{ok, Key}; | |||||
key(#'RSAPrivateKey'{} = Key) -> | |||||
{ok, Key}; | |||||
key(Binary) when is_binary(Binary) -> | |||||
case public_key:pem_decode(Binary) of | |||||
[Entry | _] -> {ok, public_key:pem_entry_decode(Entry)}; | |||||
_ -> {error, bad_key} | |||||
end. |
@ -0,0 +1,174 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_repo). | |||||
-export([ | |||||
get_names/1, | |||||
get_versions/1, | |||||
get_package/2, | |||||
get_tarball/3 | |||||
]). | |||||
%%==================================================================== | |||||
%% API functions | |||||
%%==================================================================== | |||||
%% @doc | |||||
%% Gets names resource from the repository. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_repo:get_names(r3_hex_core:default_config()). | |||||
%% {ok, {200, ..., | |||||
%% [ | |||||
%% #{name => <<"package1">>}, | |||||
%% #{name => <<"package2">>}, | |||||
%% ]}} | |||||
%% ''' | |||||
%% @end | |||||
get_names(Config) when is_map(Config) -> | |||||
Verify = maps:get(repo_verify_origin, Config, true), | |||||
Decoder = fun(Data) -> | |||||
case Verify of | |||||
true -> r3_hex_registry:decode_names(Data, repo_name(Config)); | |||||
false -> r3_hex_registry:decode_names(Data, no_verify) | |||||
end | |||||
end, | |||||
get_protobuf(Config, <<"names">>, Decoder). | |||||
%% @doc | |||||
%% Gets versions resource from the repository. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_repo:get_versions(Config). | |||||
%% {ok, {200, ..., | |||||
%% [ | |||||
%% #{name => <<"package1">>, retired => [], | |||||
%% versions => [<<"1.0.0">>]}, | |||||
%% #{name => <<"package2">>, retired => [<<"0.5.0>>"], | |||||
%% versions => [<<"0.5.0">>, <<"1.0.0">>]}, | |||||
%% ]}} | |||||
%% ''' | |||||
%% @end | |||||
get_versions(Config) when is_map(Config) -> | |||||
Verify = maps:get(repo_verify_origin, Config, true), | |||||
Decoder = fun(Data) -> | |||||
case Verify of | |||||
true -> r3_hex_registry:decode_versions(Data, repo_name(Config)); | |||||
false -> r3_hex_registry:decode_versions(Data, no_verify) | |||||
end | |||||
end, | |||||
get_protobuf(Config, <<"versions">>, Decoder). | |||||
%% @doc | |||||
%% Gets package resource from the repository. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_repo:get_package(r3_hex_core:default_config(), <<"package1">>). | |||||
%% {ok, {200, ..., | |||||
%% { | |||||
%% #{checksum => ..., version => <<"0.5.0">>, dependencies => []}, | |||||
%% #{checksum => ..., version => <<"1.0.0">>, dependencies => [ | |||||
%% #{package => <<"package2">>, optional => true, requirement => <<"~> 0.1">>} | |||||
%% ]}, | |||||
%% ]}} | |||||
%% ''' | |||||
%% @end | |||||
get_package(Config, Name) when is_binary(Name) and is_map(Config) -> | |||||
Verify = maps:get(repo_verify_origin, Config, true), | |||||
Decoder = fun(Data) -> | |||||
case Verify of | |||||
true -> r3_hex_registry:decode_package(Data, repo_name(Config), Name); | |||||
false -> r3_hex_registry:decode_package(Data, no_verify, no_verify) | |||||
end | |||||
end, | |||||
get_protobuf(Config, <<"packages/", Name/binary>>, Decoder). | |||||
%% @doc | |||||
%% Gets tarball from the repository. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > {ok, {200, _, Tarball}} = r3_hex_repo:get_tarball(<<"package1">>, <<"1.0.0">>, r3_hex_core:default_config()), | |||||
%% > {ok, #{metadata := Metadata}} = r3_hex_tarball:unpack(Tarball, memory). | |||||
%% ''' | |||||
%% @end | |||||
get_tarball(Config, Name, Version) -> | |||||
ReqHeaders = make_headers(Config), | |||||
case get(Config, tarball_url(Config, Name, Version), ReqHeaders) of | |||||
{ok, {200, RespHeaders, Tarball}} -> | |||||
{ok, {200, RespHeaders, Tarball}}; | |||||
Other -> | |||||
Other | |||||
end. | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
get(Config, URI, Headers) -> | |||||
r3_hex_http:request(Config, get, URI, Headers, undefined). | |||||
get_protobuf(Config, Path, Decoder) -> | |||||
PublicKey = maps:get(repo_public_key, Config), | |||||
ReqHeaders = make_headers(Config), | |||||
case get(Config, build_url(Config, Path), ReqHeaders) of | |||||
{ok, {200, RespHeaders, Compressed}} -> | |||||
Signed = zlib:gunzip(Compressed), | |||||
case decode(Signed, PublicKey, Decoder, Config) of | |||||
{ok, Decoded} -> | |||||
{ok, {200, RespHeaders, Decoded}}; | |||||
{error, _} = Error -> | |||||
Error | |||||
end; | |||||
Other -> | |||||
Other | |||||
end. | |||||
decode(Signed, PublicKey, Decoder, Config) -> | |||||
Verify = maps:get(repo_verify, Config, true), | |||||
case Verify of | |||||
true -> | |||||
case r3_hex_registry:decode_and_verify_signed(Signed, PublicKey) of | |||||
{ok, Payload} -> | |||||
Decoder(Payload); | |||||
Other -> | |||||
Other | |||||
end; | |||||
false -> | |||||
#{payload := Payload} = r3_hex_registry:decode_signed(Signed), | |||||
Decoder(Payload) | |||||
end. | |||||
repo_name(#{repo_organization := Name}) when is_binary(Name) -> Name; | |||||
repo_name(#{repo_name := Name}) when is_binary(Name) -> Name. | |||||
tarball_url(Config, Name, Version) -> | |||||
Filename = tarball_filename(Name, Version), | |||||
build_url(Config, <<"tarballs/", Filename/binary>>). | |||||
build_url(#{repo_url := URI, repo_organization := Org}, Path) when is_binary(Org) -> | |||||
<<URI/binary, "/repos/", Org/binary, "/", Path/binary>>; | |||||
build_url(#{repo_url := URI, repo_organization := undefined}, Path) -> | |||||
<<URI/binary, "/", Path/binary>>. | |||||
tarball_filename(Name, Version) -> | |||||
<<Name/binary, "-", Version/binary, ".tar">>. | |||||
make_headers(Config) -> | |||||
maps:fold(fun set_header/3, #{}, Config). | |||||
set_header(http_etag, ETag, Headers) when is_binary(ETag) -> maps:put(<<"if-none-match">>, ETag, Headers); | |||||
set_header(repo_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers); | |||||
set_header(_, _, Headers) -> Headers. |
@ -0,0 +1,507 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
-module(r3_hex_tarball). | |||||
-export([create/2, create_docs/1, unpack/2, format_checksum/1, format_error/1]). | |||||
-ifdef(TEST). | |||||
-export([do_decode_metadata/1, gzip/1, normalize_requirements/1]). | |||||
-endif. | |||||
-define(VERSION, <<"3">>). | |||||
-define(TARBALL_MAX_SIZE, 8 * 1024 * 1024). | |||||
-define(TARBALL_MAX_UNCOMPRESSED_SIZE, 64 * 1024 * 1024). | |||||
-define(BUILD_TOOL_FILES, [ | |||||
{<<"mix.exs">>, <<"mix">>}, | |||||
{<<"rebar.config">>, <<"rebar3">>}, | |||||
{<<"rebar">>, <<"rebar3">>}, | |||||
{<<"Makefile">>, <<"make">>}, | |||||
{<<"Makefile.win">>, <<"make">>} | |||||
]). | |||||
-include_lib("kernel/include/file.hrl"). | |||||
-type checksum() :: binary(). | |||||
-type contents() :: #{filename() => binary()}. | |||||
-type filename() :: string(). | |||||
-type files() :: [filename() | {filename(), filename()}] | contents(). | |||||
-type metadata() :: map(). | |||||
-type tarball() :: binary(). | |||||
%%==================================================================== | |||||
%% API functions | |||||
%%==================================================================== | |||||
%% @doc | |||||
%% Creates a package tarball. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > Metadata = #{<<"name">> => <<"foo">>, <<"version">> => <<"1.0.0">>}, | |||||
%% > Files = [{"src/foo.erl", <<"-module(foo).">>}], | |||||
%% > {ok, {Tarball, Checksum}} = r3_hex_tarball:create(Metadata, Files). | |||||
%% > Tarball. | |||||
%% <<86,69,...>> | |||||
%% > Checksum. | |||||
%% <<40,32,...>> | |||||
%% ''' | |||||
%% @end | |||||
-spec create(metadata(), files()) -> {ok, {tarball(), checksum()}}. | |||||
create(Metadata, Files) -> | |||||
MetadataBinary = encode_metadata(Metadata), | |||||
ContentsTarball = create_memory_tarball(Files), | |||||
ContentsTarballCompressed = gzip(ContentsTarball), | |||||
Checksum = checksum(?VERSION, MetadataBinary, ContentsTarballCompressed), | |||||
ChecksumBase16 = encode_base16(Checksum), | |||||
OuterFiles = [ | |||||
{"VERSION", ?VERSION}, | |||||
{"CHECKSUM", ChecksumBase16}, | |||||
{"metadata.config", MetadataBinary}, | |||||
{"contents.tar.gz", ContentsTarballCompressed} | |||||
], | |||||
Tarball = create_memory_tarball(OuterFiles), | |||||
UncompressedSize = byte_size(ContentsTarball), | |||||
case(byte_size(Tarball) > ?TARBALL_MAX_SIZE) or (UncompressedSize > ?TARBALL_MAX_UNCOMPRESSED_SIZE) of | |||||
true -> | |||||
{error, {tarball, too_big}}; | |||||
false -> | |||||
{ok, {Tarball, Checksum}} | |||||
end. | |||||
%% @doc | |||||
%% Creates a docs tarball. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > Files = [{"doc/index.html", <<"Docs">>}], | |||||
%% > {ok, {Tarball, Checksum}} = r3_hex_tarball:create_docs(Files). | |||||
%% > Tarball. | |||||
%% %%=> <<86,69,...>> | |||||
%% > Checksum. | |||||
%% %%=> <<40,32,...>> | |||||
%% ''' | |||||
%% @end | |||||
-spec create_docs(files()) -> {ok, {tarball(), checksum()}}. | |||||
create_docs(Files) -> | |||||
UncompressedTarball = create_memory_tarball(Files), | |||||
UncompressedSize = byte_size(UncompressedTarball), | |||||
Tarball = gzip(UncompressedTarball), | |||||
Checksum = checksum(Tarball), | |||||
Size = byte_size(Tarball), | |||||
case(Size > ?TARBALL_MAX_SIZE) or (UncompressedSize > ?TARBALL_MAX_UNCOMPRESSED_SIZE) of | |||||
true -> | |||||
{error, {tarball, too_big}}; | |||||
false -> | |||||
{ok, {Tarball, Checksum}} | |||||
end. | |||||
%% @doc | |||||
%% Unpacks a package tarball. | |||||
%% | |||||
%% Examples: | |||||
%% | |||||
%% ``` | |||||
%% > r3_hex_tarball:unpack(Tarball, memory). | |||||
%% {ok,#{checksum => <<...>>, | |||||
%% contents => [{"src/foo.erl",<<"-module(foo).">>}], | |||||
%% metadata => #{<<"name">> => <<"foo">>, ...}}} | |||||
%% | |||||
%% > r3_hex_tarball:unpack(Tarball, "path/to/unpack"). | |||||
%% {ok,#{checksum => <<...>>, | |||||
%% metadata => #{<<"name">> => <<"foo">>, ...}}} | |||||
%% ''' | |||||
-spec unpack(tarball(), memory) -> | |||||
{ok, #{checksum => checksum(), metadata => metadata(), contents => contents()}} | | |||||
{error, term()}; | |||||
(tarball(), filename()) -> | |||||
{ok, #{checksum => checksum(), metadata => metadata()}} | | |||||
{error, term()}. | |||||
unpack(Tarball, _) when byte_size(Tarball) > ?TARBALL_MAX_SIZE -> | |||||
{error, {tarball, too_big}}; | |||||
unpack(Tarball, Output) -> | |||||
case r3_hex_erl_tar:extract({binary, Tarball}, [memory]) of | |||||
{ok, []} -> | |||||
{error, {tarball, empty}}; | |||||
{ok, FileList} -> | |||||
do_unpack(maps:from_list(FileList), Output); | |||||
{error, Reason} -> | |||||
{error, {tarball, Reason}} | |||||
end. | |||||
%% @doc | |||||
%% Returns base16-encoded representation of checksum. | |||||
-spec format_checksum(checksum()) -> binary(). | |||||
format_checksum(Checksum) -> | |||||
encode_base16(Checksum). | |||||
%% @doc | |||||
%% Converts an error reason term to a human-readable error message string. | |||||
-spec format_error(term()) -> string(). | |||||
format_error({tarball, empty}) -> "empty tarball"; | |||||
format_error({tarball, too_big}) -> "tarball is too big"; | |||||
format_error({tarball, {missing_files, Files}}) -> io_lib:format("missing files: ~p", [Files]); | |||||
format_error({tarball, {invalid_files, Files}}) -> io_lib:format("invalid files: ~p", [Files]); | |||||
format_error({tarball, {bad_version, Vsn}}) -> io_lib:format("unsupported version: ~p", [Vsn]); | |||||
format_error({tarball, invalid_checksum}) -> "invalid tarball checksum"; | |||||
format_error({tarball, Reason}) -> "tarball error, " ++ r3_hex_erl_tar:format_error(Reason); | |||||
format_error({inner_tarball, Reason}) -> "inner tarball error, " ++ r3_hex_erl_tar:format_error(Reason); | |||||
format_error({metadata, invalid_terms}) -> "error reading package metadata: invalid terms"; | |||||
format_error({metadata, not_key_value}) -> "error reading package metadata: not in key-value format"; | |||||
format_error({metadata, Reason}) -> "error reading package metadata" ++ r3_safe_erl_term:format_error(Reason); | |||||
format_error({checksum_mismatch, ExpectedChecksum, ActualChecksum}) -> | |||||
io_lib:format( | |||||
"tarball checksum mismatch~n~n" ++ | |||||
"Expected (base16-encoded): ~s~n" ++ | |||||
"Actual (base16-encoded): ~s", | |||||
[encode_base16(ExpectedChecksum), encode_base16(ActualChecksum)]). | |||||
%%==================================================================== | |||||
%% Internal functions | |||||
%%==================================================================== | |||||
checksum(Version, MetadataBinary, ContentsBinary) -> | |||||
Blob = <<Version/binary, MetadataBinary/binary, ContentsBinary/binary>>, | |||||
crypto:hash(sha256, Blob). | |||||
checksum(ContentsBinary) -> | |||||
Blob = <<ContentsBinary/binary>>, | |||||
crypto:hash(sha256, Blob). | |||||
encode_metadata(Meta) -> | |||||
Data = lists:map( | |||||
fun(MetaPair) -> | |||||
String = io_lib_pretty:print(binarify(MetaPair), [{encoding, utf8}]), | |||||
unicode:characters_to_binary([String, ".\n"]) | |||||
end, maps:to_list(Meta)), | |||||
iolist_to_binary(Data). | |||||
do_unpack(Files, Output) -> | |||||
State = #{ | |||||
checksum => undefined, | |||||
contents => undefined, | |||||
files => Files, | |||||
metadata => undefined, | |||||
output => Output | |||||
}, | |||||
State1 = check_files(State), | |||||
State2 = check_version(State1), | |||||
State3 = check_checksum(State2), | |||||
State4 = decode_metadata(State3), | |||||
finish_unpack(State4). | |||||
finish_unpack({error, _} = Error) -> | |||||
Error; | |||||
finish_unpack(#{metadata := Metadata, files := Files, output := Output}) -> | |||||
_Version = maps:get("VERSION", Files), | |||||
Checksum = decode_base16(maps:get("CHECKSUM", Files)), | |||||
ContentsBinary = maps:get("contents.tar.gz", Files), | |||||
case unpack_tarball(ContentsBinary, Output) of | |||||
ok -> | |||||
copy_metadata_config(Output, maps:get("metadata.config", Files)), | |||||
{ok, #{checksum => Checksum, metadata => Metadata}}; | |||||
{ok, Contents} -> | |||||
{ok, #{checksum => Checksum, metadata => Metadata, contents => Contents}}; | |||||
{error, Reason} -> | |||||
{error, {inner_tarball, Reason}} | |||||
end. | |||||
copy_metadata_config(Output, MetadataBinary) -> | |||||
ok = file:write_file(filename:join(Output, "hex_metadata.config"), MetadataBinary). | |||||
check_files(#{files := Files} = State) -> | |||||
RequiredFiles = ["VERSION", "CHECKSUM", "metadata.config", "contents.tar.gz"], | |||||
case diff_keys(Files, RequiredFiles, []) of | |||||
ok -> | |||||
State; | |||||
{error, {missing_keys, Keys}} -> | |||||
{error, {tarball, {missing_files, Keys}}}; | |||||
{error, {unknown_keys, Keys}} -> | |||||
{error, {tarball, {invalid_files, Keys}}} | |||||
end. | |||||
check_version({error, _} = Error) -> | |||||
Error; | |||||
check_version(#{files := Files} = State) -> | |||||
case maps:get("VERSION", Files) of | |||||
<<"3">> -> | |||||
State; | |||||
Version -> | |||||
{error, {tarball, {bad_version, Version}}} | |||||
end. | |||||
check_checksum({error, _} = Error) -> | |||||
Error; | |||||
check_checksum(#{files := Files} = State) -> | |||||
ChecksumBase16 = maps:get("CHECKSUM", Files), | |||||
ExpectedChecksum = decode_base16(ChecksumBase16), | |||||
Version = maps:get("VERSION", Files), | |||||
MetadataBinary = maps:get("metadata.config", Files), | |||||
ContentsBinary = maps:get("contents.tar.gz", Files), | |||||
ActualChecksum = checksum(Version, MetadataBinary, ContentsBinary), | |||||
if | |||||
byte_size(ExpectedChecksum) /= 32 -> | |||||
{error, {tarball, invalid_checksum}}; | |||||
ExpectedChecksum == ActualChecksum -> | |||||
maps:put(checksum, ExpectedChecksum, State); | |||||
true -> | |||||
{error, {tarball, {checksum_mismatch, ExpectedChecksum, ActualChecksum}}} | |||||
end. | |||||
decode_metadata({error, _} = Error) -> | |||||
Error; | |||||
decode_metadata(#{files := #{"metadata.config" := Binary}} = State) when is_binary(Binary) -> | |||||
case do_decode_metadata(Binary) of | |||||
#{} = Metadata -> maps:put(metadata, normalize_metadata(Metadata), State); | |||||
Other -> Other | |||||
end. | |||||
do_decode_metadata(Binary) when is_binary(Binary) -> | |||||
{ok, String} = characters_to_list(Binary), | |||||
case r3_safe_erl_term:string(String) of | |||||
{ok, Tokens, _Line} -> | |||||
try | |||||
Terms = r3_safe_erl_term:terms(Tokens), | |||||
maps:from_list(Terms) | |||||
catch | |||||
error:function_clause -> | |||||
{error, {metadata, invalid_terms}}; | |||||
error:badarg -> | |||||
{error, {metadata, not_key_value}} | |||||
end; | |||||
{error, {_Line, r3_safe_erl_term, Reason}, _Line2} -> | |||||
{error, {metadata, Reason}} | |||||
end. | |||||
characters_to_list(Binary) -> | |||||
case unicode:characters_to_list(Binary) of | |||||
List when is_list(List) -> | |||||
{ok, List}; | |||||
{error, _, _} -> | |||||
case unicode:characters_to_list(Binary, latin1) of | |||||
List when is_list(List) -> {ok, List}; | |||||
Other -> Other | |||||
end | |||||
end. | |||||
normalize_metadata(Metadata1) -> | |||||
Metadata2 = maybe_update_with(<<"requirements">>, fun normalize_requirements/1, Metadata1), | |||||
Metadata3 = maybe_update_with(<<"links">>, fun try_into_map/1, Metadata2), | |||||
Metadata4 = maybe_update_with(<<"extra">>, fun try_into_map/1, Metadata3), | |||||
guess_build_tools(Metadata4). | |||||
normalize_requirements(Requirements) -> | |||||
case is_list(Requirements) andalso (Requirements /= []) andalso is_list(hd(Requirements)) of | |||||
true -> | |||||
maps:from_list(lists:map(fun normalize_legacy_requirement/1, Requirements)); | |||||
false -> | |||||
try_into_map(fun normalize_normal_requirement/1, Requirements) | |||||
end. | |||||
normalize_normal_requirement({Name, Requirement}) -> | |||||
{Name, try_into_map(Requirement)}. | |||||
normalize_legacy_requirement(Requirement) -> | |||||
Map = maps:from_list(Requirement), | |||||
Name = maps:get(<<"name">>, Map), | |||||
{Name, maps:without([<<"name">>], Map)}. | |||||
guess_build_tools(#{<<"build_tools">> := BuildTools} = Metadata) when is_list(BuildTools) -> | |||||
Metadata; | |||||
guess_build_tools(#{<<"files">> := Filenames} = Metadata) -> | |||||
BaseFiles = [Filename || Filename <- Filenames, filename:dirname(binary_to_list(Filename)) == "."], | |||||
BuildTools = lists:usort([Tool || {Filename, Tool} <- ?BUILD_TOOL_FILES, lists:member(Filename, BaseFiles)]), | |||||
Metadata#{<<"build_tools">> => BuildTools}; | |||||
guess_build_tools(Metadata) -> | |||||
Metadata. | |||||
%%==================================================================== | |||||
%% Tar Helpers | |||||
%%==================================================================== | |||||
unpack_tarball(ContentsBinary, memory) -> | |||||
r3_hex_erl_tar:extract({binary, ContentsBinary}, [memory, compressed]); | |||||
unpack_tarball(ContentsBinary, Output) -> | |||||
case r3_hex_erl_tar:extract({binary, ContentsBinary}, [{cwd, Output}, compressed]) of | |||||
ok -> | |||||
[try_updating_mtime(filename:join(Output, Path)) || Path <- filelib:wildcard("**", Output)], | |||||
ok; | |||||
Other -> | |||||
Other | |||||
end. | |||||
%% let it silently fail for bad symlinks | |||||
try_updating_mtime(Path) -> | |||||
Time = calendar:universal_time(), | |||||
_ = file:write_file_info(Path, #file_info{mtime=Time}, [{time, universal}]), | |||||
ok. | |||||
create_memory_tarball(Files) -> | |||||
Path = tmp_path(), | |||||
{ok, Tar} = r3_hex_erl_tar:open(Path, [write]), | |||||
try | |||||
add_files(Tar, Files) | |||||
after | |||||
ok = r3_hex_erl_tar:close(Tar) | |||||
end, | |||||
{ok, Tarball} = file:read_file(Path), | |||||
ok = file:delete(Path), | |||||
Tarball. | |||||
tmp_path() -> | |||||
"tmp_" ++ binary_to_list(encode_base16(crypto:strong_rand_bytes(32))). | |||||
add_files(Tar, Files) when is_list(Files) -> | |||||
lists:map(fun(File) -> add_file(Tar, File) end, Files). | |||||
add_file(Tar, {Filename, Contents}) when is_list(Filename) and is_binary(Contents) -> | |||||
ok = r3_hex_erl_tar:add(Tar, Contents, Filename, tar_opts()); | |||||
add_file(Tar, Filename) when is_list(Filename) -> | |||||
add_file(Tar, {Filename, Filename}); | |||||
add_file(Tar, {Filename, AbsFilename}) when is_list(Filename), is_list(AbsFilename) -> | |||||
{ok, FileInfo} = file:read_link_info(AbsFilename, []), | |||||
case FileInfo#file_info.type of | |||||
symlink -> | |||||
ok = r3_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts()); | |||||
directory -> | |||||
case file:list_dir(AbsFilename) of | |||||
{ok, []} -> | |||||
r3_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts()); | |||||
{ok, _} -> | |||||
ok | |||||
end; | |||||
_ -> | |||||
Mode = FileInfo#file_info.mode, | |||||
{ok, Contents} = file:read_file(AbsFilename), | |||||
ok = r3_hex_erl_tar:add(Tar, Contents, Filename, Mode, tar_opts()) | |||||
end. | |||||
tar_opts() -> | |||||
NixEpoch = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}), | |||||
Y2kEpoch = calendar:datetime_to_gregorian_seconds({{2000, 1, 1}, {0, 0, 0}}), | |||||
Epoch = Y2kEpoch - NixEpoch, | |||||
[{atime, Epoch}, {mtime, Epoch}, {ctime, Epoch}, {uid, 0}, {gid, 0}]. | |||||
%% Reproducible gzip by not setting mtime and OS | |||||
%% | |||||
%% From https://tools.ietf.org/html/rfc1952 | |||||
%% | |||||
%% +---+---+---+---+---+---+---+---+---+---+ | |||||
%% |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) | |||||
%% +---+---+---+---+---+---+---+---+---+---+ | |||||
%% | |||||
%% +=======================+ | |||||
%% |...compressed blocks...| (more-->) | |||||
%% +=======================+ | |||||
%% | |||||
%% +---+---+---+---+---+---+---+---+ | |||||
%% | CRC32 | ISIZE | | |||||
%% +---+---+---+---+---+---+---+---+ | |||||
gzip(Uncompressed) -> | |||||
Compressed = gzip_no_header(Uncompressed), | |||||
Header = <<31, 139, 8, 0, 0, 0, 0, 0, 0, 0>>, | |||||
Crc = erlang:crc32(Uncompressed), | |||||
Size = byte_size(Uncompressed), | |||||
Trailer = <<Crc:32/little, Size:32/little>>, | |||||
iolist_to_binary([Header, Compressed, Trailer]). | |||||
gzip_no_header(Uncompressed) -> | |||||
Zstream = zlib:open(), | |||||
try | |||||
zlib:deflateInit(Zstream, default, deflated, -15, 8, default), | |||||
Compressed = zlib:deflate(Zstream, Uncompressed, finish), | |||||
zlib:deflateEnd(Zstream), | |||||
iolist_to_binary(Compressed) | |||||
after | |||||
zlib:close(Zstream) | |||||
end. | |||||
%%==================================================================== | |||||
%% Helpers | |||||
%%==================================================================== | |||||
binarify(Binary) when is_binary(Binary) -> Binary; | |||||
binarify(Number) when is_number(Number) -> Number; | |||||
binarify(Atom) when Atom == undefined orelse is_boolean(Atom) -> Atom; | |||||
binarify(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8); | |||||
binarify(List) when is_list(List) -> | |||||
[binarify(E) || E <- List]; | |||||
binarify({Key, Value}) -> | |||||
{binarify(Key), binarify(Value)}; | |||||
binarify(Map) when is_map(Map) -> | |||||
List = maps:to_list(Map), | |||||
lists:map(fun({K, V}) -> binarify({K, V}) end, List). | |||||
diff_keys(Map, RequiredKeys, OptionalKeys) -> | |||||
Keys = maps:keys(Map), | |||||
MissingKeys = RequiredKeys -- Keys, | |||||
UnknownKeys = Keys -- (RequiredKeys ++ OptionalKeys), | |||||
case {MissingKeys, UnknownKeys} of | |||||
{[], []} -> | |||||
ok; | |||||
{_, [_ | _]} -> | |||||
{error, {unknown_keys, UnknownKeys}}; | |||||
_ -> | |||||
{error, {missing_keys, MissingKeys}} | |||||
end. | |||||
maybe_update_with(Key, Fun, Map) -> | |||||
case maps:find(Key, Map) of | |||||
{ok, Value} -> maps:put(Key, Fun(Value), Map); | |||||
error -> Map | |||||
end. | |||||
try_into_map(List) -> | |||||
try_into_map(fun(X) -> X end, List). | |||||
try_into_map(Fun, Input) -> | |||||
case is_list(Input) andalso lists:all(fun(E) -> is_tuple(E) andalso (tuple_size(E) == 2) end, Input) of | |||||
true -> maps:from_list(lists:map(Fun, Input)); | |||||
false -> Input | |||||
end. | |||||
encode_base16(Binary) -> | |||||
<<X:256/big-unsigned-integer>> = Binary, | |||||
String = string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X]))), | |||||
list_to_binary(String). | |||||
%% Based on https://github.com/goj/base16/blob/master/src/base16.erl | |||||
%% (C) 2012, Erlang Solutions Ltd. | |||||
decode_base16(Base16) -> | |||||
<< <<(unhex(H) bsl 4 + unhex(L))>> || <<H,L>> <= Base16 >>. | |||||
unhex(D) when $0 =< D andalso D =< $9 -> | |||||
D - $0; | |||||
unhex(D) when $a =< D andalso D =< $f -> | |||||
10 + D - $a; | |||||
unhex(D) when $A =< D andalso D =< $F -> | |||||
10 + D - $A. |
@ -0,0 +1,678 @@ | |||||
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 0). | |||||
%% The source of this file is part of leex distribution, as such it | |||||
%% has the same Copyright as the other files in the leex | |||||
%% distribution. The Copyright is defined in the accompanying file | |||||
%% COPYRIGHT. However, the resultant scanner generated by leex is the | |||||
%% property of the creator of the scanner and is not covered by that | |||||
%% Copyright. | |||||
-module(r3_safe_erl_term). | |||||
-export([string/1,string/2,token/2,token/3,tokens/2,tokens/3]). | |||||
-export([format_error/1]). | |||||
%% User code. This is placed here to allow extra attributes. | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 26). | |||||
-export([terms/1]). | |||||
terms(Tokens) -> | |||||
terms(Tokens, []). | |||||
terms([{dot, _} = H], Buffer) -> | |||||
[buffer_to_term([H|Buffer])]; | |||||
terms([{dot, _} = H|T], Buffer) -> | |||||
[buffer_to_term([H|Buffer])|terms(T, [])]; | |||||
terms([H|T], Buffer) -> | |||||
terms(T, [H|Buffer]). | |||||
buffer_to_term(Buffer) -> | |||||
{ok, Term} = erl_parse:parse_term(lists:reverse(Buffer)), | |||||
Term. | |||||
unquote(TokenChars, TokenLen) -> | |||||
lists:sublist(TokenChars, 2, TokenLen - 2). | |||||
tokenize_atom(TokenChars, TokenLine) -> | |||||
try list_to_existing_atom(TokenChars) of | |||||
Atom -> {token, {atom, TokenLine, Atom}} | |||||
catch | |||||
error:badarg -> {error, "illegal atom " ++ TokenChars} | |||||
end. | |||||
escape([$\\|Cs]) -> | |||||
do_escape(Cs); | |||||
escape([C|Cs]) -> | |||||
[C|escape(Cs)]; | |||||
escape([]) -> []. | |||||
do_escape([O1,O2,O3|S]) when | |||||
O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 -> | |||||
[(O1*8 + O2)*8 + O3 - 73*$0|escape(S)]; | |||||
do_escape([$^,C|Cs]) -> | |||||
[C band 31|escape(Cs)]; | |||||
do_escape([C|Cs]) when C >= $\000, C =< $\s -> | |||||
escape(Cs); | |||||
do_escape([C|Cs]) -> | |||||
[escape_char(C)|escape(Cs)]. | |||||
escape_char($n) -> $\n; %\n = LF | |||||
escape_char($r) -> $\r; %\r = CR | |||||
escape_char($t) -> $\t; %\t = TAB | |||||
escape_char($v) -> $\v; %\v = VT | |||||
escape_char($b) -> $\b; %\b = BS | |||||
escape_char($f) -> $\f; %\f = FF | |||||
escape_char($e) -> $\e; %\e = ESC | |||||
escape_char($s) -> $\s; %\s = SPC | |||||
escape_char($d) -> $\d; %\d = DEL | |||||
escape_char(C) -> C. | |||||
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 14). | |||||
format_error({illegal,S}) -> ["illegal characters ",io_lib:write_string(S)]; | |||||
format_error({user,S}) -> S. | |||||
string(String) -> string(String, 1). | |||||
string(String, Line) -> string(String, Line, String, []). | |||||
%% string(InChars, Line, TokenChars, Tokens) -> | |||||
%% {ok,Tokens,Line} | {error,ErrorInfo,Line}. | |||||
%% Note the line number going into yystate, L0, is line of token | |||||
%% start while line number returned is line of token end. We want line | |||||
%% of token start. | |||||
string([], L, [], Ts) -> % No partial tokens! | |||||
{ok,yyrev(Ts),L}; | |||||
string(Ics0, L0, Tcs, Ts) -> | |||||
case yystate(yystate(), Ics0, L0, 0, reject, 0) of | |||||
{A,Alen,Ics1,L1} -> % Accepting end state | |||||
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts); | |||||
{A,Alen,Ics1,L1,_S1} -> % Accepting transistion state | |||||
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L0), Ts); | |||||
{reject,_Alen,Tlen,_Ics1,L1,_S1} -> % After a non-accepting state | |||||
{error,{L0,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},L1}; | |||||
{A,Alen,Tlen,_Ics1,L1,_S1} -> | |||||
Tcs1 = yysuf(Tcs, Alen), | |||||
L2 = adjust_line(Tlen, Alen, Tcs1, L1), | |||||
string_cont(Tcs1, L2, yyaction(A, Alen, Tcs, L0), Ts) | |||||
end. | |||||
%% string_cont(RestChars, Line, Token, Tokens) | |||||
%% Test for and remove the end token wrapper. Push back characters | |||||
%% are prepended to RestChars. | |||||
-dialyzer({nowarn_function, string_cont/4}). | |||||
string_cont(Rest, Line, {token,T}, Ts) -> | |||||
string(Rest, Line, Rest, [T|Ts]); | |||||
string_cont(Rest, Line, {token,T,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
string(NewRest, Line, NewRest, [T|Ts]); | |||||
string_cont(Rest, Line, {end_token,T}, Ts) -> | |||||
string(Rest, Line, Rest, [T|Ts]); | |||||
string_cont(Rest, Line, {end_token,T,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
string(NewRest, Line, NewRest, [T|Ts]); | |||||
string_cont(Rest, Line, skip_token, Ts) -> | |||||
string(Rest, Line, Rest, Ts); | |||||
string_cont(Rest, Line, {skip_token,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
string(NewRest, Line, NewRest, Ts); | |||||
string_cont(_Rest, Line, {error,S}, _Ts) -> | |||||
{error,{Line,?MODULE,{user,S}},Line}. | |||||
%% token(Continuation, Chars) -> | |||||
%% token(Continuation, Chars, Line) -> | |||||
%% {more,Continuation} | {done,ReturnVal,RestChars}. | |||||
%% Must be careful when re-entering to append the latest characters to the | |||||
%% after characters in an accept. The continuation is: | |||||
%% {token,State,CurrLine,TokenChars,TokenLen,TokenLine,AccAction,AccLen} | |||||
token(Cont, Chars) -> token(Cont, Chars, 1). | |||||
token([], Chars, Line) -> | |||||
token(yystate(), Chars, Line, Chars, 0, Line, reject, 0); | |||||
token({token,State,Line,Tcs,Tlen,Tline,Action,Alen}, Chars, _) -> | |||||
token(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Action, Alen). | |||||
%% token(State, InChars, Line, TokenChars, TokenLen, TokenLine, | |||||
%% AcceptAction, AcceptLen) -> | |||||
%% {more,Continuation} | {done,ReturnVal,RestChars}. | |||||
%% The argument order is chosen to be more efficient. | |||||
token(S0, Ics0, L0, Tcs, Tlen0, Tline, A0, Alen0) -> | |||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of | |||||
%% Accepting end state, we have a token. | |||||
{A1,Alen1,Ics1,L1} -> | |||||
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline)); | |||||
%% Accepting transition state, can take more chars. | |||||
{A1,Alen1,[],L1,S1} -> % Need more chars to check | |||||
{more,{token,S1,L1,Tcs,Alen1,Tline,A1,Alen1}}; | |||||
{A1,Alen1,Ics1,L1,_S1} -> % Take what we got | |||||
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline)); | |||||
%% After a non-accepting state, maybe reach accept state later. | |||||
{A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check | |||||
{more,{token,S1,L1,Tcs,Tlen1,Tline,A1,Alen1}}; | |||||
{reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match | |||||
%% Check for partial token which is error. | |||||
Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE, | |||||
%% Skip eof tail in Tcs. | |||||
{illegal,yypre(Tcs, Tlen1)}},L1}; | |||||
true -> {eof,L1} | |||||
end, | |||||
{done,Ret,eof}; | |||||
{reject,_Alen1,Tlen1,Ics1,L1,_S1} -> % No token match | |||||
Error = {Tline,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, | |||||
{done,{error,Error,L1},Ics1}; | |||||
{A1,Alen1,Tlen1,_Ics1,L1,_S1} -> % Use last accept match | |||||
Tcs1 = yysuf(Tcs, Alen1), | |||||
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), | |||||
token_cont(Tcs1, L2, yyaction(A1, Alen1, Tcs, Tline)) | |||||
end. | |||||
%% token_cont(RestChars, Line, Token) | |||||
%% If we have a token or error then return done, else if we have a | |||||
%% skip_token then continue. | |||||
-dialyzer({nowarn_function, token_cont/3}). | |||||
token_cont(Rest, Line, {token,T}) -> | |||||
{done,{ok,T,Line},Rest}; | |||||
token_cont(Rest, Line, {token,T,Push}) -> | |||||
NewRest = Push ++ Rest, | |||||
{done,{ok,T,Line},NewRest}; | |||||
token_cont(Rest, Line, {end_token,T}) -> | |||||
{done,{ok,T,Line},Rest}; | |||||
token_cont(Rest, Line, {end_token,T,Push}) -> | |||||
NewRest = Push ++ Rest, | |||||
{done,{ok,T,Line},NewRest}; | |||||
token_cont(Rest, Line, skip_token) -> | |||||
token(yystate(), Rest, Line, Rest, 0, Line, reject, 0); | |||||
token_cont(Rest, Line, {skip_token,Push}) -> | |||||
NewRest = Push ++ Rest, | |||||
token(yystate(), NewRest, Line, NewRest, 0, Line, reject, 0); | |||||
token_cont(Rest, Line, {error,S}) -> | |||||
{done,{error,{Line,?MODULE,{user,S}},Line},Rest}. | |||||
%% tokens(Continuation, Chars, Line) -> | |||||
%% {more,Continuation} | {done,ReturnVal,RestChars}. | |||||
%% Must be careful when re-entering to append the latest characters to the | |||||
%% after characters in an accept. The continuation is: | |||||
%% {tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Tokens,AccAction,AccLen} | |||||
%% {skip_tokens,State,CurrLine,TokenChars,TokenLen,TokenLine,Error,AccAction,AccLen} | |||||
tokens(Cont, Chars) -> tokens(Cont, Chars, 1). | |||||
tokens([], Chars, Line) -> | |||||
tokens(yystate(), Chars, Line, Chars, 0, Line, [], reject, 0); | |||||
tokens({tokens,State,Line,Tcs,Tlen,Tline,Ts,Action,Alen}, Chars, _) -> | |||||
tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Ts, Action, Alen); | |||||
tokens({skip_tokens,State,Line,Tcs,Tlen,Tline,Error,Action,Alen}, Chars, _) -> | |||||
skip_tokens(State, Chars, Line, Tcs ++ Chars, Tlen, Tline, Error, Action, Alen). | |||||
%% tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens, | |||||
%% AcceptAction, AcceptLen) -> | |||||
%% {more,Continuation} | {done,ReturnVal,RestChars}. | |||||
tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Ts, A0, Alen0) -> | |||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of | |||||
%% Accepting end state, we have a token. | |||||
{A1,Alen1,Ics1,L1} -> | |||||
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts); | |||||
%% Accepting transition state, can take more chars. | |||||
{A1,Alen1,[],L1,S1} -> % Need more chars to check | |||||
{more,{tokens,S1,L1,Tcs,Alen1,Tline,Ts,A1,Alen1}}; | |||||
{A1,Alen1,Ics1,L1,_S1} -> % Take what we got | |||||
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Ts); | |||||
%% After a non-accepting state, maybe reach accept state later. | |||||
{A1,Alen1,Tlen1,[],L1,S1} -> % Need more chars to check | |||||
{more,{tokens,S1,L1,Tcs,Tlen1,Tline,Ts,A1,Alen1}}; | |||||
{reject,_Alen1,Tlen1,eof,L1,_S1} -> % No token match | |||||
%% Check for partial token which is error, no need to skip here. | |||||
Ret = if Tlen1 > 0 -> {error,{Tline,?MODULE, | |||||
%% Skip eof tail in Tcs. | |||||
{illegal,yypre(Tcs, Tlen1)}},L1}; | |||||
Ts == [] -> {eof,L1}; | |||||
true -> {ok,yyrev(Ts),L1} | |||||
end, | |||||
{done,Ret,eof}; | |||||
{reject,_Alen1,Tlen1,_Ics1,L1,_S1} -> | |||||
%% Skip rest of tokens. | |||||
Error = {L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, | |||||
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error); | |||||
{A1,Alen1,Tlen1,_Ics1,L1,_S1} -> | |||||
Token = yyaction(A1, Alen1, Tcs, Tline), | |||||
Tcs1 = yysuf(Tcs, Alen1), | |||||
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), | |||||
tokens_cont(Tcs1, L2, Token, Ts) | |||||
end. | |||||
%% tokens_cont(RestChars, Line, Token, Tokens) | |||||
%% If we have an end_token or error then return done, else if we have | |||||
%% a token then save it and continue, else if we have a skip_token | |||||
%% just continue. | |||||
-dialyzer({nowarn_function, tokens_cont/4}). | |||||
tokens_cont(Rest, Line, {token,T}, Ts) -> | |||||
tokens(yystate(), Rest, Line, Rest, 0, Line, [T|Ts], reject, 0); | |||||
tokens_cont(Rest, Line, {token,T,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
tokens(yystate(), NewRest, Line, NewRest, 0, Line, [T|Ts], reject, 0); | |||||
tokens_cont(Rest, Line, {end_token,T}, Ts) -> | |||||
{done,{ok,yyrev(Ts, [T]),Line},Rest}; | |||||
tokens_cont(Rest, Line, {end_token,T,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
{done,{ok,yyrev(Ts, [T]),Line},NewRest}; | |||||
tokens_cont(Rest, Line, skip_token, Ts) -> | |||||
tokens(yystate(), Rest, Line, Rest, 0, Line, Ts, reject, 0); | |||||
tokens_cont(Rest, Line, {skip_token,Push}, Ts) -> | |||||
NewRest = Push ++ Rest, | |||||
tokens(yystate(), NewRest, Line, NewRest, 0, Line, Ts, reject, 0); | |||||
tokens_cont(Rest, Line, {error,S}, _Ts) -> | |||||
skip_tokens(Rest, Line, {Line,?MODULE,{user,S}}). | |||||
%%skip_tokens(InChars, Line, Error) -> {done,{error,Error,Line},Ics}. | |||||
%% Skip tokens until an end token, junk everything and return the error. | |||||
skip_tokens(Ics, Line, Error) -> | |||||
skip_tokens(yystate(), Ics, Line, Ics, 0, Line, Error, reject, 0). | |||||
%% skip_tokens(State, InChars, Line, TokenChars, TokenLen, TokenLine, Tokens, | |||||
%% AcceptAction, AcceptLen) -> | |||||
%% {more,Continuation} | {done,ReturnVal,RestChars}. | |||||
skip_tokens(S0, Ics0, L0, Tcs, Tlen0, Tline, Error, A0, Alen0) -> | |||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of | |||||
{A1,Alen1,Ics1,L1} -> % Accepting end state | |||||
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error); | |||||
{A1,Alen1,[],L1,S1} -> % After an accepting state | |||||
{more,{skip_tokens,S1,L1,Tcs,Alen1,Tline,Error,A1,Alen1}}; | |||||
{A1,Alen1,Ics1,L1,_S1} -> | |||||
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, Tline), Error); | |||||
{A1,Alen1,Tlen1,[],L1,S1} -> % After a non-accepting state | |||||
{more,{skip_tokens,S1,L1,Tcs,Tlen1,Tline,Error,A1,Alen1}}; | |||||
{reject,_Alen1,_Tlen1,eof,L1,_S1} -> | |||||
{done,{error,Error,L1},eof}; | |||||
{reject,_Alen1,Tlen1,_Ics1,L1,_S1} -> | |||||
skip_tokens(yysuf(Tcs, Tlen1+1), L1, Error); | |||||
{A1,Alen1,Tlen1,_Ics1,L1,_S1} -> | |||||
Token = yyaction(A1, Alen1, Tcs, Tline), | |||||
Tcs1 = yysuf(Tcs, Alen1), | |||||
L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), | |||||
skip_cont(Tcs1, L2, Token, Error) | |||||
end. | |||||
%% skip_cont(RestChars, Line, Token, Error) | |||||
%% Skip tokens until we have an end_token or error then return done | |||||
%% with the original rror. | |||||
-dialyzer({nowarn_function, skip_cont/4}). | |||||
skip_cont(Rest, Line, {token,_T}, Error) -> | |||||
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0); | |||||
skip_cont(Rest, Line, {token,_T,Push}, Error) -> | |||||
NewRest = Push ++ Rest, | |||||
skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0); | |||||
skip_cont(Rest, Line, {end_token,_T}, Error) -> | |||||
{done,{error,Error,Line},Rest}; | |||||
skip_cont(Rest, Line, {end_token,_T,Push}, Error) -> | |||||
NewRest = Push ++ Rest, | |||||
{done,{error,Error,Line},NewRest}; | |||||
skip_cont(Rest, Line, skip_token, Error) -> | |||||
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0); | |||||
skip_cont(Rest, Line, {skip_token,Push}, Error) -> | |||||
NewRest = Push ++ Rest, | |||||
skip_tokens(yystate(), NewRest, Line, NewRest, 0, Line, Error, reject, 0); | |||||
skip_cont(Rest, Line, {error,_S}, Error) -> | |||||
skip_tokens(yystate(), Rest, Line, Rest, 0, Line, Error, reject, 0). | |||||
-compile({nowarn_unused_function, [yyrev/1, yyrev/2, yypre/2, yysuf/2]}). | |||||
yyrev(List) -> lists:reverse(List). | |||||
yyrev(List, Tail) -> lists:reverse(List, Tail). | |||||
yypre(List, N) -> lists:sublist(List, N). | |||||
yysuf(List, N) -> lists:nthtail(N, List). | |||||
%% adjust_line(TokenLength, AcceptLength, Chars, Line) -> NewLine | |||||
%% Make sure that newlines in Chars are not counted twice. | |||||
%% Line has been updated with respect to newlines in the prefix of | |||||
%% Chars consisting of (TokenLength - AcceptLength) characters. | |||||
-compile({nowarn_unused_function, adjust_line/4}). | |||||
adjust_line(N, N, _Cs, L) -> L; | |||||
adjust_line(T, A, [$\n|Cs], L) -> | |||||
adjust_line(T-1, A, Cs, L-1); | |||||
adjust_line(T, A, [_|Cs], L) -> | |||||
adjust_line(T-1, A, Cs, L). | |||||
%% yystate() -> InitialState. | |||||
%% yystate(State, InChars, Line, CurrTokLen, AcceptAction, AcceptLen) -> | |||||
%% {Action, AcceptLen, RestChars, Line} | | |||||
%% {Action, AcceptLen, RestChars, Line, State} | | |||||
%% {reject, AcceptLen, CurrTokLen, RestChars, Line, State} | | |||||
%% {Action, AcceptLen, CurrTokLen, RestChars, Line, State}. | |||||
%% Generated state transition functions. The non-accepting end state | |||||
%% return signal either an unrecognised character or end of current | |||||
%% input. | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.erl", 360). | |||||
yystate() -> 13. | |||||
yystate(20, [60|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(10, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(20, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,20}; | |||||
yystate(19, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(11, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, [39|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(15, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(0, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(19, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,19}; | |||||
yystate(18, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(14, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, [34|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(6, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(9, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(18, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,18}; | |||||
yystate(17, [37|Ics], Line, Tlen, _, _) -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(17, [10|Ics], Line, Tlen, _, _) -> | |||||
yystate(17, Ics, Line+1, Tlen+1, 8, Tlen); | |||||
yystate(17, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 -> | |||||
yystate(17, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(17, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 32 -> | |||||
yystate(17, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(17, Ics, Line, Tlen, _, _) -> | |||||
{8,Tlen,Ics,Line,17}; | |||||
yystate(16, Ics, Line, Tlen, _, _) -> | |||||
{4,Tlen,Ics,Line}; | |||||
yystate(15, [92|Ics], Line, Tlen, _, _) -> | |||||
yystate(11, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, [39|Ics], Line, Tlen, _, _) -> | |||||
yystate(7, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, [10|Ics], Line, Tlen, _, _) -> | |||||
yystate(0, Ics, Line+1, Tlen+1, 1, Tlen); | |||||
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 -> | |||||
yystate(0, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 38 -> | |||||
yystate(0, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 40, C =< 91 -> | |||||
yystate(0, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, [C|Ics], Line, Tlen, _, _) when C >= 93 -> | |||||
yystate(0, Ics, Line, Tlen+1, 1, Tlen); | |||||
yystate(15, Ics, Line, Tlen, _, _) -> | |||||
{1,Tlen,Ics,Line,15}; | |||||
yystate(14, [94|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(18, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [93|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(14, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [34|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(6, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(9, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, [C|Ics], Line, Tlen, Action, Alen) when C >= 95 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(14, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,14}; | |||||
yystate(13, [125|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [123|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [93|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [91|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [62|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(2, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [61|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(2, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [60|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(20, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [47|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(4, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [46|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(3, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [39|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [37|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(8, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [35|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [34|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(17, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(17, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 32 -> | |||||
yystate(17, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 43, C =< 45 -> | |||||
yystate(16, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 48, C =< 57 -> | |||||
yystate(12, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, [C|Ics], Line, Tlen, Action, Alen) when C >= 97, C =< 122 -> | |||||
yystate(5, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(13, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,13}; | |||||
yystate(12, [C|Ics], Line, Tlen, _, _) when C >= 48, C =< 57 -> | |||||
yystate(12, Ics, Line, Tlen+1, 3, Tlen); | |||||
yystate(12, Ics, Line, Tlen, _, _) -> | |||||
{3,Tlen,Ics,Line,12}; | |||||
yystate(11, [94|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(19, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [93|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(11, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [39|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(15, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(0, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, [C|Ics], Line, Tlen, Action, Alen) when C >= 95 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(11, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,11}; | |||||
yystate(10, Ics, Line, Tlen, _, _) -> | |||||
{5,Tlen,Ics,Line}; | |||||
yystate(9, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(14, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, [34|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(1, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(9, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 33 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 35, C =< 91 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 -> | |||||
yystate(9, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(9, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,9}; | |||||
yystate(8, [37|Ics], Line, Tlen, _, _) -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(8, [10|Ics], Line, Tlen, _, _) -> | |||||
yystate(17, Ics, Line+1, Tlen+1, 8, Tlen); | |||||
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 32 -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 33, C =< 36 -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(8, [C|Ics], Line, Tlen, _, _) when C >= 38 -> | |||||
yystate(8, Ics, Line, Tlen+1, 8, Tlen); | |||||
yystate(8, Ics, Line, Tlen, _, _) -> | |||||
{8,Tlen,Ics,Line,8}; | |||||
yystate(7, Ics, Line, Tlen, _, _) -> | |||||
{1,Tlen,Ics,Line}; | |||||
yystate(6, [92|Ics], Line, Tlen, _, _) -> | |||||
yystate(14, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, [34|Ics], Line, Tlen, _, _) -> | |||||
yystate(1, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, [10|Ics], Line, Tlen, _, _) -> | |||||
yystate(9, Ics, Line+1, Tlen+1, 2, Tlen); | |||||
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 0, C =< 9 -> | |||||
yystate(9, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 11, C =< 33 -> | |||||
yystate(9, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 35, C =< 91 -> | |||||
yystate(9, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, [C|Ics], Line, Tlen, _, _) when C >= 93 -> | |||||
yystate(9, Ics, Line, Tlen+1, 2, Tlen); | |||||
yystate(6, Ics, Line, Tlen, _, _) -> | |||||
{2,Tlen,Ics,Line,6}; | |||||
yystate(5, [95|Ics], Line, Tlen, _, _) -> | |||||
yystate(5, Ics, Line, Tlen+1, 0, Tlen); | |||||
yystate(5, [64|Ics], Line, Tlen, _, _) -> | |||||
yystate(5, Ics, Line, Tlen+1, 0, Tlen); | |||||
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 48, C =< 57 -> | |||||
yystate(5, Ics, Line, Tlen+1, 0, Tlen); | |||||
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 65, C =< 90 -> | |||||
yystate(5, Ics, Line, Tlen+1, 0, Tlen); | |||||
yystate(5, [C|Ics], Line, Tlen, _, _) when C >= 97, C =< 122 -> | |||||
yystate(5, Ics, Line, Tlen+1, 0, Tlen); | |||||
yystate(5, Ics, Line, Tlen, _, _) -> | |||||
{0,Tlen,Ics,Line,5}; | |||||
yystate(4, Ics, Line, Tlen, _, _) -> | |||||
{7,Tlen,Ics,Line}; | |||||
yystate(3, Ics, Line, Tlen, _, _) -> | |||||
{6,Tlen,Ics,Line}; | |||||
yystate(2, [62|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(10, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(2, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,2}; | |||||
yystate(1, Ics, Line, Tlen, _, _) -> | |||||
{2,Tlen,Ics,Line}; | |||||
yystate(0, [92|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(11, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, [39|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(7, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, [10|Ics], Line, Tlen, Action, Alen) -> | |||||
yystate(0, Ics, Line+1, Tlen+1, Action, Alen); | |||||
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 0, C =< 9 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 11, C =< 38 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 40, C =< 91 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, [C|Ics], Line, Tlen, Action, Alen) when C >= 93 -> | |||||
yystate(0, Ics, Line, Tlen+1, Action, Alen); | |||||
yystate(0, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,0}; | |||||
yystate(S, Ics, Line, Tlen, Action, Alen) -> | |||||
{Action,Alen,Tlen,Ics,Line,S}. | |||||
%% yyaction(Action, TokenLength, TokenChars, TokenLine) -> | |||||
%% {token,Token} | {end_token, Token} | skip_token | {error,String}. | |||||
%% Generated action function. | |||||
yyaction(0, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_0(TokenChars, TokenLine); | |||||
yyaction(1, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_1(TokenChars, TokenLen, TokenLine); | |||||
yyaction(2, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_2(TokenChars, TokenLen, TokenLine); | |||||
yyaction(3, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_3(TokenChars, TokenLine); | |||||
yyaction(4, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_4(TokenChars, TokenLine); | |||||
yyaction(5, TokenLen, YYtcs, TokenLine) -> | |||||
TokenChars = yypre(YYtcs, TokenLen), | |||||
yyaction_5(TokenChars, TokenLine); | |||||
yyaction(6, _, _, TokenLine) -> | |||||
yyaction_6(TokenLine); | |||||
yyaction(7, _, _, TokenLine) -> | |||||
yyaction_7(TokenLine); | |||||
yyaction(8, _, _, _) -> | |||||
yyaction_8(); | |||||
yyaction(_, _, _, _) -> error. | |||||
-compile({inline,yyaction_0/2}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 14). | |||||
yyaction_0(TokenChars, TokenLine) -> | |||||
tokenize_atom (TokenChars, TokenLine) . | |||||
-compile({inline,yyaction_1/3}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 15). | |||||
yyaction_1(TokenChars, TokenLen, TokenLine) -> | |||||
tokenize_atom (escape (unquote (TokenChars, TokenLen)), TokenLine) . | |||||
-compile({inline,yyaction_2/3}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 16). | |||||
yyaction_2(TokenChars, TokenLen, TokenLine) -> | |||||
{ token, { string, TokenLine, escape (unquote (TokenChars, TokenLen)) } } . | |||||
-compile({inline,yyaction_3/2}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 17). | |||||
yyaction_3(TokenChars, TokenLine) -> | |||||
{ token, { integer, TokenLine, list_to_integer (TokenChars) } } . | |||||
-compile({inline,yyaction_4/2}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 18). | |||||
yyaction_4(TokenChars, TokenLine) -> | |||||
{ token, { list_to_atom (TokenChars), TokenLine } } . | |||||
-compile({inline,yyaction_5/2}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 19). | |||||
yyaction_5(TokenChars, TokenLine) -> | |||||
{ token, { list_to_atom (TokenChars), TokenLine } } . | |||||
-compile({inline,yyaction_6/1}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 20). | |||||
yyaction_6(TokenLine) -> | |||||
{ token, { dot, TokenLine } } . | |||||
-compile({inline,yyaction_7/1}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 21). | |||||
yyaction_7(TokenLine) -> | |||||
{ token, { '/', TokenLine } } . | |||||
-compile({inline,yyaction_8/0}). | |||||
-file("/Users/starbelly/devel/erlang/rebar3/src/hex_core/r3_safe_erl_term.xrl", 22). | |||||
yyaction_8() -> | |||||
skip_token . | |||||
-file("/usr/local/lib/erlang/lib/parsetools-2.1.8/include/leexinc.hrl", 313). |
@ -0,0 +1,79 @@ | |||||
%% Vendored from hex_core v0.5.0, do not edit manually | |||||
%%% Author : Robert Virding | |||||
%%% Purpose : Token definitions for Erlang. | |||||
Definitions. | |||||
D = [0-9] | |||||
U = [A-Z] | |||||
L = [a-z] | |||||
A = ({U}|{L}|{D}|_|@) | |||||
WS = ([\000-\s]|%.*) | |||||
Rules. | |||||
{L}{A}* : tokenize_atom(TokenChars, TokenLine). | |||||
'(\\\^.|\\.|[^'])*' : tokenize_atom(escape(unquote(TokenChars, TokenLen)), TokenLine). | |||||
"(\\\^.|\\.|[^"])*" : {token, {string, TokenLine, escape(unquote(TokenChars, TokenLen))}}. | |||||
{D}+ : {token, {integer, TokenLine, list_to_integer(TokenChars)}}. | |||||
[\#\[\]}{,+-] : {token, {list_to_atom(TokenChars), TokenLine}}. | |||||
(<<|>>|=>) : {token, {list_to_atom(TokenChars), TokenLine}}. | |||||
\. : {token, {dot, TokenLine}}. | |||||
/ : {token, {'/', TokenLine}}. | |||||
{WS}+ : skip_token. | |||||
Erlang code. | |||||
-export([terms/1]). | |||||
terms(Tokens) -> | |||||
terms(Tokens, []). | |||||
terms([{dot, _} = H], Buffer) -> | |||||
[buffer_to_term([H|Buffer])]; | |||||
terms([{dot, _} = H|T], Buffer) -> | |||||
[buffer_to_term([H|Buffer])|terms(T, [])]; | |||||
terms([H|T], Buffer) -> | |||||
terms(T, [H|Buffer]). | |||||
buffer_to_term(Buffer) -> | |||||
{ok, Term} = erl_parse:parse_term(lists:reverse(Buffer)), | |||||
Term. | |||||
unquote(TokenChars, TokenLen) -> | |||||
lists:sublist(TokenChars, 2, TokenLen - 2). | |||||
tokenize_atom(TokenChars, TokenLine) -> | |||||
try list_to_existing_atom(TokenChars) of | |||||
Atom -> {token, {atom, TokenLine, Atom}} | |||||
catch | |||||
error:badarg -> {error, "illegal atom " ++ TokenChars} | |||||
end. | |||||
escape([$\\|Cs]) -> | |||||
do_escape(Cs); | |||||
escape([C|Cs]) -> | |||||
[C|escape(Cs)]; | |||||
escape([]) -> []. | |||||
do_escape([O1,O2,O3|S]) when | |||||
O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 -> | |||||
[(O1*8 + O2)*8 + O3 - 73*$0|escape(S)]; | |||||
do_escape([$^,C|Cs]) -> | |||||
[C band 31|escape(Cs)]; | |||||
do_escape([C|Cs]) when C >= $\000, C =< $\s -> | |||||
escape(Cs); | |||||
do_escape([C|Cs]) -> | |||||
[escape_char(C)|escape(Cs)]. | |||||
escape_char($n) -> $\n; %\n = LF | |||||
escape_char($r) -> $\r; %\r = CR | |||||
escape_char($t) -> $\t; %\t = TAB | |||||
escape_char($v) -> $\v; %\v = VT | |||||
escape_char($b) -> $\b; %\b = BS | |||||
escape_char($f) -> $\f; %\f = FF | |||||
escape_char($e) -> $\e; %\e = ESC | |||||
escape_char($s) -> $\s; %\s = SPC | |||||
escape_char($d) -> $\d; %\d = DEL | |||||
escape_char(C) -> C. |