(archive) - Generic archive interface

Library archive

This library provides generic interface to access archive libraries. Sagittarius supports tar and zip.

Following code describes a typical use of the library;

(import (rnrs) (archive))

;; extract file "bar.txt" from "foo.zip"
(call-with-input-archive-file 'zip "foo.zip"
  (lambda (zip-in)
    (do-entry (e zip-in)
      (when (string=? (archive-entry-name e) "bar.txt")
        (call-with-output-file "bar.txt"
          (lambda (out) (extract-entry e out))
           :transcoder #f)))))

;; archive "bar.txt" into foo.tar
(call-with-output-archive-file 'tar "foo.tar"
  (lambda (tar-out)
    (append-entry! tar-out (create-entry tar-out "bar.txt"))))

Following sections use type as a supported archive type. More precisely, if it's a supported archive type then there must be a library named (archive _type_).

Archive input

type must be a symbol and supported archive type. input-port must be a binary input port.

Creates an archive input which represents the specified type of archive.

Retrieves next entry of the given archive input. If there is no entry, then it returns #f.

Convenient macro. Iterates the given archive-input's entries.

The macro is expanded like this;

(do ((_entry_ (next-entry! _archive-input_) (next-entry! _archive-input_)))
    ((not _entry_) _result_)
  _body_ ...)

If the first form is used, then result is #t.

Extract the given archive entry entry to binary output port output-port.

Convenient function. Extracts all entries in the given archive-input to the file specified by destinator.

The keyword argument destinator must be a procedure which accepts one argument, archive entry, and return a string represents the file/directory path.

The keyword argument overwrite is #t, then it overwrites the file. If it is #f and there is a file, then it raises an error.

Finalize the given archive input.

archive-input must be an archive input. proc must be a procedure which accepts one argument.

Call the proc with archive input and returns the result of the proc.

The archive-input is finalized by finish!.

Creates an archive input with type and input-port, then call call-with-input-archive.

Open file binary input port with given file and call call-with-input-archive-port.

Archive output

type must be a symbol. output-port must be a output port.

Creates an archive output which represents the specified type of archive.

Creates an archive entry from the given file.

For implementing user defined archive;

This method is defined like following on the interface library:

(define-method create-entry ((out <archive-output>) file)
  (create-entry out file file))

So as long as it doesn't have to be distinguished, users don't have to implement this method.

Creates an archive entry from the given file. The entry's name is entry-name. This is useful when users want to append entry with different name from file name.

Appends the given entry to archive-output.

Finalize the given archive output.

archive-output must be an archive output. proc must be a procedure which accepts one argument.

Call the proc with archive input and returns the result of the proc.

The archive-output is finalized by finish!.

Creates an archive output with type and output-port, then call call-with-output-archive.

Open file binary output port with given file and call call-with-output-archive-port.

Entry accessor

Returns the name of entry.

Returns the type of entry. It is either file or directory.

Implementing archive implementation library

To support other archive such as RAR, then you need to create a implementation library.

The library defines all abstract class and method for the generic archive access.

To support foo archive, then the library name must be code{(archive foo)} and it must import (archive interface). So the library code should look like this;

(library (archive foo)
  (export) ;; no export procedure is needed
  (import (rnrs)
          (close user)
          (archive interface)
          ;; so on
          ...)
  ;; class and method definitions
  ...)

For archiving, the implementation needs to implement following methods and extends following classes;

make-archive-input, next-entry, extract-entry
<archive-input> <archive-entry>

For extracting, the implementation needs to implement following methods and extends following classes;

make-archive-output, create-entry, append-entry!, finish!
<archive-output> <archive-entry>

NOTE: <archive-entry> may be shared between archiving and extracting.

Abstract class of the archive input. This class has the following slot;

source

Source of the archive. For compatibility of other archive, this should be a binary input port.

Abstract class of the archive output. This class has the following slot;

sink

Destination of the archive. For compatibility of other archive, this should be a binary output port.

Abstract class of the archive entry. This class has the following slots;

name

Entry name.

type

Entry type. For compatibility of other archive, this must be file or directory.

Creates an archive input or output. type specifies the archive type. It is recommended to use eql specializer to specify.

The finish! method for archive input has a default implementation and it does nothing.

Users can specialize the method for own archive input.

The other methods must be implemented as it's described in above section.