1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2018, VU University Amsterdam 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(zip, 36 [ zip_open/4, % +File, +Mode, -Zipper, +Options 37 zip_close/1, % +Zipper 38 zip_close/2, % +Zipper, +Comment 39 % Entry predicates 40 with_zipper/2, % +Zipper, :Goal 41 zipper_open_new_file_in_zip/4, % +Zipper, +File, -Stream, +Options 42 zipper_goto/2, % +Zipper, +Where 43 zipper_open_current/3, % +Zipper, -Stream, +Options 44 zipper_members/2, % +Zipper, -Entries 45 zipper_file_info/3 % +Zipper, -Name, -Attrs 46 ]). 47:- autoload(library(error),[must_be/2]). 48:- autoload(library(option),[option/3]). 49 50 51:- meta_predicate 52 with_zipper( , ). 53 54/** <module> Access resource ZIP archives 55 56This library provides access to ZIP files. ZIP files are used to store 57SWI-Prolog _resources_. Ths library provides more high level access and 58documentation in addition to the low level access provided as built in 59as it is needed to bootstrap SWI-Prolog. 60 61Access to a zip file is provided by means of a _zipper_ object. This is 62a _blob_ that is subject to atom garbage collection. Collecting a zipper 63closes the underlying OS access. 64 65A zipper is a stateful object. We recognise the following states: 66_idle_, _scan_, _read_entry_, _write_entry_ and _close_. The interface 67raise a _permission_error_ when trying to make an illegal state 68transition. 69 70Being stateful, a zipper cannot be used simultaneously from multiple 71threads. The zipper becomes _owned_ by a thread when moving to _scan_ 72using zipper_goto/2. It is released after zipper_open_current/3 followed 73by closing the stream. 74*/ 75 76%! zip_open(+File, +Mode, -Zipper, +Options) is det. 77% 78% Create a Zipper, providing access to File. Mode is one of `read` or 79% `write`. The Options list is currently ignored. 80 81zip_open(File, Mode, Zipper, _Options) :- 82 must_be(oneof([read,write]), Mode), 83 open(File, Mode, Stream, [type(binary)]), 84 zip_open_stream(Stream, Zipper, [close_parent(true)]). 85 86%! zip_close(+Zipper) is det. 87%! zip_close(+Zipper, +Options) is det. 88% 89% Close a zipper. Options processed: 90% 91% - comment(+Comment) 92% If the zipper is open for writing, set the global comment 93% for the zip file. 94 95zip_close(Zipper) :- 96 zip_close_(Zipper, _). 97zip_close(Zipper, Options) :- 98 option(comment(Comment), Options, _), 99 zip_close_(Zipper, Comment). 100 101%! zipper_goto(+Zipper, +Where) is semidet. 102% 103% Seek Zipper to a specified entry. Where is one of 104% 105% - first 106% Go to the first entry. Fails if the zip is empty. 107% - next 108% Go to the next entry. Fails if there is no next entry. 109% - file(Name) 110% Go to the entry with the specified name. 111% 112 113%! zipper_open_current(+Zipper, -Stream, +Options) is det. 114% 115% Open the current entry as an input stream. Before this call the 116% caller must use zipper_goto/2 to position to archive. Options: 117% 118% - type(+Type) 119% - encoding(+Encoding) 120% - bom(+Boolean) 121% Determine type and encoding of the stream. The semantics 122% is the same as for open/4. 123% - release(+Boolean) 124% If `true` (default), release te archive for access by other 125% threads after the entry is closed. 126% 127% It is allowed to call zip_close/1 immediately after this call, in 128% which case the archive is closed when the entry is closed. 129 130%! with_zipper(+Zipper, :Goal) 131% 132% Run Goal while holding ownership over Zipper. 133 134with_zipper(Zipper, Goal) :- 135 setup_call_cleanup( 136 zip_lock(Zipper), 137 Goal, 138 zip_unlock(Zipper)). 139 140%! zipper_members(+Zipper, -Members:list(atom)) is det. 141% 142% True when Members is the list of file names in the Zipper. 143 144zipper_members(Zipper, Members) :- 145 with_zipper(Zipper, 146 ( zipper_goto(Zipper, first), 147 zip_members_(Zipper, Members) 148 )). 149 150zip_members_(Zipper, [Name|T]) :- 151 zip_file_info_(Zipper, Name, _Attrs), 152 ( zipper_goto(Zipper, next) 153 -> zip_members_(Zipper, T) 154 ; T = [] 155 ). 156 157%! zipper_file_info(+Zipper, -Name, -Attrs) is det. 158% 159% Obtain information about the current zip entry. Name is an atom 160% representing the name of the entry. Attrs is a dict holding: 161% 162% - compressed_size:Bytes 163% Size in the archive 164% - uncompressed_size:Bytes 165% Bytes after decompression 166% - time:Stamp 167% Numeric time stamp in Prolog native format (float 168% expressing seconds since Jan 1, 1970). Note that 169% the resolution of time in zip archives is one 170% second. 171% - extra:Extra 172% - comment:Extra 173% Optional additional fields. 174% - offset:Offset 175% Direct pointer to this entry. May be used with zip_goto/2. 176 177zipper_file_info(Zipper, Name, Attrs) :- 178 zip_file_info_(Zipper, Name, 179 info(CompressedSize, UnCompressedSize, 180 Extra, Comment, 181 Time, Offset)), 182 Attrs0 = zip{compressed_size:CompressedSize, 183 uncompressed_size:UnCompressedSize, 184 offset:Offset 185 }, 186 zip_attr(Extra, extra, Attrs0, Attrs1), 187 zip_attr(Comment, comment, Attrs1, Attrs2), 188 zip_attr(Time, time, Attrs2, Attrs). 189 190zip_attr("", _, Attrs, Attrs) :- !. 191zip_attr('', _, Attrs, Attrs) :- !. 192zip_attr(Value, Name, Attrs0, Attrs) :- 193 put_dict(Name, Attrs0, Value, Attrs). 194 195%! zipper_open_new_file_in_zip(+Zipper, +Name, -Stream, +Options) is det. 196% 197% Create a new file in a zip archive. Options provided are: 198% 199% - extra(+Text) 200% Additional meta-data 201% - comment(+Text) 202% Comment for the entry. 203% - time(+Stamp) 204% Last modified time claimed for the entry. 205% - method(+Method) 206% One of `deflated` (default) or `store` (store uncompressed) 207% - level(+Compression) 208% Compression level (0..9, default 6). 209% - zip64(+Boolean) 210% When `true` (default `false`), allow the entry to grow above 211% 4Gb.