Packages

Bindings to Erlang's zip module

Current section

Files

Jump to
zipbeam src zipbeam_ffi.erl
Raw

src/zipbeam_ffi.erl

-module(zipbeam_ffi).
-export([create_in_memory/1, open/1, close/1, files/1, get/2]).
-include("../include/zipbeam_File.hrl").
-include_lib("kernel/include/file.hrl").
-include_lib("stdlib/include/zip.hrl").
open(Zip) ->
case zip:zip_open(Zip, [memory]) of
{ok, Handle} -> {ok, Handle};
{error, _} -> {error, nil}
end.
close(Handle) ->
_ = zip:zip_close(Handle),
nil.
files(Handle) ->
% The Erlang zip is based around a process, for some reason. It also goes
% against best practices and does not use gen_server or even timeouts, so
% if you try to use it after the process exits then it hangs forever.
% This check attempts to prevent that, but there is a race condition here.
% Good luck.
case erlang:is_process_alive(Handle) of
false ->
{error, nil};
true ->
case zip:zip_list_dir(Handle) of
{ok, [#zip_comment{} | Files]} ->
{ok, lists:map(fun convert_file/1, Files)};
{error, _} ->
{error, nil}
end
end.
create(Name, Files, Options) ->
F = fun({A, B}) ->
{unicode:characters_to_list(A), B}
end,
zip:zip(Name, lists:map(F, Files), Options).
create_in_memory({zip_builder, Files}) ->
{ok, {_, Data}} = create(<<"archive.zip">>, Files, [memory]),
Data.
convert_file(#zip_file{name = Path, info = #file_info{size = Size}}) ->
#file{
path = unicode:characters_to_binary(Path),
size_bytes = Size
}.
get(Handle, Name) ->
% The Erlang zip is based around a process, for some reason. It also goes
% against best practices and does not use gen_server or even timeouts, so
% if you try to use it after the process exits then it hangs forever.
% This check attempts to prevent that, but there is a race condition here.
% Good luck.
case erlang:is_process_alive(Handle) of
false ->
{error, nil};
true ->
case zip:zip_get(Name, Handle) of
{ok, {_, Data}} -> {ok, Data};
{error, file_not_found} -> {error, nil}
end
end.