diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/stdlib/test/zip_SUITE.erl | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/stdlib/test/zip_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/zip_SUITE.erl | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl new file mode 100644 index 0000000000..55cbd277ef --- /dev/null +++ b/lib/stdlib/test/zip_SUITE.erl @@ -0,0 +1,759 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(zip_SUITE). + +-export([all/1, borderline/1, atomic/1, + bad_zip/1, unzip_from_binary/1, unzip_to_binary/1, + zip_to_binary/1, + unzip_options/1, zip_options/1, list_dir_options/1, aliases/1, + openzip_api/1, zip_api/1, unzip_jar/1, + compress_control/1]). + +-include("test_server.hrl"). +-include("test_server_line.hrl"). +-include_lib("kernel/include/file.hrl"). +-include_lib("stdlib/include/zip.hrl"). + +all(suite) -> [borderline, atomic, bad_zip, + unzip_from_binary, unzip_to_binary, + zip_to_binary, + unzip_options, zip_options, list_dir_options, aliases, + openzip_api, zip_api, unzip_jar, + compress_control]. + +borderline(doc) -> + ["Test creating, listing and extracting one file from an archive " + "multiple times with different file sizes. Also check that the " + "modification date of the extracted file has survived."]; +borderline(Config) when is_list(Config) -> + RootDir = ?config(priv_dir, Config), + TempDir = filename:join(RootDir, "borderline"), + ok = file:make_dir(TempDir), + + Record = 512, + Block = 20 * Record, + + lists:foreach(fun(Size) -> borderline_test(Size, TempDir) end, + [0, 1, 10, 13, 127, 333, Record-1, Record, Record+1, + Block-Record-1, Block-Record, Block-Record+1, + Block-1, Block, Block+1, + Block+Record-1, Block+Record, Block+Record+1]), + + %% Clean up. + delete_files([TempDir]), + ok. + +borderline_test(Size, TempDir) -> + Archive = filename:join(TempDir, "ar_"++integer_to_list(Size)++".zip"), + Name = filename:join(TempDir, "file_"++integer_to_list(Size)), + io:format("Testing size ~p", [Size]), + + %% Create a file and archive it. + {_, _, X0} = erlang:now(), + file:write_file(Name, random_byte_list(X0, Size)), + {ok, Archive} = zip:zip(Archive, [Name]), + ok = file:delete(Name), + + %% Verify listing and extracting. + {ok, [#zip_comment{comment = []}, + #zip_file{name = Name, + info = Info, + offset = 0, + comp_size = _}]} = zip:list_dir(Archive), + Size = Info#file_info.size, + {ok, [Name]} = zip:extract(Archive, [verbose]), + + %% Verify contents of extracted file. + {ok, Bin} = file:read_file(Name), + true = match_byte_list(X0, binary_to_list(Bin)), + + + %% Verify that Unix zip can read it. (if we have a unix zip that is!) + unzip_list(Archive, Name), + + ok. + +unzip_list(Archive, Name) -> + case os:find_executable("unzip") of + Unzip when is_list(Unzip) -> + unzip_list1(Archive, Name); + _ -> + ok + end. + +unzip_list1(Archive, Name) -> + Expect = Name ++ "\n", + cmd_expect("unzip -Z -1 " ++ Archive, Expect). + +cmd_expect(Cmd, Expect) -> + Port = open_port({spawn, make_cmd(Cmd)}, [stream, in, eof]), + get_data(Port, Expect). + +get_data(Port, Expect) -> + receive + {Port, {data, Bytes}} -> + get_data(Port, match_output(Bytes, Expect, Port)); + {Port, eof} -> + Port ! {self(), close}, + receive + {Port, closed} -> + true + end, + receive + {'EXIT', Port, _} -> + ok + after 1 -> % force context switch + ok + end, + match_output(eof, Expect, Port) + end. + +match_output([C|Output], [C|Expect], Port) -> + match_output(Output, Expect, Port); +match_output([_|_], [_|_], Port) -> + kill_port_and_fail(Port, badmatch); +match_output([X|Output], [], Port) -> + kill_port_and_fail(Port, {too_much_data, [X|Output]}); +match_output([], Expect, _Port) -> + Expect; +match_output(eof, [], _Port) -> + []; +match_output(eof, Expect, Port) -> + kill_port_and_fail(Port, {unexpected_end_of_input, Expect}). + +kill_port_and_fail(Port, Reason) -> + unlink(Port), + exit(Port, die), + test_server:fail(Reason). + +make_cmd(Cmd) -> + Cmd. +%% case os:type() of +%% {win32, _} -> lists:concat(["cmd /c", Cmd]); +%% {unix, _} -> lists:concat(["sh -c '", Cmd, "'"]) +%% end. + +%% Verifies a random byte list. + +match_byte_list(X0, [Byte|Rest]) -> + X = next_random(X0), + case (X bsr 26) band 16#ff of + Byte -> match_byte_list(X, Rest); + _ -> false + end; +match_byte_list(_, []) -> + true. + +%% Generates a random byte list. + +random_byte_list(X0, Count) -> + random_byte_list(X0, Count, []). + +random_byte_list(X0, Count, Result) when Count > 0-> + X = next_random(X0), + random_byte_list(X, Count-1, [(X bsr 26) band 16#ff|Result]); +random_byte_list(_X, 0, Result) -> + lists:reverse(Result). + +%% This RNG is from line 21 on page 102 in Knuth: The Art of Computer Programming, +%% Volume II, Seminumerical Algorithms. + +next_random(X) -> + (X*17059465+1) band 16#fffffffff. + +atomic(doc) -> + ["Test the 'atomic' operations: zip/unzip/list_dir, on archives." + "Also test the 'cooked' option."]; +atomic(suite) -> []; +atomic(Config) when list(Config) -> + ok = file:set_cwd(?config(priv_dir, Config)), + DataFiles = data_files(), + Names = [Name || {Name,_,_} <- DataFiles], + io:format("Names: ~p", [Names]), + + %% Create a zip archive. + + Zip2 = "zip.zip", + {ok, Zip2} = zip:zip(Zip2, Names, []), + Names = names_from_list_dir(zip:list_dir(Zip2)), + + %% Same test again, but this time created with 'cooked' + + Zip3 = "cooked.zip", + {ok, Zip3} = zip:zip(Zip3, Names, [cooked]), + Names = names_from_list_dir(zip:list_dir(Zip3)), + Names = names_from_list_dir(zip:list_dir(Zip3, [cooked])), + + %% Clean up. + delete_files([Zip2,Zip3|Names]), + + ok. + +openzip_api(doc) -> + ["Test the openzip_open/2, openzip_get/1, openzip_get/2, openzip_close/1 " + "and openzip_list_dir/1 functions."]; +openzip_api(suite) -> []; +openzip_api(Config) when list(Config) -> + ok = file:set_cwd(?config(priv_dir, Config)), + DataFiles = data_files(), + Names = [Name || {Name, _, _} <- DataFiles], + io:format("Names: ~p", [Names]), + + %% Create a zip archive + + Zip = "zip.zip", + {ok, Zip} = zip:zip(Zip, Names, []), + + %% Open archive + {ok, OpenZip} = zip:openzip_open(Zip, [memory]), + + %% List dir + Names = names_from_list_dir(zip:openzip_list_dir(OpenZip)), + + %% Get a file + Name1 = hd(Names), + {ok, Data1} = file:read_file(Name1), + {ok, {Name1, Data1}} = zip:openzip_get(Name1, OpenZip), + + %% Get all files + FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(Name), + {Name, B} end, Names), + {ok, FilesDatas} = zip:openzip_get(OpenZip), + + %% Close + ok = zip:openzip_close(OpenZip), + + %% Clean up. + delete_files([Names]), + + ok. + +zip_api(doc) -> + ["Test the zip_open/2, zip_get/1, zip_get/2, zip_close/1 " + "and zip_list_dir/1 functions."]; +zip_api(suite) -> []; +zip_api(Config) when list(Config) -> + ok = file:set_cwd(?config(priv_dir, Config)), + DataFiles = data_files(), + Names = [Name || {Name, _, _} <- DataFiles], + io:format("Names: ~p", [Names]), + + %% Create a zip archive + Zip = "zip.zip", + {ok, Zip} = zip:zip(Zip, Names, []), + + %% Open archive + {ok, ZipSrv} = zip:zip_open(Zip, [memory]), + + %% List dir + Names = names_from_list_dir(zip:zip_list_dir(ZipSrv)), + + %% Get a file + Name1 = hd(Names), + {ok, Data1} = file:read_file(Name1), + {ok, {Name1, Data1}} = zip:zip_get(Name1, ZipSrv), + + %% Get all files + FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(Name), + {Name, B} end, Names), + {ok, FilesDatas} = zip:zip_get(ZipSrv), + + %% Close + ok = zip:zip_close(ZipSrv), + + %% Clean up. + delete_files([Names]), + + ok. + +unzip_options(doc) -> + ["Test options for unzip, only cwd and file_list currently"]; +unzip_options(suite) -> + []; +unzip_options(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + Long = filename:join(DataDir, "abc.zip"), + + %% create a temp directory + Subdir = filename:join(PrivDir, "t"), + ok = file:make_dir(Subdir), + + FList = ["quotes/rain.txt","wikipedia.txt"], + + %% Unzip a zip file in Subdir + ?line {ok, RetList} = zip:unzip(Long, [{cwd, Subdir}, + {file_list, FList}]), + + %% Verify. + ?line true = (length(FList) =:= length(RetList)), + ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), + {ok,B} = file:read_file(filename:join(Subdir, F)) end, + FList), + ?line lists:foreach(fun(F)-> ok = file:delete(F) end, + RetList), + + %% Clean up and verify no more files. + ?line 0 = delete_files([Subdir]), + ok. + +unzip_jar(doc) -> + ["Test unzip a jar file (OTP-7382)"]; +unzip_jar(suite) -> + []; +unzip_jar(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + JarFile = filename:join(DataDir, "test.jar"), + + %% create a temp directory + Subdir = filename:join(PrivDir, "jartest"), + ok = file:make_dir(Subdir), + ok = file:set_cwd(Subdir), + + FList = ["META-INF/MANIFEST.MF","test.txt"], + + {ok, RetList} = zip:unzip(JarFile), + + %% Verify. + ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), + {ok,B} = file:read_file(filename:join(Subdir, F)) end, + FList), + ?line lists:foreach(fun(F)-> ok = file:delete(F) end, + RetList), + + %% Clean up and verify no more files. + ?line 0 = delete_files([Subdir]), + ok. + +zip_options(doc) -> + ["Test the options for unzip, only cwd currently"]; +zip_options(suite) -> + []; +zip_options(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + ok = file:set_cwd(PrivDir), + DataFiles = data_files(), + Names = [Name || {Name, _, _} <- DataFiles], + + %% Make sure cwd is not where we get the files + ok = file:set_cwd(?config(data_dir, Config)), + + %% Create a zip archive + {ok, Zip} = zip:zip("filename_not_used.zip", Names, [memory, {cwd, PrivDir}]), + + %% Open archive + {ok, ZipSrv} = zip:zip_open(Zip, [memory]), + + %% List dir + Names = names_from_list_dir(zip:zip_list_dir(ZipSrv)), + + %% Get a file + Name1 = hd(Names), + {ok, Data1} = file:read_file(filename:join(PrivDir, Name1)), + {ok, {Name1, Data1}} = zip:zip_get(Name1, ZipSrv), + + %% Get all files + FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(filename:join(PrivDir, Name)), + {Name, B} end, Names), + {ok, FilesDatas} = zip:zip_get(ZipSrv), + + %% Close + ok = zip:zip_close(ZipSrv), + + %% Clean up. + delete_files([Names]), + + ok. + +list_dir_options(doc) -> + ["Test the options for list_dir... one day"]; +list_dir_options(suite) -> + []; +list_dir_options(Config) when is_list(Config) -> + ok. + + + + +%% convert zip_info as returned from list_dir to a list of names +names_from_list_dir({ok, Info}) -> + names_from_list_dir(Info); +names_from_list_dir(Info) -> + tl(lists:map(fun(#zip_file{name = Name}) -> Name; + (_) -> ok end, Info)). + +%% Returns a sequence of characters. +char_seq(N, First) -> + char_seq(N, First, []). + +char_seq(0, _, Result) -> + Result; +char_seq(N, C, Result) when C < 127 -> + char_seq(N-1, C+1, [C|Result]); +char_seq(N, _, Result) -> + char_seq(N, $!, Result). + +data_files() -> + Files = [{"first_file", 1555, $a}, + {"small_file", 7, $d}, + {"big_file", 23875, $e}, + {"last_file", 7500, $g}], + create_files(Files), + Files. + +create_files([{Name, dir, _First}|Rest]) -> + ok = file:make_dir(Name), + create_files(Rest); +create_files([{Name, Size, First}|Rest]) when is_integer(Size) -> + ok = file:write_file(Name, char_seq(Size, First)), + create_files(Rest); +create_files([]) -> + ok. + +%% make_dirs([Dir|Rest], []) -> +%% ok = file:make_dir(Dir), +%% make_dirs(Rest, Dir); +%% make_dirs([Dir|Rest], Parent) -> +%% Name = filename:join(Parent, Dir), +%% ok = file:make_dir(Name), +%% make_dirs(Rest, Name); +%% make_dirs([], Dir) -> +%% Dir. + +bad_zip(doc) -> + ["Try zip:unzip/1 on some corrupted zip files."]; +bad_zip(Config) when is_list(Config) -> + ok = file:set_cwd(?config(priv_dir, Config)), + try_bad("bad_crc", {bad_crc, "abc.txt"}, Config), + try_bad("bad_central_directory", bad_central_directory, Config), + try_bad("bad_file_header", bad_file_header, Config), + try_bad("bad_eocd", bad_eocd, Config), + try_bad("enoent", enoent, Config), + GetNotFound = fun(A) -> + {ok, O} = zip:openzip_open(A, []), + zip:openzip_get("not_here", O) + end, + try_bad("abc", file_not_found, GetNotFound, Config), + ok. + +try_bad(N, R, Config) -> + try_bad(N, R, fun(A) -> io:format("name : ~p\n", [A]), + zip:unzip(A, [verbose]) end, Config). + +try_bad(Name0, Reason, What, Config) -> + %% Intentionally no macros here. + + DataDir = ?config(data_dir, Config), + Name = Name0 ++ ".zip", + io:format("~nTrying ~s", [Name]), + Full = filename:join(DataDir, Name), + Expected = {error, Reason}, + case What(Full) of + Expected -> + io:format("Result: ~p\n", [Expected]); + Other -> + io:format("unzip/2 returned ~p (expected ~p)\n", [Other, Expected]), + test_server:fail({bad_return_value, Other}) + end. + +unzip_to_binary(doc) -> + ["Test extracting to binary with memory option."]; +unzip_to_binary(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + + delete_all_in(PrivDir), + file:set_cwd(PrivDir), + Long = filename:join(DataDir, "abc.zip"), + + %% Unzip a zip file into a binary + {ok, FBList} = zip:unzip(Long, [memory]), + + %% Verify. + lists:foreach(fun({F,B}) -> {ok,B}=file:read_file(filename:join(DataDir, F)) + end, FBList), + + %% Make sure no files created in cwd + {ok,[]} = file:list_dir(PrivDir), + + ok. + +zip_to_binary(doc) -> + ["Test compressing to binary with memory option."]; +zip_to_binary(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + delete_all_in(PrivDir), + file:set_cwd(PrivDir), + FileName = "abc.txt", + ZipName = "t.zip", + FilePath = filename:join(DataDir, FileName), + {ok, _Size} = file:copy(FilePath, FileName), + + %% Zip to a binary archive + {ok, {ZipName, ZipB}} = zip:zip(ZipName, [FileName], [memory]), + + %% Make sure no files created in cwd + {ok,[FileName]} = file:list_dir(PrivDir), + + %% Zip to a file + {ok, ZipName} = zip:zip(ZipName, [FileName]), + + %% Verify. + {ok, ZipB} = file:read_file(ZipName), + {ok, FData} = file:read_file(FileName), + {ok, [{FileName, FData}]} = zip:unzip(ZipB, [memory]), + + %% Clean up. + delete_files([FileName, ZipName]), + + ok. + +aliases(doc) -> + ["Test using the aliases, extract/2, table/2 and create/3"]; +aliases(Config) when is_list(Config) -> + {_, _, X0} = erlang:now(), + Size = 100, + B = list_to_binary(random_byte_list(X0, Size)), + %% create + {ok, {"z.zip", ZArchive}} = zip:create("z.zip", [{"b", B}], [memory]), + %% extract + {ok, [{"b", B}]} = zip:extract(ZArchive, [memory]), + %% table + {ok, [#zip_comment{comment = _}, #zip_file{name = "b", + info = FI, + comp_size = _, + offset = 0}]} = + zip:table(ZArchive), + Size = FI#file_info.size, + + ok. + + + +unzip_from_binary(doc) -> + ["Test extracting a zip archive from a binary."]; +unzip_from_binary(Config) when list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ExtractDir = filename:join(PrivDir, "extract_from_binary"), + ok = file:make_dir(ExtractDir), + Archive = filename:join(ExtractDir, "abc.zip"), + {ok, _Size} = file:copy(filename:join(DataDir, "abc.zip"), Archive), + FileName = "abc.txt", + Quote = "quotes/rain.txt", + Wikipedia = "wikipedia.txt", + EmptyFile = "emptyFile", + file:set_cwd(ExtractDir), + + %% Read a zip file into a binary and extract from the binary. + {ok, Bin} = file:read_file(Archive), + {ok, [FileName,Quote,Wikipedia,EmptyFile]} = zip:unzip(Bin), + + %% Verify. + DestFilename = filename:join(ExtractDir, "abc.txt"), + {ok, Data} = file:read_file(filename:join(DataDir, FileName)), + {ok, Data} = file:read_file(DestFilename), + + DestQuote = filename:join([ExtractDir, "quotes", "rain.txt"]), + {ok, QuoteData} = file:read_file(filename:join(DataDir, Quote)), + {ok, QuoteData} = file:read_file(DestQuote), + + %% Clean up. + delete_files([DestFilename, DestQuote, Archive, ExtractDir]), + ok. + +%% oac_files() -> +%% Files = [{"oac_file", 1459, $x}, +%% {"oac_small", 99, $w}, +%% {"oac_big", 33896, $A}], +%% create_files(Files), +%% Files. + +%% Delete the given list of files and directories. +%% Return total number of deleted files (not directories) +delete_files(List) -> + do_delete_files(List, 0). +do_delete_files([],Cnt) -> + Cnt; +do_delete_files([Item|Rest], Cnt) -> + case file:delete(Item) of + ok -> + DelCnt = 1; + {error,eperm} -> + file:change_mode(Item, 8#777), + DelCnt = delete_files(filelib:wildcard(filename:join(Item, "*"))), + file:del_dir(Item); + {error,eacces} -> + %% We'll see about that! + file:change_mode(Item, 8#777), + case file:delete(Item) of + ok -> + DelCnt = 1; + {error,_} -> + erlang:yield(), + file:change_mode(Item, 8#777), + file:delete(Item), + DelCnt = 1 + end; + {error,_} -> + DelCnt = 0 + end, + do_delete_files(Rest, Cnt + DelCnt). + +delete_all_in(Dir) -> + {ok, Files} = file:list_dir(Dir), + delete_files(lists:map(fun(F) -> filename:join(Dir,F) end, + Files)). + +compress_control(doc) -> + ["Test control of which files that should be compressed"]; +compress_control(suite) -> []; +compress_control(Config) when list(Config) -> + ok = file:set_cwd(?config(priv_dir, Config)), + Dir = "compress_control", + Files = [ + {Dir, dir, $d}, + {filename:join([Dir, "first_file.txt"]), 10000, $f}, + {filename:join([Dir, "a_dir"]), dir, $d}, + {filename:join([Dir, "a_dir", "zzz.zip"]), 10000, $z}, + {filename:join([Dir, "a_dir", "lll.lzh"]), 10000, $l}, + {filename:join([Dir, "a_dir", "eee.exe"]), 10000, $e}, + {filename:join([Dir, "a_dir", "ggg.arj"]), 10000, $g}, + {filename:join([Dir, "a_dir", "b_dir"]), dir, $d}, + {filename:join([Dir, "a_dir", "b_dir", "ggg.arj"]), 10000, $a}, + {filename:join([Dir, "last_file.txt"]), 10000, $l} + ], + + test_compress_control(Dir, + Files, + [{compress, []}], + []), + + test_compress_control(Dir, + Files, + [{uncompress, all}], + []), + + test_compress_control(Dir, + Files, + [{uncompress, []}], + [".txt", ".exe", ".zip", ".lzh", ".arj"]), + + test_compress_control(Dir, + Files, + [], + [".txt", ".exe"]), + + test_compress_control(Dir, + Files, + [{uncompress, {add, [".exe"]}}, + {uncompress, {del, [".zip", "arj"]}}], + [".txt", ".zip", "arj"]), + + test_compress_control(Dir, + Files, + [{uncompress, []}, + {uncompress, {add, [".exe"]}}, + {uncompress, {del, [".zip", "arj"]}}], + [".txt", ".zip", ".lzh", ".arj"]), + + ok. + +test_compress_control(Dir, Files, ZipOptions, Expected) -> + %% Cleanup + Zip = "zip.zip", + Names = [N || {N, _, _} <- Files], + delete_files([Zip]), + delete_files(lists:reverse(Names)), + + create_files(Files), + {ok, Zip} = zip:create(Zip, [Dir], ZipOptions), + + {ok, OpenZip} = zip:openzip_open(Zip, [memory]), + {ok,[#zip_comment{comment = ""} | ZipList]} = zip:openzip_list_dir(OpenZip), + io:format("compress_control: -> ~p -> ~p\n -> ~pn", [Expected, ZipOptions, ZipList]), + verify_compression(Files, ZipList, OpenZip, ZipOptions, Expected), + ok = zip:openzip_close(OpenZip), + + %% Cleanup + delete_files([Zip]), + delete_files(lists:reverse(Names)), % Remove plain files before directories + + ok. + +verify_compression([{Name, Kind, _Filler} | Files], ZipList, OpenZip, ZipOptions, Expected) -> + {Name2, BinSz} = + case Kind of + dir -> + {Name ++ "/", 0}; + _ -> + {ok, {Name, Bin}} = zip:openzip_get(Name, OpenZip), + {Name, size(Bin)} + end, + {Name2, {value, ZipFile}} = {Name2, lists:keysearch(Name2, #zip_file.name, ZipList)}, + #zip_file{info = #file_info{size = InfoSz, type = InfoType}, comp_size = InfoCompSz} = ZipFile, + + Ext = filename:extension(Name), + IsComp = is_compressed(Ext, Kind, ZipOptions), + ExpComp = lists:member(Ext, Expected), + case {Name, Kind, InfoType, IsComp, ExpComp, BinSz, InfoSz, InfoCompSz} of + {_, dir, directory, false, _, Sz, Sz, Sz} when Sz =:= BinSz -> ok; + {_, Sz, regular, false, false, Sz, Sz, Sz} when Sz =:= BinSz -> ok; + {_, Sz, regular, true, true, Sz, Sz, OtherSz} when Sz =:= BinSz, OtherSz =/= BinSz -> ok + end, + verify_compression(Files, ZipList -- [ZipFile], OpenZip, ZipOptions, Expected); +verify_compression([], [], _OpenZip, _ZipOptions, _Expected) -> + ok. + +is_compressed(_Ext, dir, _Options) -> + false; +is_compressed(Ext, _Sz, Options) -> + CompressOpt = + case [What || {compress, What} <- Options] of + [] -> all; + CompressOpts-> extensions(CompressOpts, all) + end, + DoCompress = (CompressOpt =:= all) orelse lists:member(Ext, CompressOpt), + Default = [".Z", ".zip", ".zoo", ".arc", ".lzh", ".arj"], + UncompressOpt = + case [What || {uncompress, What} <- Options] of + [] -> Default; + UncompressOpts-> extensions(UncompressOpts, Default) + end, + DoUncompress = (UncompressOpt =:= all) orelse lists:member(Ext, UncompressOpt), + DoCompress andalso not DoUncompress. + +extensions([H | T], Old) -> + case H of + all -> + extensions(T, H); + H when is_list(H) -> + extensions(T, H); + {add, New} when is_list(New), is_list(Old) -> + extensions(T, Old ++ New); + {del, New} when is_list(New), is_list(Old) -> + extensions(T, Old -- New); + _ -> + extensions(T, Old) + end; +extensions([], Old) -> + Old. + |