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.