1@; -*- coding: utf-8 -*- 2@subsection[:tag "archive"]{(archive) - Generic archive interface} 3 4@define[Library]{@name{archive}} 5@desc{This library provides generic interface to access archive libraries. 6Sagittarius supports @code{tar} and @code{zip}. 7} 8 9Following code describes a typical use of the library; 10 11@codeblock{ 12(import (rnrs) (archive)) 13 14;; extract file "bar.txt" from "foo.zip" 15(call-with-input-archive-file 'zip "foo.zip" 16 (lambda (zip-in) 17 (do-entry (e zip-in) 18 (when (string=? (archive-entry-name e) "bar.txt") 19 (call-with-output-file "bar.txt" 20 (lambda (out) (extract-entry e out)) 21 :transcoder #f))))) 22 23;; archive "bar.txt" into foo.tar 24(call-with-output-archive-file 'tar "foo.tar" 25 (lambda (tar-out) 26 (append-entry! tar-out (create-entry tar-out "bar.txt")))) 27 28} 29 30Following sections use @var{type} as a supported archive type. More precisely, 31if it's a supported archive type then there must be a library named 32@code{(archive @var{type})}. 33 34@subsubsection{Archive input} 35 36@define[Function]{@name{make-input-archive} @args{type input-port}} 37@desc{@var{type} must be a symbol and supported archive type. 38@var{input-port} must be a binary input port. 39 40Creates an archive input which represents the specified type of archive. 41} 42 43@define[Method]{@name{next-entry!} @args{archive-input}} 44@desc{Retrieves next entry of the given archive input. If there is no entry, 45then it returns #f. 46} 47 48@define[Macro]{@name{do-entry} @args{(entry archive-input) body @dots{}}} 49@define[Macro]{@name{do-entry} @args{(entry archive-input result) body @dots{}}} 50@desc{Convenient macro. Iterates the given @var{archive-input}'s entries. 51 52The macro is expanded like this; 53 54@codeblock{ 55(do ((@var{entry} (next-entry! @var{archive-input}) (next-entry! @var{archive-input}))) 56 ((not @var{entry}) @var{result}) 57 @var{body} @dots{}) 58} 59 60If the first form is used, then @var{result} is #t. 61} 62 63@define[Method]{@name{extract-entry} @args{entry output-port}} 64@desc{Extract the given archive entry @var{entry} to binary output port 65@var{output-port}. 66} 67 68@define[Function]{@name{extract-all-entries} 69 @args{archive-input :key (destinator archive-entry-name) (overwrite #f)}} 70@desc{Convenient function. Extracts all entries in the given 71@var{archive-input} to the file specified by @var{destinator}. 72 73The keyword argument @var{destinator} must be a procedure which accepts 74one argument, archive entry, and return a string represents the 75file/directory path. 76 77The keyword argument @var{overwrite} is #t, then it overwrites the file. 78If it is #f and there is a file, then it raises an error. 79} 80 81@define[Method]{@name{finish!} @args{archive-input}} 82@desc{Finalize the given archive input.} 83 84@define[Function]{@name{call-with-input-archive} @args{archive-input proc}} 85@desc{@var{archive-input} must be an archive input. 86@var{proc} must be a procedure which accepts one argument. 87 88Call the @var{proc} with archive input and returns the result of the 89@var{proc}. 90 91The @var{archive-input} is finalized by @code{finish!}. 92} 93 94@define[Function]{@name{call-with-input-archive-port} 95 @args{type input-port proc}} 96@desc{Creates an archive input with @var{type} and @var{input-port}, then 97call @code{call-with-input-archive}. 98} 99 100@define[Function]{@name{call-with-input-archive-file} 101 @args{type file proc}} 102@desc{Open file binary input port with given @var{file} and call 103@code{call-with-input-archive-port}. 104} 105 106@subsubsection{Archive output} 107 108@define[Function]{@name{make-output-archive} @args{type output-port}} 109@desc{@var{type} must be a symbol. 110@var{output-port} must be a output port. 111 112Creates an archive output which represents the specified type of archive. 113} 114 115@define[Method]{@name{create-entry} @args{archive-output file}} 116@desc{Creates an archive entry from the given @var{file}. 117 118For implementing user defined archive; 119 120This method is defined like following on the interface library: 121@codeblock{ 122(define-method create-entry ((out <archive-output>) file) 123 (create-entry out file file)) 124} 125So as long as it doesn't have to be distinguished, users don't have to 126implement this method. 127} 128 129@define[Method]{@name{create-entry} @args{archive-output entry-name file}} 130@desc{Creates an archive entry from the given @var{file}. The entry's name 131is @var{entry-name}. This is useful when users want to append entry with 132different name from file name.} 133 134@define[Method]{@name{append-entry!} @args{archive-output entry}} 135@desc{Appends the given @var{entry} to @var{archive-output}.} 136 137@define[Method]{@name{finish!} @args{archive-output}} 138@desc{Finalize the given archive output.} 139 140@define[Function]{@name{call-with-output-archive} @args{archive-output proc}} 141@desc{@var{archive-output} must be an archive output. 142@var{proc} must be a procedure which accepts one argument. 143 144Call the @var{proc} with archive input and returns the result of the 145@var{proc}. 146 147The @var{archive-output} is finalized by @code{finish!}. 148} 149 150@define[Function]{@name{call-with-output-archive-port} 151 @args{type output-port proc}} 152@desc{Creates an archive output with @var{type} and @var{output-port}, then 153call @code{call-with-output-archive}. 154} 155 156@define[Function]{@name{call-with-output-archive-file} 157 @args{type file proc}} 158@desc{Open file binary output port with given @var{file} and call 159@code{call-with-output-archive-port}. 160} 161 162@subsubsection{Entry accessor} 163 164@define[Function]{@name{archive-entry-name} @args{entry}} 165@desc{Returns the name of @var{entry}.} 166 167@define[Function]{@name{archive-entry-type} @args{entry}} 168@desc{Returns the type of @var{entry}. It is either @code{file} or 169@code{directory}. 170} 171 172@subsubsection{Implementing archive implementation library} 173 174To support other archive such as RAR, then you need to create a implementation 175library. 176 177@define[Library]{@name{(archive interface}} 178@desc{The library defines all abstract class and method for the generic 179archive access. 180} 181 182To support @var{foo} archive, then the library name must be 183code{(archive @var{foo})} and it must import @code{(archive interface)}. 184So the library code should look like this; 185 186@codeblock{ 187(library (archive foo) 188 (export) ;; no export procedure is needed 189 (import (rnrs) 190 (close user) 191 (archive interface) 192 ;; so on 193 @dots{}) 194 ;; class and method definitions 195 @dots{} 196) 197} 198 199 200For archiving, the implementation needs to implement following methods and 201extends following classes; 202@codeblock{make-archive-input, next-entry, extract-entry} 203@codeblock{<archive-input> <archive-entry>} 204 205For extracting, the implementation needs to implement following methods and 206extends following classes; 207@codeblock{make-archive-output, create-entry, append-entry!, finish!} 208@codeblock{<archive-output> <archive-entry>} 209 210NOTE: @code{<archive-entry>} may be shared between archiving and extracting. 211 212@define[Class]{@name{<archive-input>}} 213@desc{Abstract class of the archive input. This class has the following 214slot; 215 216@dl-list{ 217 @dl-item["source"]{ 218 Source of the archive. For compatibility of other archive, this should be 219 a binary input port. 220 } 221} 222} 223 224@define[Class]{@name{<archive-output>}} 225@desc{Abstract class of the archive output. This class has the following 226slot; 227 228@dl-list{ 229 @dl-item["sink"]{ 230 Destination of the archive. For compatibility of other archive, this 231 should be a binary output port. 232 } 233} 234} 235 236@define[Class]{@name{<archive-entry>}} 237@desc{Abstract class of the archive entry. This class has the following 238slots; 239 240@dl-list{ 241 @dl-item["name"]{ Entry name. } 242 @dl-item["type"]{ 243 Entry type. For compatibility of other archive, this must be @code{file} or 244 @code{directory}. 245 } 246} 247} 248 249@define[Method]{@name{make-archive-input} @args{type (source <port>)}} 250@define[Method]{@name{make-archive-output} @args{type (sink <port>)}} 251@desc{Creates an archive input or output. @var{type} specifies the 252archive type. It is recommended to use @code{eql} specializer to specify. 253} 254 255@define[Method]{@name{finish!} @args{(in <archive-input>)}} 256@desc{The @code{finish!} method for archive input has a default 257implementation and it does nothing. 258 259Users can specialize the method for own archive input. 260} 261 262The other methods must be implemented as it's described in above section.