diff --git a/tests/.gitignore b/tests/.gitignore index 3b1e08c..562aa65 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,2 +1,5 @@ nimcache -ziptests \ No newline at end of file +ziptests +zlibtests +gziptests +bzip2tests \ No newline at end of file diff --git a/tests/bzip2tests.nim b/tests/bzip2tests.nim new file mode 100644 index 0000000..5ef541e --- /dev/null +++ b/tests/bzip2tests.nim @@ -0,0 +1,18 @@ +import os, ../zip/bzip2files + +proc readAllAndClose(f: Stream): string = + doAssert(not f.isNil, "error opening stream") + shallowCopy result, f.readAll() + f.close() + +const path = currentSourcePath().splitPath().head + +proc main() = + # reference text data + let text = newFileStream(path / "files/gzipfiletest.txt").readAllAndClose() + # reference BZIP2 archive (made with bzip2: stable 1.0.6 on OSX) + let arch_bz2 = newBz2FileStream(path / "files/gzipfiletest.txt.bz2").readAllAndClose() + + doAssert(arch_bz2 == text) + +main() diff --git a/tests/files/gzipfiletest.txt.bz2 b/tests/files/gzipfiletest.txt.bz2 new file mode 100644 index 0000000..c87bacc Binary files /dev/null and b/tests/files/gzipfiletest.txt.bz2 differ diff --git a/zip.nimble b/zip.nimble index 561f1b9..bee5226 100644 --- a/zip.nimble +++ b/zip.nimble @@ -11,8 +11,13 @@ skipDirs = @["tests"] requires "nim >= 0.10.0" +when defined(nimdistros): + import distros + foreignDep "bzip2" + task tests, "Run lib tests": withDir "tests": exec "nim c -r ziptests" exec "nim c -r zlibtests" exec "nim c -r gziptests" + exec "nim c -r bzip2tests" diff --git a/zip/bzip2.nim b/zip/bzip2.nim new file mode 100644 index 0000000..3572bab --- /dev/null +++ b/zip/bzip2.nim @@ -0,0 +1,25 @@ +when defined(windows): + const libbz2 = "bzip2.dll" +elif defined(macosx): + const libbz2 = "libbz2.dylib" +else: + const libbz2 = "libbz2.so.1" + +type + Pbytef* = cstring + Bz2File* = pointer + +proc bz2libVersion*(): cstring {.cdecl, dynlib: libbz2, + importc: "BZ2_bzlibVersion".} + +proc bz2open*(path: cstring, mode: cstring): Bz2File {.cdecl, dynlib: libbz2, + importc: "BZ2_bzopen".} + +proc bz2read*(thefile: Bz2File, buf: pointer, length: int): int32 {.cdecl, + dynlib: libbz2, importc: "BZ2_bzread".} + +proc bz2close*(thefile: Bz2File): int32 {.cdecl, dynlib: libbz2, + importc: "BZ2_bzclose".} + +proc bz2error*(thefile: Bz2File, errnum: var int32): Pbytef {.cdecl, + dynlib: libbz2, importc: "BZ2_bzerror".} diff --git a/zip/bzip2files.nim b/zip/bzip2files.nim new file mode 100644 index 0000000..3c1f78d --- /dev/null +++ b/zip/bzip2files.nim @@ -0,0 +1,37 @@ +import os +import bzip2 +import streams +export streams + +## This module implements a bzip2file stream for reading. + +type + Bz2FileStream* = ref object of Stream + mode: FileMode + f: Bz2File + +proc fsClose(s: Stream) = + if not Bz2FileStream(s).f.isNil: + discard bz2close(Bz2FileStream(s).f) + Bz2FileStream(s).f = nil + +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = bz2read(Bz2FileStream(s).f, buffer, bufLen).int + if result == -1: + raise newException(IOError, "cannot read from stream!") + +proc newBz2FileStream*(filename: string, mode=fmRead): Bz2FileStream = + ## Opens a Bz2file as a file stream. `mode` can only be ``fmRead``. + new(result) + case mode + of fmRead: result.f = bz2open(filename, "rb") + else: raise newException(IOError, "unsupported file mode '" & $mode & + "' for Bz2FileStream!") + if result.f.isNil: + let err = osLastError() + if err != OSErrorCode(0'i32): + raiseOSError(err) + + result.mode = mode + result.closeImpl = fsClose + result.readDataImpl = fsReadData