- 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. |