Merge pull request #2648 from def-/zipfiles
Make zipfiles module work again
This commit is contained in:
commit
ca67687e3b
1 changed files with 49 additions and 35 deletions
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
## This module implements a zip archive creator/reader/modifier.
|
## This module implements a zip archive creator/reader/modifier.
|
||||||
|
|
||||||
import
|
import
|
||||||
streams, libzip, times, os
|
streams, libzip, times, os, strutils
|
||||||
|
|
||||||
type
|
type
|
||||||
TZipArchive* = object of RootObj ## represents a zip archive
|
TZipArchive* = object of RootObj ## represents a zip archive
|
||||||
|
|
@ -18,14 +18,14 @@ type
|
||||||
w: PZip
|
w: PZip
|
||||||
|
|
||||||
|
|
||||||
proc zipError(z: var TZipArchive) =
|
proc zipError(z: var TZipArchive) =
|
||||||
var e: ref IOError
|
var e: ref IOError
|
||||||
new(e)
|
new(e)
|
||||||
e.msg = $zip_strerror(z.w)
|
e.msg = $zip_strerror(z.w)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
|
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
|
||||||
## Opens a zip file for reading, writing or appending. All file modes are
|
## Opens a zip file for reading, writing or appending. All file modes are
|
||||||
## supported. Returns true iff successful, false otherwise.
|
## supported. Returns true iff successful, false otherwise.
|
||||||
var err, flags: int32
|
var err, flags: int32
|
||||||
case mode
|
case mode
|
||||||
|
|
@ -41,21 +41,21 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
|
||||||
proc close*(z: var TZipArchive) =
|
proc close*(z: var TZipArchive) =
|
||||||
## Closes a zip file.
|
## Closes a zip file.
|
||||||
zip_close(z.w)
|
zip_close(z.w)
|
||||||
|
|
||||||
proc createDir*(z: var TZipArchive, dir: string) =
|
proc createDir*(z: var TZipArchive, dir: string) =
|
||||||
## Creates a directory within the `z` archive. This does not fail if the
|
## Creates a directory within the `z` archive. This does not fail if the
|
||||||
## directory already exists. Note that for adding a file like
|
## directory already exists. Note that for adding a file like
|
||||||
## ``"path1/path2/filename"`` it is not necessary
|
## ``"path1/path2/filename"`` it is not necessary
|
||||||
## to create the ``"path/path2"`` subdirectories - it will be done
|
## to create the ``"path/path2"`` subdirectories - it will be done
|
||||||
## automatically by ``addFile``.
|
## automatically by ``addFile``.
|
||||||
assert(z.mode != fmRead)
|
assert(z.mode != fmRead)
|
||||||
discard zip_add_dir(z.w, dir)
|
discard zip_add_dir(z.w, dir)
|
||||||
zip_error_clear(z.w)
|
zip_error_clear(z.w)
|
||||||
|
|
||||||
proc addFile*(z: var TZipArchive, dest, src: string) =
|
proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||||
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
|
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
|
||||||
## may contain a path that will be created.
|
## may contain a path that will be created.
|
||||||
assert(z.mode != fmRead)
|
assert(z.mode != fmRead)
|
||||||
if not fileExists(src):
|
if not fileExists(src):
|
||||||
raise newException(IOError, "File '" & src & "' does not exist")
|
raise newException(IOError, "File '" & src & "' does not exist")
|
||||||
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
||||||
|
|
@ -67,21 +67,21 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||||
zip_source_free(zipsrc)
|
zip_source_free(zipsrc)
|
||||||
zipError(z)
|
zipError(z)
|
||||||
|
|
||||||
proc addFile*(z: var TZipArchive, file: string) =
|
proc addFile*(z: var TZipArchive, file: string) =
|
||||||
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
|
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
|
||||||
## the name of the destination.
|
## the name of the destination.
|
||||||
addFile(z, file, file)
|
addFile(z, file, file)
|
||||||
|
|
||||||
proc mySourceCallback(state, data: pointer, len: int,
|
proc mySourceCallback(state, data: pointer, len: int,
|
||||||
cmd: TZipSourceCmd): int {.cdecl.} =
|
cmd: TZipSourceCmd): int {.cdecl.} =
|
||||||
var src = cast[Stream](state)
|
var src = cast[Stream](state)
|
||||||
case cmd
|
case cmd
|
||||||
of ZIP_SOURCE_OPEN:
|
of ZIP_SOURCE_OPEN:
|
||||||
if src.setPositionImpl != nil: setPosition(src, 0) # reset
|
if src.setPositionImpl != nil: setPosition(src, 0) # reset
|
||||||
of ZIP_SOURCE_READ:
|
of ZIP_SOURCE_READ:
|
||||||
result = readData(src, data, len)
|
result = readData(src, data, len)
|
||||||
of ZIP_SOURCE_CLOSE: close(src)
|
of ZIP_SOURCE_CLOSE: close(src)
|
||||||
of ZIP_SOURCE_STAT:
|
of ZIP_SOURCE_STAT:
|
||||||
var stat = cast[PZipStat](data)
|
var stat = cast[PZipStat](data)
|
||||||
zip_stat_init(stat)
|
zip_stat_init(stat)
|
||||||
stat.size = high(int32)-1 # we don't know the size
|
stat.size = high(int32)-1 # we don't know the size
|
||||||
|
|
@ -94,8 +94,8 @@ proc mySourceCallback(state, data: pointer, len: int,
|
||||||
result = 2*sizeof(cint)
|
result = 2*sizeof(cint)
|
||||||
of constZIP_SOURCE_FREE: GC_unref(src)
|
of constZIP_SOURCE_FREE: GC_unref(src)
|
||||||
else: assert(false)
|
else: assert(false)
|
||||||
|
|
||||||
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
||||||
## Adds a file named with `dest` to the archive `z`. `dest`
|
## Adds a file named with `dest` to the archive `z`. `dest`
|
||||||
## may contain a path. The file's content is read from the `src` stream.
|
## may contain a path. The file's content is read from the `src` stream.
|
||||||
assert(z.mode != fmRead)
|
assert(z.mode != fmRead)
|
||||||
|
|
@ -105,39 +105,45 @@ proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
||||||
if zip_add(z.w, dest, zipsrc) < 0'i32:
|
if zip_add(z.w, dest, zipsrc) < 0'i32:
|
||||||
zip_source_free(zipsrc)
|
zip_source_free(zipsrc)
|
||||||
zipError(z)
|
zipError(z)
|
||||||
|
|
||||||
# -------------- zip file stream ---------------------------------------------
|
# -------------- zip file stream ---------------------------------------------
|
||||||
|
|
||||||
type
|
type
|
||||||
TZipFileStream = object of StreamObj
|
TZipFileStream = object of StreamObj
|
||||||
f: PZipFile
|
f: PZipFile
|
||||||
|
atEnd: bool
|
||||||
|
|
||||||
PZipFileStream* =
|
PZipFileStream* =
|
||||||
ref TZipFileStream ## a reader stream of a file within a zip archive
|
ref TZipFileStream ## a reader stream of a file within a zip archive
|
||||||
|
|
||||||
proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
|
proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
|
||||||
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
|
||||||
|
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
|
result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
|
||||||
|
if result == 0:
|
||||||
|
PZipFileStream(s).atEnd = true
|
||||||
|
|
||||||
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
|
result.atEnd = false
|
||||||
result.closeImpl = fsClose
|
result.closeImpl = fsClose
|
||||||
result.readDataImpl = fsReadData
|
result.readDataImpl = fsReadData
|
||||||
|
result.atEndImpl = fsAtEnd
|
||||||
# other methods are nil!
|
# other methods are nil!
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
|
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
|
||||||
## returns a stream that can be used to read the file named `filename`
|
## returns a stream that can be used to read the file named `filename`
|
||||||
## from the archive `z`. Returns nil in case of an error.
|
## from the archive `z`. Returns nil in case of an error.
|
||||||
## The returned stream does not support the `setPosition`, `getPosition`,
|
## The returned stream does not support the `setPosition`, `getPosition`,
|
||||||
## `writeData` or `atEnd` methods.
|
## `writeData` or `atEnd` methods.
|
||||||
var x = zip_fopen(z.w, filename, 0'i32)
|
var x = zip_fopen(z.w, filename, 0'i32)
|
||||||
if x != nil: result = newZipFileStream(x)
|
if x != nil: result = newZipFileStream(x)
|
||||||
|
|
||||||
iterator walkFiles*(z: var TZipArchive): string =
|
iterator walkFiles*(z: var TZipArchive): string =
|
||||||
## walks over all files in the archive `z` and returns the filename
|
## walks over all files in the archive `z` and returns the filename
|
||||||
## (including the path).
|
## (including the path).
|
||||||
var i = 0'i32
|
var i = 0'i32
|
||||||
var num = zip_get_num_files(z.w)
|
var num = zip_get_num_files(z.w)
|
||||||
|
|
@ -158,12 +164,20 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
|
||||||
|
|
||||||
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
|
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
|
||||||
## extracts a file from the zip archive `z` to the destination filename.
|
## extracts a file from the zip archive `z` to the destination filename.
|
||||||
var file = newFileStream(dest, fmReadWrite)
|
var file = newFileStream(dest, fmWrite)
|
||||||
extractFile(z, srcFile, file)
|
extractFile(z, srcFile, file)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
proc extractAll*(z: var TZipArchive, dest: string) =
|
proc extractAll*(z: var TZipArchive, dest: string) =
|
||||||
## extracts all files from archive `z` to the destination directory.
|
## extracts all files from archive `z` to the destination directory.
|
||||||
for file in walkFiles(z):
|
for file in walkFiles(z):
|
||||||
extractFile(z, file, dest / extractFilename(file))
|
if file.endsWith("/"):
|
||||||
|
createDir(dest / file)
|
||||||
|
else:
|
||||||
|
extractFile(z, file, dest / file)
|
||||||
|
|
||||||
|
when not defined(testing) and isMainModule:
|
||||||
|
var zip: TZipArchive
|
||||||
|
if not zip.open("nim-0.11.0.zip"):
|
||||||
|
raise newException(IOError, "opening zip failed")
|
||||||
|
zip.extractAll("test")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue